aboutsummaryrefslogtreecommitdiff
path: root/viewer/src/services/indexfactory.ts
diff options
context:
space:
mode:
Diffstat (limited to 'viewer/src/services/indexfactory.ts')
-rw-r--r--viewer/src/services/indexfactory.ts157
1 files changed, 0 insertions, 157 deletions
diff --git a/viewer/src/services/indexfactory.ts b/viewer/src/services/indexfactory.ts
deleted file mode 100644
index 691a765..0000000
--- a/viewer/src/services/indexfactory.ts
+++ /dev/null
@@ -1,157 +0,0 @@
1/* ldgallery - A static generator which turns a collection of tagged
2-- pictures into a searchable web gallery.
3--
4-- Copyright (C) 2019-2020 Guillaume FOUET
5--
6-- This program is free software: you can redistribute it and/or modify
7-- it under the terms of the GNU Affero General Public License as
8-- published by the Free Software Foundation, either version 3 of the
9-- License, or (at your option) any later version.
10--
11-- This program is distributed in the hope that it will be useful,
12-- but WITHOUT ANY WARRANTY; without even the implied warranty of
13-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14-- GNU Affero General Public License for more details.
15--
16-- You should have received a copy of the GNU Affero General Public License
17-- along with this program. If not, see <https://www.gnu.org/licenses/>.
18*/
19
20import { Item, RawTag } from "@/@types/gallery";
21import { ItemType } from "@/@types/ItemType";
22import { Operation } from "@/@types/Operation";
23import { TagCategory, TagIndex, TagNode, TagSearch } from "@/@types/tag";
24import Navigation from "@/services/navigation";
25
26export default class IndexFactory {
27 public static generateTags(root: Item | null): TagIndex {
28 const tagsIndex: TagIndex = {};
29 if (root) IndexFactory.pushTagsForItem(tagsIndex, root);
30 return tagsIndex;
31 }
32
33 // Pushes all tags for a root item (and its children) to the index
34 private static pushTagsForItem(tagsIndex: TagIndex, item: Item): void {
35 if (item.properties.type === ItemType.DIRECTORY) {
36 item.properties.items.forEach(item => this.pushTagsForItem(tagsIndex, item));
37 return; // Directories are not indexed
38 }
39 for (const tag of item.tags) {
40 const parts = tag.split(":");
41 let lastPart: string | null = null;
42 for (const part of parts) {
43 tagsIndex[part] = IndexFactory.pushPartToIndex(tagsIndex[part], part, item, !Boolean(lastPart));
44 if (lastPart) {
45 const children = tagsIndex[lastPart].children;
46 children[part] = IndexFactory.pushPartToIndex(children[part], part, item, false);
47 }
48 lastPart = part;
49 }
50 if (lastPart) tagsIndex[lastPart].childPart = true;
51 }
52 }
53
54 private static pushPartToIndex(index: TagNode, part: string, item: Item, rootPart: boolean): TagNode {
55 if (!index)
56 index = {
57 tag: part,
58 tagfiltered: Navigation.normalize(part),
59 rootPart,
60 childPart: !rootPart,
61 items: [],
62 children: {},
63 };
64 else if (rootPart) index.rootPart = true;
65 else index.childPart = true;
66
67 if (!index.items.includes(item)) index.items.push(item);
68 return index;
69 }
70
71 // ---
72
73 public static searchTags(tagsIndex: TagIndex, filter: string, strict: boolean): TagSearch[] {
74 let search: TagSearch[] = [];
75 if (tagsIndex && filter) {
76 const operation = IndexFactory.extractOperation(filter);
77 if (operation !== Operation.INTERSECTION) filter = filter.slice(1);
78 if (filter.includes(":")) {
79 const filterParts = filter.split(":");
80 search = this.searchTagsFromFilterWithCategory(tagsIndex, operation, filterParts[0], filterParts[1], strict);
81 } else {
82 search = this.searchTagsFromFilter(tagsIndex, operation, filter, strict);
83 }
84 }
85 return search;
86 }
87
88 private static extractOperation(filter: string): Operation {
89 const first = filter.slice(0, 1);
90 switch (first) {
91 case Operation.ADDITION:
92 case Operation.SUBSTRACTION:
93 return first;
94 default:
95 return Operation.INTERSECTION;
96 }
97 }
98
99 private static searchTagsFromFilterWithCategory(
100 tagsIndex: TagIndex,
101 operation: Operation,
102 category: string,
103 disambiguation: string,
104 strict: boolean
105 ): TagSearch[] {
106 category = Navigation.normalize(category);
107 disambiguation = Navigation.normalize(disambiguation);
108 return Object.values(tagsIndex)
109 .filter(node => IndexFactory.matches(node, category, strict))
110 .flatMap(node =>
111 Object.values(node.children)
112 .filter(child => IndexFactory.matches(child, disambiguation, strict))
113 .map(child => ({ ...child, parent: node, operation, display: `${operation}${node.tag}:${child.tag}` }))
114 );
115 }
116
117 private static searchTagsFromFilter(
118 tagsIndex: TagIndex,
119 operation: Operation,
120 filter: string,
121 strict: boolean
122 ): TagSearch[] {
123 filter = Navigation.normalize(filter);
124 return Object.values(tagsIndex)
125 .filter(node => IndexFactory.matches(node, filter, strict))
126 .map(node => ({ ...node, operation, display: `${operation}${node.tag}` }));
127 }
128
129 private static matches(node: TagNode, filter: string, strict: boolean): boolean {
130 if (strict) return node.tagfiltered === filter;
131 return node.tagfiltered.includes(filter);
132 }
133
134 // ---
135
136 public static generateCategories(tagsIndex: TagIndex, categoryTags?: RawTag[]): TagCategory[] {
137 if (!categoryTags?.length) return [{ tag: "", index: tagsIndex }];
138
139 const tagsCategories: TagCategory[] = [];
140 const tagsRemaining = new Map(Object.entries(tagsIndex));
141 categoryTags
142 .map(tag => ({ tag, index: tagsIndex[tag]?.children }))
143 .filter(category => category.index && Object.keys(category.index).length)
144 .forEach(category => {
145 tagsCategories.push(category);
146 [category.tag, ...Object.values(category.index).map(node => node.tag)]
147 .filter(tag => IndexFactory.isDiscriminantTagOnly(categoryTags, tagsIndex[tag]))
148 .forEach(tag => tagsRemaining.delete(tag));
149 });
150 tagsCategories.push({ tag: "", index: Object.fromEntries(tagsRemaining) });
151 return tagsCategories;
152 }
153
154 private static isDiscriminantTagOnly(tags: RawTag[], node: TagNode): boolean {
155 return !tags.includes(node.tag) || !node.childPart;
156 }
157}