@internetarchive/collection-browser 1.14.14-alpha.1 → 1.14.16-alpha.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.
Files changed (69) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +1 -0
  3. package/dist/index.js.map +1 -1
  4. package/dist/src/app-root.d.ts +0 -2
  5. package/dist/src/app-root.js +0 -8
  6. package/dist/src/app-root.js.map +1 -1
  7. package/dist/src/collection-browser.d.ts +24 -169
  8. package/dist/src/collection-browser.js +68 -684
  9. package/dist/src/collection-browser.js.map +1 -1
  10. package/dist/src/collection-facets/facet-row.d.ts +2 -2
  11. package/dist/src/collection-facets/facet-row.js +5 -10
  12. package/dist/src/collection-facets/facet-row.js.map +1 -1
  13. package/dist/src/collection-facets/facets-template.d.ts +2 -2
  14. package/dist/src/collection-facets/facets-template.js +2 -2
  15. package/dist/src/collection-facets/facets-template.js.map +1 -1
  16. package/dist/src/collection-facets/more-facets-content.d.ts +2 -9
  17. package/dist/src/collection-facets/more-facets-content.js +13 -18
  18. package/dist/src/collection-facets/more-facets-content.js.map +1 -1
  19. package/dist/src/collection-facets.d.ts +2 -3
  20. package/dist/src/collection-facets.js +5 -9
  21. package/dist/src/collection-facets.js.map +1 -1
  22. package/dist/src/data-source/collection-browser-data-source.d.ts +402 -0
  23. package/dist/src/data-source/collection-browser-data-source.js +742 -0
  24. package/dist/src/data-source/collection-browser-data-source.js.map +1 -0
  25. package/dist/src/data-source/models.d.ts +35 -0
  26. package/dist/src/data-source/models.js +2 -0
  27. package/dist/src/data-source/models.js.map +1 -0
  28. package/dist/src/tiles/hover/hover-pane-controller.d.ts +2 -2
  29. package/dist/src/tiles/hover/hover-pane-controller.js +1 -1
  30. package/dist/src/tiles/hover/hover-pane-controller.js.map +1 -1
  31. package/dist/src/tiles/hover/tile-hover-pane.d.ts +2 -2
  32. package/dist/src/tiles/hover/tile-hover-pane.js +2 -2
  33. package/dist/src/tiles/hover/tile-hover-pane.js.map +1 -1
  34. package/dist/src/tiles/list/tile-list.d.ts +3 -3
  35. package/dist/src/tiles/list/tile-list.js +7 -13
  36. package/dist/src/tiles/list/tile-list.js.map +1 -1
  37. package/dist/src/tiles/tile-dispatcher.d.ts +2 -2
  38. package/dist/src/tiles/tile-dispatcher.js +2 -3
  39. package/dist/src/tiles/tile-dispatcher.js.map +1 -1
  40. package/dist/test/collection-browser.test.js +43 -67
  41. package/dist/test/collection-browser.test.js.map +1 -1
  42. package/dist/test/collection-facets/facet-row.test.js +6 -17
  43. package/dist/test/collection-facets/facet-row.test.js.map +1 -1
  44. package/dist/test/collection-facets.test.js +0 -5
  45. package/dist/test/collection-facets.test.js.map +1 -1
  46. package/dist/test/tiles/list/tile-list.test.js +0 -5
  47. package/dist/test/tiles/list/tile-list.test.js.map +1 -1
  48. package/index.ts +4 -0
  49. package/package.json +3 -3
  50. package/src/app-root.ts +0 -10
  51. package/src/collection-browser.ts +79 -841
  52. package/src/collection-facets/facet-row.ts +4 -9
  53. package/src/collection-facets/facets-template.ts +3 -3
  54. package/src/collection-facets/more-facets-content.ts +15 -20
  55. package/src/collection-facets.ts +5 -10
  56. package/src/data-source/collection-browser-data-source.ts +1133 -0
  57. package/src/data-source/models.ts +45 -0
  58. package/src/tiles/hover/hover-pane-controller.ts +3 -3
  59. package/src/tiles/hover/tile-hover-pane.ts +3 -3
  60. package/src/tiles/list/tile-list.ts +13 -18
  61. package/src/tiles/tile-dispatcher.ts +3 -4
  62. package/test/collection-browser.test.ts +57 -79
  63. package/test/collection-facets/facet-row.test.ts +5 -18
  64. package/test/collection-facets.test.ts +0 -5
  65. package/test/tiles/list/tile-list.test.ts +0 -5
  66. package/dist/test/mocks/mock-collection-name-cache.d.ts +0 -9
  67. package/dist/test/mocks/mock-collection-name-cache.js +0 -18
  68. package/dist/test/mocks/mock-collection-name-cache.js.map +0 -1
  69. package/test/mocks/mock-collection-name-cache.ts +0 -24
@@ -4,7 +4,7 @@ import { html, css, LitElement, nothing, } from 'lit';
4
4
  import { customElement, property, query, state } from 'lit/decorators.js';
5
5
  import { classMap } from 'lit/directives/class-map.js';
6
6
  import { msg } from '@lit/localize';
7
- import { FilterConstraint, FilterMapBuilder, SearchType, } from '@internetarchive/search-service';
7
+ import { SearchType, } from '@internetarchive/search-service';
8
8
  import '@internetarchive/infinite-scroller';
9
9
  import './tiles/tile-dispatcher';
10
10
  import './tiles/collection-browser-loading-tile';
@@ -12,8 +12,9 @@ import './sort-filter-bar/sort-filter-bar';
12
12
  import './manage/manage-bar';
13
13
  import './collection-facets';
14
14
  import './circular-activity-indicator';
15
- import { SortField, getDefaultSelectedFacets, prefixFilterAggregationKeys, sortOptionFromAPIString, SORT_OPTIONS, } from './models';
15
+ import { SortField, getDefaultSelectedFacets, sortOptionFromAPIString, SORT_OPTIONS, } from './models';
16
16
  import { RestorationStateHandler, } from './restoration-state-handler';
17
+ import { CollectionBrowserDataSource, } from './data-source/collection-browser-data-source';
17
18
  import chevronIcon from './assets/img/icons/chevron';
18
19
  import './empty-placeholder';
19
20
  import { analyticsActions, analyticsCategories, } from './utils/analytics-events';
@@ -25,7 +26,6 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
25
26
  super(...arguments);
26
27
  this.baseImageUrl = 'https://archive.org';
27
28
  this.searchType = SearchType.METADATA;
28
- this.sortParam = null;
29
29
  this.defaultSortParam = null;
30
30
  this.selectedSort = SortField.default;
31
31
  this.selectedTitleFilter = null;
@@ -53,6 +53,14 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
53
53
  */
54
54
  this.isManageView = false;
55
55
  this.isLoansTab = false;
56
+ /**
57
+ * The results per page so we can paginate.
58
+ *
59
+ * This allows us to start in the middle of the search results and
60
+ * fetch data before or after the current page. If we don't have a key
61
+ * for the previous/next page, we'll fetch the next/previous page to populate it
62
+ */
63
+ this.dataSource = new CollectionBrowserDataSource(this, this.pageSize);
56
64
  /**
57
65
  * The page that the consumer wants to load.
58
66
  */
@@ -69,7 +77,6 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
69
77
  */
70
78
  this.searchResultsLoading = false;
71
79
  this.facetsLoading = false;
72
- this.fullYearAggregationLoading = false;
73
80
  this.mobileView = false;
74
81
  this.mobileFacetsVisible = false;
75
82
  this.defaultSortField = SortField.relevance;
@@ -91,14 +98,6 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
91
98
  */
92
99
  this.isResizeToMobile = false;
93
100
  this.placeholderCellTemplate = html `<collection-browser-loading-tile></collection-browser-loading-tile>`;
94
- /**
95
- * The results per page so we can paginate.
96
- *
97
- * This allows us to start in the middle of the search results and
98
- * fetch data before or after the current page. If we don't have a key
99
- * for the previous/next page, we'll fetch the next/previous page to populate it
100
- */
101
- this.dataSource = {};
102
101
  /**
103
102
  * How many tiles to offset the data source by, to account for any removed tiles.
104
103
  */
@@ -137,32 +136,24 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
137
136
  this._initialSearchCompletePromise = new Promise(res => {
138
137
  this._initialSearchCompleteResolver = res;
139
138
  });
140
- // this maps the query to the pages being fetched for that query
141
- this.pageFetchesInProgress = {};
142
139
  }
143
140
  tileModelAtCellIndex(index) {
144
- var _a;
145
141
  const offsetIndex = index + this.tileModelOffset;
146
- const pageNumber = Math.floor(offsetIndex / this.pageSize) + 1;
147
- const itemIndex = offsetIndex % this.pageSize;
148
- const model = (_a = this.dataSource[pageNumber]) === null || _a === void 0 ? void 0 : _a[itemIndex];
142
+ const model = this.dataSource.getTileModelAt(offsetIndex);
149
143
  /**
150
144
  * If we encounter a model we don't have yet and we're not in the middle of an
151
145
  * automated scroll, fetch the page and just return undefined.
152
146
  * The datasource will be updated once the page is loaded and the cell will be rendered.
153
147
  *
154
- * We disable it during the automated scroll since we may fetch pages for cells the
148
+ * We disable it during the automated scroll since we don't want to fetch pages for intervening cells the
155
149
  * user may never see.
156
150
  */
157
151
  if (!model && !this.isScrollingToCell) {
158
- this.fetchPage(pageNumber);
152
+ const pageNumber = Math.floor(offsetIndex / this.pageSize) + 1;
153
+ this.dataSource.fetchPage(pageNumber);
159
154
  }
160
155
  return model;
161
156
  }
162
- get sortFilterQueries() {
163
- const queries = [this.titleQuery, this.creatorQuery];
164
- return queries.filter(q => q).join(' AND ');
165
- }
166
157
  // this is the total number of tiles we expect if
167
158
  // the data returned is a full page worth
168
159
  // this is useful for putting in placeholders for the expected number of tiles
@@ -205,6 +196,12 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
205
196
  this.pagesToRender = pageNumber;
206
197
  return this.scrollToPage(pageNumber);
207
198
  }
199
+ setSearchResultsLoading(loading) {
200
+ this.searchResultsLoading = loading;
201
+ }
202
+ setFacetsLoading(loading) {
203
+ this.facetsLoading = loading;
204
+ }
208
205
  /**
209
206
  * Clears all selected/negated facets, date ranges, and letter filters.
210
207
  *
@@ -230,7 +227,6 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
230
227
  this.selectedCreatorFilter = null;
231
228
  }
232
229
  if (sort) {
233
- this.sortParam = null;
234
230
  this.sortDirection = null;
235
231
  this.selectedSort = SortField.default;
236
232
  }
@@ -452,7 +448,7 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
452
448
  .displayMode=${this.displayMode}
453
449
  .selectedTitleFilter=${this.selectedTitleFilter}
454
450
  .selectedCreatorFilter=${this.selectedCreatorFilter}
455
- .prefixFilterCountMap=${this.prefixFilterCountMap}
451
+ .prefixFilterCountMap=${this.dataSource.prefixFilterCountMap}
456
452
  .resizeObserver=${this.resizeObserver}
457
453
  @sortChanged=${this.userChangedSort}
458
454
  @displayModeChanged=${this.displayModeChanged}
@@ -476,11 +472,11 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
476
472
  showSelectAll
477
473
  showUnselectAll
478
474
  @removeItems=${this.handleRemoveItems}
479
- @selectAll=${this.checkAllTiles}
480
- @unselectAll=${this.uncheckAllTiles}
475
+ @selectAll=${this.dataSource.checkAllTiles}
476
+ @unselectAll=${this.dataSource.uncheckAllTiles}
481
477
  @cancel=${() => {
482
478
  this.isManageView = false;
483
- this.uncheckAllTiles();
479
+ this.dataSource.uncheckAllTiles();
484
480
  }}
485
481
  ></manage-bar>
486
482
  `;
@@ -492,7 +488,7 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
492
488
  handleRemoveItems() {
493
489
  this.dispatchEvent(new CustomEvent('itemRemovalRequested', {
494
490
  detail: {
495
- items: this.checkedTileModels.map(model => ({
491
+ items: this.dataSource.checkedTileModels.map(model => ({
496
492
  ...model,
497
493
  date: formatDate(model.datePublished, 'long'),
498
494
  })),
@@ -504,95 +500,7 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
504
500
  * of the data source to account for any new gaps in the data.
505
501
  */
506
502
  removeCheckedTiles() {
507
- // To make sure our data source remains page-aligned, we will offset our data source by
508
- // the number of removed tiles, so that we can just add the offset when the infinite
509
- // scroller queries for cell contents.
510
- // This only matters while we're still viewing the same set of results. If the user changes
511
- // their query/filters/sort, then the data source is overwritten and the offset cleared.
512
- const { checkedTileModels, uncheckedTileModels } = this;
513
- const numChecked = checkedTileModels.length;
514
- if (numChecked === 0)
515
- return;
516
- this.tileModelOffset += numChecked;
517
- const newDataSource = {};
518
- // Which page the remaining tile models start on, post-offset
519
- let offsetPageNumber = Math.floor(this.tileModelOffset / this.pageSize) + 1;
520
- let indexOnPage = this.tileModelOffset % this.pageSize;
521
- // Fill the pages up to that point with empty models
522
- for (let page = 1; page <= offsetPageNumber; page += 1) {
523
- const remainingHidden = this.tileModelOffset - this.pageSize * (page - 1);
524
- const offsetCellsOnPage = Math.min(this.pageSize, remainingHidden);
525
- newDataSource[page] = Array(offsetCellsOnPage).fill(undefined);
526
- }
527
- // Shift all the remaining tiles into their new positions in the data source
528
- for (const model of uncheckedTileModels) {
529
- if (!newDataSource[offsetPageNumber])
530
- newDataSource[offsetPageNumber] = [];
531
- newDataSource[offsetPageNumber].push(model);
532
- indexOnPage += 1;
533
- if (indexOnPage >= this.pageSize) {
534
- offsetPageNumber += 1;
535
- indexOnPage = 0;
536
- }
537
- }
538
- // Swap in the new data source and update the infinite scroller
539
- this.dataSource = newDataSource;
540
- if (this.totalResults)
541
- this.totalResults -= numChecked;
542
- if (this.infiniteScroller) {
543
- this.infiniteScroller.itemCount -= numChecked;
544
- this.infiniteScroller.refreshAllVisibleCells();
545
- }
546
- }
547
- /**
548
- * Checks every tile's management checkbox
549
- */
550
- checkAllTiles() {
551
- this.mapDataSource(model => ({ ...model, checked: true }));
552
- }
553
- /**
554
- * Unchecks every tile's management checkbox
555
- */
556
- uncheckAllTiles() {
557
- this.mapDataSource(model => ({ ...model, checked: false }));
558
- }
559
- /**
560
- * Applies the given map function to all of the tile models in every page of the data
561
- * source. This method updates the data source object in immutable fashion.
562
- *
563
- * @param mapFn A callback function to apply on each tile model, as with Array.map
564
- */
565
- mapDataSource(mapFn) {
566
- var _a;
567
- this.dataSource = Object.fromEntries(Object.entries(this.dataSource).map(([page, tileModels]) => [
568
- page,
569
- tileModels.map((model, index, array) => model ? mapFn(model, index, array) : model),
570
- ]));
571
- (_a = this.infiniteScroller) === null || _a === void 0 ? void 0 : _a.refreshAllVisibleCells();
572
- }
573
- /**
574
- * An array of all the tile models whose management checkboxes are checked
575
- */
576
- get checkedTileModels() {
577
- return this.getFilteredTileModels(model => model.checked);
578
- }
579
- /**
580
- * An array of all the tile models whose management checkboxes are unchecked
581
- */
582
- get uncheckedTileModels() {
583
- return this.getFilteredTileModels(model => !model.checked);
584
- }
585
- /**
586
- * Returns a flattened, filtered array of all the tile models in the data source
587
- * for which the given predicate returns a truthy value.
588
- *
589
- * @param predicate A callback function to apply on each tile model, as with Array.filter
590
- * @returns A filtered array of tile models satisfying the predicate
591
- */
592
- getFilteredTileModels(predicate) {
593
- return Object.values(this.dataSource)
594
- .flat()
595
- .filter((model, index, array) => model ? predicate(model, index, array) : false);
503
+ this.dataSource.removeCheckedTiles();
596
504
  }
597
505
  userChangedSort(e) {
598
506
  var _a;
@@ -614,11 +522,14 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
614
522
  });
615
523
  }
616
524
  selectedSortChanged() {
525
+ // Lazy-load the alphabet counts for title/creator sort bar as needed
526
+ this.updatePrefixFiltersForCurrentSort();
527
+ }
528
+ get sortParam() {
617
529
  var _a;
618
530
  const sortOption = SORT_OPTIONS[this.selectedSort];
619
- if (!sortOption.handledBySearchService) {
620
- this.sortParam = null;
621
- return;
531
+ if (!(sortOption === null || sortOption === void 0 ? void 0 : sortOption.handledBySearchService)) {
532
+ return null;
622
533
  }
623
534
  // If the sort option specified in the URL is unrecognized, we just use it as-is
624
535
  const urlSortParam = new URL(window.location.href).searchParams.get('sort');
@@ -628,10 +539,8 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
628
539
  if (!this.sortDirection)
629
540
  this.sortDirection = 'asc';
630
541
  if (!sortField)
631
- return;
632
- this.sortParam = { field: sortField, direction: this.sortDirection };
633
- // Lazy-load the alphabet counts for title/creator sort bar as needed
634
- this.updatePrefixFiltersForCurrentSort();
542
+ return null;
543
+ return { field: sortField, direction: this.sortDirection };
635
544
  }
636
545
  displayModeChanged(e) {
637
546
  var _a;
@@ -740,12 +649,13 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
740
649
  * The template for the facets component alone, without any surrounding wrappers.
741
650
  */
742
651
  get facetsTemplate() {
743
- if (this.suppressFacets)
652
+ if (this.suppressFacets) {
744
653
  return html `
745
654
  <p class="facets-message">
746
655
  ${msg('Facets are temporarily unavailable.')}
747
656
  </p>
748
657
  `;
658
+ }
749
659
  return html `
750
660
  <collection-facets
751
661
  @facetsChanged=${this.facetsChanged}
@@ -758,18 +668,19 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
758
668
  .recaptchaManager=${this.recaptchaManager}
759
669
  .resizeObserver=${this.resizeObserver}
760
670
  .searchType=${this.searchType}
761
- .aggregations=${this.aggregations}
762
- .fullYearsHistogramAggregation=${this.fullYearsHistogramAggregation}
671
+ .aggregations=${this.dataSource.aggregations}
672
+ .fullYearsHistogramAggregation=${this.dataSource
673
+ .yearHistogramAggregation}
763
674
  .minSelectedDate=${this.minSelectedDate}
764
675
  .maxSelectedDate=${this.maxSelectedDate}
765
676
  .selectedFacets=${this.selectedFacets}
766
677
  .baseNavigationUrl=${this.baseNavigationUrl}
767
- .collectionNameCache=${this.collectionNameCache}
678
+ .collectionTitles=${this.dataSource.collectionTitles}
768
679
  .showHistogramDatePicker=${this.showHistogramDatePicker}
769
680
  .allowExpandingDatePicker=${!this.mobileView}
770
681
  .contentWidth=${this.contentWidth}
771
682
  .query=${this.baseQuery}
772
- .filterMap=${this.filterMap}
683
+ .filterMap=${this.dataSource.filterMap}
773
684
  .isManageView=${this.isManageView}
774
685
  .modalManager=${this.modalManager}
775
686
  ?collapsableFacets=${this.mobileView}
@@ -931,7 +842,8 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
931
842
  changed.has('selectedCreatorFilter') ||
932
843
  changed.has('minSelectedDate') ||
933
844
  changed.has('maxSelectedDate') ||
934
- changed.has('sortParam') ||
845
+ changed.has('selectedSort') ||
846
+ changed.has('sortDirection') ||
935
847
  changed.has('selectedFacets') ||
936
848
  changed.has('searchService') ||
937
849
  changed.has('withinCollection')) {
@@ -1090,19 +1002,16 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
1090
1002
  async handleQueryChange() {
1091
1003
  var _a;
1092
1004
  // only reset if the query has actually changed
1093
- if (!this.searchService || this.pageFetchQueryKey === this.previousQueryKey)
1005
+ if (!this.searchService ||
1006
+ this.dataSource.pageFetchQueryKey === this.previousQueryKey)
1094
1007
  return;
1095
1008
  // If the new state prevents us from updating the search results, don't reset
1096
- if (!this.canPerformSearch &&
1009
+ if (!this.dataSource.canPerformSearch &&
1097
1010
  !(this.clearResultsOnEmptyQuery && this.baseQuery === ''))
1098
1011
  return;
1099
- this.previousQueryKey = this.pageFetchQueryKey;
1100
- this.dataSource = {};
1012
+ this.previousQueryKey = this.dataSource.pageFetchQueryKey;
1101
1013
  this.tileModelOffset = 0;
1102
1014
  this.totalResults = undefined;
1103
- this.aggregations = undefined;
1104
- this.fullYearsHistogramAggregation = undefined;
1105
- this.pageFetchesInProgress = {};
1106
1015
  this.endOfDataReached = false;
1107
1016
  this.pagesToRender =
1108
1017
  this.initialPageNumber === 1
@@ -1134,10 +1043,7 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
1134
1043
  this._initialSearchCompleteResolver = res;
1135
1044
  });
1136
1045
  // Fire the initial page and facets requests
1137
- await Promise.all([
1138
- this.doInitialPageFetch(),
1139
- this.suppressFacets ? null : this.fetchFacets(),
1140
- ]);
1046
+ await this.dataSource.handleQueryChange();
1141
1047
  // Resolve the `initialSearchComplete` promise for this search
1142
1048
  this._initialSearchCompleteResolver(true);
1143
1049
  }
@@ -1190,12 +1096,6 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
1190
1096
  };
1191
1097
  this.restorationStateHandler.persistState(restorationState);
1192
1098
  }
1193
- async doInitialPageFetch() {
1194
- this.searchResultsLoading = true;
1195
- // Try to batch 2 initial page requests when possible
1196
- await this.fetchPage(this.initialPageNumber, 2);
1197
- this.searchResultsLoading = false;
1198
- }
1199
1099
  emitSearchResultsLoadingChanged() {
1200
1100
  this.dispatchEvent(new CustomEvent('searchResultsLoadingChanged', {
1201
1101
  detail: {
@@ -1203,159 +1103,6 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
1203
1103
  },
1204
1104
  }));
1205
1105
  }
1206
- /**
1207
- * Produces a compact unique ID for a search request that can help with debugging
1208
- * on the backend by making related requests easier to trace through different services.
1209
- * (e.g., tying the hits/aggregations requests for the same page back to a single hash).
1210
- *
1211
- * @param params The search service parameters for the request
1212
- * @param kind The kind of request (hits-only, aggregations-only, or both)
1213
- * @returns A Promise resolving to the uid to apply to the request
1214
- */
1215
- async requestUID(params, kind) {
1216
- var _a;
1217
- const paramsToHash = JSON.stringify({
1218
- pageType: params.pageType,
1219
- pageTarget: params.pageTarget,
1220
- query: params.query,
1221
- fields: params.fields,
1222
- filters: params.filters,
1223
- sort: params.sort,
1224
- searchType: this.searchType,
1225
- });
1226
- const fullQueryHash = (await sha1(paramsToHash)).slice(0, 20); // First 80 bits of SHA-1 are plenty for this
1227
- const sessionId = (await this.getSessionId()).slice(0, 20); // Likewise
1228
- const page = (_a = params.page) !== null && _a !== void 0 ? _a : 0;
1229
- const kindPrefix = kind.charAt(0); // f = full, h = hits, a = aggregations
1230
- const currentTime = Date.now();
1231
- return `R:${fullQueryHash}-S:${sessionId}-P:${page}-K:${kindPrefix}-T:${currentTime}`;
1232
- }
1233
- /**
1234
- * Constructs a search service FilterMap object from the combination of
1235
- * all the currently-applied filters. This includes any facets, letter
1236
- * filters, and date range.
1237
- */
1238
- get filterMap() {
1239
- const builder = new FilterMapBuilder();
1240
- // Add the date range, if applicable
1241
- if (this.minSelectedDate) {
1242
- builder.addFilter('year', this.minSelectedDate, FilterConstraint.GREATER_OR_EQUAL);
1243
- }
1244
- if (this.maxSelectedDate) {
1245
- builder.addFilter('year', this.maxSelectedDate, FilterConstraint.LESS_OR_EQUAL);
1246
- }
1247
- // Add any selected facets
1248
- if (this.selectedFacets) {
1249
- for (const [facetName, facetValues] of Object.entries(this.selectedFacets)) {
1250
- const { name, values } = this.prepareFacetForFetch(facetName, facetValues);
1251
- for (const [value, bucket] of Object.entries(values)) {
1252
- let constraint;
1253
- if (bucket.state === 'selected') {
1254
- constraint = FilterConstraint.INCLUDE;
1255
- }
1256
- else if (bucket.state === 'hidden') {
1257
- constraint = FilterConstraint.EXCLUDE;
1258
- }
1259
- if (constraint) {
1260
- builder.addFilter(name, value, constraint);
1261
- }
1262
- }
1263
- }
1264
- }
1265
- // Add any letter filters
1266
- if (this.selectedTitleFilter) {
1267
- builder.addFilter('firstTitle', this.selectedTitleFilter, FilterConstraint.INCLUDE);
1268
- }
1269
- if (this.selectedCreatorFilter) {
1270
- builder.addFilter('firstCreator', this.selectedCreatorFilter, FilterConstraint.INCLUDE);
1271
- }
1272
- const filterMap = builder.build();
1273
- return filterMap;
1274
- }
1275
- /** The full query, including year facets and date range clauses */
1276
- get fullQuery() {
1277
- var _a, _b;
1278
- let fullQuery = (_b = (_a = this.baseQuery) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : '';
1279
- const { facetQuery, dateRangeQueryClause, sortFilterQueries } = this;
1280
- if (facetQuery) {
1281
- fullQuery += ` AND ${facetQuery}`;
1282
- }
1283
- if (dateRangeQueryClause) {
1284
- fullQuery += ` AND ${dateRangeQueryClause}`;
1285
- }
1286
- if (sortFilterQueries) {
1287
- fullQuery += ` AND ${sortFilterQueries}`;
1288
- }
1289
- return fullQuery.trim();
1290
- }
1291
- /**
1292
- * Generates a query string for the given facets
1293
- *
1294
- * Example: `mediatype:("collection" OR "audio" OR -"etree") AND year:("2000" OR "2001")`
1295
- */
1296
- get facetQuery() {
1297
- var _a;
1298
- if (!this.selectedFacets)
1299
- return undefined;
1300
- const facetClauses = [];
1301
- for (const [facetName, facetValues] of Object.entries(this.selectedFacets)) {
1302
- facetClauses.push(this.buildFacetClause(facetName, facetValues));
1303
- }
1304
- return (_a = this.joinFacetClauses(facetClauses)) === null || _a === void 0 ? void 0 : _a.trim();
1305
- }
1306
- /**
1307
- * Builds an OR-joined facet clause for the given facet name and values.
1308
- *
1309
- * E.g., for name `subject` and values
1310
- * `{ foo: { state: 'selected' }, bar: { state: 'hidden' } }`
1311
- * this will produce the clause
1312
- * `subject:("foo" OR -"bar")`.
1313
- *
1314
- * @param facetName The facet type (e.g., 'collection')
1315
- * @param facetValues The facet buckets, mapped by their keys
1316
- */
1317
- buildFacetClause(facetName, facetValues) {
1318
- const { name: facetQueryName, values } = this.prepareFacetForFetch(facetName, facetValues);
1319
- const facetEntries = Object.entries(values);
1320
- if (facetEntries.length === 0)
1321
- return '';
1322
- const facetValuesArray = [];
1323
- for (const [key, facetData] of facetEntries) {
1324
- const plusMinusPrefix = facetData.state === 'hidden' ? '-' : '';
1325
- facetValuesArray.push(`${plusMinusPrefix}"${key}"`);
1326
- }
1327
- const valueQuery = facetValuesArray.join(` OR `);
1328
- return `${facetQueryName}:(${valueQuery})`;
1329
- }
1330
- /**
1331
- * Handles some special pre-request normalization steps for certain facet types
1332
- * that require them.
1333
- *
1334
- * @param facetName The name of the facet type (e.g., 'language')
1335
- * @param facetValues An array of values for that facet type
1336
- */
1337
- prepareFacetForFetch(facetName, facetValues) {
1338
- // eslint-disable-next-line prefer-const
1339
- let [normalizedName, normalizedValues] = [facetName, facetValues];
1340
- // The full "search engine" name of the lending field is "lending___status"
1341
- if (facetName === 'lending') {
1342
- normalizedName = 'lending___status';
1343
- }
1344
- return {
1345
- name: normalizedName,
1346
- values: normalizedValues,
1347
- };
1348
- }
1349
- /**
1350
- * Takes an array of facet clauses, and combines them into a
1351
- * full AND-joined facet query string. Empty clauses are ignored.
1352
- */
1353
- joinFacetClauses(facetClauses) {
1354
- const nonEmptyFacetClauses = facetClauses.filter(clause => clause.length > 0);
1355
- return nonEmptyFacetClauses.length > 0
1356
- ? `(${nonEmptyFacetClauses.join(' AND ')})`
1357
- : undefined;
1358
- }
1359
1106
  facetsChanged(e) {
1360
1107
  this.selectedFacets = e.detail;
1361
1108
  }
@@ -1380,54 +1127,6 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
1380
1127
  label: facetType,
1381
1128
  });
1382
1129
  }
1383
- async fetchFacets() {
1384
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
1385
- const trimmedQuery = (_a = this.baseQuery) === null || _a === void 0 ? void 0 : _a.trim();
1386
- if (!this.canPerformSearch)
1387
- return;
1388
- const { facetFetchQueryKey } = this;
1389
- const sortParams = this.sortParam ? [this.sortParam] : [];
1390
- const params = {
1391
- ...this.collectionParams,
1392
- query: trimmedQuery || '',
1393
- rows: 0,
1394
- filters: this.filterMap,
1395
- // Fetch a few extra buckets beyond the 6 we show, in case some get suppressed
1396
- aggregationsSize: 10,
1397
- // Note: we don't need an aggregations param to fetch the default aggregations from the PPS.
1398
- // The default aggregations for the search_results page type should be what we need here.
1399
- };
1400
- params.uid = await this.requestUID({ ...params, sort: sortParams }, 'aggregations');
1401
- this.facetsLoading = true;
1402
- const searchResponse = await ((_b = this.searchService) === null || _b === void 0 ? void 0 : _b.search(params, this.searchType));
1403
- const success = searchResponse === null || searchResponse === void 0 ? void 0 : searchResponse.success;
1404
- // This is checking to see if the query has changed since the data was fetched.
1405
- // If so, we just want to discard this set of aggregations because they are
1406
- // likely no longer valid for the newer query.
1407
- const queryChangedSinceFetch = facetFetchQueryKey !== this.facetFetchQueryKey;
1408
- if (queryChangedSinceFetch)
1409
- return;
1410
- if (!success) {
1411
- const errorMsg = (_c = searchResponse === null || searchResponse === void 0 ? void 0 : searchResponse.error) === null || _c === void 0 ? void 0 : _c.message;
1412
- 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;
1413
- if (!errorMsg && !detailMsg) {
1414
- // @ts-ignore: Property 'Sentry' does not exist on type 'Window & typeof globalThis'
1415
- (_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');
1416
- }
1417
- return;
1418
- }
1419
- const { aggregations, collectionTitles } = success.response;
1420
- this.aggregations = aggregations;
1421
- if (collectionTitles) {
1422
- (_h = this.collectionNameCache) === null || _h === void 0 ? void 0 : _h.addKnownTitles(collectionTitles);
1423
- }
1424
- else if ((_j = this.aggregations) === null || _j === void 0 ? void 0 : _j.collection) {
1425
- (_k = this.collectionNameCache) === null || _k === void 0 ? void 0 : _k.preloadIdentifiers(this.aggregations.collection.buckets.map(bucket => { var _a; return (_a = bucket.key) === null || _a === void 0 ? void 0 : _a.toString(); }));
1426
- }
1427
- this.fullYearsHistogramAggregation =
1428
- (_m = (_l = success === null || success === void 0 ? void 0 : success.response) === null || _l === void 0 ? void 0 : _l.aggregations) === null || _m === void 0 ? void 0 : _m.year_histogram;
1429
- this.facetsLoading = false;
1430
- }
1431
1130
  scrollToPage(pageNumber) {
1432
1131
  return new Promise(resolve => {
1433
1132
  const cellIndexToScrollTo = this.pageSize * (pageNumber - 1);
@@ -1458,177 +1157,11 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
1458
1157
  var _a;
1459
1158
  return !!((_a = this.baseQuery) === null || _a === void 0 ? void 0 : _a.trim());
1460
1159
  }
1461
- /**
1462
- * Whether a search may be performed in the current state of the component.
1463
- * This is only true if the search service is defined, and either
1464
- * (a) a non-empty query is set, or
1465
- * (b) we are on a collection page in metadata search mode.
1466
- */
1467
- get canPerformSearch() {
1468
- var _a;
1469
- if (!this.searchService)
1470
- return false;
1471
- const trimmedQuery = (_a = this.baseQuery) === null || _a === void 0 ? void 0 : _a.trim();
1472
- const hasNonEmptyQuery = !!trimmedQuery;
1473
- const isCollectionSearch = !!this.withinCollection;
1474
- const isMetadataSearch = this.searchType === SearchType.METADATA;
1475
- // Metadata searches within a collection are allowed to have no query.
1476
- // Otherwise, a non-empty query must be set.
1477
- return hasNonEmptyQuery || (isCollectionSearch && isMetadataSearch);
1478
- }
1479
- /**
1480
- * Additional params to pass to the search service if targeting a collection page,
1481
- * or null otherwise.
1482
- */
1483
- get collectionParams() {
1484
- return this.withinCollection
1485
- ? { pageType: 'collection_details', pageTarget: this.withinCollection }
1486
- : null;
1487
- }
1488
- /**
1489
- * The query key is a string that uniquely identifies the current search.
1490
- * It consists of:
1491
- * - The current base query
1492
- * - The current collection
1493
- * - The current search type
1494
- * - Any currently-applied facets
1495
- * - Any currently-applied date range
1496
- * - Any currently-applied prefix filters
1497
- * - The current sort options
1498
- *
1499
- * This lets us keep track of queries so we don't persist data that's
1500
- * no longer relevant.
1501
- */
1502
- get pageFetchQueryKey() {
1503
- var _a, _b, _c, _d;
1504
- const sortField = (_b = (_a = this.sortParam) === null || _a === void 0 ? void 0 : _a.field) !== null && _b !== void 0 ? _b : 'none';
1505
- const sortDirection = (_d = (_c = this.sortParam) === null || _c === void 0 ? void 0 : _c.direction) !== null && _d !== void 0 ? _d : 'none';
1506
- return `${this.fullQuery}-${this.withinCollection}-${this.searchType}-${sortField}-${sortDirection}`;
1507
- }
1508
- /**
1509
- * Similar to `pageFetchQueryKey` above, but excludes sort fields since they
1510
- * are not relevant in determining aggregation queries.
1511
- */
1512
- get facetFetchQueryKey() {
1513
- return `${this.fullQuery}-${this.withinCollection}-${this.searchType}`;
1514
- }
1515
- /**
1516
- * Fetches one or more pages of results and updates the data source.
1517
- *
1518
- * @param pageNumber The page number to fetch
1519
- * @param numInitialPages If this is an initial page fetch (`pageNumber = 1`),
1520
- * specifies how many pages to batch together in one request. Ignored
1521
- * if `pageNumber != 1`, defaulting to a single page.
1522
- */
1523
- async fetchPage(pageNumber, numInitialPages = 1) {
1524
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
1525
- const trimmedQuery = (_a = this.baseQuery) === null || _a === void 0 ? void 0 : _a.trim();
1526
- if (!this.canPerformSearch)
1527
- return;
1528
- // if we already have data, don't fetch again
1529
- if (this.dataSource[pageNumber])
1530
- return;
1531
- if (this.endOfDataReached)
1532
- return;
1533
- // Batch multiple initial page requests together if needed (e.g., can request
1534
- // pages 1 and 2 together in a single request).
1535
- const numPages = pageNumber === 1 ? numInitialPages : 1;
1536
- const numRows = this.pageSize * numPages;
1537
- // if a fetch is already in progress for this query and page, don't fetch again
1538
- const { pageFetchQueryKey } = this;
1539
- const pageFetches = (_b = this.pageFetchesInProgress[pageFetchQueryKey]) !== null && _b !== void 0 ? _b : new Set();
1540
- if (pageFetches.has(pageNumber))
1541
- return;
1542
- for (let i = 0; i < numPages; i += 1) {
1543
- pageFetches.add(pageNumber + i);
1544
- }
1545
- this.pageFetchesInProgress[pageFetchQueryKey] = pageFetches;
1546
- const sortParams = this.sortParam ? [this.sortParam] : [];
1547
- const params = {
1548
- ...this.collectionParams,
1549
- query: trimmedQuery || '',
1550
- page: pageNumber,
1551
- rows: numRows,
1552
- sort: sortParams,
1553
- filters: this.filterMap,
1554
- aggregations: { omit: true },
1555
- };
1556
- params.uid = await this.requestUID(params, 'hits');
1557
- const searchResponse = await ((_c = this.searchService) === null || _c === void 0 ? void 0 : _c.search(params, this.searchType));
1558
- const success = searchResponse === null || searchResponse === void 0 ? void 0 : searchResponse.success;
1559
- // This is checking to see if the query has changed since the data was fetched.
1560
- // If so, we just want to discard the data since there should be a new query
1561
- // right behind it.
1562
- const queryChangedSinceFetch = pageFetchQueryKey !== this.pageFetchQueryKey;
1563
- if (queryChangedSinceFetch)
1564
- return;
1565
- if (!success) {
1566
- const errorMsg = (_d = searchResponse === null || searchResponse === void 0 ? void 0 : searchResponse.error) === null || _d === void 0 ? void 0 : _d.message;
1567
- const detailMsg = (_f = (_e = searchResponse === null || searchResponse === void 0 ? void 0 : searchResponse.error) === null || _e === void 0 ? void 0 : _e.details) === null || _f === void 0 ? void 0 : _f.message;
1568
- this.queryErrorMessage = `${errorMsg !== null && errorMsg !== void 0 ? errorMsg : ''}${detailMsg ? `; ${detailMsg}` : ''}`;
1569
- if (!this.queryErrorMessage) {
1570
- this.queryErrorMessage = 'Missing or malformed response from backend';
1571
- // @ts-ignore: Property 'Sentry' does not exist on type 'Window & typeof globalThis'
1572
- (_h = (_g = window === null || window === void 0 ? void 0 : window.Sentry) === null || _g === void 0 ? void 0 : _g.captureMessage) === null || _h === void 0 ? void 0 : _h.call(_g, this.queryErrorMessage, 'error');
1573
- }
1574
- for (let i = 0; i < numPages; i += 1) {
1575
- (_j = this.pageFetchesInProgress[pageFetchQueryKey]) === null || _j === void 0 ? void 0 : _j.delete(pageNumber + i);
1576
- }
1577
- this.searchResultsLoading = false;
1578
- return;
1579
- }
1580
- this.totalResults = success.response.totalResults - this.tileModelOffset;
1581
- // display event to offshoot when result count is zero.
1582
- if (this.totalResults === 0) {
1583
- this.emitEmptyResults();
1584
- }
1585
- if (this.withinCollection) {
1586
- this.collectionInfo = success.response.collectionExtraInfo;
1587
- // For collections, we want the UI to respect the default sort option
1588
- // which can be specified in metadata, or otherwise assumed to be week:desc
1589
- this.applyDefaultCollectionSort(this.collectionInfo);
1590
- if (this.collectionInfo) {
1591
- this.parentCollections = [].concat((_l = (_k = this.collectionInfo.public_metadata) === null || _k === void 0 ? void 0 : _k.collection) !== null && _l !== void 0 ? _l : []);
1592
- }
1593
- }
1594
- const { results, collectionTitles } = success.response;
1595
- if (results && results.length > 0) {
1596
- // Load any collection titles present on the response into the cache,
1597
- // or queue up preload fetches for them if none were present.
1598
- if (collectionTitles) {
1599
- (_m = this.collectionNameCache) === null || _m === void 0 ? void 0 : _m.addKnownTitles(collectionTitles);
1600
- }
1601
- else {
1602
- this.preloadCollectionNames(results);
1603
- }
1604
- // Update the data source for each returned page
1605
- for (let i = 0; i < numPages; i += 1) {
1606
- const pageStartIndex = this.pageSize * i;
1607
- this.updateDataSource(pageNumber + i, results.slice(pageStartIndex, pageStartIndex + this.pageSize));
1608
- }
1609
- }
1610
- // When we reach the end of the data, we can set the infinite scroller's
1611
- // item count to the real total number of results (rather than the
1612
- // temporary estimates based on pages rendered so far).
1613
- const resultCountDiscrepancy = numRows - results.length;
1614
- if (resultCountDiscrepancy > 0) {
1615
- this.endOfDataReached = true;
1616
- if (this.infiniteScroller) {
1617
- this.infiniteScroller.itemCount = this.totalResults;
1618
- }
1619
- }
1620
- for (let i = 0; i < numPages; i += 1) {
1621
- (_o = this.pageFetchesInProgress[pageFetchQueryKey]) === null || _o === void 0 ? void 0 : _o.delete(pageNumber + i);
1160
+ setTotalResultCount(count) {
1161
+ if (this.infiniteScroller) {
1162
+ this.infiniteScroller.itemCount = count;
1622
1163
  }
1623
1164
  }
1624
- preloadCollectionNames(results) {
1625
- var _a;
1626
- const collectionIds = results
1627
- .map(result => { var _a; return (_a = result.collection) === null || _a === void 0 ? void 0 : _a.values; })
1628
- .flat();
1629
- const collectionIdsArray = Array.from(new Set(collectionIds));
1630
- (_a = this.collectionNameCache) === null || _a === void 0 ? void 0 : _a.preloadIdentifiers(collectionIdsArray);
1631
- }
1632
1165
  /**
1633
1166
  * Applies any default sort option for the current collection, by checking
1634
1167
  * for one in the collection's metadata. If none is found, defaults to sorting
@@ -1691,147 +1224,11 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
1691
1224
  return Array.from(visiblePages);
1692
1225
  }
1693
1226
  /**
1694
- * Update the datasource from the fetch response
1695
- *
1696
- * @param pageNumber
1697
- * @param results
1227
+ * Refreshes all visible result cells in the infinite scroller.
1698
1228
  */
1699
- updateDataSource(pageNumber, results) {
1229
+ refreshVisibleResults() {
1700
1230
  var _a;
1701
- // copy our existing datasource so when we set it below, it gets set
1702
- // instead of modifying the existing dataSource since object changes
1703
- // don't trigger a re-render
1704
- const datasource = { ...this.dataSource };
1705
- const tiles = [];
1706
- results === null || results === void 0 ? void 0 : results.forEach(result => {
1707
- 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;
1708
- if (!result.identifier)
1709
- return;
1710
- let loginRequired = false;
1711
- let contentWarning = false;
1712
- // Check if item and item in "modifying" collection, setting above flags
1713
- if (((_a = result.collection) === null || _a === void 0 ? void 0 : _a.values.length) &&
1714
- ((_b = result.mediatype) === null || _b === void 0 ? void 0 : _b.value) !== 'collection') {
1715
- for (const collection of (_d = (_c = result.collection) === null || _c === void 0 ? void 0 : _c.values) !== null && _d !== void 0 ? _d : []) {
1716
- if (collection === 'loggedin') {
1717
- loginRequired = true;
1718
- if (contentWarning)
1719
- break;
1720
- }
1721
- if (collection === 'no-preview') {
1722
- contentWarning = true;
1723
- if (loginRequired)
1724
- break;
1725
- }
1726
- }
1727
- }
1728
- tiles.push({
1729
- averageRating: (_e = result.avg_rating) === null || _e === void 0 ? void 0 : _e.value,
1730
- checked: false,
1731
- collections: (_g = (_f = result.collection) === null || _f === void 0 ? void 0 : _f.values) !== null && _g !== void 0 ? _g : [],
1732
- collectionFilesCount: (_j = (_h = result.collection_files_count) === null || _h === void 0 ? void 0 : _h.value) !== null && _j !== void 0 ? _j : 0,
1733
- collectionSize: (_l = (_k = result.collection_size) === null || _k === void 0 ? void 0 : _k.value) !== null && _l !== void 0 ? _l : 0,
1734
- commentCount: (_o = (_m = result.num_reviews) === null || _m === void 0 ? void 0 : _m.value) !== null && _o !== void 0 ? _o : 0,
1735
- creator: (_p = result.creator) === null || _p === void 0 ? void 0 : _p.value,
1736
- creators: (_r = (_q = result.creator) === null || _q === void 0 ? void 0 : _q.values) !== null && _r !== void 0 ? _r : [],
1737
- dateAdded: (_s = result.addeddate) === null || _s === void 0 ? void 0 : _s.value,
1738
- dateArchived: (_t = result.publicdate) === null || _t === void 0 ? void 0 : _t.value,
1739
- datePublished: (_u = result.date) === null || _u === void 0 ? void 0 : _u.value,
1740
- dateReviewed: (_v = result.reviewdate) === null || _v === void 0 ? void 0 : _v.value,
1741
- description: (_w = result.description) === null || _w === void 0 ? void 0 : _w.values.join('\n'),
1742
- favCount: (_y = (_x = result.num_favorites) === null || _x === void 0 ? void 0 : _x.value) !== null && _y !== void 0 ? _y : 0,
1743
- href: this.collapseRepeatedQuotes((_z = result.__href__) === null || _z === void 0 ? void 0 : _z.value),
1744
- identifier: result.identifier,
1745
- issue: (_0 = result.issue) === null || _0 === void 0 ? void 0 : _0.value,
1746
- itemCount: (_2 = (_1 = result.item_count) === null || _1 === void 0 ? void 0 : _1.value) !== null && _2 !== void 0 ? _2 : 0,
1747
- mediatype: this.getMediatype(result),
1748
- snippets: (_4 = (_3 = result.highlight) === null || _3 === void 0 ? void 0 : _3.values) !== null && _4 !== void 0 ? _4 : [],
1749
- source: (_5 = result.source) === null || _5 === void 0 ? void 0 : _5.value,
1750
- subjects: (_7 = (_6 = result.subject) === null || _6 === void 0 ? void 0 : _6.values) !== null && _7 !== void 0 ? _7 : [],
1751
- title: (_9 = (_8 = result.title) === null || _8 === void 0 ? void 0 : _8.value) !== null && _9 !== void 0 ? _9 : '',
1752
- volume: (_10 = result.volume) === null || _10 === void 0 ? void 0 : _10.value,
1753
- viewCount: (_12 = (_11 = result.downloads) === null || _11 === void 0 ? void 0 : _11.value) !== null && _12 !== void 0 ? _12 : 0,
1754
- weeklyViewCount: (_13 = result.week) === null || _13 === void 0 ? void 0 : _13.value,
1755
- loginRequired,
1756
- contentWarning,
1757
- });
1758
- });
1759
- datasource[pageNumber] = tiles;
1760
- this.dataSource = datasource;
1761
- const visiblePages = this.currentVisiblePageNumbers;
1762
- const needsReload = visiblePages.includes(pageNumber);
1763
- if (needsReload) {
1764
- (_a = this.infiniteScroller) === null || _a === void 0 ? void 0 : _a.refreshAllVisibleCells();
1765
- }
1766
- }
1767
- getMediatype(result) {
1768
- var _a, _b, _c;
1769
- /**
1770
- * hit_type == 'favorited_search' is basically a new hit_type
1771
- * - we are getting from PPS.
1772
- * - which gives response for fav- collection
1773
- * - having favorited items like account/collection/item etc..
1774
- * - as user can also favorite a search result (a search page)
1775
- * - so we need to have response (having fav- items and fav- search results)
1776
- *
1777
- * if backend hit_type == 'favorited_search'
1778
- * - let's assume a "search" as new mediatype
1779
- */
1780
- if (((_a = result === null || result === void 0 ? void 0 : result.rawMetadata) === null || _a === void 0 ? void 0 : _a.hit_type) === 'favorited_search') {
1781
- return 'search';
1782
- }
1783
- return (_c = (_b = result.mediatype) === null || _b === void 0 ? void 0 : _b.value) !== null && _c !== void 0 ? _c : 'data';
1784
- }
1785
- /**
1786
- * Returns the input string, but removing one set of quotes from all instances of
1787
- * ""clauses wrapped in two sets of quotes"". This assumes the quotes are already
1788
- * URL-encoded.
1789
- *
1790
- * This should be a temporary measure to address the fact that the __href__ field
1791
- * sometimes acquires extra quotation marks during query rewriting. Once there is a
1792
- * full Lucene parser in place that handles quoted queries correctly, this can likely
1793
- * be removed.
1794
- */
1795
- collapseRepeatedQuotes(str) {
1796
- return str === null || str === void 0 ? void 0 : str.replace(/%22%22(?!%22%22)(.+?)%22%22/g, '%22$1%22');
1797
- }
1798
- /** Fetches the aggregation buckets for the given prefix filter type. */
1799
- async fetchPrefixFilterBuckets(filterType) {
1800
- var _a, _b, _c, _d, _e, _f, _g;
1801
- const trimmedQuery = (_a = this.baseQuery) === null || _a === void 0 ? void 0 : _a.trim();
1802
- if (!this.canPerformSearch)
1803
- return [];
1804
- const filterAggregationKey = prefixFilterAggregationKeys[filterType];
1805
- const sortParams = this.sortParam ? [this.sortParam] : [];
1806
- const params = {
1807
- ...this.collectionParams,
1808
- query: trimmedQuery || '',
1809
- rows: 0,
1810
- filters: this.filterMap,
1811
- // Only fetch the firstTitle or firstCreator aggregation
1812
- aggregations: { simpleParams: [filterAggregationKey] },
1813
- // Fetch all 26 letter buckets
1814
- aggregationsSize: 26,
1815
- };
1816
- params.uid = await this.requestUID({ ...params, sort: sortParams }, 'aggregations');
1817
- const searchResponse = await ((_b = this.searchService) === null || _b === void 0 ? void 0 : _b.search(params, this.searchType));
1818
- return ((_g = (_f = (_e = (_d = (_c = searchResponse === null || searchResponse === void 0 ? void 0 : searchResponse.success) === null || _c === void 0 ? void 0 : _c.response) === null || _d === void 0 ? void 0 : _d.aggregations) === null || _e === void 0 ? void 0 : _e[filterAggregationKey]) === null || _f === void 0 ? void 0 : _f.buckets) !== null && _g !== void 0 ? _g : []);
1819
- }
1820
- /** Fetches and caches the prefix filter counts for the given filter type. */
1821
- async updatePrefixFilterCounts(filterType) {
1822
- const { facetFetchQueryKey } = this;
1823
- const buckets = await this.fetchPrefixFilterBuckets(filterType);
1824
- // Don't update the filter counts for an outdated query (if it has been changed
1825
- // since we sent the request)
1826
- const queryChangedSinceFetch = facetFetchQueryKey !== this.facetFetchQueryKey;
1827
- if (queryChangedSinceFetch)
1828
- return;
1829
- // Unpack the aggregation buckets into a simple map like { 'A': 50, 'B': 25, ... }
1830
- this.prefixFilterCountMap = { ...this.prefixFilterCountMap }; // Clone the object to trigger an update
1831
- this.prefixFilterCountMap[filterType] = buckets.reduce((acc, bucket) => {
1832
- acc[bucket.key.toUpperCase()] = bucket.doc_count;
1833
- return acc;
1834
- }, {});
1231
+ (_a = this.infiniteScroller) === null || _a === void 0 ? void 0 : _a.refreshAllVisibleCells();
1835
1232
  }
1836
1233
  /**
1837
1234
  * Fetches and caches the prefix filter counts for the current sort type,
@@ -1841,7 +1238,7 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
1841
1238
  if (['title', 'creator'].includes(this.selectedSort)) {
1842
1239
  const filterType = this.selectedSort;
1843
1240
  if (!this.prefixFilterCountMap[filterType]) {
1844
- this.updatePrefixFilterCounts(filterType);
1241
+ this.dataSource.updatePrefixFilterCounts(filterType);
1845
1242
  }
1846
1243
  }
1847
1244
  }
@@ -1895,7 +1292,7 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
1895
1292
  .model=${model}
1896
1293
  .tileDisplayMode=${this.displayMode}
1897
1294
  .resizeObserver=${this.resizeObserver}
1898
- .collectionNameCache=${this.collectionNameCache}
1295
+ .collectionTitles=${this.dataSource.collectionTitles}
1899
1296
  .sortParam=${this.sortParam}
1900
1297
  .defaultSortParam=${this.defaultSortParam}
1901
1298
  .creatorFilter=${this.selectedCreatorFilter}
@@ -1915,7 +1312,7 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
1915
1312
  scrollThresholdReached() {
1916
1313
  if (!this.endOfDataReached) {
1917
1314
  this.pagesToRender += 1;
1918
- this.fetchPage(this.pagesToRender);
1315
+ this.dataSource.fetchPage(this.pagesToRender);
1919
1316
  }
1920
1317
  }
1921
1318
  static get styles() {
@@ -2086,8 +1483,7 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
2086
1483
  }
2087
1484
 
2088
1485
  .facets-message {
2089
- text-align: center;
2090
- font-size: 1.2rem;
1486
+ font-size: 1.4rem;
2091
1487
  }
2092
1488
 
2093
1489
  .desktop #left-column-scroll-sentinel {
@@ -2321,9 +1717,6 @@ __decorate([
2321
1717
  __decorate([
2322
1718
  property({ type: String })
2323
1719
  ], CollectionBrowser.prototype, "displayMode", void 0);
2324
- __decorate([
2325
- property({ type: Object })
2326
- ], CollectionBrowser.prototype, "sortParam", void 0);
2327
1720
  __decorate([
2328
1721
  property({ type: Object })
2329
1722
  ], CollectionBrowser.prototype, "defaultSortParam", void 0);
@@ -2342,9 +1735,6 @@ __decorate([
2342
1735
  __decorate([
2343
1736
  property({ type: Number })
2344
1737
  ], CollectionBrowser.prototype, "pageSize", void 0);
2345
- __decorate([
2346
- property({ type: Object })
2347
- ], CollectionBrowser.prototype, "resizeObserver", void 0);
2348
1738
  __decorate([
2349
1739
  property({ type: Number })
2350
1740
  ], CollectionBrowser.prototype, "currentPage", void 0);
@@ -2384,9 +1774,6 @@ __decorate([
2384
1774
  __decorate([
2385
1775
  property({ type: String, reflect: true })
2386
1776
  ], CollectionBrowser.prototype, "searchContext", void 0);
2387
- __decorate([
2388
- property({ type: Object })
2389
- ], CollectionBrowser.prototype, "collectionNameCache", void 0);
2390
1777
  __decorate([
2391
1778
  property({ type: String })
2392
1779
  ], CollectionBrowser.prototype, "pageContext", void 0);
@@ -2399,6 +1786,9 @@ __decorate([
2399
1786
  __decorate([
2400
1787
  property({ type: Boolean })
2401
1788
  ], CollectionBrowser.prototype, "loggedIn", void 0);
1789
+ __decorate([
1790
+ property({ type: Object })
1791
+ ], CollectionBrowser.prototype, "resizeObserver", void 0);
2402
1792
  __decorate([
2403
1793
  property({ type: Object })
2404
1794
  ], CollectionBrowser.prototype, "modalManager", void 0);
@@ -2414,6 +1804,12 @@ __decorate([
2414
1804
  __decorate([
2415
1805
  property({ type: Boolean })
2416
1806
  ], CollectionBrowser.prototype, "isLoansTab", void 0);
1807
+ __decorate([
1808
+ property({ type: String })
1809
+ ], CollectionBrowser.prototype, "queryErrorMessage", void 0);
1810
+ __decorate([
1811
+ property({ type: Object })
1812
+ ], CollectionBrowser.prototype, "dataSource", void 0);
2417
1813
  __decorate([
2418
1814
  state()
2419
1815
  ], CollectionBrowser.prototype, "pagesToRender", void 0);
@@ -2423,21 +1819,9 @@ __decorate([
2423
1819
  __decorate([
2424
1820
  state()
2425
1821
  ], CollectionBrowser.prototype, "facetsLoading", void 0);
2426
- __decorate([
2427
- state()
2428
- ], CollectionBrowser.prototype, "fullYearAggregationLoading", void 0);
2429
- __decorate([
2430
- state()
2431
- ], CollectionBrowser.prototype, "aggregations", void 0);
2432
- __decorate([
2433
- state()
2434
- ], CollectionBrowser.prototype, "fullYearsHistogramAggregation", void 0);
2435
1822
  __decorate([
2436
1823
  state()
2437
1824
  ], CollectionBrowser.prototype, "totalResults", void 0);
2438
- __decorate([
2439
- state()
2440
- ], CollectionBrowser.prototype, "queryErrorMessage", void 0);
2441
1825
  __decorate([
2442
1826
  state()
2443
1827
  ], CollectionBrowser.prototype, "mobileView", void 0);