diff options
-rw-r--r-- | viewer/src/@types/tag.d.ts | 40 | ||||
-rw-r--r-- | viewer/src/components/LdProposition.vue | 9 | ||||
-rw-r--r-- | viewer/src/components/LdTagInput.vue | 11 | ||||
-rw-r--r-- | viewer/src/services/indexfactory.ts | 29 | ||||
-rw-r--r-- | viewer/src/services/indexsearch.ts | 13 | ||||
-rw-r--r-- | viewer/src/store/galleryStore.ts | 13 | ||||
-rw-r--r-- | viewer/src/views/PanelLeft.vue | 3 |
7 files changed, 62 insertions, 56 deletions
diff --git a/viewer/src/@types/tag.d.ts b/viewer/src/@types/tag.d.ts index bb908d3..9ed2c04 100644 --- a/viewer/src/@types/tag.d.ts +++ b/viewer/src/@types/tag.d.ts | |||
@@ -17,25 +17,25 @@ | |||
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 | ||
20 | declare namespace Tag { | 20 | import { Item, RawTag } from "./gallery"; |
21 | interface Node { | ||
22 | tag: RawTag; | ||
23 | tagfiltered: RawTag; | ||
24 | rootPart: boolean; | ||
25 | childPart: boolean; | ||
26 | items: Item[]; | ||
27 | children: Index; | ||
28 | } | ||
29 | interface Search extends Node { | ||
30 | parent?: Node; | ||
31 | operation: string; // Enum Operation | ||
32 | display: string; | ||
33 | } | ||
34 | type SearchByOperation = Record<string, Tag.Search[]>; | ||
35 | type Index = Record<string, Node>; | ||
36 | 21 | ||
37 | interface Category { | 22 | export interface TagNode { |
38 | tag: string; | 23 | tag: RawTag; |
39 | index: Index; | 24 | tagfiltered: RawTag; |
40 | } | 25 | rootPart: boolean; |
26 | childPart: boolean; | ||
27 | items: Item[]; | ||
28 | children: TagIndex; | ||
29 | } | ||
30 | export interface TagSearch extends TagNode { | ||
31 | parent?: TagNode; | ||
32 | operation: string; // Enum Operation | ||
33 | display: string; | ||
34 | } | ||
35 | export type TagSearchByOperation = Record<string, TagSearch[]>; | ||
36 | export type TagIndex = Record<string, TagNode>; | ||
37 | |||
38 | export interface TagCategory { | ||
39 | tag: string; | ||
40 | index: TagIndex; | ||
41 | } | 41 | } |
diff --git a/viewer/src/components/LdProposition.vue b/viewer/src/components/LdProposition.vue index 2396d1f..088e249 100644 --- a/viewer/src/components/LdProposition.vue +++ b/viewer/src/components/LdProposition.vue | |||
@@ -56,15 +56,16 @@ | |||
56 | <script lang="ts"> | 56 | <script lang="ts"> |
57 | import { Item, RawTag } from "@/@types/gallery"; | 57 | import { Item, RawTag } from "@/@types/gallery"; |
58 | import { Operation } from "@/@types/Operation"; | 58 | import { Operation } from "@/@types/Operation"; |
59 | import { TagIndex, TagNode, TagSearch } from "@/@types/tag"; | ||
59 | import { Component, Prop, PropSync, Vue, Watch } from "vue-property-decorator"; | 60 | import { Component, Prop, PropSync, Vue, Watch } from "vue-property-decorator"; |
60 | 61 | ||
61 | @Component | 62 | @Component |
62 | export default class LdProposition extends Vue { | 63 | export default class LdProposition extends Vue { |
63 | @Prop() readonly category?: Tag.Node; | 64 | @Prop() readonly category?: TagNode; |
64 | @Prop({ type: Boolean, required: true }) readonly showCategory!: boolean; | 65 | @Prop({ type: Boolean, required: true }) readonly showCategory!: boolean; |
65 | @Prop({ type: Array, required: true }) readonly currentTags!: string[]; | 66 | @Prop({ type: Array, required: true }) readonly currentTags!: string[]; |
66 | @Prop({ required: true }) readonly tagsIndex!: Tag.Index; | 67 | @Prop({ required: true }) readonly tagsIndex!: TagIndex; |
67 | @PropSync("searchFilters", { type: Array, required: true }) model!: Tag.Search[]; | 68 | @PropSync("searchFilters", { type: Array, required: true }) model!: TagSearch[]; |
68 | 69 | ||
69 | readonly INITIAL_TAG_DISPLAY_LIMIT = this.getInitialTagDisplayLimit(); | 70 | readonly INITIAL_TAG_DISPLAY_LIMIT = this.getInitialTagDisplayLimit(); |
70 | 71 | ||
@@ -119,7 +120,7 @@ export default class LdProposition extends Vue { | |||
119 | return this.category?.tag ?? this.$t("panelLeft.propositions.other"); | 120 | return this.category?.tag ?? this.$t("panelLeft.propositions.other"); |
120 | } | 121 | } |
121 | 122 | ||
122 | extractDistinctItems(currentTags: Tag.Search[]): Item[] { | 123 | extractDistinctItems(currentTags: TagSearch[]): Item[] { |
123 | return [...new Set(currentTags.flatMap(tag => tag.items))]; | 124 | return [...new Set(currentTags.flatMap(tag => tag.items))]; |
124 | } | 125 | } |
125 | 126 | ||
diff --git a/viewer/src/components/LdTagInput.vue b/viewer/src/components/LdTagInput.vue index ef585f0..855813a 100644 --- a/viewer/src/components/LdTagInput.vue +++ b/viewer/src/components/LdTagInput.vue | |||
@@ -40,22 +40,23 @@ | |||
40 | </template> | 40 | </template> |
41 | 41 | ||
42 | <script lang="ts"> | 42 | <script lang="ts"> |
43 | import { TagIndex, TagSearch } from "@/@types/tag"; | ||
43 | import IndexFactory from "@/services/indexfactory"; | 44 | import IndexFactory from "@/services/indexfactory"; |
44 | import { Component, Emit, Prop, PropSync, Vue } from "vue-property-decorator"; | 45 | import { Component, Emit, Prop, PropSync, Vue } from "vue-property-decorator"; |
45 | 46 | ||
46 | @Component | 47 | @Component |
47 | export default class LdTagInput extends Vue { | 48 | export default class LdTagInput extends Vue { |
48 | @Prop({ required: true }) readonly tagsIndex!: Tag.Index; | 49 | @Prop({ required: true }) readonly tagsIndex!: TagIndex; |
49 | @PropSync("searchFilters", { type: Array, required: true }) model!: Tag.Search[]; | 50 | @PropSync("searchFilters", { type: Array, required: true }) model!: TagSearch[]; |
50 | 51 | ||
51 | currentFilter: string = ""; | 52 | currentFilter: string = ""; |
52 | filteredTags: Tag.Search[] = []; | 53 | filteredTags: TagSearch[] = []; |
53 | 54 | ||
54 | displayOption(option: Tag.Search): string { | 55 | displayOption(option: TagSearch): string { |
55 | return `${option.display} (${option.items.length})`; | 56 | return `${option.display} (${option.items.length})`; |
56 | } | 57 | } |
57 | 58 | ||
58 | filterAlreadyPresent(newSearch: Tag.Search) { | 59 | filterAlreadyPresent(newSearch: TagSearch) { |
59 | return !this.model.find( | 60 | return !this.model.find( |
60 | currentSearch => | 61 | currentSearch => |
61 | currentSearch.tag === newSearch.tag && (!currentSearch.parent || currentSearch.parent === newSearch.parent) | 62 | currentSearch.tag === newSearch.tag && (!currentSearch.parent || currentSearch.parent === newSearch.parent) |
diff --git a/viewer/src/services/indexfactory.ts b/viewer/src/services/indexfactory.ts index 0c5fdc5..691a765 100644 --- a/viewer/src/services/indexfactory.ts +++ b/viewer/src/services/indexfactory.ts | |||
@@ -20,17 +20,18 @@ | |||
20 | import { Item, RawTag } from "@/@types/gallery"; | 20 | import { Item, RawTag } from "@/@types/gallery"; |
21 | import { ItemType } from "@/@types/ItemType"; | 21 | import { ItemType } from "@/@types/ItemType"; |
22 | import { Operation } from "@/@types/Operation"; | 22 | import { Operation } from "@/@types/Operation"; |
23 | import { TagCategory, TagIndex, TagNode, TagSearch } from "@/@types/tag"; | ||
23 | import Navigation from "@/services/navigation"; | 24 | import Navigation from "@/services/navigation"; |
24 | 25 | ||
25 | export default class IndexFactory { | 26 | export default class IndexFactory { |
26 | public static generateTags(root: Item | null): Tag.Index { | 27 | public static generateTags(root: Item | null): TagIndex { |
27 | const tagsIndex: Tag.Index = {}; | 28 | const tagsIndex: TagIndex = {}; |
28 | if (root) IndexFactory.pushTagsForItem(tagsIndex, root); | 29 | if (root) IndexFactory.pushTagsForItem(tagsIndex, root); |
29 | return tagsIndex; | 30 | return tagsIndex; |
30 | } | 31 | } |
31 | 32 | ||
32 | // 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 |
33 | private static pushTagsForItem(tagsIndex: Tag.Index, item: Item): void { | 34 | private static pushTagsForItem(tagsIndex: TagIndex, item: Item): void { |
34 | if (item.properties.type === ItemType.DIRECTORY) { | 35 | if (item.properties.type === ItemType.DIRECTORY) { |
35 | item.properties.items.forEach(item => this.pushTagsForItem(tagsIndex, item)); | 36 | item.properties.items.forEach(item => this.pushTagsForItem(tagsIndex, item)); |
36 | return; // Directories are not indexed | 37 | return; // Directories are not indexed |
@@ -50,7 +51,7 @@ export default class IndexFactory { | |||
50 | } | 51 | } |
51 | } | 52 | } |
52 | 53 | ||
53 | private static pushPartToIndex(index: Tag.Node, part: string, item: Item, rootPart: boolean): Tag.Node { | 54 | private static pushPartToIndex(index: TagNode, part: string, item: Item, rootPart: boolean): TagNode { |
54 | if (!index) | 55 | if (!index) |
55 | index = { | 56 | index = { |
56 | tag: part, | 57 | tag: part, |
@@ -69,8 +70,8 @@ export default class IndexFactory { | |||
69 | 70 | ||
70 | // --- | 71 | // --- |
71 | 72 | ||
72 | public static searchTags(tagsIndex: Tag.Index, filter: string, strict: boolean): Tag.Search[] { | 73 | public static searchTags(tagsIndex: TagIndex, filter: string, strict: boolean): TagSearch[] { |
73 | let search: Tag.Search[] = []; | 74 | let search: TagSearch[] = []; |
74 | if (tagsIndex && filter) { | 75 | if (tagsIndex && filter) { |
75 | const operation = IndexFactory.extractOperation(filter); | 76 | const operation = IndexFactory.extractOperation(filter); |
76 | if (operation !== Operation.INTERSECTION) filter = filter.slice(1); | 77 | if (operation !== Operation.INTERSECTION) filter = filter.slice(1); |
@@ -96,12 +97,12 @@ export default class IndexFactory { | |||
96 | } | 97 | } |
97 | 98 | ||
98 | private static searchTagsFromFilterWithCategory( | 99 | private static searchTagsFromFilterWithCategory( |
99 | tagsIndex: Tag.Index, | 100 | tagsIndex: TagIndex, |
100 | operation: Operation, | 101 | operation: Operation, |
101 | category: string, | 102 | category: string, |
102 | disambiguation: string, | 103 | disambiguation: string, |
103 | strict: boolean | 104 | strict: boolean |
104 | ): Tag.Search[] { | 105 | ): TagSearch[] { |
105 | category = Navigation.normalize(category); | 106 | category = Navigation.normalize(category); |
106 | disambiguation = Navigation.normalize(disambiguation); | 107 | disambiguation = Navigation.normalize(disambiguation); |
107 | return Object.values(tagsIndex) | 108 | return Object.values(tagsIndex) |
@@ -114,28 +115,28 @@ export default class IndexFactory { | |||
114 | } | 115 | } |
115 | 116 | ||
116 | private static searchTagsFromFilter( | 117 | private static searchTagsFromFilter( |
117 | tagsIndex: Tag.Index, | 118 | tagsIndex: TagIndex, |
118 | operation: Operation, | 119 | operation: Operation, |
119 | filter: string, | 120 | filter: string, |
120 | strict: boolean | 121 | strict: boolean |
121 | ): Tag.Search[] { | 122 | ): TagSearch[] { |
122 | filter = Navigation.normalize(filter); | 123 | filter = Navigation.normalize(filter); |
123 | return Object.values(tagsIndex) | 124 | return Object.values(tagsIndex) |
124 | .filter(node => IndexFactory.matches(node, filter, strict)) | 125 | .filter(node => IndexFactory.matches(node, filter, strict)) |
125 | .map(node => ({ ...node, operation, display: `${operation}${node.tag}` })); | 126 | .map(node => ({ ...node, operation, display: `${operation}${node.tag}` })); |
126 | } | 127 | } |
127 | 128 | ||
128 | private static matches(node: Tag.Node, filter: string, strict: boolean): boolean { | 129 | private static matches(node: TagNode, filter: string, strict: boolean): boolean { |
129 | if (strict) return node.tagfiltered === filter; | 130 | if (strict) return node.tagfiltered === filter; |
130 | return node.tagfiltered.includes(filter); | 131 | return node.tagfiltered.includes(filter); |
131 | } | 132 | } |