diff --git a/src/components/Autocomplete.vue b/src/components/Autocomplete.vue index ff6ec0b3a..bb5b67b86 100644 --- a/src/components/Autocomplete.vue +++ b/src/components/Autocomplete.vue @@ -1,31 +1,59 @@ <template> <section class="search-bar" ref="autocomplete"> <div class="input-group"> - <b-form-input :class="`search-input ${showSuggestions ? 'has-suggestions' : ''}`" - :placeholder="$tc('placeholder.search', filterCount)" v-model.trim="q" @update:modelValue="search" - @focus="selectInput" @blur="blurHandler" @keyup="keyup" data-testid="autocomplete-input" /> + <b-form-input + :class="`search-input ${showSuggestions ? 'has-suggestions' : ''}`" + :placeholder="$tc('placeholder.search', filterCount)" + v-model.trim="q" + @update:modelValue="search" + @focus="selectInput" + @blur="blurHandler" + @keyup="keyup" + data-testid="autocomplete-input" + /> <div class="input-group-append"> - <button type="button" class="btn btn-outline-primary" ref="searchButton" - :title="$tc('placeholder.search', filterCount)" @click="submit({ type: 'string', q })" - data-testid="add-keyword-button"> + <button + type="button" + class="btn btn-outline-primary" + ref="searchButton" + :title="$tc('placeholder.search', filterCount)" + @click="submit({ type: 'string', q })" + data-testid="add-keyword-button" + > <div v-if="filterCount > 1" class="d-flex search-submit dripicons-search"></div> <div v-else class="d-flex search-submit dripicons-search"></div> </button> - <button type="button" class="btn btn-outline-primary" :title="$t('actions.addFilter')" @click="showExplorer" - data-testid="add-filter-button"> + <button + type="button" + class="btn btn-outline-primary" + :title="$t('actions.addFilter')" + @click="showExplorer" + data-testid="add-filter-button" + > <div class="d-flex dripicons-experiment"></div> </button> </div> </div> - <div class="suggestions border-left border-right border-bottom border-primary drop-shadow" v-show="showSuggestions"> + <div + class="suggestions border-left border-right border-bottom border-primary drop-shadow" + v-show="showSuggestions" + > <div class="border-bottom"> - <div class="suggestion p-1" v-for="(suggestion, index) in staticSuggestions" v-bind:key="index" - @click="submitStaticSuggestion(suggestion)" :data-idx="suggestion.idx" @mouseover="select(suggestion)" - :class="{ selected: selectedIndex === suggestion.idx }"> + <div + class="suggestion p-1" + v-for="(suggestion, index) in staticSuggestions" + v-bind:key="index" + @click="submitStaticSuggestion(suggestion)" + :data-idx="suggestion.idx" + @mouseover="select(suggestion)" + :class="{ selected: selectedIndex === suggestion.idx }" + > <div :class="`suggestion-${suggestion.type}`"> <span class="small" v-if="suggestion.h" v-html="suggestion.h" /> - <span class="small" v-else>...<b>{{ q }}</b></span> + <span class="small" v-else + >...<b>{{ q }}</b></span + > <b-badge variant="light" class="border border-medium"> {{ $t(`label.${suggestion.type}.title`) }} </b-badge> @@ -39,21 +67,35 @@ </div> <div class="col"> <!-- <span v-if="type !== 'mention'" class="small-caps px-2">{{$t(`label.${type}.title`)}}</span> --> - <div v-for="(s, j) in suggestionIndex[type]" :key="j" @click="submit(s)" @mouseover="select(s)" - :data-idx="s.idx" class="suggestion pr-1 pl-2 py-1" :class="{ - selected: selectedIndex === s.idx, - }"> + <div + v-for="(s, j) in suggestionIndex[type]" + :key="j" + @click="submit(s)" + @mouseover="select(s)" + :data-idx="s.idx" + class="suggestion pr-1 pl-2 py-1" + :class="{ + selected: selectedIndex === s.idx + }" + > <div v-if="s.fake && type !== 'mention'" :title="$t(`label.${type}.moreLikeThis`)"> - <span class="small">... <b>{{ q }}</b></span> + <span class="small" + >... <b>{{ q }}</b></span + > <b-badge variant="light" class="border border-medium"> - {{ $t(`label.${type}.moreLikeThis`) }}</b-badge> + {{ $t(`label.${type}.moreLikeThis`) }}</b-badge + > </div> <div v-else :class="`${type} small`"> <span v-if="['location', 'person'].indexOf(type) !== -1" v-html="s.h" /> - <span v-if="['collection', 'newspaper'].indexOf(type) !== -1" v-html="s.item.name" /> + <span + v-if="['collection', 'newspaper'].indexOf(type) !== -1" + v-html="s.item.name" + /> <span v-if="['topic', 'mention'].indexOf(type) !== -1" v-html="s.h" /> - <span v-if="s.type === 'daterange'">{{ $d(s.daterange.start, 'short') }} - {{ $d(s.daterange.end, - 'short') }}</span> + <span v-if="s.type === 'daterange'" + >{{ $d(s.daterange.start, 'short') }} - {{ $d(s.daterange.end, 'short') }}</span + > </div> </div> </div> @@ -61,9 +103,15 @@ </div> </div> - <explorer v-model="explorerFilters" :is-visible="explorerVisible" @onHide="handleExplorerHide" - :searching-enabled="true" :initial-search-query="q" :initial-type="explorerInitialType" - :included-types="explorerIncludedTypes" /> + <explorer + v-model="explorerFilters" + :is-visible="explorerVisible" + @onHide="handleExplorerHide" + :searching-enabled="true" + :initial-search-query="q" + :initial-type="explorerInitialType" + :included-types="explorerIncludedTypes" + /> </section> </template> @@ -83,11 +131,11 @@ export default { q: '', initialSuggestions: [ { - type: 'string', + type: 'string' }, { - type: 'title', - }, + type: 'title' + } ], recentSuggestions: [], collectionSuggestions: [], @@ -98,23 +146,23 @@ export default { maxSelectedIndex: 0, selectableSuggestions: [], showSuggestions: false, - explorerVisible: false, + explorerVisible: false }), emits: ['submit', 'submitEmpty', 'input-focus'], props: { variant: { type: String, - default: 'primary', + default: 'primary' }, explorerIncludedTypes: { type: Array, - default: () => ['newspaper', 'topic', 'location', 'person', 'collection'], + default: () => ['newspaper', 'topic', 'location', 'person', 'collection'] }, /** @type {import('vue').PropOptions<Filter[]>} */ filters: { type: Array, - default: () => [], - }, + default: () => [] + } }, beforeMount() { const autocomplete = ref(this.$refs.autocomplete) @@ -129,7 +177,7 @@ export default { staticSuggestions() { return this.initialSuggestions.concat(this.recentSuggestions).map((d, idx) => ({ ...d, - idx, + idx })) }, explorerInitialType() { @@ -147,7 +195,7 @@ export default { suggestionIndex() { const key = 'type' const index = this.suggestions.reduce((reduced, item) => { - ; (reduced[item[key]] = reduced[item[key]] || []).push(item) + ;(reduced[item[key]] = reduced[item[key]] || []).push(item) return reduced }, {}) @@ -161,7 +209,7 @@ export default { // add correct index to choice return { ...d, - idx, + idx } }) // exclude extra suggestions for mentions @@ -171,7 +219,7 @@ export default { index[type].push({ type, fake: true, - idx, + idx }) } } @@ -197,13 +245,13 @@ export default { const filter = filters[0] this.$emit('submit', filter) this.q = '' - }, + } }, filterCount() { return typeof this.filters === 'undefined' ? 1 : this.filters.filter(d => d.type !== 'hasTextContents').length + 1 - }, + } }, methods: { showExplorer() { @@ -240,7 +288,7 @@ export default { const res = this.autocompleteStore.suggestRecentQuery(this.q) this.recentSuggestions = res.map(d => ({ ...d, - type: 'string', + type: 'string' })) } @@ -266,7 +314,7 @@ export default { console.info('submitStaticSuggestion', type, sq) this.submit({ type, - q: sq, + q: sq }) this.q = '' } @@ -284,8 +332,8 @@ export default { FilterFactory.create({ type, q: [sq], - op: 'OR', - }), + op: 'OR' + }) ) this.q = '' } else { @@ -297,8 +345,8 @@ export default { FilterFactory.create({ type, q: [item.uid], - items: [item], - }), + items: [item] + }) ) this.q = '' } @@ -320,7 +368,7 @@ export default { console.info( '@keyup ENTER', this.selectedIndex, - this.selectableSuggestions[this.selectedIndex], + this.selectableSuggestions[this.selectedIndex] ) this.submit(this.selectableSuggestions[this.selectedIndex]) this.selectInput(event) @@ -343,11 +391,11 @@ export default { } else if (this.selectedIndex < 0) { this.selectedIndex = this.maxSelectedIndex } - }, + } }, components: { - Explorer, - }, + Explorer + } } </script> @@ -402,7 +450,7 @@ export default { border: 1px solid transparent; cursor: pointer; - >div { + > div { display: flex; flex-direction: row; align-items: center; @@ -425,14 +473,14 @@ export default { } } -.search-bar .input-group>.form-control { +.search-bar .input-group > .form-control { border-top-width: 0; border-left-width: 0; border-right-width: 0; z-index: 1; } -.search-box .search-bar .input-group>.form-control { +.search-box .search-bar .input-group > .form-control { background: white; &:focus { @@ -441,7 +489,7 @@ export default { } .bg-dark { - .search-bar .input-group>.form-control { + .search-bar .input-group > .form-control { border-top-width: 0; border-left-width: 0; border-right-width: 0; @@ -477,9 +525,11 @@ export default { // background: rgb(253,233,119); // background: linear-gradient(90deg, rgba(253,233,119,1) 0%, rgba(253,233,119,0) 100%); // width: 100px; -// }</style> +// } +</style> -<i18n lang="json">{ +<i18n lang="json"> +{ "en": { "placeholder": { "search": "search for ... | add keyword to search" @@ -527,4 +577,5 @@ export default { "topic": "Onderwerp", "collection": "Collectie" } -}</i18n> +} +</i18n> diff --git a/src/components/Explorer.vue b/src/components/Explorer.vue index d1c523b9e..3da3a7d27 100644 --- a/src/components/Explorer.vue +++ b/src/components/Explorer.vue @@ -1,79 +1,122 @@ <template> - <Modal :id="id" :show="isModalVisible" body-class="p-0" @close="$emit(events.Hide)"> + <Modal :id="id" :show="isVisible" body-class="p-0" @close="$emit(events.Hide)"> <template v-slot:modal-header="{ titleId, close }"> - <div> + <div data-testid="tabs"> <div class="tb-title small-caps font-weight-bold" :id="titleId">{{ $t('explore') }}</div> - <b-button v-for="(availableType, i) in typeOptions" v-bind:key="i" class="mr-1 mt-1" variant="outline-primary" - size="sm" v-on:click="handleTypeChange(availableType)" - v-bind:class="{ 'active': currentType === availableType }"> + <b-button + v-for="(availableType, i) in typeOptions" + v-bind:key="i" + class="mr-1 mt-1" + variant="outline-primary" + size="sm" + v-on:click="handleTypeChange(availableType)" + v-bind:class="{ active: currentType === availableType }" + > {{ $t(`labels.${availableType}`) }} </b-button> <div class="small mt-2"> <span v-if="isLoading">{{ $t('loading') }}</span> - <span v-else v-html="$tc(`description.${searchingEnabled ? 'search' : 'facets'}`, totalResults, { - searchQuery, - })"></span> + <span + v-else + v-html=" + $tc(`description.${searchingEnabled ? 'search' : 'facets'}`, totalResults, { + searchQuery + }) + " + ></span> </div> <form v-if="searchingEnabled" v-on:submit.prevent="search" class="mt-2"> <div class="input-group"> - <b-form-input :placeholder="$tc('searchField.placeholder', totalResults)" v-model.trim="searchQueryModel" - autofocus /> + <b-form-input + :placeholder="$tc('searchField.placeholder', totalResults)" + v-model.trim="searchQueryModel" + autofocus + data-testid="search-field" + /> <div class="input-group-append"> - <button type="button" class="btn btn-outline-primary pt-2 pb-1 px-2" v-on:click="search"> + <button + type="button" + class="btn btn-outline-primary pt-2 pb-1 px-2" + v-on:click="search" + > <div class="search-submit dripicons-search"></div> </button> </div> </div> </form> - </div> <div class="ml-auto"> - <b-button pill class="dripicons-cross px-0" variant="outline-danger" style="width:1.5em; height:1.5em" size="sm" - v-on:click.prevent="close"> + <b-button + pill + class="dripicons-cross px-0" + variant="outline-danger" + style="width: 1.5em; height: 1.5em" + size="sm" + v-on:click.prevent="close" + > </b-button> </div> - </template> <!-- .modal-body --> <div class="bg-light"> - <div v-if='isLoading' class="position-absolute w-100 h-100" - style="z-index:1; left:-1px; background:rgba(255,255,255,0.8)"> + <div + v-if="isLoading" + class="position-absolute w-100 h-100" + style="z-index: 1; left: -1px; background: rgba(255, 255, 255, 0.8)" + > <i-spinner class="text-center pt-4" /> </div> - <facet-explorer v-if="!RangeFacets.includes(currentType)" :filter-type="currentType" :buckets="buckets" - v-model="filter"> + <facet-explorer + v-if="!RangeFacets.includes(currentType)" + :filter-type="currentType" + :buckets="buckets" + v-model="filter" + > <template v-slot:pagination> - <pagination :current-page="currentPageModel" @change="$event => currentPageModel = $event" - v-bind:perPage="pageSize" v-bind:totalRows="totalResults" v-bind:showDescription="false" /> + <pagination + :current-page="currentPageModel" + @change="$event => (currentPageModel = $event)" + v-bind:perPage="pageSize" + v-bind:totalRows="totalResults" + v-bind:showDescription="false" + /> </template> - </facet-Explorer> - <range-facet-explorer class="p-3" v-if="NumericRangeFacets.includes(currentType)" :filter-type="currentType" - :buckets="buckets" :range="range" v-model="filter" /> - <time-facet-explorer v-if="TimeRangeFacets.includes(currentType)" v-model="filter" :filter-type="currentType" - :buckets="buckets" /> - </div><!-- .modal-body --> + </facet-explorer> + <range-facet-explorer + class="p-3" + v-if="NumericRangeFacets.includes(currentType)" + :filter-type="currentType" + :buckets="buckets" + :range="range" + v-model="filter" + /> + <time-facet-explorer + v-if="TimeRangeFacets.includes(currentType)" + v-model="filter" + :filter-type="currentType" + :buckets="buckets" + /> + </div> + <!-- .modal-body --> <!-- footer --> <template v-slot:modal-footer="{ close }"> - <b-button @click="close()" size="sm" variant="outline-primary">{{ $t('actions.close') }}</b-button> + <b-button @click="close()" size="sm" variant="outline-primary">{{ + $t('actions.close') + }}</b-button> </template> </Modal> </template> <script> -import { - entities, - topics, - newspapers, - collections, - getSearchFacetsService -} from '@/services' +import { entities, topics, newspapers, collections, getSearchFacetsService } from '@/services' import Modal from '@/components/base/Modal.vue' -import FacetExplorer from './modules/FacetExplorer.vue'; -import TimeFacetExplorer from './modules/TimeFacetExplorer.vue'; -import RangeFacetExplorer from './modules/RangeFacetExplorer.vue'; -import Pagination from './modules/Pagination.vue'; -import Bucket from '@/models/Bucket'; +import FacetExplorer from './modules/FacetExplorer.vue' +import TimeFacetExplorer from './modules/TimeFacetExplorer.vue' +import RangeFacetExplorer from './modules/RangeFacetExplorer.vue' +import Pagination from './modules/Pagination.vue' +import Bucket from '@/models/Bucket' import { NumericRangeFacets, RangeFacets, TimeRangeFacets } from '@/logic/filters' +import { v4 } from 'uuid' const TypeToServiceMap = Object.freeze({ person: entities, @@ -96,15 +139,19 @@ function buildEntitySearchQuery(page, limit, type, q) { } if (type === 'person') { - query.filters = [{ - type: 'type', - q: 'Person', - }]; + query.filters = [ + { + type: 'type', + q: 'Person' + } + ] } else if (type === 'location') { - query.filters = [{ - type: 'type', - q: 'Location', - }]; + query.filters = [ + { + type: 'type', + q: 'Location' + } + ] } if (q != null && q.length > 0) { query.q = q @@ -112,63 +159,86 @@ function buildEntitySearchQuery(page, limit, type, q) { return query } -async function search({ - searchingEnabled, - filters, - type, - searchQuery, - currentPage, - pageSize -}, index) { +async function search( + { searchingEnabled, filters, type, searchQuery, currentPage, pageSize }, + index +) { const service = TypeToServiceMap[type] if (searchingEnabled) { const query = buildEntitySearchQuery(currentPage, pageSize, type, searchQuery) const response = await service.find({ query }) return { totalResults: response.total, - buckets: response.data.filter(d => d.uid.length).map(item => new Bucket({ - val: item.uid, - item, - type, - })) + buckets: response.data + .filter(d => d.uid.length) + .map( + item => + new Bucket({ + val: item.uid, + item, + type + }) + ) } } else { const query = { filters: filters, page: currentPage, limit: pageSize, - order_by: '-count', - }; + order_by: '-count' + } const response = await getSearchFacetsService(index).get(type, { query }) const result = response return { totalResults: result.numBuckets, - buckets: result.buckets.map(d => new Bucket({ - ...d, - type - })), - range: Number.isFinite(result.min) && Number.isFinite(result.max) - ? [result.min, result.max] : undefined + buckets: result.buckets.map( + d => + new Bucket({ + ...d, + type + }) + ), + range: + Number.isFinite(result.min) && Number.isFinite(result.max) + ? [result.min, result.max] + : undefined } } } const AllSupportedFilterTypes = [ - 'location', 'country', 'person', 'language', - 'topic', 'newspaper', 'collection', 'year', 'month', - 'textReuseClusterSize', 'textReuseClusterLexicalOverlap', - 'textReuseClusterDayDelta', 'daterange' + 'location', + 'country', + 'person', + 'language', + 'topic', + 'newspaper', + 'collection', + 'year', + 'month', + 'textReuseClusterSize', + 'textReuseClusterLexicalOverlap', + 'textReuseClusterDayDelta', + 'daterange' ] const DefaultFilterTypes = [ - 'location', 'country', 'person', 'language', - 'topic', 'newspaper', 'collection', 'year', 'month' + 'location', + 'country', + 'person', + 'language', + 'topic', + 'newspaper', + 'collection', + 'year', + 'month' ] export default { data: () => ({ /** @type {string | undefined} */ id: undefined, + uid: undefined, events: Events, currentType: 'person', searchQuery: undefined, @@ -181,8 +251,7 @@ export default { pageSize: PageSize, RangeFacets, NumericRangeFacets, - TimeRangeFacets, - isModalVisible: false, + TimeRangeFacets }), props: { /** @type {import('vue').PropOptions<import('@/models').Filter[]>} */ @@ -207,15 +276,11 @@ export default { default: 'search' } }, - emits: ['update:modelValue'], + emits: ['update:modelValue', 'hide'], methods: { - openDialog() { - this.isModalVisible = true - }, - closeDialog() { - this.isModalVisible = false + handleTypeChange(type) { + this.currentType = type }, - handleTypeChange(type) { this.currentType = type }, async search() { if (!this.isVisible) return try { @@ -231,7 +296,9 @@ export default { } }, computed: { - filters() { return this.modelValue }, + filters() { + return this.modelValue + }, filter: { get() { return this.filters.find(({ type }) => type === this.currentType) @@ -243,26 +310,34 @@ export default { if (index >= 0) updatedFilters[index] = filter else updatedFilters.push(filter) - this.$emit('modelValue:updated', updatedFilters) - this.closeDialog() + this.$emit('update:modelValue', updatedFilters) + this.$emit(this.events.Hide) } }, currentPageModel: { - get() { return this.currentPage }, - set(val) { this.currentPage = val } + get() { + return this.currentPage + }, + set(val) { + this.currentPage = val + } }, searchQueryModel: { - get() { return this.searchQuery }, - set(q) { this.searchQuery = q } + get() { + return this.searchQuery + }, + set(q) { + this.searchQuery = q + } }, typeOptions() { if (this.includedTypes) { return this.includedTypes.filter(type => AllSupportedFilterTypes.includes(type)) } if (this.searchingEnabled) { - return ['newspaper', 'person', 'location', 'topic', 'collection']; + return ['newspaper', 'person', 'location', 'topic', 'collection'] } - return DefaultFilterTypes; + return DefaultFilterTypes }, searchParameters() { const { @@ -284,25 +359,26 @@ export default { } }, mounted() { - this.id = `facet-explorer-modal-${this._uid}` + this.uid = v4() + this.id = `facet-explorer-modal-${this.uid}` }, components: { FacetExplorer, Pagination, RangeFacetExplorer, TimeFacetExplorer, - Modal, + Modal }, watch: { searchParameters: { - async handler() { return this.search() }, + async handler() { + return this.search() + }, immediate: true }, isVisible: { async handler() { - if (!this.isVisible) return this.closeDialog() - this.openDialog() - return this.search() + if (this.isVisible) return this.search() }, immediate: true }, @@ -312,7 +388,9 @@ export default { }, immediate: true }, - currentType() { this.currentPage = 1 }, + currentType() { + this.currentPage = 1 + }, initialType: { handler() { if (this.initialType == null) { @@ -323,17 +401,18 @@ export default { }, immediate: true } - }, -}; + } +} </script> <style lang="scss"></style> -<i18n lang="json">{ +<i18n lang="json"> +{ "en": { "explore": "refine", "description": { - "search": "It looks like there are <b>no available options</b> matching for type: | ... Just <b>one</b> option mathing for type:| Select among<b> {count}</b> options matching {q} for type:", + "search": "It looks like there are <b>no available options</b> matching for type: | ... Just <b>one</b> option matching for type:| Select among<b> {count}</b> options matching {q} for type:", "facets": "It looks like there are <b>no available options</b> using current search for type: | ... Just <b>one</b> option to refine your search for type:| Select among<b> {count}</b> options to refine your search for type:" }, "searchField": { @@ -356,4 +435,5 @@ export default { "textReuseClusterDayDelta": "cluster span in days" } } -}</i18n> +} +</i18n> diff --git a/src/components/modules/FacetExplorer.vue b/src/components/modules/FacetExplorer.vue index 1cc21358e..ea5d31765 100644 --- a/src/components/modules/FacetExplorer.vue +++ b/src/components/modules/FacetExplorer.vue @@ -1,5 +1,5 @@ <template> - <div class="facet-explorer"> + <div class="facet-explorer" data-testid="facet-explorer"> <div> <!-- The Loop --> <div class="position-relative"> @@ -7,34 +7,40 @@ role="group" tabindex="-1" class="position-relative px-3 pt-2 pb-5 bv-no-focus-ring" - style="min-height: 4em; max-height: 16em; overflow: scroll"> - <b-form-checkbox v-for="(bucket, idx) in buckets" - v-bind:key="idx" - :modelValue="bucket.val" - class="d-block" - @update:modelValue="handleChecked($event, bucket.val)"> + style="min-height: 4em; max-height: 16em; overflow: scroll" + data-testid="facet-explorer-list" + > + <b-form-checkbox + v-for="(bucket, idx) in buckets" + v-bind:key="idx" + :modelValue="selectedIds.includes(bucket.val)" + class="d-block" + @update:modelValue="handleChecked($event, bucket.val)" + data-testid="facet-explorer-list-item-checkbox" + > <item-label v-if="bucket.item" :item="bucket.item" :type="type" /> <span v-if="bucket.count > -1"> - (<span v-html="$tc('numbers.results', bucket.count, { n : $n(bucket.count) })"/>) + (<span v-html="$tc('numbers.results', bucket.count, { n: $n(bucket.count) })" />) </span> - <item-selector :uid="bucket.val" :item="bucket.item" :type="type"/> + <item-selector :uid="bucket.val" :item="bucket.item" :type="type" /> <div class="matches" v-if="bucket.item && bucket.item.matches"> - <span v-for="(match, i) in bucket.item.matches" v-html="match" :key="i"/> + <span v-for="(match, i) in bucket.item.matches" v-html="match" :key="i" /> </div> </b-form-checkbox> </div> <div class="fixed-pagination-footer p-1 mb-2 small"> - <slot name="pagination"> - </slot> + <slot name="pagination"> </slot> </div> </div> </div> <!-- Apply! --> - <div class="p-2 border-top text-center" v-if='selectedIdsChanged'> + <div class="p-2 border-top text-center" v-if="selectedIdsChanged"> <b-button @click="applyFilter()" - size="sm" variant="success" - v-html="$tc('actions.addToCurrentFiltersDetailed', selectedIds.length)"></b-button> + size="sm" + variant="success" + v-html="$tc('actions.addToCurrentFiltersDetailed', selectedIds.length)" + ></b-button> </div> </div> </template> @@ -44,7 +50,7 @@ import ItemLabel from './lists/ItemLabel.vue' import ItemSelector from './ItemSelector.vue' function getEntitiesForIds(ids, entities = []) { - return ids.map(id => entities.find(entity => entity && entity.uid === id)) + return ids.map(id => entities.find(entity => entity && entity.uid === id)) } export default { @@ -52,7 +58,7 @@ export default { data: () => ({ /** @type {string[]} */ selectedIds: [], - selectedIdsEntities: [], + selectedIdsEntities: [] }), props: { modelValue: { @@ -74,17 +80,15 @@ export default { throw new Error('"filter" type must be equal to "filterType"') }, computed: { - filter() { return this.modelValue }, + filter() { + return this.modelValue + }, // Filter type https://github.com/impresso/impresso-jscommons/blob/master/proto/query.proto#L19-L45 type() { - return this.filter && this.filter.type - ? this.filter.type - : this.filterType + return this.filter && this.filter.type ? this.filter.type : this.filterType }, filterIds() { - return this.filter && Array.isArray(this.filter.q) - ? this.filter.q - : [] + return this.filter && Array.isArray(this.filter.q) ? this.filter.q : [] }, selectedIdsChanged() { const a = JSON.stringify([...this.selectedIds].sort()) @@ -98,8 +102,7 @@ export default { this.selectedIds.forEach((id, idx) => { if (id === val) this.selectedIds.splice(idx, 1) }) - } - else this.selectedIds.push(val) + } else this.selectedIds.push(val) }, applyFilter() { const entities = getEntitiesForIds( @@ -107,15 +110,13 @@ export default { this.selectedIdsEntities.concat(this.buckets.map(({ item }) => item)) ) - const originalFilter = this.filter - ? this.filter - : { type: this.filterType } + const originalFilter = this.filter ? this.filter : { type: this.filterType } const updatedFilter = Object.assign({}, originalFilter, { q: this.selectedIds, items: entities }) this.$emit('update:modelValue', updatedFilter) - }, + } }, watch: { filter: { @@ -129,13 +130,12 @@ export default { }, components: { ItemLabel, - ItemSelector, - }, -}; + ItemSelector + } +} </script> <style scoped lang="less"> - .fixed-pagination-footer { position: absolute; bottom: 0; @@ -147,7 +147,6 @@ export default { </style> <i18n lang="json"> { - "en": { - } + "en": {} } </i18n>