diff options
Diffstat (limited to 'viewer/src/components/LdTagInput.vue')
-rw-r--r-- | viewer/src/components/LdTagInput.vue | 75 |
1 files changed, 9 insertions, 66 deletions
diff --git a/viewer/src/components/LdTagInput.vue b/viewer/src/components/LdTagInput.vue index eff02e6..d9d932f 100644 --- a/viewer/src/components/LdTagInput.vue +++ b/viewer/src/components/LdTagInput.vue | |||
@@ -19,7 +19,7 @@ | |||
19 | 19 | ||
20 | <template> | 20 | <template> |
21 | <b-taginput | 21 | <b-taginput |
22 | v-model="$uiStore.currentTags" | 22 | v-model="model" |
23 | :placeholder="$t('tagInput.placeholder')" | 23 | :placeholder="$t('tagInput.placeholder')" |
24 | autocomplete | 24 | autocomplete |
25 | ellipsis | 25 | ellipsis |
@@ -30,8 +30,6 @@ | |||
30 | size="is-medium" | 30 | size="is-medium" |
31 | class="paneltag-input" | 31 | class="paneltag-input" |
32 | @typing="searchTags" | 32 | @typing="searchTags" |
33 | @add="onAdd" | ||
34 | @remove="onRemove" | ||
35 | > | 33 | > |
36 | <template slot-scope="props">{{displayOption(props.option)}}</template> | 34 | <template slot-scope="props">{{displayOption(props.option)}}</template> |
37 | <template slot="empty">{{$t('tagInput.nomatch')}}</template> | 35 | <template slot="empty">{{$t('tagInput.nomatch')}}</template> |
@@ -39,80 +37,25 @@ | |||
39 | </template> | 37 | </template> |
40 | 38 | ||
41 | <script lang="ts"> | 39 | <script lang="ts"> |
42 | import { Component, Vue } from "vue-property-decorator"; | 40 | import { Component, Vue, Model, Prop } from "vue-property-decorator"; |
43 | import { Operation } from "@/@types/Operation"; | 41 | import { Operation } from "@/@types/Operation"; |
44 | import Tools from "@/tools"; | 42 | import Navigation from "@/services/navigation"; |
43 | import IndexFactory from "@/services/indexfactory"; | ||
45 | 44 | ||
46 | @Component | 45 | @Component |
47 | export default class LdTagInput extends Vue { | 46 | export default class LdTagInput extends Vue { |
48 | filteredTags: Tag.Search[] = []; | 47 | @Prop({ required: true }) readonly tagsIndex!: Tag.Index; |
49 | 48 | @Model() model!: Tag.Search[]; | |
50 | onAdd(e: any) { | ||
51 | this.$uiStore.mode = "search"; | ||
52 | } | ||
53 | 49 | ||
54 | onRemove() { | 50 | filteredTags: Tag.Search[] = []; |
55 | if (this.$uiStore.currentTags.length === 0) this.$uiStore.mode = "navigation"; | ||
56 | } | ||
57 | 51 | ||
58 | displayOption(option: Tag.Search): string { | 52 | displayOption(option: Tag.Search): string { |
59 | return `${option.display} (${option.items.length})`; | 53 | return `${option.display} (${option.items.length})`; |
60 | } | 54 | } |
61 | 55 | ||
62 | extractOperation(filter: string): Operation { | ||
63 | const first = filter.slice(0, 1); | ||
64 | switch (first) { | ||
65 | case Operation.ADDITION: | ||
66 | case Operation.SUBSTRACTION: | ||
67 | return first; | ||
68 | default: | ||
69 | return Operation.INTERSECTION; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | searchTags(filter: string) { | 56 | searchTags(filter: string) { |
74 | const tags = this.$galleryStore.tags; | 57 | this.filteredTags = IndexFactory.searchTags(this.tagsIndex, filter) |
75 | let search: Tag.Search[] = []; | 58 | .filter(newSearch => !this.model.find(currentSearch => currentSearch.tag === newSearch.tag)) |
76 | if (tags && filter) { | ||
77 | const operation = this.extractOperation(filter); | ||
78 | if (operation !== Operation.INTERSECTION) filter = filter.slice(1); | ||
79 | if (filter.includes(":")) { | ||
80 | const filterParts = filter.split(":"); | ||
81 | search = this.searchTagsFromFilterWithCategory(tags, operation, filterParts[0], filterParts[1]); | ||
82 | } else { | ||
83 | search = this.searchTagsFromFilter(tags, operation, filter); | ||
84 | } | ||
85 | } | ||
86 | this.filteredTags = this.cleanupAndSort(search); | ||
87 | } | ||
88 | |||
89 | searchTagsFromFilterWithCategory( | ||
90 | tags: Tag.Index, | ||
91 | operation: Operation, | ||
92 | category: string, | ||
93 | disambiguation: string | ||
94 | ): Tag.Search[] { | ||
95 | disambiguation = Tools.normalize(disambiguation); | ||
96 | return Object.values(tags) | ||
97 | .filter(node => node.tag.includes(category)) | ||
98 | .flatMap(node => | ||
99 | Object.values(node.children) | ||
100 | .filter(child => child.tagfiltered.includes(disambiguation)) | ||
101 | .map(child => ({ ...child, parent: node, operation, display: `${operation}${node.tag}:${child.tag}` })) | ||
102 | ); | ||
103 | } | ||
104 | |||
105 | searchTagsFromFilter(tags: Tag.Index, operation: Operation, filter: string): Tag.Search[] { | ||
106 | filter = Tools.normalize(filter); | ||
107 | return Object.values(tags) | ||
108 | .filter(node => node.tagfiltered.includes(filter)) | ||
109 | .map(node => ({ ...node, operation, display: `${operation}${node.tag}` })); | ||
110 | } | ||
111 | |||
112 | cleanupAndSort(search: Tag.Search[]): Tag.Search[] { | ||
113 | const currentTags = this.$uiStore.currentTags; | ||
114 | return search | ||
115 | .filter(node => !currentTags.find(currentTag => currentTag.tag === node.tag)) | ||
116 | .sort((a, b) => b.items.length - a.items.length); | 59 | .sort((a, b) => b.items.length - a.items.length); |
117 | } | 60 | } |
118 | } | 61 | } |