@internetarchive/collection-browser 1.14.17-alpha.2 → 1.14.17-alpha.21
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.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/src/app-root.d.ts +1 -0
- package/dist/src/app-root.js +38 -0
- package/dist/src/app-root.js.map +1 -1
- package/dist/src/collection-browser.d.ts +2 -15
- package/dist/src/collection-browser.js +22 -29
- package/dist/src/collection-browser.js.map +1 -1
- package/dist/src/data-source/collection-browser-data-source.d.ts +55 -32
- package/dist/src/data-source/collection-browser-data-source.js +155 -162
- package/dist/src/data-source/collection-browser-data-source.js.map +1 -1
- package/dist/src/data-source/models.d.ts +6 -3
- package/dist/src/data-source/models.js.map +1 -1
- package/dist/src/manage/manage-bar.d.ts +1 -1
- package/dist/src/manage/manage-bar.js.map +1 -1
- package/dist/src/models.d.ts +20 -4
- package/dist/src/models.js +105 -0
- package/dist/src/models.js.map +1 -1
- package/dist/src/sort-filter-bar/sort-filter-bar.js +25 -16
- package/dist/src/sort-filter-bar/sort-filter-bar.js.map +1 -1
- package/dist/src/tiles/grid/item-tile.d.ts +1 -0
- package/dist/src/tiles/grid/item-tile.js +28 -1
- package/dist/src/tiles/grid/item-tile.js.map +1 -1
- package/dist/src/tiles/grid/tile-stats.js +13 -8
- package/dist/src/tiles/grid/tile-stats.js.map +1 -1
- package/dist/src/tiles/list/tile-list-compact.js +1 -1
- package/dist/src/tiles/list/tile-list-compact.js.map +1 -1
- package/dist/src/tiles/list/tile-list.d.ts +1 -0
- package/dist/src/tiles/list/tile-list.js +32 -1
- package/dist/src/tiles/list/tile-list.js.map +1 -1
- package/dist/src/tiles/tile-dispatcher.js +3 -2
- package/dist/src/tiles/tile-dispatcher.js.map +1 -1
- package/dist/src/tiles/tile-display-value-provider.d.ts +6 -2
- package/dist/src/tiles/tile-display-value-provider.js +15 -1
- package/dist/src/tiles/tile-display-value-provider.js.map +1 -1
- package/dist/src/utils/collapse-repeated-quotes.d.ts +11 -0
- package/dist/src/utils/collapse-repeated-quotes.js +14 -0
- package/dist/src/utils/collapse-repeated-quotes.js.map +1 -0
- package/dist/src/utils/resolve-mediatype.d.ts +8 -0
- package/dist/src/utils/resolve-mediatype.js +24 -0
- package/dist/src/utils/resolve-mediatype.js.map +1 -0
- package/dist/test/collection-browser.test.js +39 -19
- package/dist/test/collection-browser.test.js.map +1 -1
- package/dist/test/collection-facets/more-facets-content.test.js +2 -2
- package/dist/test/collection-facets/more-facets-content.test.js.map +1 -1
- package/dist/test/collection-facets.test.js +5 -0
- package/dist/test/collection-facets.test.js.map +1 -1
- package/dist/test/item-image.test.js +33 -34
- package/dist/test/item-image.test.js.map +1 -1
- package/dist/test/mocks/mock-search-responses.d.ts +1 -0
- package/dist/test/mocks/mock-search-responses.js +62 -0
- package/dist/test/mocks/mock-search-responses.js.map +1 -1
- package/dist/test/sort-filter-bar/sort-filter-bar.test.js +41 -4
- package/dist/test/sort-filter-bar/sort-filter-bar.test.js.map +1 -1
- package/dist/test/tiles/hover/hover-pane-controller.test.js +18 -17
- package/dist/test/tiles/hover/hover-pane-controller.test.js.map +1 -1
- package/package.json +2 -2
- package/src/app-root.ts +39 -0
- package/src/collection-browser.ts +24 -40
- package/src/data-source/collection-browser-data-source.ts +160 -132
- package/src/data-source/models.ts +6 -2
- package/src/manage/manage-bar.ts +1 -1
- package/src/models.ts +154 -3
- package/src/sort-filter-bar/sort-filter-bar.ts +26 -16
- package/src/tiles/grid/item-tile.ts +36 -1
- package/src/tiles/grid/tile-stats.ts +12 -7
- package/src/tiles/list/tile-list-compact.ts +1 -1
- package/src/tiles/list/tile-list.ts +43 -5
- package/src/tiles/tile-dispatcher.ts +2 -1
- package/src/tiles/tile-display-value-provider.ts +20 -2
- package/src/utils/collapse-repeated-quotes.ts +13 -0
- package/src/utils/resolve-mediatype.ts +26 -0
- package/test/collection-browser.test.ts +74 -19
- package/test/collection-facets/more-facets-content.test.ts +4 -2
- package/test/collection-facets.test.ts +5 -0
- package/test/item-image.test.ts +34 -36
- package/test/mocks/mock-search-responses.ts +66 -0
- package/test/sort-filter-bar/sort-filter-bar.test.ts +50 -4
- package/test/tiles/hover/hover-pane-controller.test.ts +19 -17
- package/dist/src/data-source/data-source-fetch-provider.d.ts +0 -13
- package/dist/src/data-source/data-source-fetch-provider.js +0 -61
- package/dist/src/data-source/data-source-fetch-provider.js.map +0 -1
- package/dist/src/selected-facets.d.ts +0 -67
- package/dist/src/selected-facets.js +0 -149
- package/dist/src/selected-facets.js.map +0 -1
- package/src/data-source/data-source-fetch-provider.ts +0 -79
- package/src/selected-facets.ts +0 -216
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { ReactiveController, ReactiveControllerHost } from 'lit';
|
|
2
2
|
import { AccountExtraInfo, Aggregation, CollectionExtraInfo, FilterMap, PageElementMap, SearchParams } from '@internetarchive/search-service';
|
|
3
|
-
import { type PrefixFilterType,
|
|
3
|
+
import { type PrefixFilterType, TileModel, PrefixFilterCounts, RequestKind } from '../models';
|
|
4
4
|
import type { CollectionBrowserSearchInterface, CollectionTitles, PageSpecifierParams } from './models';
|
|
5
|
-
declare type RequestKind = 'full' | 'hits' | 'aggregations';
|
|
6
5
|
export interface CollectionBrowserDataSourceInterface extends ReactiveController {
|
|
7
6
|
/**
|
|
8
7
|
* How many tile models are present in this data source
|
|
@@ -15,6 +14,11 @@ export interface CollectionBrowserDataSourceInterface extends ReactiveController
|
|
|
15
14
|
* for MDS but not FTS.
|
|
16
15
|
*/
|
|
17
16
|
readonly canPerformSearch: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Whether the end of the set of results for the current query state has been
|
|
19
|
+
* encountered (i.e., the last page of results).
|
|
20
|
+
*/
|
|
21
|
+
readonly endOfDataReached: boolean;
|
|
18
22
|
/**
|
|
19
23
|
* A string key compactly representing the current full search state, which can
|
|
20
24
|
* be used to determine, e.g., when a new search is required or whether an arriving
|
|
@@ -83,6 +87,18 @@ export interface CollectionBrowserDataSourceInterface extends ReactiveController
|
|
|
83
87
|
* An array of all the tile models whose management checkboxes are unchecked
|
|
84
88
|
*/
|
|
85
89
|
readonly uncheckedTileModels: TileModel[];
|
|
90
|
+
/**
|
|
91
|
+
* A Promise which, after each query change, resolves once the fetches for the initial
|
|
92
|
+
* search have completed. Waits for *both* the hits and aggregations fetches to finish.
|
|
93
|
+
*
|
|
94
|
+
* Ensure you await this component's `updateComplete` promise before awaiting this
|
|
95
|
+
* one, to ensure you do not await an obsolete promise from the previous update.
|
|
96
|
+
*/
|
|
97
|
+
readonly initialSearchComplete: Promise<boolean>;
|
|
98
|
+
/**
|
|
99
|
+
* Resets the data source to its empty state, with no result pages, aggregations, etc.
|
|
100
|
+
*/
|
|
101
|
+
reset(): void;
|
|
86
102
|
/**
|
|
87
103
|
* Adds the given page of tile models to the data source.
|
|
88
104
|
* If the given page number already exists, that page will be overwritten.
|
|
@@ -137,10 +153,6 @@ export interface CollectionBrowserDataSourceInterface extends ReactiveController
|
|
|
137
153
|
* @param pageSize
|
|
138
154
|
*/
|
|
139
155
|
setPageSize(pageSize: number): void;
|
|
140
|
-
/**
|
|
141
|
-
* Resets the data source to its empty state, with no result pages, aggregations, etc.
|
|
142
|
-
*/
|
|
143
|
-
reset(): void;
|
|
144
156
|
/**
|
|
145
157
|
* Notifies the data source that a query change has occurred, which may trigger a data
|
|
146
158
|
* reset & new fetches.
|
|
@@ -178,7 +190,19 @@ export declare class CollectionBrowserDataSource implements CollectionBrowserDat
|
|
|
178
190
|
* Maps the full query key to the pages being fetched for that query
|
|
179
191
|
*/
|
|
180
192
|
private pageFetchesInProgress;
|
|
193
|
+
/**
|
|
194
|
+
* A record of the query key used for the last search.
|
|
195
|
+
* If this changes, we need to load new results.
|
|
196
|
+
*/
|
|
197
|
+
private previousQueryKey;
|
|
198
|
+
private id;
|
|
199
|
+
/**
|
|
200
|
+
* @inheritdoc
|
|
201
|
+
*/
|
|
181
202
|
totalResults: number;
|
|
203
|
+
/**
|
|
204
|
+
* @inheritdoc
|
|
205
|
+
*/
|
|
182
206
|
endOfDataReached: boolean;
|
|
183
207
|
/**
|
|
184
208
|
* @inheritdoc
|
|
@@ -212,15 +236,33 @@ export declare class CollectionBrowserDataSource implements CollectionBrowserDat
|
|
|
212
236
|
* @inheritdoc
|
|
213
237
|
*/
|
|
214
238
|
prefixFilterCountMap: Partial<Record<PrefixFilterType, PrefixFilterCounts>>;
|
|
239
|
+
/**
|
|
240
|
+
* Internal property to store the `resolve` function for the most recent
|
|
241
|
+
* `initialSearchComplete` promise, allowing us to resolve it at the appropriate time.
|
|
242
|
+
*/
|
|
243
|
+
private _initialSearchCompleteResolver;
|
|
244
|
+
/**
|
|
245
|
+
* Internal property to store the private value backing the `initialSearchComplete` getter.
|
|
246
|
+
*/
|
|
247
|
+
private _initialSearchCompletePromise;
|
|
248
|
+
/**
|
|
249
|
+
* @inheritdoc
|
|
250
|
+
*/
|
|
251
|
+
get initialSearchComplete(): Promise<boolean>;
|
|
215
252
|
constructor(
|
|
216
253
|
/** The host element to which this controller should attach listeners */
|
|
217
254
|
host: ReactiveControllerHost & CollectionBrowserSearchInterface,
|
|
218
255
|
/** Default size of result pages */
|
|
219
256
|
pageSize: number);
|
|
257
|
+
hostUpdate(): void;
|
|
220
258
|
/**
|
|
221
259
|
* @inheritdoc
|
|
222
260
|
*/
|
|
223
261
|
get size(): number;
|
|
262
|
+
/**
|
|
263
|
+
* @inheritdoc
|
|
264
|
+
*/
|
|
265
|
+
reset(): void;
|
|
224
266
|
/**
|
|
225
267
|
* @inheritdoc
|
|
226
268
|
*/
|
|
@@ -241,15 +283,14 @@ export declare class CollectionBrowserDataSource implements CollectionBrowserDat
|
|
|
241
283
|
* @inheritdoc
|
|
242
284
|
*/
|
|
243
285
|
getTileModelAt(index: number): TileModel | undefined;
|
|
244
|
-
indexOf(tile: TileModel): number;
|
|
245
286
|
/**
|
|
246
287
|
* @inheritdoc
|
|
247
288
|
*/
|
|
248
|
-
|
|
289
|
+
indexOf(tile: TileModel): number;
|
|
249
290
|
/**
|
|
250
291
|
* @inheritdoc
|
|
251
292
|
*/
|
|
252
|
-
|
|
293
|
+
setPageSize(pageSize: number): void;
|
|
253
294
|
/**
|
|
254
295
|
* @inheritdoc
|
|
255
296
|
*/
|
|
@@ -261,15 +302,15 @@ export declare class CollectionBrowserDataSource implements CollectionBrowserDat
|
|
|
261
302
|
/**
|
|
262
303
|
* @inheritdoc
|
|
263
304
|
*/
|
|
264
|
-
checkAllTiles()
|
|
305
|
+
checkAllTiles: () => void;
|
|
265
306
|
/**
|
|
266
307
|
* @inheritdoc
|
|
267
308
|
*/
|
|
268
|
-
uncheckAllTiles()
|
|
309
|
+
uncheckAllTiles: () => void;
|
|
269
310
|
/**
|
|
270
311
|
* @inheritdoc
|
|
271
312
|
*/
|
|
272
|
-
removeCheckedTiles()
|
|
313
|
+
removeCheckedTiles: () => void;
|
|
273
314
|
/**
|
|
274
315
|
* @inheritdoc
|
|
275
316
|
*/
|
|
@@ -301,8 +342,8 @@ export declare class CollectionBrowserDataSource implements CollectionBrowserDat
|
|
|
301
342
|
* - Any currently-applied prefix filters
|
|
302
343
|
* - The current sort options
|
|
303
344
|
*
|
|
304
|
-
* This lets us keep track of queries so we don't persist data that's
|
|
305
|
-
* no longer relevant.
|
|
345
|
+
* This lets us internally keep track of queries so we don't persist data that's
|
|
346
|
+
* no longer relevant. Not meant to be human-readable.
|
|
306
347
|
*/
|
|
307
348
|
get pageFetchQueryKey(): string;
|
|
308
349
|
/**
|
|
@@ -402,23 +443,6 @@ export declare class CollectionBrowserDataSource implements CollectionBrowserDat
|
|
|
402
443
|
* @param results
|
|
403
444
|
*/
|
|
404
445
|
private addTilesToDataSource;
|
|
405
|
-
/**
|
|
406
|
-
* Returns the mediatype string for the given search result, taking into account
|
|
407
|
-
* the special `favorited_search` hit type.
|
|
408
|
-
* @param result The search result to extract a mediatype from
|
|
409
|
-
*/
|
|
410
|
-
private getMediatype;
|
|
411
|
-
/**
|
|
412
|
-
* Returns the input string, but removing one set of quotes from all instances of
|
|
413
|
-
* ""clauses wrapped in two sets of quotes"". This assumes the quotes are already
|
|
414
|
-
* URL-encoded.
|
|
415
|
-
*
|
|
416
|
-
* This should be a temporary measure to address the fact that the __href__ field
|
|
417
|
-
* sometimes acquires extra quotation marks during query rewriting. Once there is a
|
|
418
|
-
* full Lucene parser in place that handles quoted queries correctly, this can likely
|
|
419
|
-
* be removed.
|
|
420
|
-
*/
|
|
421
|
-
private collapseRepeatedQuotes;
|
|
422
446
|
/**
|
|
423
447
|
* Fetches the aggregation buckets for the given prefix filter type.
|
|
424
448
|
*/
|
|
@@ -428,4 +452,3 @@ export declare class CollectionBrowserDataSource implements CollectionBrowserDat
|
|
|
428
452
|
*/
|
|
429
453
|
updatePrefixFilterCounts(filterType: PrefixFilterType): Promise<void>;
|
|
430
454
|
}
|
|
431
|
-
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FilterConstraint, FilterMapBuilder, SearchType, } from '@internetarchive/search-service';
|
|
2
|
-
import { prefixFilterAggregationKeys, } from '../models';
|
|
2
|
+
import { prefixFilterAggregationKeys, TileModel, } from '../models';
|
|
3
3
|
import { sha1 } from '../utils/sha1';
|
|
4
4
|
export class CollectionBrowserDataSource {
|
|
5
5
|
constructor(
|
|
@@ -16,7 +16,19 @@ export class CollectionBrowserDataSource {
|
|
|
16
16
|
* Maps the full query key to the pages being fetched for that query
|
|
17
17
|
*/
|
|
18
18
|
this.pageFetchesInProgress = {};
|
|
19
|
+
/**
|
|
20
|
+
* A record of the query key used for the last search.
|
|
21
|
+
* If this changes, we need to load new results.
|
|
22
|
+
*/
|
|
23
|
+
this.previousQueryKey = '';
|
|
24
|
+
this.id = Math.random();
|
|
25
|
+
/**
|
|
26
|
+
* @inheritdoc
|
|
27
|
+
*/
|
|
19
28
|
this.totalResults = 0;
|
|
29
|
+
/**
|
|
30
|
+
* @inheritdoc
|
|
31
|
+
*/
|
|
20
32
|
this.endOfDataReached = false;
|
|
21
33
|
/**
|
|
22
34
|
* @inheritdoc
|
|
@@ -30,14 +42,126 @@ export class CollectionBrowserDataSource {
|
|
|
30
42
|
* @inheritdoc
|
|
31
43
|
*/
|
|
32
44
|
this.prefixFilterCountMap = {};
|
|
45
|
+
/**
|
|
46
|
+
* Internal property to store the private value backing the `initialSearchComplete` getter.
|
|
47
|
+
*/
|
|
48
|
+
this._initialSearchCompletePromise = new Promise(res => {
|
|
49
|
+
this._initialSearchCompleteResolver = res;
|
|
50
|
+
});
|
|
51
|
+
/**
|
|
52
|
+
* @inheritdoc
|
|
53
|
+
*/
|
|
54
|
+
this.checkAllTiles = () => {
|
|
55
|
+
this.map(model => {
|
|
56
|
+
const cloned = model.clone();
|
|
57
|
+
cloned.checked = true;
|
|
58
|
+
return cloned;
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* @inheritdoc
|
|
63
|
+
*/
|
|
64
|
+
this.uncheckAllTiles = () => {
|
|
65
|
+
this.map(model => {
|
|
66
|
+
const cloned = model.clone();
|
|
67
|
+
cloned.checked = false;
|
|
68
|
+
return cloned;
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* @inheritdoc
|
|
73
|
+
*/
|
|
74
|
+
this.removeCheckedTiles = () => {
|
|
75
|
+
// To make sure our data source remains page-aligned, we will offset our data source by
|
|
76
|
+
// the number of removed tiles, so that we can just add the offset when the infinite
|
|
77
|
+
// scroller queries for cell contents.
|
|
78
|
+
// This only matters while we're still viewing the same set of results. If the user changes
|
|
79
|
+
// their query/filters/sort, then the data source is overwritten and the offset cleared.
|
|
80
|
+
const { checkedTileModels, uncheckedTileModels } = this;
|
|
81
|
+
const numChecked = checkedTileModels.length;
|
|
82
|
+
if (numChecked === 0)
|
|
83
|
+
return;
|
|
84
|
+
this.offset += numChecked;
|
|
85
|
+
const newPages = {};
|
|
86
|
+
// Which page the remaining tile models start on, post-offset
|
|
87
|
+
let offsetPageNumber = Math.floor(this.offset / this.pageSize) + 1;
|
|
88
|
+
let indexOnPage = this.offset % this.pageSize;
|
|
89
|
+
// Fill the pages up to that point with empty models
|
|
90
|
+
for (let page = 1; page <= offsetPageNumber; page += 1) {
|
|
91
|
+
const remainingHidden = this.offset - this.pageSize * (page - 1);
|
|
92
|
+
const offsetCellsOnPage = Math.min(this.pageSize, remainingHidden);
|
|
93
|
+
newPages[page] = Array(offsetCellsOnPage).fill(undefined);
|
|
94
|
+
}
|
|
95
|
+
// Shift all the remaining tiles into their new positions in the data source
|
|
96
|
+
for (const model of uncheckedTileModels) {
|
|
97
|
+
if (!newPages[offsetPageNumber])
|
|
98
|
+
newPages[offsetPageNumber] = [];
|
|
99
|
+
newPages[offsetPageNumber].push(model);
|
|
100
|
+
indexOnPage += 1;
|
|
101
|
+
if (indexOnPage >= this.pageSize) {
|
|
102
|
+
offsetPageNumber += 1;
|
|
103
|
+
indexOnPage = 0;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Swap in the new pages
|
|
107
|
+
this.pages = newPages;
|
|
108
|
+
this.numTileModels -= numChecked;
|
|
109
|
+
this.host.requestUpdate();
|
|
110
|
+
this.host.refreshVisibleResults();
|
|
111
|
+
};
|
|
33
112
|
this.host.addController(this);
|
|
34
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* @inheritdoc
|
|
116
|
+
*/
|
|
117
|
+
get initialSearchComplete() {
|
|
118
|
+
return this._initialSearchCompletePromise;
|
|
119
|
+
}
|
|
120
|
+
hostUpdate() {
|
|
121
|
+
// This reactive controller hook is run whenever the host component (collection-browser) performs an update.
|
|
122
|
+
// We check whether the host's state has changed in a way which should trigger a reset & new results fetch.
|
|
123
|
+
// Only the currently-installed data source should react to the update
|
|
124
|
+
if (this.host.dataSource !== this)
|
|
125
|
+
return;
|
|
126
|
+
// Can't perform searches without a search service
|
|
127
|
+
if (!this.host.searchService)
|
|
128
|
+
return;
|
|
129
|
+
// We should only reset if part of the full query state has changed
|
|
130
|
+
const queryKeyChanged = this.pageFetchQueryKey !== this.previousQueryKey;
|
|
131
|
+
console.log('query keys', this.pageFetchQueryKey, this.previousQueryKey);
|
|
132
|
+
if (!queryKeyChanged)
|
|
133
|
+
return;
|
|
134
|
+
// We should only reset if either:
|
|
135
|
+
// (a) our state permits a valid search, or
|
|
136
|
+
// (b) we have a blank query that we want to show empty results for
|
|
137
|
+
const shouldShowEmptyQueryResults = this.host.clearResultsOnEmptyQuery && this.host.baseQuery === '';
|
|
138
|
+
if (!(this.canPerformSearch || shouldShowEmptyQueryResults))
|
|
139
|
+
return;
|
|
140
|
+
this.handleQueryChange();
|
|
141
|
+
}
|
|
35
142
|
/**
|
|
36
143
|
* @inheritdoc
|
|
37
144
|
*/
|
|
38
145
|
get size() {
|
|
39
146
|
return this.numTileModels;
|
|
40
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* @inheritdoc
|
|
150
|
+
*/
|
|
151
|
+
reset() {
|
|
152
|
+
this.pages = {};
|
|
153
|
+
this.aggregations = {};
|
|
154
|
+
this.yearHistogramAggregation = undefined;
|
|
155
|
+
this.pageFetchesInProgress = {};
|
|
156
|
+
this.pageElements = undefined;
|
|
157
|
+
this.parentCollections = [];
|
|
158
|
+
this.prefixFilterCountMap = {};
|
|
159
|
+
this.offset = 0;
|
|
160
|
+
this.numTileModels = 0;
|
|
161
|
+
this.totalResults = 0;
|
|
162
|
+
this.endOfDataReached = false;
|
|
163
|
+
this.host.requestUpdate();
|
|
164
|
+
}
|
|
41
165
|
/**
|
|
42
166
|
* @inheritdoc
|
|
43
167
|
*/
|
|
@@ -73,6 +197,9 @@ export class CollectionBrowserDataSource {
|
|
|
73
197
|
const indexOnPage = index % this.pageSize;
|
|
74
198
|
return (_a = this.pages[pageNum]) === null || _a === void 0 ? void 0 : _a[indexOnPage];
|
|
75
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* @inheritdoc
|
|
202
|
+
*/
|
|
76
203
|
indexOf(tile) {
|
|
77
204
|
return Object.values(this.pages).flat().indexOf(tile);
|
|
78
205
|
}
|
|
@@ -83,32 +210,22 @@ export class CollectionBrowserDataSource {
|
|
|
83
210
|
this.reset();
|
|
84
211
|
this.pageSize = pageSize;
|
|
85
212
|
}
|
|
86
|
-
/**
|
|
87
|
-
* @inheritdoc
|
|
88
|
-
*/
|
|
89
|
-
reset() {
|
|
90
|
-
this.pages = {};
|
|
91
|
-
this.aggregations = {};
|
|
92
|
-
this.yearHistogramAggregation = undefined;
|
|
93
|
-
this.pageFetchesInProgress = {};
|
|
94
|
-
this.pageElements = undefined;
|
|
95
|
-
this.parentCollections = [];
|
|
96
|
-
this.prefixFilterCountMap = {};
|
|
97
|
-
this.offset = 0;
|
|
98
|
-
this.numTileModels = 0;
|
|
99
|
-
this.totalResults = 0;
|
|
100
|
-
this.endOfDataReached = false;
|
|
101
|
-
this.host.requestUpdate();
|
|
102
|
-
}
|
|
103
213
|
/**
|
|
104
214
|
* @inheritdoc
|
|
105
215
|
*/
|
|
106
216
|
async handleQueryChange() {
|
|
107
217
|
this.reset();
|
|
218
|
+
// Reset the `initialSearchComplete` promise with a new value for the imminent search
|
|
219
|
+
this._initialSearchCompletePromise = new Promise(res => {
|
|
220
|
+
this._initialSearchCompleteResolver = res;
|
|
221
|
+
});
|
|
222
|
+
// Fire the initial page & facet requests
|
|
108
223
|
await Promise.all([
|
|
109
224
|
this.doInitialPageFetch(),
|
|
110
225
|
this.host.suppressFacets ? null : this.fetchFacets(),
|
|
111
226
|
]);
|
|
227
|
+
// Resolve the `initialSearchComplete` promise for this search
|
|
228
|
+
this._initialSearchCompleteResolver(true);
|
|
112
229
|
}
|
|
113
230
|
/**
|
|
114
231
|
* @inheritdoc
|
|
@@ -119,58 +236,7 @@ export class CollectionBrowserDataSource {
|
|
|
119
236
|
tileModels.map((model, index, array) => model ? callback(model, index, array) : model),
|
|
120
237
|
]));
|
|
121
238
|
this.host.requestUpdate();
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* @inheritdoc
|
|
125
|
-
*/
|
|
126
|
-
checkAllTiles() {
|
|
127
|
-
this.map(model => ({ ...model, checked: true }));
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* @inheritdoc
|
|
131
|
-
*/
|
|
132
|
-
uncheckAllTiles() {
|
|
133
|
-
this.map(model => ({ ...model, checked: false }));
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* @inheritdoc
|
|
137
|
-
*/
|
|
138
|
-
removeCheckedTiles() {
|
|
139
|
-
// To make sure our data source remains page-aligned, we will offset our data source by
|
|
140
|
-
// the number of removed tiles, so that we can just add the offset when the infinite
|
|
141
|
-
// scroller queries for cell contents.
|
|
142
|
-
// This only matters while we're still viewing the same set of results. If the user changes
|
|
143
|
-
// their query/filters/sort, then the data source is overwritten and the offset cleared.
|
|
144
|
-
const { checkedTileModels, uncheckedTileModels } = this;
|
|
145
|
-
const numChecked = checkedTileModels.length;
|
|
146
|
-
if (numChecked === 0)
|
|
147
|
-
return;
|
|
148
|
-
this.offset += numChecked;
|
|
149
|
-
const newPages = {};
|
|
150
|
-
// Which page the remaining tile models start on, post-offset
|
|
151
|
-
let offsetPageNumber = Math.floor(this.offset / this.pageSize) + 1;
|
|
152
|
-
let indexOnPage = this.offset % this.pageSize;
|
|
153
|
-
// Fill the pages up to that point with empty models
|
|
154
|
-
for (let page = 1; page <= offsetPageNumber; page += 1) {
|
|
155
|
-
const remainingHidden = this.offset - this.pageSize * (page - 1);
|
|
156
|
-
const offsetCellsOnPage = Math.min(this.pageSize, remainingHidden);
|
|
157
|
-
newPages[page] = Array(offsetCellsOnPage).fill(undefined);
|
|
158
|
-
}
|
|
159
|
-
// Shift all the remaining tiles into their new positions in the data source
|
|
160
|
-
for (const model of uncheckedTileModels) {
|
|
161
|
-
if (!newPages[offsetPageNumber])
|
|
162
|
-
newPages[offsetPageNumber] = [];
|
|
163
|
-
newPages[offsetPageNumber].push(model);
|
|
164
|
-
indexOnPage += 1;
|
|
165
|
-
if (indexOnPage >= this.pageSize) {
|
|
166
|
-
offsetPageNumber += 1;
|
|
167
|
-
indexOnPage = 0;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
// Swap in the new pages
|
|
171
|
-
this.pages = newPages;
|
|
172
|
-
this.numTileModels -= numChecked;
|
|
173
|
-
this.host.requestUpdate();
|
|
239
|
+
this.host.refreshVisibleResults();
|
|
174
240
|
}
|
|
175
241
|
/**
|
|
176
242
|
* @inheritdoc
|
|
@@ -227,16 +293,16 @@ export class CollectionBrowserDataSource {
|
|
|
227
293
|
* - Any currently-applied prefix filters
|
|
228
294
|
* - The current sort options
|
|
229
295
|
*
|
|
230
|
-
* This lets us keep track of queries so we don't persist data that's
|
|
231
|
-
* no longer relevant.
|
|
296
|
+
* This lets us internally keep track of queries so we don't persist data that's
|
|
297
|
+
* no longer relevant. Not meant to be human-readable.
|
|
232
298
|
*/
|
|
233
299
|
get pageFetchQueryKey() {
|
|
234
300
|
var _a, _b, _c, _d, _e;
|
|
235
|
-
const profileKey =
|
|
301
|
+
const profileKey = `pf;${this.host.withinProfile}--pe;${this.host.profileElement}`;
|
|
236
302
|
const pageTarget = (_a = this.host.withinCollection) !== null && _a !== void 0 ? _a : profileKey;
|
|
237
303
|
const sortField = (_c = (_b = this.host.sortParam) === null || _b === void 0 ? void 0 : _b.field) !== null && _c !== void 0 ? _c : 'none';
|
|
238
304
|
const sortDirection = (_e = (_d = this.host.sortParam) === null || _d === void 0 ? void 0 : _d.direction) !== null && _e !== void 0 ? _e : 'none';
|
|
239
|
-
return
|
|
305
|
+
return `fq:${this.fullQuery}-pt:${pageTarget}-st:${this.host.searchType}-sf:${sortField}-sd:${sortDirection}`;
|
|
240
306
|
}
|
|
241
307
|
/**
|
|
242
308
|
* Similar to `pageFetchQueryKey` above, but excludes sort fields since they
|
|
@@ -458,9 +524,11 @@ export class CollectionBrowserDataSource {
|
|
|
458
524
|
*/
|
|
459
525
|
async fetchFacets() {
|
|
460
526
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
527
|
+
console.log('fetchFacets', this.id, this.host.profileElement);
|
|
461
528
|
const trimmedQuery = (_a = this.host.baseQuery) === null || _a === void 0 ? void 0 : _a.trim();
|
|
462
529
|
if (!this.canPerformSearch)
|
|
463
530
|
return;
|
|
531
|
+
console.log('will actually fetch facets');
|
|
464
532
|
const { facetFetchQueryKey } = this;
|
|
465
533
|
const sortParams = this.host.sortParam ? [this.host.sortParam] : [];
|
|
466
534
|
const params = {
|
|
@@ -481,8 +549,10 @@ export class CollectionBrowserDataSource {
|
|
|
481
549
|
// If so, we just want to discard this set of aggregations because they are
|
|
482
550
|
// likely no longer valid for the newer query.
|
|
483
551
|
const queryChangedSinceFetch = facetFetchQueryKey !== this.facetFetchQueryKey;
|
|
484
|
-
if (queryChangedSinceFetch)
|
|
552
|
+
if (queryChangedSinceFetch) {
|
|
553
|
+
console.log('facet query has changed since fetch, returning. new/old:', this.facetFetchQueryKey, facetFetchQueryKey);
|
|
485
554
|
return;
|
|
555
|
+
}
|
|
486
556
|
if (!success) {
|
|
487
557
|
const errorMsg = (_c = searchResponse === null || searchResponse === void 0 ? void 0 : searchResponse.error) === null || _c === void 0 ? void 0 : _c.message;
|
|
488
558
|
const detailMsg = (_e = (_d = searchResponse === null || searchResponse === void 0 ? void 0 : searchResponse.error) === null || _d === void 0 ? void 0 : _d.details) === null || _e === void 0 ? void 0 : _e.message;
|
|
@@ -490,6 +560,7 @@ export class CollectionBrowserDataSource {
|
|
|
490
560
|
// @ts-ignore: Property 'Sentry' does not exist on type 'Window & typeof globalThis'
|
|
491
561
|
(_g = (_f = window === null || window === void 0 ? void 0 : window.Sentry) === null || _f === void 0 ? void 0 : _f.captureMessage) === null || _g === void 0 ? void 0 : _g.call(_f, 'Missing or malformed facet response from backend', 'error');
|
|
492
562
|
}
|
|
563
|
+
this.host.setFacetsLoading(false);
|
|
493
564
|
return;
|
|
494
565
|
}
|
|
495
566
|
const { aggregations, collectionTitles } = success.response;
|
|
@@ -523,7 +594,7 @@ export class CollectionBrowserDataSource {
|
|
|
523
594
|
*/
|
|
524
595
|
async fetchPage(pageNumber, numInitialPages = 1) {
|
|
525
596
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
526
|
-
console.log(`fetchPage(${pageNumber})`, this.canPerformSearch, this.hasPage(pageNumber), this.endOfDataReached, this.host.baseQuery, JSON.stringify(this.host.selectedFacets));
|
|
597
|
+
console.log(`fetchPage(${pageNumber})`, this.id, this.canPerformSearch, this.hasPage(pageNumber), this.endOfDataReached, this.host.baseQuery, JSON.stringify(this.host.selectedFacets), this.pageFetchQueryKey);
|
|
527
598
|
const trimmedQuery = (_a = this.host.baseQuery) === null || _a === void 0 ? void 0 : _a.trim();
|
|
528
599
|
if (!this.canPerformSearch)
|
|
529
600
|
return;
|
|
@@ -547,6 +618,7 @@ export class CollectionBrowserDataSource {
|
|
|
547
618
|
pageFetches.add(pageNumber + i);
|
|
548
619
|
}
|
|
549
620
|
this.pageFetchesInProgress[pageFetchQueryKey] = pageFetches;
|
|
621
|
+
this.previousQueryKey = pageFetchQueryKey;
|
|
550
622
|
const sortParams = this.host.sortParam ? [this.host.sortParam] : [];
|
|
551
623
|
const params = {
|
|
552
624
|
...this.pageSpecifierParams,
|
|
@@ -592,6 +664,7 @@ export class CollectionBrowserDataSource {
|
|
|
592
664
|
this.host.emitEmptyResults();
|
|
593
665
|
}
|
|
594
666
|
if (this.host.withinCollection) {
|
|
667
|
+
console.log('host is within collection, setting collection info:', success.response.collectionExtraInfo);
|
|
595
668
|
this.collectionExtraInfo = success.response.collectionExtraInfo;
|
|
596
669
|
// For collections, we want the UI to respect the default sort option
|
|
597
670
|
// which can be specified in metadata, or otherwise assumed to be week:desc
|
|
@@ -601,10 +674,13 @@ export class CollectionBrowserDataSource {
|
|
|
601
674
|
}
|
|
602
675
|
}
|
|
603
676
|
else if (this.host.withinProfile) {
|
|
604
|
-
console.log('host is within profile, setting acct info:', success.response.accountExtraInfo);
|
|
677
|
+
console.log('host is within profile, setting acct info:', success.response.accountExtraInfo, success.response.pageElements);
|
|
605
678
|
this.accountExtraInfo = success.response.accountExtraInfo;
|
|
606
679
|
this.pageElements = success.response.pageElements;
|
|
607
680
|
}
|
|
681
|
+
else {
|
|
682
|
+
console.log('not within profile/collxn', this.host.withinCollection, this.host.withinProfile);
|
|
683
|
+
}
|
|
608
684
|
const { results, collectionTitles } = success.response;
|
|
609
685
|
if (results && results.length > 0) {
|
|
610
686
|
// Load any collection titles present on the response into the cache,
|
|
@@ -625,6 +701,7 @@ export class CollectionBrowserDataSource {
|
|
|
625
701
|
// temporary estimates based on pages rendered so far).
|
|
626
702
|
const resultCountDiscrepancy = numRows - results.length;
|
|
627
703
|
if (resultCountDiscrepancy > 0) {
|
|
704
|
+
console.log('End of data reached');
|
|
628
705
|
this.endOfDataReached = true;
|
|
629
706
|
this.host.setTileCount(this.totalResults);
|
|
630
707
|
}
|
|
@@ -646,57 +723,9 @@ export class CollectionBrowserDataSource {
|
|
|
646
723
|
// const datasource = { ...this.dataSource };
|
|
647
724
|
const tiles = [];
|
|
648
725
|
results === null || results === void 0 ? void 0 : results.forEach(result => {
|
|
649
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13;
|
|
650
726
|
if (!result.identifier)
|
|
651
727
|
return;
|
|
652
|
-
|
|
653
|
-
let contentWarning = false;
|
|
654
|
-
// Check if item and item in "modifying" collection, setting above flags
|
|
655
|
-
if (((_a = result.collection) === null || _a === void 0 ? void 0 : _a.values.length) &&
|
|
656
|
-
((_b = result.mediatype) === null || _b === void 0 ? void 0 : _b.value) !== 'collection') {
|
|
657
|
-
for (const collection of (_d = (_c = result.collection) === null || _c === void 0 ? void 0 : _c.values) !== null && _d !== void 0 ? _d : []) {
|
|
658
|
-
if (collection === 'loggedin') {
|
|
659
|
-
loginRequired = true;
|
|
660
|
-
if (contentWarning)
|
|
661
|
-
break;
|
|
662
|
-
}
|
|
663
|
-
if (collection === 'no-preview') {
|
|
664
|
-
contentWarning = true;
|
|
665
|
-
if (loginRequired)
|
|
666
|
-
break;
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
tiles.push({
|
|
671
|
-
averageRating: (_e = result.avg_rating) === null || _e === void 0 ? void 0 : _e.value,
|
|
672
|
-
checked: false,
|
|
673
|
-
collections: (_g = (_f = result.collection) === null || _f === void 0 ? void 0 : _f.values) !== null && _g !== void 0 ? _g : [],
|
|
674
|
-
collectionFilesCount: (_j = (_h = result.collection_files_count) === null || _h === void 0 ? void 0 : _h.value) !== null && _j !== void 0 ? _j : 0,
|
|
675
|
-
collectionSize: (_l = (_k = result.collection_size) === null || _k === void 0 ? void 0 : _k.value) !== null && _l !== void 0 ? _l : 0,
|
|
676
|
-
commentCount: (_o = (_m = result.num_reviews) === null || _m === void 0 ? void 0 : _m.value) !== null && _o !== void 0 ? _o : 0,
|
|
677
|
-
creator: (_p = result.creator) === null || _p === void 0 ? void 0 : _p.value,
|
|
678
|
-
creators: (_r = (_q = result.creator) === null || _q === void 0 ? void 0 : _q.values) !== null && _r !== void 0 ? _r : [],
|
|
679
|
-
dateAdded: (_s = result.addeddate) === null || _s === void 0 ? void 0 : _s.value,
|
|
680
|
-
dateArchived: (_t = result.publicdate) === null || _t === void 0 ? void 0 : _t.value,
|
|
681
|
-
datePublished: (_u = result.date) === null || _u === void 0 ? void 0 : _u.value,
|
|
682
|
-
dateReviewed: (_v = result.reviewdate) === null || _v === void 0 ? void 0 : _v.value,
|
|
683
|
-
description: (_w = result.description) === null || _w === void 0 ? void 0 : _w.values.join('\n'),
|
|
684
|
-
favCount: (_y = (_x = result.num_favorites) === null || _x === void 0 ? void 0 : _x.value) !== null && _y !== void 0 ? _y : 0,
|
|
685
|
-
href: this.collapseRepeatedQuotes((_z = result.__href__) === null || _z === void 0 ? void 0 : _z.value),
|
|
686
|
-
identifier: result.identifier,
|
|
687
|
-
issue: (_0 = result.issue) === null || _0 === void 0 ? void 0 : _0.value,
|
|
688
|
-
itemCount: (_2 = (_1 = result.item_count) === null || _1 === void 0 ? void 0 : _1.value) !== null && _2 !== void 0 ? _2 : 0,
|
|
689
|
-
mediatype: this.getMediatype(result),
|
|
690
|
-
snippets: (_4 = (_3 = result.highlight) === null || _3 === void 0 ? void 0 : _3.values) !== null && _4 !== void 0 ? _4 : [],
|
|
691
|
-
source: (_5 = result.source) === null || _5 === void 0 ? void 0 : _5.value,
|
|
692
|
-
subjects: (_7 = (_6 = result.subject) === null || _6 === void 0 ? void 0 : _6.values) !== null && _7 !== void 0 ? _7 : [],
|
|
693
|
-
title: (_9 = (_8 = result.title) === null || _8 === void 0 ? void 0 : _8.value) !== null && _9 !== void 0 ? _9 : '',
|
|
694
|
-
volume: (_10 = result.volume) === null || _10 === void 0 ? void 0 : _10.value,
|
|
695
|
-
viewCount: (_12 = (_11 = result.downloads) === null || _11 === void 0 ? void 0 : _11.value) !== null && _12 !== void 0 ? _12 : 0,
|
|
696
|
-
weeklyViewCount: (_13 = result.week) === null || _13 === void 0 ? void 0 : _13.value,
|
|
697
|
-
loginRequired,
|
|
698
|
-
contentWarning,
|
|
699
|
-
});
|
|
728
|
+
tiles.push(new TileModel(result));
|
|
700
729
|
});
|
|
701
730
|
this.addPage(pageNumber, tiles);
|
|
702
731
|
const visiblePages = this.host.currentVisiblePageNumbers;
|
|
@@ -705,42 +734,6 @@ export class CollectionBrowserDataSource {
|
|
|
705
734
|
this.host.refreshVisibleResults();
|
|
706
735
|
}
|
|
707
736
|
}
|
|
708
|
-
/**
|
|
709
|
-
* Returns the mediatype string for the given search result, taking into account
|
|
710
|
-
* the special `favorited_search` hit type.
|
|
711
|
-
* @param result The search result to extract a mediatype from
|
|
712
|
-
*/
|
|
713
|
-
getMediatype(result) {
|
|
714
|
-
var _a, _b, _c;
|
|
715
|
-
/**
|
|
716
|
-
* hit_type == 'favorited_search' is basically a new hit_type
|
|
717
|
-
* - we are getting from PPS.
|
|
718
|
-
* - which gives response for fav- collection
|
|
719
|
-
* - having favorited items like account/collection/item etc..
|
|
720
|
-
* - as user can also favorite a search result (a search page)
|
|
721
|
-
* - so we need to have response (having fav- items and fav- search results)
|
|
722
|
-
*
|
|
723
|
-
* if backend hit_type == 'favorited_search'
|
|
724
|
-
* - let's assume a "search" as new mediatype
|
|
725
|
-
*/
|
|
726
|
-
if (((_a = result === null || result === void 0 ? void 0 : result.rawMetadata) === null || _a === void 0 ? void 0 : _a.hit_type) === 'favorited_search') {
|
|
727
|
-
return 'search';
|
|
728
|
-
}
|
|
729
|
-
return (_c = (_b = result.mediatype) === null || _b === void 0 ? void 0 : _b.value) !== null && _c !== void 0 ? _c : 'data';
|
|
730
|
-
}
|
|
731
|
-
/**
|
|
732
|
-
* Returns the input string, but removing one set of quotes from all instances of
|
|
733
|
-
* ""clauses wrapped in two sets of quotes"". This assumes the quotes are already
|
|
734
|
-
* URL-encoded.
|
|
735
|
-
*
|
|
736
|
-
* This should be a temporary measure to address the fact that the __href__ field
|
|
737
|
-
* sometimes acquires extra quotation marks during query rewriting. Once there is a
|
|
738
|
-
* full Lucene parser in place that handles quoted queries correctly, this can likely
|
|
739
|
-
* be removed.
|
|
740
|
-
*/
|
|
741
|
-
collapseRepeatedQuotes(str) {
|
|
742
|
-
return str === null || str === void 0 ? void 0 : str.replace(/%22%22(?!%22%22)(.+?)%22%22/g, '%22$1%22');
|
|
743
|
-
}
|
|
744
737
|
/**
|
|
745
738
|
* Fetches the aggregation buckets for the given prefix filter type.
|
|
746
739
|
*/
|