@internetarchive/collection-browser 0.4.16-alpha.9 → 0.4.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/app-root.js +12 -0
- package/dist/src/app-root.js.map +1 -1
- package/dist/src/collection-browser.d.ts +53 -14
- package/dist/src/collection-browser.js +264 -110
- package/dist/src/collection-browser.js.map +1 -1
- package/dist/src/collection-facets/facets-template.d.ts +3 -0
- package/dist/src/collection-facets/facets-template.js +20 -1
- package/dist/src/collection-facets/facets-template.js.map +1 -1
- package/dist/src/collection-facets/more-facets-content.js +7 -4
- package/dist/src/collection-facets/more-facets-content.js.map +1 -1
- package/dist/src/collection-facets.d.ts +0 -2
- package/dist/src/collection-facets.js +1 -4
- package/dist/src/collection-facets.js.map +1 -1
- package/dist/src/empty-placeholder.js +1 -0
- package/dist/src/empty-placeholder.js.map +1 -1
- package/dist/src/models.d.ts +5 -0
- package/dist/src/models.js.map +1 -1
- package/dist/src/tiles/grid/item-tile.js +10 -3
- package/dist/src/tiles/grid/item-tile.js.map +1 -1
- package/dist/src/tiles/list/tile-list-compact.d.ts +1 -0
- package/dist/src/tiles/list/tile-list-compact.js +13 -1
- package/dist/src/tiles/list/tile-list-compact.js.map +1 -1
- package/dist/src/tiles/list/tile-list.js +10 -1
- package/dist/src/tiles/list/tile-list.js.map +1 -1
- package/dist/src/utils/format-date.d.ts +1 -1
- package/dist/src/utils/format-date.js +3 -0
- package/dist/src/utils/format-date.js.map +1 -1
- package/dist/src/utils/local-date-from-utc.d.ts +9 -0
- package/dist/src/utils/local-date-from-utc.js +16 -0
- package/dist/src/utils/local-date-from-utc.js.map +1 -0
- package/dist/test/collection-browser.test.js +41 -10
- package/dist/test/collection-browser.test.js.map +1 -1
- package/dist/test/collection-facets/facets-template.test.js +80 -0
- package/dist/test/collection-facets/facets-template.test.js.map +1 -1
- package/dist/test/tiles/grid/item-tile.test.js +124 -3
- package/dist/test/tiles/grid/item-tile.test.js.map +1 -1
- package/dist/test/tiles/list/tile-list-compact.test.js +65 -20
- package/dist/test/tiles/list/tile-list-compact.test.js.map +1 -1
- package/dist/test/tiles/list/tile-list.test.js +106 -4
- package/dist/test/tiles/list/tile-list.test.js.map +1 -1
- package/dist/test/utils/local-date-from-utc.test.d.ts +1 -0
- package/dist/test/utils/local-date-from-utc.test.js +27 -0
- package/dist/test/utils/local-date-from-utc.test.js.map +1 -0
- package/index.html +1 -0
- package/package.json +1 -1
- package/src/app-root.ts +12 -0
- package/src/collection-browser.ts +294 -112
- package/src/collection-facets/facets-template.ts +32 -1
- package/src/collection-facets/more-facets-content.ts +4 -1
- package/src/collection-facets.ts +1 -8
- package/src/empty-placeholder.ts +1 -0
- package/src/models.ts +6 -0
- package/src/tiles/grid/item-tile.ts +11 -4
- package/src/tiles/list/tile-list-compact.ts +16 -2
- package/src/tiles/list/tile-list.ts +12 -5
- package/src/utils/format-date.ts +4 -0
- package/src/utils/local-date-from-utc.ts +15 -0
- package/test/collection-browser.test.ts +57 -12
- package/test/collection-facets/facets-template.test.ts +98 -0
- package/test/tiles/grid/item-tile.test.ts +145 -3
- package/test/tiles/list/tile-list-compact.test.ts +70 -19
- package/test/tiles/list/tile-list.test.ts +118 -4
- package/test/utils/local-date-from-utc.test.ts +37 -0
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
FacetBucket,
|
|
11
11
|
SelectedFacets,
|
|
12
12
|
getDefaultSelectedFacets,
|
|
13
|
+
FacetEventDetails,
|
|
14
|
+
FacetState,
|
|
13
15
|
} from '../models';
|
|
14
16
|
|
|
15
17
|
@customElement('facets-template')
|
|
@@ -31,6 +33,12 @@ export class FacetsTemplate extends LitElement {
|
|
|
31
33
|
} else {
|
|
32
34
|
this.facetUnchecked(name as FacetOption, value);
|
|
33
35
|
}
|
|
36
|
+
|
|
37
|
+
this.dispatchFacetClickEvent(
|
|
38
|
+
name as FacetOption,
|
|
39
|
+
this.getFacetState(checked, negative),
|
|
40
|
+
negative
|
|
41
|
+
);
|
|
34
42
|
}
|
|
35
43
|
|
|
36
44
|
private facetChecked(
|
|
@@ -49,7 +57,7 @@ export class FacetsTemplate extends LitElement {
|
|
|
49
57
|
newFacets = getDefaultSelectedFacets();
|
|
50
58
|
}
|
|
51
59
|
newFacets[key][value] = {
|
|
52
|
-
state: negative
|
|
60
|
+
state: this.getFacetState(true, negative),
|
|
53
61
|
count,
|
|
54
62
|
} as FacetBucket;
|
|
55
63
|
|
|
@@ -73,6 +81,29 @@ export class FacetsTemplate extends LitElement {
|
|
|
73
81
|
this.dispatchSelectedFacetsChanged();
|
|
74
82
|
}
|
|
75
83
|
|
|
84
|
+
/** Returns the composed facet state corresponding to a positive or negative facet's checked state */
|
|
85
|
+
private getFacetState(checked: boolean, negative: boolean): FacetState {
|
|
86
|
+
let state: FacetState;
|
|
87
|
+
if (checked) {
|
|
88
|
+
state = negative ? 'hidden' : 'selected';
|
|
89
|
+
} else {
|
|
90
|
+
state = 'none';
|
|
91
|
+
}
|
|
92
|
+
return state;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private dispatchFacetClickEvent(
|
|
96
|
+
key: FacetOption,
|
|
97
|
+
state: FacetState,
|
|
98
|
+
negative: boolean
|
|
99
|
+
) {
|
|
100
|
+
const event = new CustomEvent<FacetEventDetails>('facetClick', {
|
|
101
|
+
detail: { key, state, negative },
|
|
102
|
+
composed: true,
|
|
103
|
+
});
|
|
104
|
+
this.dispatchEvent(event);
|
|
105
|
+
}
|
|
106
|
+
|
|
76
107
|
private dispatchSelectedFacetsChanged() {
|
|
77
108
|
const event = new CustomEvent<SelectedFacets>('selectedFacetsChanged', {
|
|
78
109
|
detail: this.selectedFacets,
|
|
@@ -130,13 +130,16 @@ export class MoreFacetsContent extends LitElement {
|
|
|
130
130
|
* - this.aggregations - hold result of search service and being used for further processing.
|
|
131
131
|
*/
|
|
132
132
|
async updateSpecificFacets(): Promise<void> {
|
|
133
|
+
const trimmedQuery = this.query?.trim();
|
|
134
|
+
if (!trimmedQuery) return;
|
|
135
|
+
|
|
133
136
|
const aggregations = {
|
|
134
137
|
simpleParams: [this.facetAggregationKey as string],
|
|
135
138
|
};
|
|
136
139
|
const aggregationsSize = 65535; // todo - do we want to have all the records at once?
|
|
137
140
|
|
|
138
141
|
const params: SearchParams = {
|
|
139
|
-
query:
|
|
142
|
+
query: trimmedQuery,
|
|
140
143
|
filters: this.filterMap,
|
|
141
144
|
aggregations,
|
|
142
145
|
aggregationsSize,
|
package/src/collection-facets.ts
CHANGED
|
@@ -99,13 +99,6 @@ export class CollectionFacets extends LitElement {
|
|
|
99
99
|
@property({ type: Object, attribute: false })
|
|
100
100
|
collectionNameCache?: CollectionNameCacheInterface;
|
|
101
101
|
|
|
102
|
-
/** Fires when a facet is clicked */
|
|
103
|
-
@property({ type: Function }) onFacetClick?: (
|
|
104
|
-
name: FacetOption,
|
|
105
|
-
facetChecked: boolean,
|
|
106
|
-
negative: boolean
|
|
107
|
-
) => void;
|
|
108
|
-
|
|
109
102
|
@state() openFacets: Record<FacetOption, boolean> = {
|
|
110
103
|
subject: false,
|
|
111
104
|
lending: false,
|
|
@@ -554,7 +547,7 @@ export class CollectionFacets extends LitElement {
|
|
|
554
547
|
transform: rotate(90deg);
|
|
555
548
|
}
|
|
556
549
|
|
|
557
|
-
.facet-group {
|
|
550
|
+
.facet-group:not(:last-child) {
|
|
558
551
|
margin-bottom: 2rem;
|
|
559
552
|
}
|
|
560
553
|
|
package/src/empty-placeholder.ts
CHANGED
package/src/models.ts
CHANGED
|
@@ -220,6 +220,12 @@ export interface FacetGroup {
|
|
|
220
220
|
buckets: FacetBucket[];
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
+
export type FacetEventDetails = {
|
|
224
|
+
key: FacetOption;
|
|
225
|
+
state: FacetState;
|
|
226
|
+
negative: boolean;
|
|
227
|
+
};
|
|
228
|
+
|
|
223
229
|
export type FacetValue = string;
|
|
224
230
|
|
|
225
231
|
export type SelectedFacets = Record<
|
|
@@ -11,7 +11,8 @@ import { customElement, property } from 'lit/decorators.js';
|
|
|
11
11
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
12
12
|
import type { SortParam } from '@internetarchive/search-service';
|
|
13
13
|
|
|
14
|
-
import { formatDate } from '../../utils/format-date';
|
|
14
|
+
import { DateFormat, formatDate } from '../../utils/format-date';
|
|
15
|
+
import { isFirstMillisecondOfUTCYear } from '../../utils/local-date-from-utc';
|
|
15
16
|
import type { TileModel } from '../../models';
|
|
16
17
|
|
|
17
18
|
import { baseTileStyles } from './styles/tile-grid-shared-styles';
|
|
@@ -104,10 +105,16 @@ export class ItemTile extends LitElement {
|
|
|
104
105
|
|
|
105
106
|
private get sortedDateInfoTemplate() {
|
|
106
107
|
let sortedValue;
|
|
108
|
+
let format: DateFormat = 'long';
|
|
107
109
|
switch (this.sortParam?.field) {
|
|
108
|
-
case 'date':
|
|
109
|
-
|
|
110
|
+
case 'date': {
|
|
111
|
+
const datePublished = this.model?.datePublished;
|
|
112
|
+
sortedValue = { field: 'published', value: datePublished };
|
|
113
|
+
if (isFirstMillisecondOfUTCYear(datePublished)) {
|
|
114
|
+
format = 'year-only';
|
|
115
|
+
}
|
|
110
116
|
break;
|
|
117
|
+
}
|
|
111
118
|
case 'reviewdate':
|
|
112
119
|
sortedValue = { field: 'reviewed', value: this.model?.dateReviewed };
|
|
113
120
|
break;
|
|
@@ -127,7 +134,7 @@ export class ItemTile extends LitElement {
|
|
|
127
134
|
return html`
|
|
128
135
|
<div class="date-sorted-by truncated">
|
|
129
136
|
<span>
|
|
130
|
-
${sortedValue?.field} ${formatDate(sortedValue?.value,
|
|
137
|
+
${sortedValue?.field} ${formatDate(sortedValue?.value, format)}
|
|
131
138
|
</span>
|
|
132
139
|
</div>
|
|
133
140
|
`;
|
|
@@ -6,6 +6,7 @@ import type { TileModel } from '../../models';
|
|
|
6
6
|
|
|
7
7
|
import { formatCount, NumberFormat } from '../../utils/format-count';
|
|
8
8
|
import { formatDate, DateFormat } from '../../utils/format-date';
|
|
9
|
+
import { isFirstMillisecondOfUTCYear } from '../../utils/local-date-from-utc';
|
|
9
10
|
import { accountLabel } from './account-label';
|
|
10
11
|
|
|
11
12
|
import '../image-block';
|
|
@@ -49,7 +50,7 @@ export class TileListCompact extends LitElement {
|
|
|
49
50
|
? accountLabel(this.model?.dateAdded)
|
|
50
51
|
: DOMPurify.sanitize(this.model?.creator ?? '')}
|
|
51
52
|
</div>
|
|
52
|
-
<div id="date">${formatDate(this.date, this.
|
|
53
|
+
<div id="date">${formatDate(this.date, this.dateFormatSize)}</div>
|
|
53
54
|
<div id="icon">
|
|
54
55
|
<mediatype-icon
|
|
55
56
|
.mediatype=${this.model?.mediatype}
|
|
@@ -111,7 +112,20 @@ export class TileListCompact extends LitElement {
|
|
|
111
112
|
return 'desktop';
|
|
112
113
|
}
|
|
113
114
|
|
|
114
|
-
private get
|
|
115
|
+
private get dateFormatSize(): DateFormat {
|
|
116
|
+
// If we're showing a date published of Jan 1 at midnight, only show the year.
|
|
117
|
+
// This is because items with only a year for their publication date are normalized to
|
|
118
|
+
// Jan 1 at midnight timestamps in the search engine documents.
|
|
119
|
+
if (
|
|
120
|
+
(!this.sortParam?.field || this.sortParam.field === 'date') && // No sort or date published
|
|
121
|
+
isFirstMillisecondOfUTCYear(this.model?.datePublished)
|
|
122
|
+
) {
|
|
123
|
+
return 'year-only';
|
|
124
|
+
}
|
|
125
|
+
return this.formatSize;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private get formatSize(): NumberFormat {
|
|
115
129
|
if (
|
|
116
130
|
this.mobileBreakpoint &&
|
|
117
131
|
this.currentWidth &&
|
|
@@ -21,6 +21,7 @@ import { dateLabel } from './date-label';
|
|
|
21
21
|
import { accountLabel } from './account-label';
|
|
22
22
|
import { formatCount, NumberFormat } from '../../utils/format-count';
|
|
23
23
|
import { formatDate, DateFormat } from '../../utils/format-date';
|
|
24
|
+
import { isFirstMillisecondOfUTCYear } from '../../utils/local-date-from-utc';
|
|
24
25
|
|
|
25
26
|
import '../image-block';
|
|
26
27
|
import '../mediatype-icon';
|
|
@@ -205,10 +206,16 @@ export class TileList extends LitElement {
|
|
|
205
206
|
}
|
|
206
207
|
|
|
207
208
|
private get datePublishedTemplate() {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
209
|
+
// If we're showing a date published of Jan 1 at midnight, only show the year.
|
|
210
|
+
// This is because items with only a year for their publication date are normalized to
|
|
211
|
+
// Jan 1 at midnight timestamps in the search engine documents.
|
|
212
|
+
const date: Date | undefined = this.model?.datePublished;
|
|
213
|
+
let format: DateFormat = 'long';
|
|
214
|
+
if (isFirstMillisecondOfUTCYear(date)) {
|
|
215
|
+
format = 'year-only';
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return this.metadataTemplate(formatDate(date, format), 'Published');
|
|
212
219
|
}
|
|
213
220
|
|
|
214
221
|
// Show date label/value when sorted by date type
|
|
@@ -430,7 +437,7 @@ export class TileList extends LitElement {
|
|
|
430
437
|
return 'desktop';
|
|
431
438
|
}
|
|
432
439
|
|
|
433
|
-
private get formatSize():
|
|
440
|
+
private get formatSize(): NumberFormat {
|
|
434
441
|
if (
|
|
435
442
|
this.mobileBreakpoint &&
|
|
436
443
|
this.currentWidth &&
|
package/src/utils/format-date.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Override browser timezone to always display same date as in data
|
|
4
4
|
*/
|
|
5
5
|
export type DateFormat =
|
|
6
|
+
| 'year-only' // 2020
|
|
6
7
|
| 'short' // Dec 2020
|
|
7
8
|
| 'long'; // Dec 20, 2020
|
|
8
9
|
|
|
@@ -18,6 +19,9 @@ export function formatDate(
|
|
|
18
19
|
timeZone: 'UTC', // Override browser timezone
|
|
19
20
|
};
|
|
20
21
|
switch (format) {
|
|
22
|
+
case 'year-only':
|
|
23
|
+
options.year = 'numeric';
|
|
24
|
+
break;
|
|
21
25
|
case 'short':
|
|
22
26
|
options.month = 'short';
|
|
23
27
|
options.year = 'numeric';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a given UTC date into the equivalent local-timestamp one.
|
|
3
|
+
*/
|
|
4
|
+
export function localDateFromUTC(date: Date): Date {
|
|
5
|
+
return new Date(date.getTime() - date.getTimezoneOffset() * 1000 * 60);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Returns whether a given UTC date corresponds to the first
|
|
10
|
+
* millisecond of the year (e.g., Jan 1 at exactly midnight).
|
|
11
|
+
*/
|
|
12
|
+
export function isFirstMillisecondOfUTCYear(date?: Date): boolean {
|
|
13
|
+
if (!date) return false;
|
|
14
|
+
return localDateFromUTC(date).toISOString().endsWith('-01-01T00:00:00.000Z');
|
|
15
|
+
}
|
|
@@ -3,7 +3,7 @@ import { aTimeout, expect, fixture } from '@open-wc/testing';
|
|
|
3
3
|
import { html } from 'lit';
|
|
4
4
|
import sinon from 'sinon';
|
|
5
5
|
import type { InfiniteScroller } from '@internetarchive/infinite-scroller';
|
|
6
|
-
import { SearchType } from '@internetarchive/search-service';
|
|
6
|
+
import { FilterConstraint, SearchType } from '@internetarchive/search-service';
|
|
7
7
|
import type { HistogramDateRange } from '@internetarchive/histogram-date-range';
|
|
8
8
|
import type { CollectionBrowser } from '../src/collection-browser';
|
|
9
9
|
import '../src/collection-browser';
|
|
@@ -174,12 +174,20 @@ describe('Collection Browser', () => {
|
|
|
174
174
|
el.selectedFacets = mockedSelectedFacets;
|
|
175
175
|
await el.updateComplete;
|
|
176
176
|
|
|
177
|
-
el.facetClickHandler(
|
|
177
|
+
el.facetClickHandler(
|
|
178
|
+
new CustomEvent('facetClick', {
|
|
179
|
+
detail: { key: 'mediatype', state: 'selected', negative: false },
|
|
180
|
+
})
|
|
181
|
+
);
|
|
178
182
|
expect(mockAnalyticsHandler.callCategory).to.equal('search-service');
|
|
179
183
|
expect(mockAnalyticsHandler.callAction).to.equal('facetSelected');
|
|
180
184
|
expect(mockAnalyticsHandler.callLabel).to.equal('mediatype');
|
|
181
185
|
|
|
182
|
-
el.facetClickHandler(
|
|
186
|
+
el.facetClickHandler(
|
|
187
|
+
new CustomEvent('facetClick', {
|
|
188
|
+
detail: { key: 'mediatype', state: 'none', negative: false },
|
|
189
|
+
})
|
|
190
|
+
);
|
|
183
191
|
expect(el.selectedFacets).to.equal(mockedSelectedFacets);
|
|
184
192
|
expect(mockAnalyticsHandler.callCategory).to.equal('search-service');
|
|
185
193
|
expect(mockAnalyticsHandler.callAction).to.equal('facetDeselected');
|
|
@@ -208,12 +216,20 @@ describe('Collection Browser', () => {
|
|
|
208
216
|
el.selectedFacets = mockedSelectedFacets;
|
|
209
217
|
await el.updateComplete;
|
|
210
218
|
|
|
211
|
-
el.facetClickHandler(
|
|
219
|
+
el.facetClickHandler(
|
|
220
|
+
new CustomEvent('facetClick', {
|
|
221
|
+
detail: { key: 'mediatype', state: 'hidden', negative: true },
|
|
222
|
+
})
|
|
223
|
+
);
|
|
212
224
|
expect(mockAnalyticsHandler.callCategory).to.equal('beta-search-service');
|
|
213
225
|
expect(mockAnalyticsHandler.callAction).to.equal('facetNegativeSelected');
|
|
214
226
|
expect(mockAnalyticsHandler.callLabel).to.equal('mediatype');
|
|
215
227
|
|
|
216
|
-
el.facetClickHandler(
|
|
228
|
+
el.facetClickHandler(
|
|
229
|
+
new CustomEvent('facetClick', {
|
|
230
|
+
detail: { key: 'mediatype', state: 'none', negative: true },
|
|
231
|
+
})
|
|
232
|
+
);
|
|
217
233
|
expect(el.selectedFacets).to.equal(mockedSelectedFacets);
|
|
218
234
|
expect(mockAnalyticsHandler.callCategory).to.equal('beta-search-service');
|
|
219
235
|
expect(mockAnalyticsHandler.callAction).to.equal('facetNegativeDeselected');
|
|
@@ -727,8 +743,9 @@ describe('Collection Browser', () => {
|
|
|
727
743
|
el.selectedTitleFilter = 'X';
|
|
728
744
|
await el.updateComplete;
|
|
729
745
|
|
|
730
|
-
expect(searchService.searchParams?.query).to.equal(
|
|
731
|
-
|
|
746
|
+
expect(searchService.searchParams?.query).to.equal('first-title');
|
|
747
|
+
expect(searchService.searchParams?.filters?.firstTitle?.X).to.equal(
|
|
748
|
+
FilterConstraint.INCLUDE
|
|
732
749
|
);
|
|
733
750
|
});
|
|
734
751
|
|
|
@@ -745,8 +762,9 @@ describe('Collection Browser', () => {
|
|
|
745
762
|
el.selectedCreatorFilter = 'X';
|
|
746
763
|
await el.updateComplete;
|
|
747
764
|
|
|
748
|
-
expect(searchService.searchParams?.query).to.equal(
|
|
749
|
-
|
|
765
|
+
expect(searchService.searchParams?.query).to.equal('first-creator');
|
|
766
|
+
expect(searchService.searchParams?.filters?.firstCreator?.X).to.equal(
|
|
767
|
+
FilterConstraint.INCLUDE
|
|
750
768
|
);
|
|
751
769
|
});
|
|
752
770
|
|
|
@@ -776,9 +794,7 @@ describe('Collection Browser', () => {
|
|
|
776
794
|
el.selectedCreatorFilter = 'X';
|
|
777
795
|
await el.updateComplete;
|
|
778
796
|
|
|
779
|
-
expect(searchService.searchParams?.query).to.equal(
|
|
780
|
-
'first-creator AND firstCreator:X'
|
|
781
|
-
);
|
|
797
|
+
expect(searchService.searchParams?.query).to.equal('first-creator');
|
|
782
798
|
expect(searchService.searchParams?.filters).to.deep.equal({
|
|
783
799
|
collection: {
|
|
784
800
|
foo: 'inc',
|
|
@@ -787,9 +803,38 @@ describe('Collection Browser', () => {
|
|
|
787
803
|
'1950': 'gte',
|
|
788
804
|
'1970': 'lte',
|
|
789
805
|
},
|
|
806
|
+
firstCreator: {
|
|
807
|
+
X: 'inc',
|
|
808
|
+
},
|
|
790
809
|
});
|
|
791
810
|
});
|
|
792
811
|
|
|
812
|
+
it('resets letter filters when query changes', async () => {
|
|
813
|
+
const searchService = new MockSearchService();
|
|
814
|
+
const el = await fixture<CollectionBrowser>(
|
|
815
|
+
html`<collection-browser .searchService=${searchService}>
|
|
816
|
+
</collection-browser>`
|
|
817
|
+
);
|
|
818
|
+
|
|
819
|
+
el.baseQuery = 'first-creator';
|
|
820
|
+
el.selectedSort = 'creator' as SortField;
|
|
821
|
+
el.sortDirection = 'asc';
|
|
822
|
+
el.selectedCreatorFilter = 'X';
|
|
823
|
+
await el.updateComplete;
|
|
824
|
+
await nextTick();
|
|
825
|
+
|
|
826
|
+
expect(searchService.searchParams?.query).to.equal('first-creator');
|
|
827
|
+
expect(searchService.searchParams?.filters?.firstCreator?.X).to.equal(
|
|
828
|
+
FilterConstraint.INCLUDE
|
|
829
|
+
);
|
|
830
|
+
|
|
831
|
+
el.baseQuery = 'collection:foo';
|
|
832
|
+
await el.updateComplete;
|
|
833
|
+
|
|
834
|
+
expect(searchService.searchParams?.query).to.equal('collection:foo');
|
|
835
|
+
expect(searchService.searchParams?.filters?.firstCreator).not.to.exist;
|
|
836
|
+
});
|
|
837
|
+
|
|
793
838
|
it('sets date range query when date picker selection changed', async () => {
|
|
794
839
|
const searchService = new MockSearchService();
|
|
795
840
|
const el = await fixture<CollectionBrowser>(
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { expect, fixture } from '@open-wc/testing';
|
|
2
|
+
import sinon from 'sinon';
|
|
2
3
|
import { html } from 'lit';
|
|
3
4
|
import type { FacetsTemplate } from '../../src/collection-facets/facets-template';
|
|
4
5
|
import '../../src/collection-facets/facets-template';
|
|
6
|
+
import { getDefaultSelectedFacets, FacetEventDetails } from '../../src/models';
|
|
5
7
|
|
|
6
8
|
const facetGroup = {
|
|
7
9
|
title: 'Media Type',
|
|
@@ -102,4 +104,100 @@ describe('Render facets', () => {
|
|
|
102
104
|
'Hide mediatype: movies'
|
|
103
105
|
);
|
|
104
106
|
});
|
|
107
|
+
|
|
108
|
+
it('emits facetClick events for normal facets', async () => {
|
|
109
|
+
const facetClickSpy = sinon.spy();
|
|
110
|
+
const mediatypeGroup = {
|
|
111
|
+
title: 'Media Type',
|
|
112
|
+
key: 'mediatype',
|
|
113
|
+
buckets: [
|
|
114
|
+
{ displayText: 'audio', key: 'audio', count: 42, state: 'none' },
|
|
115
|
+
],
|
|
116
|
+
};
|
|
117
|
+
const selectedFacets = getDefaultSelectedFacets();
|
|
118
|
+
const el = await fixture<FacetsTemplate>(
|
|
119
|
+
html`<facets-template
|
|
120
|
+
.facetGroup=${mediatypeGroup}
|
|
121
|
+
.selectedFacets=${selectedFacets}
|
|
122
|
+
@facetClick=${facetClickSpy}
|
|
123
|
+
></facets-template>`
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
const checkbox = el.shadowRoot?.querySelector(
|
|
127
|
+
'.select-facet-checkbox'
|
|
128
|
+
) as HTMLInputElement;
|
|
129
|
+
expect(checkbox).to.exist;
|
|
130
|
+
|
|
131
|
+
// Select it
|
|
132
|
+
checkbox.click();
|
|
133
|
+
await el.updateComplete;
|
|
134
|
+
expect(facetClickSpy.callCount).to.equal(1);
|
|
135
|
+
|
|
136
|
+
const selectEvent = facetClickSpy
|
|
137
|
+
.args[0][0] as CustomEvent<FacetEventDetails>;
|
|
138
|
+
expect(selectEvent).to.exist;
|
|
139
|
+
expect(selectEvent?.detail?.key).to.equal('mediatype');
|
|
140
|
+
expect(selectEvent?.detail?.state).to.equal('selected');
|
|
141
|
+
expect(selectEvent?.detail?.negative).to.be.false;
|
|
142
|
+
|
|
143
|
+
// Unselect it
|
|
144
|
+
checkbox.click();
|
|
145
|
+
await el.updateComplete;
|
|
146
|
+
expect(facetClickSpy.callCount).to.equal(2);
|
|
147
|
+
|
|
148
|
+
const unselectEvent = facetClickSpy
|
|
149
|
+
.args[1][0] as CustomEvent<FacetEventDetails>;
|
|
150
|
+
expect(unselectEvent).to.exist;
|
|
151
|
+
expect(unselectEvent?.detail?.key).to.equal('mediatype');
|
|
152
|
+
expect(unselectEvent?.detail?.state).to.equal('none');
|
|
153
|
+
expect(unselectEvent?.detail?.negative).to.be.false;
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('emits facetClick events for negative facets', async () => {
|
|
157
|
+
const facetClickSpy = sinon.spy();
|
|
158
|
+
const mediatypeGroup = {
|
|
159
|
+
title: 'Media Type',
|
|
160
|
+
key: 'mediatype',
|
|
161
|
+
buckets: [
|
|
162
|
+
{ displayText: 'audio', key: 'audio', count: 42, state: 'none' },
|
|
163
|
+
],
|
|
164
|
+
};
|
|
165
|
+
const selectedFacets = getDefaultSelectedFacets();
|
|
166
|
+
const el = await fixture<FacetsTemplate>(
|
|
167
|
+
html`<facets-template
|
|
168
|
+
.facetGroup=${mediatypeGroup}
|
|
169
|
+
.selectedFacets=${selectedFacets}
|
|
170
|
+
@facetClick=${facetClickSpy}
|
|
171
|
+
></facets-template>`
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
const checkbox = el.shadowRoot?.querySelector(
|
|
175
|
+
'.hide-facet-checkbox'
|
|
176
|
+
) as HTMLInputElement;
|
|
177
|
+
expect(checkbox).to.exist;
|
|
178
|
+
|
|
179
|
+
// Select it
|
|
180
|
+
checkbox.click();
|
|
181
|
+
await el.updateComplete;
|
|
182
|
+
expect(facetClickSpy.callCount).to.equal(1);
|
|
183
|
+
|
|
184
|
+
const selectEvent = facetClickSpy
|
|
185
|
+
.args[0][0] as CustomEvent<FacetEventDetails>;
|
|
186
|
+
expect(selectEvent).to.exist;
|
|
187
|
+
expect(selectEvent?.detail?.key).to.equal('mediatype');
|
|
188
|
+
expect(selectEvent?.detail?.state).to.equal('hidden');
|
|
189
|
+
expect(selectEvent?.detail?.negative).to.be.true;
|
|
190
|
+
|
|
191
|
+
// Unselect it
|
|
192
|
+
checkbox.click();
|
|
193
|
+
await el.updateComplete;
|
|
194
|
+
expect(facetClickSpy.callCount).to.equal(2);
|
|
195
|
+
|
|
196
|
+
const unselectEvent = facetClickSpy
|
|
197
|
+
.args[1][0] as CustomEvent<FacetEventDetails>;
|
|
198
|
+
expect(unselectEvent).to.exist;
|
|
199
|
+
expect(unselectEvent?.detail?.key).to.equal('mediatype');
|
|
200
|
+
expect(unselectEvent?.detail?.state).to.equal('none');
|
|
201
|
+
expect(unselectEvent?.detail?.negative).to.be.true;
|
|
202
|
+
});
|
|
105
203
|
});
|