@internetarchive/collection-browser 1.4.1-alpha.6 → 1.4.1
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/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/src/app-root.d.ts +0 -3
- package/dist/src/app-root.js +1 -27
- package/dist/src/app-root.js.map +1 -1
- package/dist/src/collection-browser.d.ts +11 -8
- package/dist/src/collection-browser.js +28 -39
- package/dist/src/collection-browser.js.map +1 -1
- package/dist/src/collection-facets/facets-template.d.ts +0 -1
- package/dist/src/collection-facets/facets-template.js +1 -8
- package/dist/src/collection-facets/facets-template.js.map +1 -1
- package/dist/src/collection-facets.d.ts +0 -1
- package/dist/src/collection-facets.js +0 -5
- package/dist/src/collection-facets.js.map +1 -1
- package/dist/src/sort-filter-bar/alpha-bar.js +1 -1
- package/dist/src/sort-filter-bar/alpha-bar.js.map +1 -1
- package/dist/src/tiles/list/tile-list-compact.d.ts +0 -1
- package/dist/src/tiles/list/tile-list-compact.js +4 -10
- package/dist/src/tiles/list/tile-list-compact.js.map +1 -1
- package/dist/src/tiles/list/tile-list.d.ts +0 -1
- package/dist/src/tiles/list/tile-list.js +6 -15
- package/dist/src/tiles/list/tile-list.js.map +1 -1
- package/dist/src/tiles/tile-dispatcher.d.ts +0 -1
- package/dist/src/tiles/tile-dispatcher.js +4 -12
- package/dist/src/tiles/tile-dispatcher.js.map +1 -1
- package/dist/test/collection-browser.test.js +19 -1
- package/dist/test/collection-browser.test.js.map +1 -1
- package/dist/test/mocks/mock-search-responses.d.ts +1 -0
- package/dist/test/mocks/mock-search-responses.js +33 -1
- package/dist/test/mocks/mock-search-responses.js.map +1 -1
- package/dist/test/mocks/mock-search-service.js +2 -1
- package/dist/test/mocks/mock-search-service.js.map +1 -1
- package/index.ts +1 -1
- package/package.json +1 -1
- package/src/app-root.ts +0 -26
- package/src/collection-browser.ts +28 -40
- package/src/collection-facets/facets-template.ts +1 -3
- package/src/collection-facets.ts +0 -3
- package/src/sort-filter-bar/alpha-bar.ts +1 -1
- package/src/tiles/list/tile-list-compact.ts +3 -10
- package/src/tiles/list/tile-list.ts +8 -21
- package/src/tiles/tile-dispatcher.ts +3 -12
- package/test/collection-browser.test.ts +28 -1
- package/test/mocks/mock-search-responses.ts +37 -0
- package/test/mocks/mock-search-service.ts +2 -0
package/src/app-root.ts
CHANGED
|
@@ -39,8 +39,6 @@ export class AppRoot extends LitElement {
|
|
|
39
39
|
|
|
40
40
|
@state() private searchQuery?: string;
|
|
41
41
|
|
|
42
|
-
@state() private withinCollection?: string;
|
|
43
|
-
|
|
44
42
|
@state() private cellWidth: number = 18;
|
|
45
43
|
|
|
46
44
|
@state() private cellHeight: number = 29;
|
|
@@ -57,9 +55,6 @@ export class AppRoot extends LitElement {
|
|
|
57
55
|
|
|
58
56
|
@query('#base-query-field') private baseQueryField!: HTMLInputElement;
|
|
59
57
|
|
|
60
|
-
@query('#base-collection-field')
|
|
61
|
-
private baseCollectionField!: HTMLInputElement;
|
|
62
|
-
|
|
63
58
|
@query('#page-number-input') private pageNumberInput!: HTMLInputElement;
|
|
64
59
|
|
|
65
60
|
@query('collection-browser') private collectionBrowser!: CollectionBrowser;
|
|
@@ -100,16 +95,6 @@ export class AppRoot extends LitElement {
|
|
|
100
95
|
}
|
|
101
96
|
}
|
|
102
97
|
|
|
103
|
-
private collectionChanged(e: Event) {
|
|
104
|
-
e.preventDefault();
|
|
105
|
-
this.withinCollection = this.baseCollectionField.value;
|
|
106
|
-
this.collectionBrowser.withinCollection = this.withinCollection;
|
|
107
|
-
|
|
108
|
-
if ((this.currentPage ?? 1) > 1) {
|
|
109
|
-
this.collectionBrowser.goToPage(this.currentPage ?? 1);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
98
|
private changePagePressed(e: Event) {
|
|
114
99
|
e.preventDefault();
|
|
115
100
|
this.currentPage = this.pageNumberInput.valueAsNumber;
|
|
@@ -156,17 +141,6 @@ export class AppRoot extends LitElement {
|
|
|
156
141
|
<input type="submit" value="Go" />
|
|
157
142
|
</form>
|
|
158
143
|
</div>
|
|
159
|
-
<div>
|
|
160
|
-
<form @submit=${this.collectionChanged}>
|
|
161
|
-
<label for="base-collection-field"> Within collection: </label>
|
|
162
|
-
<input
|
|
163
|
-
type="text"
|
|
164
|
-
id="base-collection-field"
|
|
165
|
-
.value=${this.withinCollection ?? ''}
|
|
166
|
-
/>
|
|
167
|
-
<input type="submit" value="Search" />
|
|
168
|
-
</form>
|
|
169
|
-
</div>
|
|
170
144
|
|
|
171
145
|
<div id="search-types">
|
|
172
146
|
Search type:
|
|
@@ -90,8 +90,6 @@ export class CollectionBrowser
|
|
|
90
90
|
|
|
91
91
|
@property({ type: String }) searchType: SearchType = SearchType.METADATA;
|
|
92
92
|
|
|
93
|
-
@property({ type: String }) withinCollection?: string;
|
|
94
|
-
|
|
95
93
|
@property({ type: String }) baseQuery?: string;
|
|
96
94
|
|
|
97
95
|
@property({ type: String }) displayMode?: CollectionDisplayMode;
|
|
@@ -120,8 +118,6 @@ export class CollectionBrowser
|
|
|
120
118
|
|
|
121
119
|
@property({ type: Boolean }) showHistogramDatePicker = false;
|
|
122
120
|
|
|
123
|
-
@property({ type: String }) collectionPagePath: string = '/details/';
|
|
124
|
-
|
|
125
121
|
/** describes where this component is being used */
|
|
126
122
|
@property({ type: String, reflect: true }) searchContext: string =
|
|
127
123
|
analyticsCategories.default;
|
|
@@ -386,7 +382,7 @@ export class CollectionBrowser
|
|
|
386
382
|
|
|
387
383
|
private setPlaceholderType() {
|
|
388
384
|
this.placeholderType = null;
|
|
389
|
-
if (!this.baseQuery?.trim()
|
|
385
|
+
if (!this.baseQuery?.trim()) {
|
|
390
386
|
this.placeholderType = 'empty-query';
|
|
391
387
|
} else if (
|
|
392
388
|
!this.searchResultsLoading &&
|
|
@@ -716,7 +712,6 @@ export class CollectionBrowser
|
|
|
716
712
|
<collection-facets
|
|
717
713
|
@facetsChanged=${this.facetsChanged}
|
|
718
714
|
@histogramDateRangeUpdated=${this.histogramDateRangeUpdated}
|
|
719
|
-
.collectionPagePath=${this.collectionPagePath}
|
|
720
715
|
.searchService=${this.searchService}
|
|
721
716
|
.featureFeedbackService=${this.featureFeedbackService}
|
|
722
717
|
.recaptchaManager=${this.recaptchaManager}
|
|
@@ -914,8 +909,7 @@ export class CollectionBrowser
|
|
|
914
909
|
changed.has('maxSelectedDate') ||
|
|
915
910
|
changed.has('sortParam') ||
|
|
916
911
|
changed.has('selectedFacets') ||
|
|
917
|
-
changed.has('searchService')
|
|
918
|
-
changed.has('withinCollection')
|
|
912
|
+
changed.has('searchService')
|
|
919
913
|
) {
|
|
920
914
|
this.handleQueryChange();
|
|
921
915
|
}
|
|
@@ -956,8 +950,7 @@ export class CollectionBrowser
|
|
|
956
950
|
const previousView = this.mobileView;
|
|
957
951
|
if (entry.target === this.contentContainer) {
|
|
958
952
|
this.contentWidth = entry.contentRect.width;
|
|
959
|
-
this.mobileView =
|
|
960
|
-
this.contentWidth > 0 && this.contentWidth < this.mobileBreakpoint;
|
|
953
|
+
this.mobileView = this.contentWidth < this.mobileBreakpoint;
|
|
961
954
|
// If changing from desktop to mobile disable transition
|
|
962
955
|
if (this.mobileView && !previousView) {
|
|
963
956
|
this.isResizeToMobile = true;
|
|
@@ -1354,7 +1347,8 @@ export class CollectionBrowser
|
|
|
1354
1347
|
|
|
1355
1348
|
/** The full query, including year facets and date range clauses */
|
|
1356
1349
|
private get fullQuery(): string | undefined {
|
|
1357
|
-
|
|
1350
|
+
if (!this.baseQuery) return undefined;
|
|
1351
|
+
let fullQuery = this.baseQuery.trim();
|
|
1358
1352
|
|
|
1359
1353
|
const { facetQuery, dateRangeQueryClause, sortFilterQueries } = this;
|
|
1360
1354
|
|
|
@@ -1486,15 +1480,14 @@ export class CollectionBrowser
|
|
|
1486
1480
|
|
|
1487
1481
|
private async fetchFacets() {
|
|
1488
1482
|
const trimmedQuery = this.baseQuery?.trim();
|
|
1489
|
-
if (!trimmedQuery
|
|
1483
|
+
if (!trimmedQuery) return;
|
|
1490
1484
|
if (!this.searchService) return;
|
|
1491
1485
|
|
|
1492
1486
|
const { facetFetchQueryKey } = this;
|
|
1493
1487
|
|
|
1494
1488
|
const sortParams = this.sortParam ? [this.sortParam] : [];
|
|
1495
1489
|
const params: SearchParams = {
|
|
1496
|
-
|
|
1497
|
-
query: trimmedQuery || '',
|
|
1490
|
+
query: trimmedQuery,
|
|
1498
1491
|
rows: 0,
|
|
1499
1492
|
filters: this.filterMap,
|
|
1500
1493
|
// Fetch a few extra buckets beyond the 6 we show, in case some get suppressed
|
|
@@ -1576,24 +1569,10 @@ export class CollectionBrowser
|
|
|
1576
1569
|
});
|
|
1577
1570
|
}
|
|
1578
1571
|
|
|
1579
|
-
/**
|
|
1580
|
-
* Additional params to pass to the search service if targeting a collection page,
|
|
1581
|
-
* or null otherwise.
|
|
1582
|
-
*/
|
|
1583
|
-
private get collectionParams(): {
|
|
1584
|
-
pageType: string;
|
|
1585
|
-
pageTarget: string;
|
|
1586
|
-
} | null {
|
|
1587
|
-
return this.withinCollection
|
|
1588
|
-
? { pageType: 'collection_details', pageTarget: this.withinCollection }
|
|
1589
|
-
: null;
|
|
1590
|
-
}
|
|
1591
|
-
|
|
1592
1572
|
/**
|
|
1593
1573
|
* The query key is a string that uniquely identifies the current search.
|
|
1594
1574
|
* It consists of:
|
|
1595
1575
|
* - The current base query
|
|
1596
|
-
* - The current collection
|
|
1597
1576
|
* - The current search type
|
|
1598
1577
|
* - Any currently-applied facets
|
|
1599
1578
|
* - Any currently-applied date range
|
|
@@ -1606,7 +1585,7 @@ export class CollectionBrowser
|
|
|
1606
1585
|
private get pageFetchQueryKey(): string {
|
|
1607
1586
|
const sortField = this.sortParam?.field ?? 'none';
|
|
1608
1587
|
const sortDirection = this.sortParam?.direction ?? 'none';
|
|
1609
|
-
return `${this.fullQuery}-${this.
|
|
1588
|
+
return `${this.fullQuery}-${this.searchType}-${sortField}-${sortDirection}`;
|
|
1610
1589
|
}
|
|
1611
1590
|
|
|
1612
1591
|
/**
|
|
@@ -1614,7 +1593,7 @@ export class CollectionBrowser
|
|
|
1614
1593
|
* are not relevant in determining aggregation queries.
|
|
1615
1594
|
*/
|
|
1616
1595
|
private get facetFetchQueryKey(): string {
|
|
1617
|
-
return `${this.fullQuery}-${this.
|
|
1596
|
+
return `${this.fullQuery}-${this.searchType}`;
|
|
1618
1597
|
}
|
|
1619
1598
|
|
|
1620
1599
|
// this maps the query to the pages being fetched for that query
|
|
@@ -1630,7 +1609,7 @@ export class CollectionBrowser
|
|
|
1630
1609
|
*/
|
|
1631
1610
|
async fetchPage(pageNumber: number, numInitialPages = 1) {
|
|
1632
1611
|
const trimmedQuery = this.baseQuery?.trim();
|
|
1633
|
-
if (!trimmedQuery
|
|
1612
|
+
if (!trimmedQuery) return;
|
|
1634
1613
|
if (!this.searchService) return;
|
|
1635
1614
|
|
|
1636
1615
|
// if we already have data, don't fetch again
|
|
@@ -1655,8 +1634,7 @@ export class CollectionBrowser
|
|
|
1655
1634
|
|
|
1656
1635
|
const sortParams = this.sortParam ? [this.sortParam] : [];
|
|
1657
1636
|
const params: SearchParams = {
|
|
1658
|
-
|
|
1659
|
-
query: trimmedQuery || '',
|
|
1637
|
+
query: trimmedQuery,
|
|
1660
1638
|
page: pageNumber,
|
|
1661
1639
|
rows: numRows,
|
|
1662
1640
|
sort: sortParams,
|
|
@@ -1808,7 +1786,7 @@ export class CollectionBrowser
|
|
|
1808
1786
|
dateReviewed: result.reviewdate?.value,
|
|
1809
1787
|
description: result.description?.values.join('\n'),
|
|
1810
1788
|
favCount: result.num_favorites?.value ?? 0,
|
|
1811
|
-
href: result.__href__?.value,
|
|
1789
|
+
href: this.collapseRepeatedQuotes(result.__href__?.value),
|
|
1812
1790
|
identifier: result.identifier,
|
|
1813
1791
|
issue: result.issue?.value,
|
|
1814
1792
|
itemCount: result.item_count?.value ?? 0,
|
|
@@ -1833,19 +1811,31 @@ export class CollectionBrowser
|
|
|
1833
1811
|
}
|
|
1834
1812
|
}
|
|
1835
1813
|
|
|
1814
|
+
/**
|
|
1815
|
+
* Returns the input string, but removing one set of quotes from all instances of
|
|
1816
|
+
* ""clauses wrapped in two sets of quotes"". This assumes the quotes are already
|
|
1817
|
+
* URL-encoded.
|
|
1818
|
+
*
|
|
1819
|
+
* This should be a temporary measure to address the fact that the __href__ field
|
|
1820
|
+
* sometimes acquires extra quotation marks during query rewriting. Once there is a
|
|
1821
|
+
* full Lucene parser in place that handles quoted queries correctly, this can likely
|
|
1822
|
+
* be removed.
|
|
1823
|
+
*/
|
|
1824
|
+
private collapseRepeatedQuotes(str?: string): string | undefined {
|
|
1825
|
+
return str?.replace(/%22%22(?!%22%22)(.+?)%22%22/g, '%22$1%22');
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1836
1828
|
/** Fetches the aggregation buckets for the given prefix filter type. */
|
|
1837
1829
|
private async fetchPrefixFilterBuckets(
|
|
1838
1830
|
filterType: PrefixFilterType
|
|
1839
1831
|
): Promise<Bucket[]> {
|
|
1840
1832
|
const trimmedQuery = this.baseQuery?.trim();
|
|
1841
|
-
if (!trimmedQuery
|
|
1833
|
+
if (!trimmedQuery) return [];
|
|
1842
1834
|
|
|
1843
1835
|
const filterAggregationKey = prefixFilterAggregationKeys[filterType];
|
|
1844
1836
|
const sortParams = this.sortParam ? [this.sortParam] : [];
|
|
1845
|
-
|
|
1846
1837
|
const params: SearchParams = {
|
|
1847
|
-
|
|
1848
|
-
query: trimmedQuery || '',
|
|
1838
|
+
query: trimmedQuery,
|
|
1849
1839
|
rows: 0,
|
|
1850
1840
|
filters: this.filterMap,
|
|
1851
1841
|
// Only fetch the firstTitle or firstCreator aggregation
|
|
@@ -1942,7 +1932,6 @@ export class CollectionBrowser
|
|
|
1942
1932
|
|
|
1943
1933
|
return html`
|
|
1944
1934
|
<tile-dispatcher
|
|
1945
|
-
.collectionPagePath=${this.collectionPagePath}
|
|
1946
1935
|
.baseNavigationUrl=${this.baseNavigationUrl}
|
|
1947
1936
|
.baseImageUrl=${this.baseImageUrl}
|
|
1948
1937
|
.model=${model}
|
|
@@ -2046,7 +2035,6 @@ export class CollectionBrowser
|
|
|
2046
2035
|
border-right: 1px solid rgb(232, 232, 232);
|
|
2047
2036
|
padding-left: 1rem;
|
|
2048
2037
|
padding-right: 1rem;
|
|
2049
|
-
margin-top: var(--rightColumnMarginTop, 0);
|
|
2050
2038
|
background: #fff;
|
|
2051
2039
|
}
|
|
2052
2040
|
|
|
@@ -22,8 +22,6 @@ export class FacetsTemplate extends LitElement {
|
|
|
22
22
|
|
|
23
23
|
@property({ type: String }) renderOn?: string;
|
|
24
24
|
|
|
25
|
-
@property({ type: String }) collectionPagePath: string = '/details/';
|
|
26
|
-
|
|
27
25
|
@property({ type: Object })
|
|
28
26
|
collectionNameCache?: CollectionNameCacheInterface;
|
|
29
27
|
|
|
@@ -148,7 +146,7 @@ export class FacetsTemplate extends LitElement {
|
|
|
148
146
|
const bucketTextDisplay =
|
|
149
147
|
facetGroup.key !== 'collection'
|
|
150
148
|
? html`${bucket.displayText ?? bucket.key}`
|
|
151
|
-
: html`<a href="
|
|
149
|
+
: html`<a href="/details/${bucket.key}">
|
|
152
150
|
<async-collection-name
|
|
153
151
|
.collectionNameCache=${this.collectionNameCache}
|
|
154
152
|
.identifier=${bucket.key}
|
package/src/collection-facets.ts
CHANGED
|
@@ -90,8 +90,6 @@ export class CollectionFacets extends LitElement {
|
|
|
90
90
|
|
|
91
91
|
@property({ type: Object }) filterMap?: FilterMap;
|
|
92
92
|
|
|
93
|
-
@property({ type: String }) collectionPagePath: string = '/details/';
|
|
94
|
-
|
|
95
93
|
@property({ type: Object, attribute: false })
|
|
96
94
|
modalManager?: ModalManagerInterface;
|
|
97
95
|
|
|
@@ -628,7 +626,6 @@ export class CollectionFacets extends LitElement {
|
|
|
628
626
|
private getFacetTemplate(facetGroup: FacetGroup): TemplateResult {
|
|
629
627
|
return html`
|
|
630
628
|
<facets-template
|
|
631
|
-
.collectionPagePath=${this.collectionPagePath}
|
|
632
629
|
.facetGroup=${facetGroup}
|
|
633
630
|
.selectedFacets=${this.selectedFacets}
|
|
634
631
|
.renderOn=${'page'}
|
|
@@ -30,8 +30,6 @@ export class TileListCompact extends LitElement {
|
|
|
30
30
|
|
|
31
31
|
@property({ type: Boolean }) loggedIn = false;
|
|
32
32
|
|
|
33
|
-
@property({ type: String }) collectionPagePath: string = '/details/';
|
|
34
|
-
|
|
35
33
|
render() {
|
|
36
34
|
return html`
|
|
37
35
|
<div id="list-line" class="${this.classSize}">
|
|
@@ -68,14 +66,9 @@ export class TileListCompact extends LitElement {
|
|
|
68
66
|
private get href(): string {
|
|
69
67
|
// Use the server-specified href if available.
|
|
70
68
|
// Otherwise, construct a details page URL from the item identifier.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const isCollection = this.model?.mediatype === 'collection';
|
|
76
|
-
return `${this.baseNavigationUrl}${
|
|
77
|
-
isCollection ? this.collectionPagePath : '/details/'
|
|
78
|
-
}${this.model?.identifier}`;
|
|
69
|
+
return this.model?.href
|
|
70
|
+
? `${this.baseNavigationUrl}${this.model.href}`
|
|
71
|
+
: `${this.baseNavigationUrl}/details/${this.model?.identifier}`;
|
|
79
72
|
}
|
|
80
73
|
|
|
81
74
|
/*
|
|
@@ -49,8 +49,6 @@ export class TileList extends LitElement {
|
|
|
49
49
|
|
|
50
50
|
@property({ type: Boolean }) loggedIn = false;
|
|
51
51
|
|
|
52
|
-
@property({ type: String }) collectionPagePath: string = '/details/';
|
|
53
|
-
|
|
54
52
|
render() {
|
|
55
53
|
return html`
|
|
56
54
|
<div id="list-line" class="${this.classSize}">
|
|
@@ -95,11 +93,10 @@ export class TileList extends LitElement {
|
|
|
95
93
|
private get imageBlockTemplate() {
|
|
96
94
|
if (!this.model) return nothing;
|
|
97
95
|
|
|
98
|
-
const isCollection = this.model.mediatype === 'collection';
|
|
99
96
|
return html`<a
|
|
100
|
-
href="${this.baseNavigationUrl}
|
|
101
|
-
|
|
102
|
-
|
|
97
|
+
href="${this.baseNavigationUrl}/details/${encodeURI(
|
|
98
|
+
this.model.identifier
|
|
99
|
+
)}"
|
|
103
100
|
>
|
|
104
101
|
<image-block
|
|
105
102
|
.model=${this.model}
|
|
@@ -151,11 +148,7 @@ export class TileList extends LitElement {
|
|
|
151
148
|
? html`<a href="${this.baseNavigationUrl}${this.model.href}"
|
|
152
149
|
>${this.model.title ?? this.model.identifier}</a
|
|
153
150
|
>`
|
|
154
|
-
: this.detailsLink(
|
|
155
|
-
this.model.identifier,
|
|
156
|
-
this.model.title,
|
|
157
|
-
this.model.mediatype === 'collection'
|
|
158
|
-
);
|
|
151
|
+
: this.detailsLink(this.model.identifier, this.model.title);
|
|
159
152
|
}
|
|
160
153
|
|
|
161
154
|
private get itemLineTemplate() {
|
|
@@ -348,18 +341,12 @@ export class TileList extends LitElement {
|
|
|
348
341
|
/* eslint-enable lit/no-invalid-html */
|
|
349
342
|
}
|
|
350
343
|
|
|
351
|
-
private detailsLink(
|
|
352
|
-
identifier: string,
|
|
353
|
-
text?: string,
|
|
354
|
-
collection = false
|
|
355
|
-
): TemplateResult {
|
|
344
|
+
private detailsLink(identifier: string, text?: string): TemplateResult {
|
|
356
345
|
const linkText = text ?? identifier;
|
|
357
346
|
// No whitespace after closing tag
|
|
358
347
|
// identifiers (all ASCII in their creation) should be safe to use in href, but sanitize anyway
|
|
359
348
|
return html`<a
|
|
360
|
-
href="${this.baseNavigationUrl}
|
|
361
|
-
? this.collectionPagePath
|
|
362
|
-
: '/details/'}${encodeURI(identifier)}"
|
|
349
|
+
href="${this.baseNavigationUrl}/details/${encodeURI(identifier)}"
|
|
363
350
|
>${DOMPurify.sanitize(linkText)}</a
|
|
364
351
|
>`;
|
|
365
352
|
}
|
|
@@ -377,7 +364,7 @@ export class TileList extends LitElement {
|
|
|
377
364
|
case 'account':
|
|
378
365
|
return nothing;
|
|
379
366
|
default:
|
|
380
|
-
return `${this.baseNavigationUrl}
|
|
367
|
+
return `${this.baseNavigationUrl}/details/${encodeURI(
|
|
381
368
|
this.model.mediatype
|
|
382
369
|
)}`;
|
|
383
370
|
}
|
|
@@ -411,7 +398,7 @@ export class TileList extends LitElement {
|
|
|
411
398
|
promises.push(
|
|
412
399
|
this.collectionNameCache?.collectionNameFor(collection).then(name => {
|
|
413
400
|
newCollectionLinks.push(
|
|
414
|
-
this.detailsLink(collection, name ?? collection
|
|
401
|
+
this.detailsLink(collection, name ?? collection)
|
|
415
402
|
);
|
|
416
403
|
})
|
|
417
404
|
);
|
|
@@ -56,8 +56,6 @@ export class TileDispatcher
|
|
|
56
56
|
/** Whether this tile should include a hover pane at all (for applicable tile modes) */
|
|
57
57
|
@property({ type: Boolean }) enableHoverPane = false;
|
|
58
58
|
|
|
59
|
-
@property({ type: String }) collectionPagePath: string = '/details/';
|
|
60
|
-
|
|
61
59
|
private hoverPaneController?: HoverPaneControllerInterface;
|
|
62
60
|
|
|
63
61
|
@query('#container')
|
|
@@ -142,14 +140,9 @@ export class TileDispatcher
|
|
|
142
140
|
private get linkTileHref() {
|
|
143
141
|
// Use the server-specified href if available.
|
|
144
142
|
// Otherwise, construct a details page URL from the item identifier.
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const isCollection = this.model?.mediatype === 'collection';
|
|
150
|
-
return `${this.baseNavigationUrl}${
|
|
151
|
-
isCollection ? this.collectionPagePath : '/details/'
|
|
152
|
-
}${this.model?.identifier}`;
|
|
143
|
+
return this.model?.href
|
|
144
|
+
? `${this.baseNavigationUrl}${this.model?.href}`
|
|
145
|
+
: `${this.baseNavigationUrl}/details/${this.model?.identifier}`;
|
|
153
146
|
}
|
|
154
147
|
|
|
155
148
|
/**
|
|
@@ -273,7 +266,6 @@ export class TileDispatcher
|
|
|
273
266
|
case 'list-compact':
|
|
274
267
|
return html`<tile-list-compact
|
|
275
268
|
.model=${model}
|
|
276
|
-
.collectionPagePath=${this.collectionPagePath}
|
|
277
269
|
.currentWidth=${currentWidth}
|
|
278
270
|
.currentHeight=${currentHeight}
|
|
279
271
|
.baseNavigationUrl=${baseNavigationUrl}
|
|
@@ -286,7 +278,6 @@ export class TileDispatcher
|
|
|
286
278
|
case 'list-detail':
|
|
287
279
|
return html`<tile-list
|
|
288
280
|
.model=${model}
|
|
289
|
-
.collectionPagePath=${this.collectionPagePath}
|
|
290
281
|
.collectionNameCache=${this.collectionNameCache}
|
|
291
282
|
.currentWidth=${currentWidth}
|
|
292
283
|
.currentHeight=${currentHeight}
|
|
@@ -945,7 +945,6 @@ describe('Collection Browser', () => {
|
|
|
945
945
|
const searchService = new MockSearchService();
|
|
946
946
|
const el = await fixture<CollectionBrowser>(
|
|
947
947
|
html`<collection-browser
|
|
948
|
-
.log=${true}
|
|
949
948
|
.searchService=${searchService}
|
|
950
949
|
></collection-browser>`
|
|
951
950
|
);
|
|
@@ -961,6 +960,34 @@ describe('Collection Browser', () => {
|
|
|
961
960
|
expect(spy.secondCall.firstArg?.detail?.loading).to.equal(false);
|
|
962
961
|
});
|
|
963
962
|
|
|
963
|
+
it('collapses extra set of quotes around href field', async () => {
|
|
964
|
+
const searchService = new MockSearchService();
|
|
965
|
+
const el = await fixture<CollectionBrowser>(
|
|
966
|
+
html`<collection-browser
|
|
967
|
+
.searchService=${searchService}
|
|
968
|
+
.baseNavigationUrl=${''}
|
|
969
|
+
></collection-browser>`
|
|
970
|
+
);
|
|
971
|
+
|
|
972
|
+
el.baseQuery = 'extra-quoted-href';
|
|
973
|
+
await el.updateComplete;
|
|
974
|
+
await el.initialSearchComplete;
|
|
975
|
+
await el.updateComplete;
|
|
976
|
+
await nextTick();
|
|
977
|
+
|
|
978
|
+
const infiniteScroller = el.shadowRoot?.querySelector('infinite-scroller');
|
|
979
|
+
expect(infiniteScroller).to.exist;
|
|
980
|
+
|
|
981
|
+
const firstResult =
|
|
982
|
+
infiniteScroller!.shadowRoot?.querySelector('tile-dispatcher');
|
|
983
|
+
expect(firstResult).to.exist;
|
|
984
|
+
|
|
985
|
+
// Original href q param starts/ends with %22%22, but should be collapsed to %22 before render
|
|
986
|
+
expect(
|
|
987
|
+
firstResult!.shadowRoot?.querySelector('a[href]')?.getAttribute('href')
|
|
988
|
+
).to.equal('/details/foo?q=%22quoted+query%22');
|
|
989
|
+
});
|
|
990
|
+
|
|
964
991
|
it('scrolls to page', async () => {
|
|
965
992
|
const searchService = new MockSearchService();
|
|
966
993
|
const el = await fixture<CollectionBrowser>(
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
ItemHit,
|
|
5
5
|
SearchResponse,
|
|
6
6
|
SearchServiceError,
|
|
7
|
+
TextHit,
|
|
7
8
|
} from '@internetarchive/search-service';
|
|
8
9
|
import { SearchServiceErrorType } from '@internetarchive/search-service/dist/src/search-service-error';
|
|
9
10
|
|
|
@@ -475,6 +476,42 @@ export const getMockSuccessMultiLineDescription: () => Result<
|
|
|
475
476
|
},
|
|
476
477
|
});
|
|
477
478
|
|
|
479
|
+
export const getMockSuccessExtraQuotedHref: () => Result<
|
|
480
|
+
SearchResponse,
|
|
481
|
+
SearchServiceError
|
|
482
|
+
> = () => ({
|
|
483
|
+
success: {
|
|
484
|
+
request: {
|
|
485
|
+
clientParameters: {
|
|
486
|
+
user_query: 'extra-quoted-href',
|
|
487
|
+
sort: [],
|
|
488
|
+
},
|
|
489
|
+
finalizedParameters: {
|
|
490
|
+
user_query: 'extra-quoted-href',
|
|
491
|
+
sort: [],
|
|
492
|
+
},
|
|
493
|
+
},
|
|
494
|
+
rawResponse: {},
|
|
495
|
+
response: {
|
|
496
|
+
totalResults: 1,
|
|
497
|
+
returnedCount: 1,
|
|
498
|
+
results: [
|
|
499
|
+
new TextHit({
|
|
500
|
+
fields: {
|
|
501
|
+
identifier: 'foo',
|
|
502
|
+
title: 'Foo',
|
|
503
|
+
__href__: '/details/foo?q=%22%22quoted+query%22%22',
|
|
504
|
+
},
|
|
505
|
+
}),
|
|
506
|
+
],
|
|
507
|
+
},
|
|
508
|
+
responseHeader: {
|
|
509
|
+
succeeded: true,
|
|
510
|
+
query_time: 0,
|
|
511
|
+
},
|
|
512
|
+
},
|
|
513
|
+
});
|
|
514
|
+
|
|
478
515
|
export const getMockErrorResult: () => Result<
|
|
479
516
|
SearchResponse,
|
|
480
517
|
SearchServiceError
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
getMockMalformedResult,
|
|
22
22
|
getMockSuccessWithCollectionTitles,
|
|
23
23
|
getMockSuccessWithCollectionAggregations,
|
|
24
|
+
getMockSuccessExtraQuotedHref,
|
|
24
25
|
} from './mock-search-responses';
|
|
25
26
|
|
|
26
27
|
const responses: Record<
|
|
@@ -37,6 +38,7 @@ const responses: Record<
|
|
|
37
38
|
'first-creator': getMockSuccessFirstCreatorResult,
|
|
38
39
|
'collection-titles': getMockSuccessWithCollectionTitles,
|
|
39
40
|
'collection-aggregations': getMockSuccessWithCollectionAggregations,
|
|
41
|
+
'extra-quoted-href': getMockSuccessExtraQuotedHref,
|
|
40
42
|
error: getMockErrorResult,
|
|
41
43
|
malformed: getMockMalformedResult,
|
|
42
44
|
};
|