@internetarchive/collection-browser 4.2.0-alpha-webdev8164.3 → 4.2.1-alpha-webdev7004.0
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/.claude/settings.local.json +11 -0
- package/.editorconfig +29 -29
- package/.github/workflows/ci.yml +27 -27
- package/.github/workflows/gh-pages-main.yml +39 -39
- package/.github/workflows/npm-publish.yml +39 -39
- package/.github/workflows/pr-preview.yml +38 -38
- package/.husky/pre-commit +1 -1
- package/.prettierignore +1 -1
- package/LICENSE +661 -661
- package/README.md +83 -83
- package/dist/src/app-root.js +4 -0
- package/dist/src/app-root.js.map +1 -1
- package/dist/src/collection-browser.js +32 -27
- package/dist/src/collection-browser.js.map +1 -1
- package/dist/src/collection-facets/facets-template.js +0 -5
- package/dist/src/collection-facets/facets-template.js.map +1 -1
- package/dist/src/collection-facets/more-facets-content.d.ts +8 -106
- package/dist/src/collection-facets/more-facets-content.js +103 -612
- package/dist/src/collection-facets/more-facets-content.js.map +1 -1
- package/dist/src/collection-facets/more-facets-pagination.d.ts +3 -12
- package/dist/src/collection-facets/more-facets-pagination.js +9 -71
- package/dist/src/collection-facets/more-facets-pagination.js.map +1 -1
- package/dist/src/collection-facets/toggle-switch.js +0 -1
- package/dist/src/collection-facets/toggle-switch.js.map +1 -1
- package/dist/src/collection-facets.js +9 -10
- package/dist/src/collection-facets.js.map +1 -1
- package/dist/src/data-source/collection-browser-data-source.d.ts +7 -0
- package/dist/src/data-source/collection-browser-data-source.js +27 -10
- package/dist/src/data-source/collection-browser-data-source.js.map +1 -1
- package/dist/src/mediatype/mediatype-config.js +1 -1
- package/dist/src/mediatype/mediatype-config.js.map +1 -1
- package/dist/src/models.d.ts +12 -2
- package/dist/src/models.js +13 -8
- package/dist/src/models.js.map +1 -1
- package/dist/src/restoration-state-handler.js +9 -3
- package/dist/src/restoration-state-handler.js.map +1 -1
- package/dist/src/tiles/hover/hover-pane-controller.js +2 -1
- package/dist/src/tiles/hover/hover-pane-controller.js.map +1 -1
- package/dist/src/tiles/tile-dispatcher.d.ts +6 -0
- package/dist/src/tiles/tile-dispatcher.js +11 -3
- package/dist/src/tiles/tile-dispatcher.js.map +1 -1
- package/dist/test/collection-browser.test.js +72 -0
- package/dist/test/collection-browser.test.js.map +1 -1
- package/dist/test/collection-facets/more-facets-content.test.js +3 -212
- package/dist/test/collection-facets/more-facets-content.test.js.map +1 -1
- package/dist/test/collection-facets/more-facets-pagination.test.js +3 -63
- package/dist/test/collection-facets/more-facets-pagination.test.js.map +1 -1
- package/dist/test/data-source/collection-browser-data-source.test.js +52 -0
- package/dist/test/data-source/collection-browser-data-source.test.js.map +1 -1
- package/dist/test/mocks/mock-search-responses.d.ts +0 -5
- package/dist/test/mocks/mock-search-responses.js +0 -44
- package/dist/test/mocks/mock-search-responses.js.map +1 -1
- package/dist/test/mocks/mock-search-service.js +1 -2
- package/dist/test/mocks/mock-search-service.js.map +1 -1
- package/dist/test/tiles/tile-dispatcher.test.js +14 -0
- package/dist/test/tiles/tile-dispatcher.test.js.map +1 -1
- package/dist/test/tiles/tile-mediatype-icon.test.js +4 -4
- package/dist/test/tiles/tile-mediatype-icon.test.js.map +1 -1
- package/eslint.config.mjs +53 -53
- package/index.html +24 -24
- package/local.archive.org.cert +86 -86
- package/local.archive.org.key +27 -27
- package/package.json +120 -121
- package/renovate.json +6 -6
- package/src/app-root.ts +4 -0
- package/src/collection-browser.ts +43 -36
- package/src/collection-facets/facets-template.ts +0 -5
- package/src/collection-facets/more-facets-content.ts +113 -662
- package/src/collection-facets/more-facets-pagination.ts +10 -84
- package/src/collection-facets/toggle-switch.ts +0 -1
- package/src/collection-facets.ts +13 -10
- package/src/data-source/collection-browser-data-source.ts +31 -10
- package/src/mediatype/mediatype-config.ts +1 -1
- package/src/models.ts +30 -8
- package/src/restoration-state-handler.ts +7 -3
- package/src/tiles/hover/hover-pane-controller.ts +2 -1
- package/src/tiles/tile-dispatcher.ts +12 -3
- package/test/collection-browser.test.ts +105 -0
- package/test/collection-facets/more-facets-content.test.ts +4 -326
- package/test/collection-facets/more-facets-pagination.test.ts +3 -87
- package/test/data-source/collection-browser-data-source.test.ts +62 -0
- package/test/mocks/mock-search-responses.ts +0 -48
- package/test/mocks/mock-search-service.ts +0 -2
- package/test/tiles/tile-dispatcher.test.ts +17 -0
- package/test/tiles/tile-mediatype-icon.test.ts +4 -4
- package/tsconfig.json +25 -25
- package/web-dev-server.config.mjs +30 -30
- package/web-test-runner.config.mjs +52 -52
|
@@ -25,27 +25,19 @@ export class MoreFacetsPagination extends LitElement {
|
|
|
25
25
|
|
|
26
26
|
@property({ type: Number }) currentPage: number = 1;
|
|
27
27
|
|
|
28
|
-
/**
|
|
29
|
-
* When true, shows a more compact set of page numbers
|
|
30
|
-
* (only 1 neighbor on each side of the current page).
|
|
31
|
-
*/
|
|
32
|
-
@property({ type: Boolean }) compact = false;
|
|
33
|
-
|
|
34
28
|
@state() pages?: number[] = [];
|
|
35
29
|
|
|
30
|
+
firstUpdated() {
|
|
31
|
+
this.observePageCount();
|
|
32
|
+
}
|
|
33
|
+
|
|
36
34
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
37
|
-
override
|
|
38
|
-
if (
|
|
39
|
-
|
|
40
|
-
changed.has('compact') ||
|
|
41
|
-
changed.has('currentPage')
|
|
42
|
-
) {
|
|
43
|
-
this.updatePages();
|
|
35
|
+
override updated(changed: Map<string, any>) {
|
|
36
|
+
if (changed.has('size')) {
|
|
37
|
+
this.observePageCount();
|
|
44
38
|
}
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
changed.get('currentPage') !== undefined
|
|
48
|
-
) {
|
|
39
|
+
if (changed.has('currentPage')) {
|
|
40
|
+
this.observePageCount();
|
|
49
41
|
this.emitPageClick();
|
|
50
42
|
}
|
|
51
43
|
}
|
|
@@ -58,14 +50,9 @@ export class MoreFacetsPagination extends LitElement {
|
|
|
58
50
|
* - outlier: last page selected, show 1 ... N-2 N-1 _N_
|
|
59
51
|
* - outlier: if page count = 7, & selected is either [2, 3, 4, 5, 6], show all pages
|
|
60
52
|
*/
|
|
61
|
-
|
|
53
|
+
observePageCount() {
|
|
62
54
|
this.pages = []; /* `0` is elipses marker */
|
|
63
55
|
|
|
64
|
-
if (this.compact) {
|
|
65
|
-
this.updatePagesCompact();
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
56
|
const paginatorMaxPagesToShow = 7;
|
|
70
57
|
const atMinThreshold = this.size <= paginatorMaxPagesToShow;
|
|
71
58
|
|
|
@@ -179,52 +166,6 @@ export class MoreFacetsPagination extends LitElement {
|
|
|
179
166
|
}
|
|
180
167
|
}
|
|
181
168
|
|
|
182
|
-
/**
|
|
183
|
-
* Compact page calculation: shows first, ..., prev, current, next, ..., last.
|
|
184
|
-
* Only 1 neighbor on each side of the current page for minimal width.
|
|
185
|
-
*/
|
|
186
|
-
private updatePagesCompact() {
|
|
187
|
-
if (this.size <= 3) {
|
|
188
|
-
this.pages = [...Array(this.size).keys()].map(i => i + 1);
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const pages: number[] = [];
|
|
193
|
-
|
|
194
|
-
// First page
|
|
195
|
-
pages.push(1);
|
|
196
|
-
|
|
197
|
-
// Ellipsis after first if current is far enough away
|
|
198
|
-
if (this.currentPage > 3) {
|
|
199
|
-
pages.push(0);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Previous page (if not already shown as first)
|
|
203
|
-
if (this.currentPage - 1 > 1) {
|
|
204
|
-
pages.push(this.currentPage - 1);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Current page (if not first or last)
|
|
208
|
-
if (this.currentPage !== 1 && this.currentPage !== this.size) {
|
|
209
|
-
pages.push(this.currentPage);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Next page (if not already the last)
|
|
213
|
-
if (this.currentPage + 1 < this.size) {
|
|
214
|
-
pages.push(this.currentPage + 1);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Ellipsis before last if current is far enough away
|
|
218
|
-
if (this.currentPage < this.size - 2) {
|
|
219
|
-
pages.push(0);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Last page
|
|
223
|
-
pages.push(this.size);
|
|
224
|
-
|
|
225
|
-
this.pages = pages;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
169
|
private get getEllipsisTemplate() {
|
|
229
170
|
return html`<i class="ellipses">...</i>`;
|
|
230
171
|
}
|
|
@@ -309,10 +250,6 @@ export class MoreFacetsPagination extends LitElement {
|
|
|
309
250
|
margin-top: 10px;
|
|
310
251
|
background-color: #eee;
|
|
311
252
|
text-align: center;
|
|
312
|
-
display: flex;
|
|
313
|
-
align-items: center;
|
|
314
|
-
justify-content: center;
|
|
315
|
-
flex-wrap: nowrap;
|
|
316
253
|
}
|
|
317
254
|
.facets-pagination button {
|
|
318
255
|
border: none;
|
|
@@ -339,7 +276,6 @@ export class MoreFacetsPagination extends LitElement {
|
|
|
339
276
|
vertical-align: baseline;
|
|
340
277
|
display: inline-block;
|
|
341
278
|
min-width: 2.5rem;
|
|
342
|
-
font-family: inherit;
|
|
343
279
|
}
|
|
344
280
|
.facets-pagination i {
|
|
345
281
|
cursor: auto;
|
|
@@ -352,16 +288,6 @@ export class MoreFacetsPagination extends LitElement {
|
|
|
352
288
|
.page-numbers {
|
|
353
289
|
display: inline-block;
|
|
354
290
|
}
|
|
355
|
-
|
|
356
|
-
@media (max-width: 560px) {
|
|
357
|
-
.facets-pagination button,
|
|
358
|
-
.facets-pagination i {
|
|
359
|
-
margin: 5px 2px;
|
|
360
|
-
padding: 3px;
|
|
361
|
-
min-width: 2rem;
|
|
362
|
-
font-size: 1.2rem;
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
291
|
`,
|
|
366
292
|
];
|
|
367
293
|
}
|
package/src/collection-facets.ts
CHANGED
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
FacetBucket,
|
|
43
43
|
defaultFacetDisplayOrder,
|
|
44
44
|
facetTitles,
|
|
45
|
-
|
|
45
|
+
customFacetDisplayNames,
|
|
46
46
|
lendingFacetKeysVisibility,
|
|
47
47
|
LendingFacetKey,
|
|
48
48
|
suppressedCollections,
|
|
@@ -612,10 +612,12 @@ export class CollectionFacets extends LitElement {
|
|
|
612
612
|
const buckets: FacetBucket[] = Object.entries(selectedFacets).map(
|
|
613
613
|
([value, facetData]) => {
|
|
614
614
|
let displayText: string = value;
|
|
615
|
-
//
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
615
|
+
// For certain facet types/keys, we use a custom readable display name
|
|
616
|
+
const currentGroupCustomNames = customFacetDisplayNames[
|
|
617
|
+
option
|
|
618
|
+
] as Record<string, string>;
|
|
619
|
+
if (currentGroupCustomNames) {
|
|
620
|
+
displayText = currentGroupCustomNames[value] ?? value;
|
|
619
621
|
}
|
|
620
622
|
return {
|
|
621
623
|
displayText,
|
|
@@ -667,11 +669,12 @@ export class CollectionFacets extends LitElement {
|
|
|
667
669
|
const facetBuckets: FacetBucket[] = castedBuckets.map(bucket => {
|
|
668
670
|
const bucketKey = bucket.key;
|
|
669
671
|
let displayText = `${bucket.key}`;
|
|
670
|
-
//
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
672
|
+
// For certain facet types/keys, we use a custom readable display name
|
|
673
|
+
const currentGroupCustomNames = customFacetDisplayNames[
|
|
674
|
+
option
|
|
675
|
+
] as Record<string, string>;
|
|
676
|
+
if (currentGroupCustomNames) {
|
|
677
|
+
displayText = currentGroupCustomNames[bucket.key] ?? `${bucket.key}`;
|
|
675
678
|
}
|
|
676
679
|
return {
|
|
677
680
|
displayText,
|
|
@@ -603,6 +603,24 @@ export class CollectionBrowserDataSource
|
|
|
603
603
|
);
|
|
604
604
|
}
|
|
605
605
|
|
|
606
|
+
/**
|
|
607
|
+
* Returns the search type to actually use for fetches.
|
|
608
|
+
* When within a collection with an empty query and FTS selected,
|
|
609
|
+
* falls back to metadata search since FTS requires a non-empty query
|
|
610
|
+
* and we'd still like to show the unfiltered collection in that case.
|
|
611
|
+
*/
|
|
612
|
+
private get effectiveSearchType(): SearchType {
|
|
613
|
+
const trimmedQuery = this.host.baseQuery?.trim();
|
|
614
|
+
if (
|
|
615
|
+
!trimmedQuery &&
|
|
616
|
+
this.host.withinCollection &&
|
|
617
|
+
this.host.searchType === SearchType.FULLTEXT
|
|
618
|
+
) {
|
|
619
|
+
return SearchType.METADATA;
|
|
620
|
+
}
|
|
621
|
+
return this.host.searchType;
|
|
622
|
+
}
|
|
623
|
+
|
|
606
624
|
/**
|
|
607
625
|
* @inheritdoc
|
|
608
626
|
*/
|
|
@@ -615,9 +633,11 @@ export class CollectionBrowserDataSource
|
|
|
615
633
|
const isCollectionSearch = !!this.host.withinCollection;
|
|
616
634
|
const isProfileSearch = !!this.host.withinProfile;
|
|
617
635
|
const hasProfileElement = !!this.host.profileElement;
|
|
618
|
-
|
|
619
|
-
const
|
|
620
|
-
const
|
|
636
|
+
|
|
637
|
+
const searchType = this.effectiveSearchType;
|
|
638
|
+
const isDefaultedSearch = searchType === SearchType.DEFAULT;
|
|
639
|
+
const isMetadataSearch = searchType === SearchType.METADATA;
|
|
640
|
+
const isTvSearch = searchType === SearchType.TV;
|
|
621
641
|
|
|
622
642
|
// Metadata/tv searches within a collection are allowed to have no query.
|
|
623
643
|
const isValidForCollectionSearch =
|
|
@@ -696,7 +716,7 @@ export class CollectionBrowserDataSource
|
|
|
696
716
|
const pageTarget = this.host.withinCollection ?? profileKey;
|
|
697
717
|
const sortField = this.host.selectedSort ?? 'none';
|
|
698
718
|
const sortDirection = this.host.sortDirection ?? 'none';
|
|
699
|
-
return `fq:${this.fullQuery}-pt:${pageTarget}-st:${this.
|
|
719
|
+
return `fq:${this.fullQuery}-pt:${pageTarget}-st:${this.effectiveSearchType}-sf:${sortField}-sd:${sortDirection}`;
|
|
700
720
|
}
|
|
701
721
|
|
|
702
722
|
/**
|
|
@@ -706,7 +726,7 @@ export class CollectionBrowserDataSource
|
|
|
706
726
|
get facetFetchQueryKey(): string {
|
|
707
727
|
const profileKey = `pf;${this.host.withinProfile}--pe;${this.host.profileElement}`;
|
|
708
728
|
const pageTarget = this.host.withinCollection ?? profileKey;
|
|
709
|
-
return `facets-fq:${this.fullQuery}-pt:${pageTarget}-st:${this.
|
|
729
|
+
return `facets-fq:${this.fullQuery}-pt:${pageTarget}-st:${this.effectiveSearchType}`;
|
|
710
730
|
}
|
|
711
731
|
|
|
712
732
|
/**
|
|
@@ -1017,7 +1037,7 @@ export class CollectionBrowserDataSource
|
|
|
1017
1037
|
|
|
1018
1038
|
const searchResponse = await this.host.searchService?.search(
|
|
1019
1039
|
params,
|
|
1020
|
-
this.
|
|
1040
|
+
this.effectiveSearchType,
|
|
1021
1041
|
);
|
|
1022
1042
|
const success = searchResponse?.success;
|
|
1023
1043
|
|
|
@@ -1127,10 +1147,11 @@ export class CollectionBrowserDataSource
|
|
|
1127
1147
|
this.host.defaultSortField
|
|
1128
1148
|
) {
|
|
1129
1149
|
const sortOption = SORT_OPTIONS[this.host.defaultSortField];
|
|
1130
|
-
|
|
1150
|
+
const { searchServiceKey, handledBySearchService } = sortOption;
|
|
1151
|
+
if (searchServiceKey && handledBySearchService) {
|
|
1131
1152
|
sortParams = [
|
|
1132
1153
|
{
|
|
1133
|
-
field:
|
|
1154
|
+
field: searchServiceKey,
|
|
1134
1155
|
direction: this.host.defaultSortDirection ?? 'desc',
|
|
1135
1156
|
},
|
|
1136
1157
|
];
|
|
@@ -1152,7 +1173,7 @@ export class CollectionBrowserDataSource
|
|
|
1152
1173
|
// log('=== FIRING PAGE REQUEST ===', params);
|
|
1153
1174
|
const searchResponse = await this.host.searchService?.search(
|
|
1154
1175
|
params,
|
|
1155
|
-
this.
|
|
1176
|
+
this.effectiveSearchType,
|
|
1156
1177
|
);
|
|
1157
1178
|
// log('=== RECEIVED PAGE RESPONSE IN CB ===', searchResponse);
|
|
1158
1179
|
const success = searchResponse?.success;
|
|
@@ -1341,7 +1362,7 @@ export class CollectionBrowserDataSource
|
|
|
1341
1362
|
|
|
1342
1363
|
const searchResponse = await this.host.searchService?.search(
|
|
1343
1364
|
params,
|
|
1344
|
-
this.
|
|
1365
|
+
this.effectiveSearchType,
|
|
1345
1366
|
);
|
|
1346
1367
|
|
|
1347
1368
|
return (searchResponse?.success?.response?.aggregations?.[
|
package/src/models.ts
CHANGED
|
@@ -588,6 +588,7 @@ export const defaultProfileElementSorts: Record<
|
|
|
588
588
|
reviews: SortField.datereviewed,
|
|
589
589
|
collections: SortField.datearchived,
|
|
590
590
|
web_archives: SortField.datearchived,
|
|
591
|
+
favorites: SortField.datefavorited,
|
|
591
592
|
};
|
|
592
593
|
|
|
593
594
|
/** A union of the fields that permit prefix filtering (e.g., alphabetical filtering) */
|
|
@@ -735,7 +736,7 @@ export const tvFacetDisplayOrder: FacetOption[] = [
|
|
|
735
736
|
'creator',
|
|
736
737
|
'year',
|
|
737
738
|
'subject',
|
|
738
|
-
'person',
|
|
739
|
+
// 'person', Omitting the Person facet group for now, though it may be re-added later with new semantics
|
|
739
740
|
'language',
|
|
740
741
|
'clip_type',
|
|
741
742
|
];
|
|
@@ -824,14 +825,35 @@ export const lendingFacetKeysVisibility: Record<LendingFacetKey, boolean> = {
|
|
|
824
825
|
};
|
|
825
826
|
|
|
826
827
|
/**
|
|
827
|
-
*
|
|
828
|
+
* Most facet options allow any string as keys, while some others can only take on a
|
|
829
|
+
* limited set of strings. This type just defines those restrictions for the specific
|
|
830
|
+
* facet types where they apply.
|
|
828
831
|
*/
|
|
829
|
-
export
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
832
|
+
export type AllowedFacetKey<T extends FacetOption> = T extends 'lending'
|
|
833
|
+
? LendingFacetKey
|
|
834
|
+
: T extends 'clip_type'
|
|
835
|
+
? TvClipFilterType
|
|
836
|
+
: string;
|
|
837
|
+
|
|
838
|
+
/**
|
|
839
|
+
* A type mapping FacetOptions to objects that define custom display names for some
|
|
840
|
+
* or all of their valid keys.
|
|
841
|
+
*/
|
|
842
|
+
export type FacetDisplayNameMap = {
|
|
843
|
+
[K in FacetOption]?: Partial<Record<AllowedFacetKey<K>, string>>;
|
|
844
|
+
};
|
|
845
|
+
|
|
846
|
+
export const customFacetDisplayNames: FacetDisplayNameMap = {
|
|
847
|
+
lending: {
|
|
848
|
+
is_lendable: 'Lending Library',
|
|
849
|
+
available_to_borrow: 'Borrow 14 Days',
|
|
850
|
+
is_readable: 'Always Available',
|
|
851
|
+
},
|
|
852
|
+
clip_type: {
|
|
853
|
+
quote: 'Quote',
|
|
854
|
+
commercial: 'Political Ad',
|
|
855
|
+
'fact check': 'Fact Check',
|
|
856
|
+
},
|
|
835
857
|
};
|
|
836
858
|
|
|
837
859
|
/**
|
|
@@ -337,7 +337,9 @@ export class RestorationStateHandler
|
|
|
337
337
|
if (facetAnds) {
|
|
338
338
|
facetAnds.forEach(and => {
|
|
339
339
|
// eslint-disable-next-line prefer-const
|
|
340
|
-
let [field,
|
|
340
|
+
let [field, ...valueParts] = and.split(':');
|
|
341
|
+
if (!valueParts.length) return;
|
|
342
|
+
const value = valueParts.join(':');
|
|
341
343
|
|
|
342
344
|
// Legacy search allowed and[] fields like 'creatorSorter', 'languageSorter', etc.
|
|
343
345
|
// which we want to normalize to 'creator', 'language', etc. if redirected here.
|
|
@@ -396,7 +398,9 @@ export class RestorationStateHandler
|
|
|
396
398
|
|
|
397
399
|
if (facetNots) {
|
|
398
400
|
facetNots.forEach(not => {
|
|
399
|
-
const [field,
|
|
401
|
+
const [field, ...valueParts] = not.split(':');
|
|
402
|
+
if (!valueParts.length) return;
|
|
403
|
+
const value = valueParts.join(':');
|
|
400
404
|
this.setSelectedFacetState(
|
|
401
405
|
restorationState.selectedFacets,
|
|
402
406
|
field as FacetOption,
|
|
@@ -531,7 +535,7 @@ export class RestorationStateHandler
|
|
|
531
535
|
if (!facet) return; // Unrecognized facet group, ignore it.
|
|
532
536
|
|
|
533
537
|
const unQuotedValue = this.stripQuotes(value);
|
|
534
|
-
facet[unQuotedValue] ??= this.getDefaultBucket(
|
|
538
|
+
facet[unQuotedValue] ??= this.getDefaultBucket(unQuotedValue);
|
|
535
539
|
facet[unQuotedValue].state = state;
|
|
536
540
|
}
|
|
537
541
|
|
|
@@ -227,7 +227,7 @@ export class HoverPaneController implements HoverPaneControllerInterface {
|
|
|
227
227
|
|
|
228
228
|
/** @inheritdoc */
|
|
229
229
|
toggleHoverPane(options: ToggleHoverPaneOptions): void {
|
|
230
|
-
if (this.hoverPaneState
|
|
230
|
+
if (this.hoverPaneState !== 'hidden') {
|
|
231
231
|
this.fadeOutHoverPane();
|
|
232
232
|
this.forceTouchBackdrop = false;
|
|
233
233
|
} else {
|
|
@@ -546,6 +546,7 @@ export class HoverPaneController implements HoverPaneControllerInterface {
|
|
|
546
546
|
if (this.hoverPaneState !== 'hidden') {
|
|
547
547
|
this.fadeOutHoverPane();
|
|
548
548
|
}
|
|
549
|
+
e.preventDefault();
|
|
549
550
|
e.stopPropagation();
|
|
550
551
|
};
|
|
551
552
|
|
|
@@ -218,6 +218,15 @@ export class TileDispatcher
|
|
|
218
218
|
return window.matchMedia('(hover: hover)').matches;
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Whether the info button should be shown on this tile.
|
|
223
|
+
* Only shown on touch/non-hover devices where a hover pane is available,
|
|
224
|
+
* so the button always has something to toggle.
|
|
225
|
+
*/
|
|
226
|
+
private get shouldShowInfoButton(): boolean {
|
|
227
|
+
return !this.isHoverEnabled && this.shouldPrepareHoverPane;
|
|
228
|
+
}
|
|
229
|
+
|
|
221
230
|
/** @inheritdoc */
|
|
222
231
|
getHoverPane(): TileHoverPane | undefined {
|
|
223
232
|
return this.hoverPane;
|
|
@@ -326,7 +335,7 @@ export class TileDispatcher
|
|
|
326
335
|
.suppressBlurring=${this.suppressBlurring}
|
|
327
336
|
.isManageView=${this.isManageView}
|
|
328
337
|
.layoutType=${this.layoutType}
|
|
329
|
-
?showInfoButton=${
|
|
338
|
+
?showInfoButton=${this.shouldShowInfoButton}
|
|
330
339
|
@infoButtonPressed=${this.tileInfoButtonPressed}
|
|
331
340
|
>
|
|
332
341
|
</collection-tile>`;
|
|
@@ -340,7 +349,7 @@ export class TileDispatcher
|
|
|
340
349
|
.creatorFilter=${creatorFilter}
|
|
341
350
|
.suppressBlurring=${this.suppressBlurring}
|
|
342
351
|
.isManageView=${this.isManageView}
|
|
343
|
-
?showInfoButton=${
|
|
352
|
+
?showInfoButton=${this.shouldShowInfoButton}
|
|
344
353
|
@infoButtonPressed=${this.tileInfoButtonPressed}
|
|
345
354
|
>
|
|
346
355
|
</account-tile>`;
|
|
@@ -373,7 +382,7 @@ export class TileDispatcher
|
|
|
373
382
|
.isManageView=${this.isManageView}
|
|
374
383
|
.layoutType=${this.layoutType}
|
|
375
384
|
?showTvClips=${this.showTvClips}
|
|
376
|
-
?showInfoButton=${
|
|
385
|
+
?showInfoButton=${this.shouldShowInfoButton}
|
|
377
386
|
?useLocalTime=${this.useLocalTime}
|
|
378
387
|
@infoButtonPressed=${this.tileInfoButtonPressed}
|
|
379
388
|
>
|
|
@@ -1906,6 +1906,111 @@ describe('Collection Browser', () => {
|
|
|
1906
1906
|
expect(el.maxSelectedDate).not.to.exist;
|
|
1907
1907
|
});
|
|
1908
1908
|
|
|
1909
|
+
it('does not include stale facets in the search request when query changes', async () => {
|
|
1910
|
+
const searchService = new MockSearchService();
|
|
1911
|
+
const el = await fixture<CollectionBrowser>(
|
|
1912
|
+
html`<collection-browser .searchService=${searchService}>
|
|
1913
|
+
</collection-browser>`,
|
|
1914
|
+
);
|
|
1915
|
+
|
|
1916
|
+
// Perform an initial search with a facet applied
|
|
1917
|
+
const selectedFacets = getDefaultSelectedFacets();
|
|
1918
|
+
selectedFacets.collection.radio = {
|
|
1919
|
+
count: 1,
|
|
1920
|
+
key: 'radio',
|
|
1921
|
+
state: 'selected',
|
|
1922
|
+
} as FacetBucket;
|
|
1923
|
+
el.baseQuery = 'cookies';
|
|
1924
|
+
el.selectedFacets = selectedFacets;
|
|
1925
|
+
await el.updateComplete;
|
|
1926
|
+
await el.initialSearchComplete;
|
|
1927
|
+
|
|
1928
|
+
// The initial search should include the facet filter
|
|
1929
|
+
expect(searchService.searchParams?.filters?.collection?.radio).to.equal(
|
|
1930
|
+
FilterConstraint.INCLUDE,
|
|
1931
|
+
);
|
|
1932
|
+
|
|
1933
|
+
// Ensure that the first search after the query change doesn't have stale facets
|
|
1934
|
+
const searchSpy = sinon.spy(searchService, 'search');
|
|
1935
|
+
el.baseQuery = 'cookies AND NOT collection:radio';
|
|
1936
|
+
await el.updateComplete;
|
|
1937
|
+
await el.initialSearchComplete;
|
|
1938
|
+
|
|
1939
|
+
const firstCall = searchSpy.firstCall;
|
|
1940
|
+
expect(firstCall.args[0].query).to.equal(
|
|
1941
|
+
'cookies AND NOT collection:radio',
|
|
1942
|
+
);
|
|
1943
|
+
expect(firstCall.args[0].filters?.collection).not.to.exist;
|
|
1944
|
+
|
|
1945
|
+
searchSpy.restore();
|
|
1946
|
+
});
|
|
1947
|
+
|
|
1948
|
+
it('does not include stale date range in the search request when query changes', async () => {
|
|
1949
|
+
const searchService = new MockSearchService();
|
|
1950
|
+
const el = await fixture<CollectionBrowser>(
|
|
1951
|
+
html`<collection-browser .searchService=${searchService}>
|
|
1952
|
+
</collection-browser>`,
|
|
1953
|
+
);
|
|
1954
|
+
|
|
1955
|
+
// Perform an initial search with a date range applied
|
|
1956
|
+
el.baseQuery = 'foo';
|
|
1957
|
+
el.minSelectedDate = '2000';
|
|
1958
|
+
el.maxSelectedDate = '2010';
|
|
1959
|
+
await el.updateComplete;
|
|
1960
|
+
await el.initialSearchComplete;
|
|
1961
|
+
|
|
1962
|
+
expect(searchService.searchParams?.filters?.year?.['2000']).to.equal(
|
|
1963
|
+
FilterConstraint.GREATER_OR_EQUAL,
|
|
1964
|
+
);
|
|
1965
|
+
expect(searchService.searchParams?.filters?.year?.['2010']).to.equal(
|
|
1966
|
+
FilterConstraint.LESS_OR_EQUAL,
|
|
1967
|
+
);
|
|
1968
|
+
|
|
1969
|
+
// Change the query, which should clear the date range before searching
|
|
1970
|
+
el.baseQuery = 'bar';
|
|
1971
|
+
await el.updateComplete;
|
|
1972
|
+
await el.initialSearchComplete;
|
|
1973
|
+
|
|
1974
|
+
expect(searchService.searchParams?.filters?.year).not.to.exist;
|
|
1975
|
+
expect(el.minSelectedDate).not.to.exist;
|
|
1976
|
+
expect(el.maxSelectedDate).not.to.exist;
|
|
1977
|
+
});
|
|
1978
|
+
|
|
1979
|
+
it('does not include stale letter filters in the search request when query changes', async () => {
|
|
1980
|
+
const searchService = new MockSearchService();
|
|
1981
|
+
const el = await fixture<CollectionBrowser>(
|
|
1982
|
+
html`<collection-browser .searchService=${searchService}>
|
|
1983
|
+
</collection-browser>`,
|
|
1984
|
+
);
|
|
1985
|
+
|
|
1986
|
+
// Perform an initial search with a letter filter applied
|
|
1987
|
+
el.baseQuery = 'first-creator';
|
|
1988
|
+
el.selectedSort = 'creator' as SortField;
|
|
1989
|
+
el.sortDirection = 'asc';
|
|
1990
|
+
el.selectedCreatorFilter = 'X';
|
|
1991
|
+
await el.updateComplete;
|
|
1992
|
+
await el.initialSearchComplete;
|
|
1993
|
+
await nextTick();
|
|
1994
|
+
|
|
1995
|
+
expect(searchService.searchParams?.filters?.firstCreator?.X).to.equal(
|
|
1996
|
+
FilterConstraint.INCLUDE,
|
|
1997
|
+
);
|
|
1998
|
+
|
|
1999
|
+
// Change the query, which should clear the letter filter before searching.
|
|
2000
|
+
// Check the first search call to ensure stale filters aren't sent initially.
|
|
2001
|
+
const searchSpy = sinon.spy(searchService, 'search');
|
|
2002
|
+
el.baseQuery = 'bar';
|
|
2003
|
+
await el.updateComplete;
|
|
2004
|
+
await el.initialSearchComplete;
|
|
2005
|
+
await nextTick();
|
|
2006
|
+
|
|
2007
|
+
// The very first search after the query change should not include the old filter
|
|
2008
|
+
const firstCall = searchSpy.firstCall;
|
|
2009
|
+
expect(firstCall.args[0].filters?.firstCreator).not.to.exist;
|
|
2010
|
+
|
|
2011
|
+
searchSpy.restore();
|
|
2012
|
+
});
|
|
2013
|
+
|
|
1909
2014
|
it('correctly retrieves web archive hits', async () => {
|
|
1910
2015
|
const searchService = new MockSearchService();
|
|
1911
2016
|
const el = await fixture<CollectionBrowser>(
|