aboutsummaryrefslogtreecommitdiff
path: root/viewer/src/services
diff options
context:
space:
mode:
Diffstat (limited to 'viewer/src/services')
-rw-r--r--viewer/src/services/fetchWithCheck.ts7
-rw-r--r--viewer/src/services/indexfactory.ts32
-rw-r--r--viewer/src/services/indexsearch.ts24
-rw-r--r--viewer/src/services/itemComparators.ts13
-rw-r--r--viewer/src/services/ldzoom.ts9
-rw-r--r--viewer/src/services/navigation.ts15
6 files changed, 56 insertions, 44 deletions
diff --git a/viewer/src/services/fetchWithCheck.ts b/viewer/src/services/fetchWithCheck.ts
new file mode 100644
index 0000000..e84e8b6
--- /dev/null
+++ b/viewer/src/services/fetchWithCheck.ts
@@ -0,0 +1,7 @@
1export default class FetchWithCheck {
2 static async get(url: RequestInfo): Promise<Response> {
3 const response = await fetch(url);
4 if (!response.ok) throw new Error(`${response.status}: ${response.statusText}`);
5 return response;
6 }
7}
diff --git a/viewer/src/services/indexfactory.ts b/viewer/src/services/indexfactory.ts
index 4b28a60..691a765 100644
--- a/viewer/src/services/indexfactory.ts
+++ b/viewer/src/services/indexfactory.ts
@@ -17,19 +17,21 @@
17-- along with this program. If not, see <https://www.gnu.org/licenses/>. 17-- along with this program. If not, see <https://www.gnu.org/licenses/>.
18*/ 18*/
19 19
20import { Operation } from "@/@types/Operation"; 20import { Item, RawTag } from "@/@types/gallery";
21import { ItemType } from "@/@types/ItemType"; 21import { ItemType } from "@/@types/ItemType";
22import { Operation } from "@/@types/Operation";
23import { TagCategory, TagIndex, TagNode, TagSearch } from "@/@types/tag";
22import Navigation from "@/services/navigation"; 24import Navigation from "@/services/navigation";
23 25
24export default class IndexFactory { 26export default class IndexFactory {
25 public static generateTags(root: Gallery.Item | null): Tag.Index { 27 public static generateTags(root: Item | null): TagIndex {
26 const tagsIndex: Tag.Index = {}; 28 const tagsIndex: TagIndex = {};
27 if (root) IndexFactory.pushTagsForItem(tagsIndex, root); 29 if (root) IndexFactory.pushTagsForItem(tagsIndex, root);
28 return tagsIndex; 30 return tagsIndex;
29 } 31 }
30 32
31 // Pushes all tags for a root item (and its children) to the index 33 // Pushes all tags for a root item (and its children) to the index
32 private static pushTagsForItem(tagsIndex: Tag.Index, item: Gallery.Item): void { 34 private static pushTagsForItem(tagsIndex: TagIndex, item: Item): void {
33 if (item.properties.type === ItemType.DIRECTORY) { 35 if (item.properties.type === ItemType.DIRECTORY) {
34 item.properties.items.forEach(item => this.pushTagsForItem(tagsIndex, item)); 36 item.properties.items.forEach(item => this.pushTagsForItem(tagsIndex, item));
35 return; // Directories are not indexed 37 return; // Directories are not indexed
@@ -49,7 +51,7 @@ export default class IndexFactory {
49 } 51 }
50 } 52 }
51 53
52 private static pushPartToIndex(index: Tag.Node, part: string, item: Gallery.Item, rootPart: boolean): Tag.Node { 54 private static pushPartToIndex(index: TagNode, part: string, item: Item, rootPart: boolean): TagNode {
53 if (!index) 55 if (!index)
54 index = { 56 index = {
55 tag: part, 57 tag: part,
@@ -68,8 +70,8 @@ export default class IndexFactory {
68 70
69 // --- 71 // ---
70 72
71 public static searchTags(tagsIndex: Tag.Index, filter: string, strict: boolean): Tag.Search[] { 73 public static searchTags(tagsIndex: TagIndex, filter: string, strict: boolean): TagSearch[] {
72 let search: Tag.Search[] = []; 74 let search: TagSearch[] = [];
73 if (tagsIndex && filter) { 75 if (tagsIndex && filter) {
74 const operation = IndexFactory.extractOperation(filter); 76 const operation = IndexFactory.extractOperation(filter);
75 if (operation !== Operation.INTERSECTION) filter = filter.slice(1); 77 if (operation !== Operation.INTERSECTION) filter = filter.slice(1);
@@ -95,12 +97,12 @@ export default class IndexFactory {
95 } 97 }
96 98
97 private static searchTagsFromFilterWithCategory( 99 private static searchTagsFromFilterWithCategory(
98 tagsIndex: Tag.Index, 100 tagsIndex: TagIndex,
99 operation: Operation, 101 operation: Operation,
100 category: string, 102 category: string,
101 disambiguation: string, 103 disambiguation: string,
102 strict: boolean 104 strict: boolean
103 ): Tag.Search[] { 105 ): TagSearch[] {
104 category = Navigation.normalize(category); 106 category = Navigation.normalize(category);
105 disambiguation = Navigation.normalize(disambiguation); 107 disambiguation = Navigation.normalize(disambiguation);
106 return Object.values(tagsIndex) 108 return Object.values(tagsIndex)
@@ -113,28 +115,28 @@ export default class IndexFactory {
113 } 115 }
114 116
115 private static searchTagsFromFilter( 117 private static searchTagsFromFilter(
116 tagsIndex: Tag.Index, 118 tagsIndex: TagIndex,
117 operation: Operation, 119 operation: Operation,
118 filter: string, 120 filter: string,
119 strict: boolean 121 strict: boolean
120 ): Tag.Search[] { 122 ): TagSearch[] {
121 filter = Navigation.normalize(filter); 123 filter = Navigation.normalize(filter);
122 return Object.values(tagsIndex) 124 return Object.values(tagsIndex)
123 .filter(node => IndexFactory.matches(node, filter, strict)) 125 .filter(node => IndexFactory.matches(node, filter, strict))
124 .map(node => ({ ...node, operation, display: `${operation}${node.tag}` })); 126 .map(node => ({ ...node, operation, display: `${operation}${node.tag}` }));
125 } 127 }
126 128
127 private static matches(node: Tag.Node, filter: string, strict: boolean): boolean { 129 private static matches(node: TagNode, filter: string, strict: boolean): boolean {
128 if (strict) return node.tagfiltered === filter; 130 if (strict) return node.tagfiltered === filter;
129 return node.tagfiltered.includes(filter); 131 return node.tagfiltered.includes(filter);
130 } 132 }
131 133
132 // --- 134 // ---
133 135
134 public static generateCategories(tagsIndex: Tag.Index, categoryTags?: Gallery.RawTag[]): Tag.Category[] { 136 public static generateCategories(tagsIndex: TagIndex, categoryTags?: RawTag[]): TagCategory[] {
135 if (!categoryTags?.length) return [{ tag: "", index: tagsIndex }]; 137 if (!categoryTags?.length) return [{ tag: "", index: tagsIndex }];
136 138
137 const tagsCategories: Tag.Category[] = []; 139 const tagsCategories: TagCategory[] = [];
138 const tagsRemaining = new Map(Object.entries(tagsIndex)); 140 const tagsRemaining = new Map(Object.entries(tagsIndex));
139 categoryTags 141 categoryTags
140 .map(tag => ({ tag, index: tagsIndex[tag]?.children })) 142 .map(tag => ({ tag, index: tagsIndex[tag]?.children }))
@@ -149,7 +151,7 @@ export default class IndexFactory {
149 return tagsCategories; 151 return tagsCategories;
150 } 152 }
151 153
152 private static isDiscriminantTagOnly(tags: Gallery.RawTag[], node: Tag.Node): boolean { 154 private static isDiscriminantTagOnly(tags: RawTag[], node: TagNode): boolean {
153 return !tags.includes(node.tag) || !node.childPart; 155 return !tags.includes(node.tag) || !node.childPart;
154 } 156 }
155} 157}
diff --git a/viewer/src/services/indexsearch.ts b/viewer/src/services/indexsearch.ts
index 00f8cfc..57bd03c 100644
--- a/viewer/src/services/indexsearch.ts
+++ b/viewer/src/services/indexsearch.ts
@@ -17,27 +17,29 @@
17-- along with this program. If not, see <https://www.gnu.org/licenses/>. 17-- along with this program. If not, see <https://www.gnu.org/licenses/>.
18*/ 18*/
19 19
20import { Item } from "@/@types/gallery";
20import { Operation } from "@/@types/Operation"; 21import { Operation } from "@/@types/Operation";
22import { TagSearch, TagSearchByOperation } from "@/@types/tag";
21 23
22export default class IndexSearch { 24export default class IndexSearch {
23 // Results of the search (by tags) 25 // Results of the search (by tags)
24 public static search(searchTags: Tag.Search[]): Gallery.Item[] { 26 public static search(searchTags: TagSearch[]): Item[] {
25 const byOperation = this.extractTagsByOperation(searchTags); 27 const byOperation = this.extractTagsByOperation(searchTags);
26 const intersection = this.extractIntersection(byOperation); 28 const intersection = this.extractIntersection(byOperation);
27 const substraction = this.extractSubstraction(byOperation); 29 const substraction = this.extractSubstraction(byOperation);
28 return this.aggregateAll(byOperation, intersection, substraction); 30 return this.aggregateAll(byOperation, intersection, substraction);
29 } 31 }
30 32
31 private static extractTagsByOperation(searchTags: Tag.Search[]): Tag.SearchByOperation { 33 private static extractTagsByOperation(searchTags: TagSearch[]): TagSearchByOperation {
32 const byOperation: Tag.SearchByOperation = {}; 34 const byOperation: TagSearchByOperation = {};
33 Object.values(Operation).forEach( 35 Object.values(Operation).forEach(
34 operation => (byOperation[operation] = searchTags.filter(tag => tag.operation === operation)) 36 operation => (byOperation[operation] = searchTags.filter(tag => tag.operation === operation))
35 ); 37 );
36 return byOperation; 38 return byOperation;
37 } 39 }
38 40
39 private static extractIntersection(byOperation: Tag.SearchByOperation): Set<Gallery.Item> { 41 private static extractIntersection(byOperation: TagSearchByOperation): Set<Item> {
40 const intersection = new Set<Gallery.Item>(); 42 const intersection = new Set<Item>();
41 if (byOperation[Operation.INTERSECTION].length > 0) { 43 if (byOperation[Operation.INTERSECTION].length > 0) {
42 byOperation[Operation.INTERSECTION] 44 byOperation[Operation.INTERSECTION]
43 .map(tag => tag.items) 45 .map(tag => tag.items)
@@ -48,8 +50,8 @@ export default class IndexSearch {
48 return intersection; 50 return intersection;
49 } 51 }
50 52
51 private static extractSubstraction(byOperation: Tag.SearchByOperation): Set<Gallery.Item> { 53 private static extractSubstraction(byOperation: TagSearchByOperation): Set<Item> {
52 const substraction = new Set<Gallery.Item>(); 54 const substraction = new Set<Item>();
53 if (byOperation[Operation.SUBSTRACTION].length > 0) { 55 if (byOperation[Operation.SUBSTRACTION].length > 0) {
54 byOperation[Operation.SUBSTRACTION].flatMap(tag => tag.items).forEach(item => substraction.add(item)); 56 byOperation[Operation.SUBSTRACTION].flatMap(tag => tag.items).forEach(item => substraction.add(item));
55 } 57 }
@@ -57,10 +59,10 @@ export default class IndexSearch {
57 } 59 }
58 60
59 private static aggregateAll( 61 private static aggregateAll(
60 byOperation: Tag.SearchByOperation, 62 byOperation: TagSearchByOperation,
61 intersection: Set<Gallery.Item>, 63 intersection: Set<Item>,
62 substraction: Set<Gallery.Item> 64 substraction: Set<Item>
63 ): Gallery.Item[] { 65 ): Item[] {
64 byOperation[Operation.ADDITION].flatMap(tag => tag.items).forEach(item => intersection.add(item)); 66 byOperation[Operation.ADDITION].flatMap(tag => tag.items).forEach(item => intersection.add(item));
65 substraction.forEach(item => intersection.delete(item)); 67 substraction.forEach(item => intersection.delete(item));
66 return [...intersection];