From 370e3db3455f548699ff5e046e0f8dcc304991ac Mon Sep 17 00:00:00 2001
From: Zero~Informatique
Date: Fri, 14 Feb 2020 09:19:53 +0100
Subject: viewer: major code and search mode overhaul
Updated libraries to the lastest version
SCSS Formatter as suggested VSC extensions
Renamed toolbar-color by scrollbar-color
LD components use Props in favor of touching the stores directly (when possible)
Moved most common algorithms to a "services" folder
Complete search overhaul (lots of code change)
---
viewer/src/services/indexfactory.ts | 101 ++++++++++++++++++++++++++++++++++++
1 file changed, 101 insertions(+)
create mode 100644 viewer/src/services/indexfactory.ts
(limited to 'viewer/src/services/indexfactory.ts')
diff --git a/viewer/src/services/indexfactory.ts b/viewer/src/services/indexfactory.ts
new file mode 100644
index 0000000..a6bc865
--- /dev/null
+++ b/viewer/src/services/indexfactory.ts
@@ -0,0 +1,101 @@
+/* ldgallery - A static generator which turns a collection of tagged
+-- pictures into a searchable web gallery.
+--
+-- Copyright (C) 2019-2020 Guillaume FOUET
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero General Public License as
+-- published by the Free Software Foundation, either version 3 of the
+-- License, or (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with this program. If not, see .
+*/
+
+import { Operation } from '@/@types/Operation';
+import Navigation from '@/services/navigation';
+
+export default class IndexFactory {
+
+ public static generateTags(root: Gallery.Item | null): Tag.Index {
+ let tagsIndex: Tag.Index = {};
+ if (root) IndexFactory.pushTagsForItem(tagsIndex, root);
+ return tagsIndex;
+ }
+
+ // Pushes all tags for a root item (and its children) to the index
+ private static pushTagsForItem(tagsIndex: Tag.Index, item: Gallery.Item): void {
+ console.log("IndexingTagsFor: ", item.path);
+ if (item.properties.type === "directory") {
+ item.properties.items.forEach(item => this.pushTagsForItem(tagsIndex, item));
+ return; // Directories are not indexed
+ }
+ for (const tag of item.tags) {
+ const parts = tag.split('.');
+ let lastPart: string | null = null;
+ for (const part of parts) {
+ if (!tagsIndex[part]) tagsIndex[part] = { tag: part, tagfiltered: Navigation.normalize(part), items: [], children: {} };
+ if (!tagsIndex[part].items.includes(item)) tagsIndex[part].items.push(item);
+ if (lastPart) tagsIndex[lastPart].children[part] = tagsIndex[part];
+ lastPart = part;
+ }
+ }
+ }
+
+ // ---
+
+
+ public static searchTags(tagsIndex: Tag.Index, filter: string): Tag.Search[] {
+ let search: Tag.Search[] = [];
+ if (tagsIndex && filter) {
+ const operation = IndexFactory.extractOperation(filter);
+ if (operation !== Operation.INTERSECTION) filter = filter.slice(1);
+ if (filter.includes(":")) {
+ const filterParts = filter.split(":");
+ search = this.searchTagsFromFilterWithCategory(tagsIndex, operation, filterParts[0], filterParts[1]);
+ } else {
+ search = this.searchTagsFromFilter(tagsIndex, operation, filter);
+ }
+ }
+ return search;
+ }
+
+ private static extractOperation(filter: string): Operation {
+ const first = filter.slice(0, 1);
+ switch (first) {
+ case Operation.ADDITION:
+ case Operation.SUBSTRACTION:
+ return first;
+ default:
+ return Operation.INTERSECTION;
+ }
+ }
+
+ private static searchTagsFromFilterWithCategory(
+ tagsIndex: Tag.Index,
+ operation: Operation,
+ category: string,
+ disambiguation: string
+ ): Tag.Search[] {
+ disambiguation = Navigation.normalize(disambiguation);
+ return Object.values(tagsIndex)
+ .filter(node => node.tag.includes(category))
+ .flatMap(node =>
+ Object.values(node.children)
+ .filter(child => child.tagfiltered.includes(disambiguation))
+ .map(child => ({ ...child, parent: node, operation, display: `${operation}${node.tag}:${child.tag}` }))
+ );
+ }
+
+ private static searchTagsFromFilter(tagsIndex: Tag.Index, operation: Operation, filter: string): Tag.Search[] {
+ filter = Navigation.normalize(filter);
+ return Object.values(tagsIndex)
+ .filter(node => node.tagfiltered.includes(filter))
+ .map(node => ({ ...node, operation, display: `${operation}${node.tag}` }));
+ }
+}
--
cgit v1.2.3
From c7fa5bd40d0e5c9ea50190a90a0ccfee8ad96c25 Mon Sep 17 00:00:00 2001
From: pacien
Date: Thu, 27 Feb 2020 21:05:51 +0100
Subject: viewer: use colon as tag separator instead of dot
For consistency with the query language
and allowing the use of the very common dot in tags.
This also introduces a migration script.
GitHub: closes #164
---
viewer/src/services/indexfactory.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'viewer/src/services/indexfactory.ts')
diff --git a/viewer/src/services/indexfactory.ts b/viewer/src/services/indexfactory.ts
index a6bc865..6fed6cc 100644
--- a/viewer/src/services/indexfactory.ts
+++ b/viewer/src/services/indexfactory.ts
@@ -36,7 +36,7 @@ export default class IndexFactory {
return; // Directories are not indexed
}
for (const tag of item.tags) {
- const parts = tag.split('.');
+ const parts = tag.split(':');
let lastPart: string | null = null;
for (const part of parts) {
if (!tagsIndex[part]) tagsIndex[part] = { tag: part, tagfiltered: Navigation.normalize(part), items: [], children: {} };
--
cgit v1.2.3
From f2ff937fe4a5782741886ef4920fd0e284775463 Mon Sep 17 00:00:00 2001
From: Zero~Informatique
Date: Thu, 27 Feb 2020 23:26:00 +0100
Subject: viewer: tag index bugfix
Search from the URL requires a strict match instead of a loose match
Category search was case sensitive
Category + disambiguation was matching like an intersection of both tags instead of being hard-coupled
Removed the logs for the release (coming soon)
---
viewer/src/services/indexfactory.ts | 36 ++++++++++++++++++++++++------------
1 file changed, 24 insertions(+), 12 deletions(-)
(limited to 'viewer/src/services/indexfactory.ts')
diff --git a/viewer/src/services/indexfactory.ts b/viewer/src/services/indexfactory.ts
index 6fed6cc..45abcd5 100644
--- a/viewer/src/services/indexfactory.ts
+++ b/viewer/src/services/indexfactory.ts
@@ -30,7 +30,6 @@ export default class IndexFactory {
// Pushes all tags for a root item (and its children) to the index
private static pushTagsForItem(tagsIndex: Tag.Index, item: Gallery.Item): void {
- console.log("IndexingTagsFor: ", item.path);
if (item.properties.type === "directory") {
item.properties.items.forEach(item => this.pushTagsForItem(tagsIndex, item));
return; // Directories are not indexed
@@ -39,27 +38,35 @@ export default class IndexFactory {
const parts = tag.split(':');
let lastPart: string | null = null;
for (const part of parts) {
- if (!tagsIndex[part]) tagsIndex[part] = { tag: part, tagfiltered: Navigation.normalize(part), items: [], children: {} };
- if (!tagsIndex[part].items.includes(item)) tagsIndex[part].items.push(item);
- if (lastPart) tagsIndex[lastPart].children[part] = tagsIndex[part];
+ tagsIndex[part] = IndexFactory.pushPartToIndex(tagsIndex[part], part, item);
+ if (lastPart) {
+ const children = tagsIndex[lastPart].children;
+ children[part] = IndexFactory.pushPartToIndex(children[part], part, item);
+ }
lastPart = part;
}
}
}
+ private static pushPartToIndex(index: Tag.Node, part: string, item: Gallery.Item): Tag.Node {
+ if (!index) index = { tag: part, tagfiltered: Navigation.normalize(part), items: [], children: {} };
+ if (!index.items.includes(item)) index.items.push(item);
+ return index;
+ }
+
// ---
- public static searchTags(tagsIndex: Tag.Index, filter: string): Tag.Search[] {
+ public static searchTags(tagsIndex: Tag.Index, filter: string, strict: boolean): Tag.Search[] {
let search: Tag.Search[] = [];
if (tagsIndex && filter) {
const operation = IndexFactory.extractOperation(filter);
if (operation !== Operation.INTERSECTION) filter = filter.slice(1);
if (filter.includes(":")) {
const filterParts = filter.split(":");
- search = this.searchTagsFromFilterWithCategory(tagsIndex, operation, filterParts[0], filterParts[1]);
+ search = this.searchTagsFromFilterWithCategory(tagsIndex, operation, filterParts[0], filterParts[1], strict);
} else {
- search = this.searchTagsFromFilter(tagsIndex, operation, filter);
+ search = this.searchTagsFromFilter(tagsIndex, operation, filter, strict);
}
}
return search;
@@ -80,22 +87,27 @@ export default class IndexFactory {
tagsIndex: Tag.Index,
operation: Operation,
category: string,
- disambiguation: string
+ disambiguation: string,
+ strict: boolean
): Tag.Search[] {
+ category = Navigation.normalize(category);
disambiguation = Navigation.normalize(disambiguation);
return Object.values(tagsIndex)
- .filter(node => node.tag.includes(category))
+ .filter(node => strict || node.tagfiltered.includes(category))
+ .filter(node => !strict || node.tagfiltered === category)
.flatMap(node =>
Object.values(node.children)
- .filter(child => child.tagfiltered.includes(disambiguation))
+ .filter(child => strict || child.tagfiltered.includes(disambiguation))
+ .filter(child => !strict || child.tagfiltered === disambiguation)
.map(child => ({ ...child, parent: node, operation, display: `${operation}${node.tag}:${child.tag}` }))
);
}
- private static searchTagsFromFilter(tagsIndex: Tag.Index, operation: Operation, filter: string): Tag.Search[] {
+ private static searchTagsFromFilter(tagsIndex: Tag.Index, operation: Operation, filter: string, strict: boolean): Tag.Search[] {
filter = Navigation.normalize(filter);
return Object.values(tagsIndex)
- .filter(node => node.tagfiltered.includes(filter))
+ .filter(node => strict || node.tagfiltered.includes(filter))
+ .filter(node => !strict || node.tagfiltered === filter)
.map(node => ({ ...node, operation, display: `${operation}${node.tag}` }));
}
}
--
cgit v1.2.3
From 8d889762872501eebd5edb5d7cacddfd4cd55ad4 Mon Sep 17 00:00:00 2001
From: Zero~Informatique
Date: Fri, 28 Feb 2020 04:09:40 +0100
Subject: viewer: more minor architectural improvement
---
viewer/src/services/indexfactory.ts | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
(limited to 'viewer/src/services/indexfactory.ts')
diff --git a/viewer/src/services/indexfactory.ts b/viewer/src/services/indexfactory.ts
index 45abcd5..a31f3ef 100644
--- a/viewer/src/services/indexfactory.ts
+++ b/viewer/src/services/indexfactory.ts
@@ -93,12 +93,10 @@ export default class IndexFactory {
category = Navigation.normalize(category);
disambiguation = Navigation.normalize(disambiguation);
return Object.values(tagsIndex)
- .filter(node => strict || node.tagfiltered.includes(category))
- .filter(node => !strict || node.tagfiltered === category)
+ .filter(node => IndexFactory.matches(node, category, strict))
.flatMap(node =>
Object.values(node.children)
- .filter(child => strict || child.tagfiltered.includes(disambiguation))
- .filter(child => !strict || child.tagfiltered === disambiguation)
+ .filter(child => IndexFactory.matches(child, disambiguation, strict))
.map(child => ({ ...child, parent: node, operation, display: `${operation}${node.tag}:${child.tag}` }))
);
}
@@ -106,8 +104,12 @@ export default class IndexFactory {
private static searchTagsFromFilter(tagsIndex: Tag.Index, operation: Operation, filter: string, strict: boolean): Tag.Search[] {
filter = Navigation.normalize(filter);
return Object.values(tagsIndex)
- .filter(node => strict || node.tagfiltered.includes(filter))
- .filter(node => !strict || node.tagfiltered === filter)
+ .filter(node => IndexFactory.matches(node, filter, strict))
.map(node => ({ ...node, operation, display: `${operation}${node.tag}` }));
}
+
+ private static matches(node: Tag.Node, filter: string, strict: boolean): boolean {
+ if (strict) return node.tagfiltered === filter;
+ return node.tagfiltered.includes(filter)
+ }
}
--
cgit v1.2.3
From 577f49ab6e1fd9cd8007804a13dea1471ee2fb1f Mon Sep 17 00:00:00 2001
From: Zero~Informatique
Date: Fri, 3 Apr 2020 03:42:35 +0200
Subject: viewer: tag categories implementation
GitHub: Resolves #29
---
viewer/src/services/indexfactory.ts | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
(limited to 'viewer/src/services/indexfactory.ts')
diff --git a/viewer/src/services/indexfactory.ts b/viewer/src/services/indexfactory.ts
index a31f3ef..466b509 100644
--- a/viewer/src/services/indexfactory.ts
+++ b/viewer/src/services/indexfactory.ts
@@ -112,4 +112,23 @@ export default class IndexFactory {
if (strict) return node.tagfiltered === filter;
return node.tagfiltered.includes(filter)
}
+
+ // ---
+
+ public static generateCategories(tagsIndex: Tag.Index, tags?: Gallery.RawTag[]): Tag.Category[] {
+ if (!tags?.length) return [{ tag: "", index: tagsIndex }];
+
+ const tagsCategories: Tag.Category[] = [];
+ const tagsRemaining = new Map(Object.entries(tagsIndex));
+ tags
+ .map(tag => ({ tag, index: tagsIndex[tag]?.children }))
+ .filter(category => category.index && Object.keys(category.index).length)
+ .forEach(category => {
+ tagsCategories.push(category);
+ tagsRemaining.delete(category.tag);
+ Object.values(category.index).map(node => node.tag).forEach(tag => tagsRemaining.delete(tag));
+ });
+ tagsCategories.push({ tag: "", index: Object.fromEntries(tagsRemaining) });
+ return tagsCategories;
+ }
}
--
cgit v1.2.3
From ce04802f300ba627a3b9e9612d938b825045e63f Mon Sep 17 00:00:00 2001
From: Zero~Informatique
Date: Sat, 4 Apr 2020 01:36:34 +0200
Subject: viewer: tag categories implementation
fixed single tags not appearing in the "Other filters" special category, following code review
GitHub: Resolves #29
---
viewer/src/services/indexfactory.ts | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
(limited to 'viewer/src/services/indexfactory.ts')
diff --git a/viewer/src/services/indexfactory.ts b/viewer/src/services/indexfactory.ts
index 466b509..0a84951 100644
--- a/viewer/src/services/indexfactory.ts
+++ b/viewer/src/services/indexfactory.ts
@@ -38,18 +38,19 @@ export default class IndexFactory {
const parts = tag.split(':');
let lastPart: string | null = null;
for (const part of parts) {
- tagsIndex[part] = IndexFactory.pushPartToIndex(tagsIndex[part], part, item);
+ tagsIndex[part] = IndexFactory.pushPartToIndex(tagsIndex[part], part, item, !Boolean(lastPart));
if (lastPart) {
const children = tagsIndex[lastPart].children;
- children[part] = IndexFactory.pushPartToIndex(children[part], part, item);
+ children[part] = IndexFactory.pushPartToIndex(children[part], part, item, false);
}
lastPart = part;
}
}
}
- private static pushPartToIndex(index: Tag.Node, part: string, item: Gallery.Item): Tag.Node {
- if (!index) index = { tag: part, tagfiltered: Navigation.normalize(part), items: [], children: {} };
+ private static pushPartToIndex(index: Tag.Node, part: string, item: Gallery.Item, rootPart: boolean): Tag.Node {
+ if (!index) index = { tag: part, tagfiltered: Navigation.normalize(part), rootPart, items: [], children: {} };
+ else if (rootPart) index.rootPart = true;
if (!index.items.includes(item)) index.items.push(item);
return index;
}
@@ -125,8 +126,14 @@ export default class IndexFactory {
.filter(category => category.index && Object.keys(category.index).length)
.forEach(category => {
tagsCategories.push(category);
- tagsRemaining.delete(category.tag);
- Object.values(category.index).map(node => node.tag).forEach(tag => tagsRemaining.delete(tag));
+
+ if (!tagsIndex[category.tag].rootPart)
+ tagsRemaining.delete(category.tag);
+
+ Object.values(category.index)
+ .map(node => node.tag)
+ .filter(tag => !tagsIndex[tag].rootPart)
+ .forEach(tag => tagsRemaining.delete(tag));
});
tagsCategories.push({ tag: "", index: Object.fromEntries(tagsRemaining) });
return tagsCategories;
--
cgit v1.2.3
From 84090e0f534cfa8bf601ae6df21e5df695fd149a Mon Sep 17 00:00:00 2001
From: Zero~Informatique
Date: Sat, 4 Apr 2020 02:24:10 +0200
Subject: viewer: tag categories implementation
code cleaning
GitHub: Resolves #29
---
viewer/src/services/indexfactory.ts | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
(limited to 'viewer/src/services/indexfactory.ts')
diff --git a/viewer/src/services/indexfactory.ts b/viewer/src/services/indexfactory.ts
index 0a84951..25027f3 100644
--- a/viewer/src/services/indexfactory.ts
+++ b/viewer/src/services/indexfactory.ts
@@ -127,11 +127,7 @@ export default class IndexFactory {
.forEach(category => {
tagsCategories.push(category);
- if (!tagsIndex[category.tag].rootPart)
- tagsRemaining.delete(category.tag);
-
- Object.values(category.index)
- .map(node => node.tag)
+ [category.tag, ...Object.values(category.index).map(node => node.tag)]
.filter(tag => !tagsIndex[tag].rootPart)
.forEach(tag => tagsRemaining.delete(tag));
});
--
cgit v1.2.3
From c9c69214dcb16a581525eee319ced6e7d9c98bf3 Mon Sep 17 00:00:00 2001
From: Zero~Informatique
Date: Fri, 17 Apr 2020 23:19:49 +0200
Subject: viewer: fixed tag categories proposed again in "other filters"
github: resolves #186
---
viewer/src/services/indexfactory.ts | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
(limited to 'viewer/src/services/indexfactory.ts')
diff --git a/viewer/src/services/indexfactory.ts b/viewer/src/services/indexfactory.ts
index 25027f3..18a2800 100644
--- a/viewer/src/services/indexfactory.ts
+++ b/viewer/src/services/indexfactory.ts
@@ -45,12 +45,15 @@ export default class IndexFactory {
}
lastPart = part;
}
+ if (lastPart) tagsIndex[lastPart].childPart = true;
}
}
private static pushPartToIndex(index: Tag.Node, part: string, item: Gallery.Item, rootPart: boolean): Tag.Node {
- if (!index) index = { tag: part, tagfiltered: Navigation.normalize(part), rootPart, items: [], children: {} };
+ if (!index) index = { tag: part, tagfiltered: Navigation.normalize(part), rootPart, childPart: !rootPart, items: [], children: {} };
else if (rootPart) index.rootPart = true;
+ else index.childPart = true;
+
if (!index.items.includes(item)) index.items.push(item);
return index;
}
@@ -116,22 +119,25 @@ export default class IndexFactory {
// ---
- public static generateCategories(tagsIndex: Tag.Index, tags?: Gallery.RawTag[]): Tag.Category[] {
- if (!tags?.length) return [{ tag: "", index: tagsIndex }];
+ public static generateCategories(tagsIndex: Tag.Index, categoryTags?: Gallery.RawTag[]): Tag.Category[] {
+ if (!categoryTags?.length) return [{ tag: "", index: tagsIndex }];
const tagsCategories: Tag.Category[] = [];
const tagsRemaining = new Map(Object.entries(tagsIndex));
- tags
+ categoryTags
.map(tag => ({ tag, index: tagsIndex[tag]?.children }))
.filter(category => category.index && Object.keys(category.index).length)
.forEach(category => {
tagsCategories.push(category);
-
[category.tag, ...Object.values(category.index).map(node => node.tag)]
- .filter(tag => !tagsIndex[tag].rootPart)
+ .filter(tag => IndexFactory.isDiscriminantTagOnly(categoryTags, tagsIndex[tag]))
.forEach(tag => tagsRemaining.delete(tag));
});
tagsCategories.push({ tag: "", index: Object.fromEntries(tagsRemaining) });
return tagsCategories;
}
+
+ private static isDiscriminantTagOnly(tags: Gallery.RawTag[], node: Tag.Node): boolean {
+ return !tags.includes(node.tag) || !node.childPart;
+ }
}
--
cgit v1.2.3
From ccecfd9421f4550a71134cd46e1388e486f8c564 Mon Sep 17 00:00:00 2001
From: Zero~Informatique
Date: Tue, 28 Apr 2020 03:47:39 +0200
Subject: viewer: global formatting unification
---
viewer/src/services/indexfactory.ts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
(limited to 'viewer/src/services/indexfactory.ts')
diff --git a/viewer/src/services/indexfactory.ts b/viewer/src/services/indexfactory.ts
index 18a2800..e402185 100644
--- a/viewer/src/services/indexfactory.ts
+++ b/viewer/src/services/indexfactory.ts
@@ -17,8 +17,8 @@
-- along with this program. If not, see .
*/
-import { Operation } from '@/@types/Operation';
-import Navigation from '@/services/navigation';
+import { Operation } from "@/@types/Operation";
+import Navigation from "@/services/navigation";
export default class IndexFactory {
@@ -35,7 +35,7 @@ export default class IndexFactory {
return; // Directories are not indexed
}
for (const tag of item.tags) {
- const parts = tag.split(':');
+ const parts = tag.split(":");
let lastPart: string | null = null;
for (const part of parts) {
tagsIndex[part] = IndexFactory.pushPartToIndex(tagsIndex[part], part, item, !Boolean(lastPart));
--
cgit v1.2.3