@internetarchive/collection-browser 0.4.16-alpha.8 → 0.4.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/src/app-root.js +12 -0
  2. package/dist/src/app-root.js.map +1 -1
  3. package/dist/src/collection-browser.d.ts +53 -14
  4. package/dist/src/collection-browser.js +262 -116
  5. package/dist/src/collection-browser.js.map +1 -1
  6. package/dist/src/collection-facets/facets-template.d.ts +3 -0
  7. package/dist/src/collection-facets/facets-template.js +20 -1
  8. package/dist/src/collection-facets/facets-template.js.map +1 -1
  9. package/dist/src/collection-facets/more-facets-content.js +7 -4
  10. package/dist/src/collection-facets/more-facets-content.js.map +1 -1
  11. package/dist/src/collection-facets.d.ts +0 -2
  12. package/dist/src/collection-facets.js +1 -4
  13. package/dist/src/collection-facets.js.map +1 -1
  14. package/dist/src/empty-placeholder.js +1 -0
  15. package/dist/src/empty-placeholder.js.map +1 -1
  16. package/dist/src/models.d.ts +5 -0
  17. package/dist/src/models.js.map +1 -1
  18. package/dist/src/tiles/grid/item-tile.js +10 -3
  19. package/dist/src/tiles/grid/item-tile.js.map +1 -1
  20. package/dist/src/tiles/list/tile-list-compact.d.ts +1 -0
  21. package/dist/src/tiles/list/tile-list-compact.js +13 -1
  22. package/dist/src/tiles/list/tile-list-compact.js.map +1 -1
  23. package/dist/src/tiles/list/tile-list.js +10 -1
  24. package/dist/src/tiles/list/tile-list.js.map +1 -1
  25. package/dist/src/utils/format-date.d.ts +1 -1
  26. package/dist/src/utils/format-date.js +3 -0
  27. package/dist/src/utils/format-date.js.map +1 -1
  28. package/dist/src/utils/local-date-from-utc.d.ts +9 -0
  29. package/dist/src/utils/local-date-from-utc.js +16 -0
  30. package/dist/src/utils/local-date-from-utc.js.map +1 -0
  31. package/dist/test/collection-browser.test.js +41 -10
  32. package/dist/test/collection-browser.test.js.map +1 -1
  33. package/dist/test/collection-facets/facets-template.test.js +80 -0
  34. package/dist/test/collection-facets/facets-template.test.js.map +1 -1
  35. package/dist/test/tiles/grid/item-tile.test.js +124 -3
  36. package/dist/test/tiles/grid/item-tile.test.js.map +1 -1
  37. package/dist/test/tiles/list/tile-list-compact.test.js +65 -20
  38. package/dist/test/tiles/list/tile-list-compact.test.js.map +1 -1
  39. package/dist/test/tiles/list/tile-list.test.js +106 -4
  40. package/dist/test/tiles/list/tile-list.test.js.map +1 -1
  41. package/dist/test/utils/local-date-from-utc.test.d.ts +1 -0
  42. package/dist/test/utils/local-date-from-utc.test.js +27 -0
  43. package/dist/test/utils/local-date-from-utc.test.js.map +1 -0
  44. package/index.html +1 -0
  45. package/package.json +1 -1
  46. package/src/app-root.ts +12 -0
  47. package/src/collection-browser.ts +300 -126
  48. package/src/collection-facets/facets-template.ts +32 -1
  49. package/src/collection-facets/more-facets-content.ts +4 -1
  50. package/src/collection-facets.ts +1 -8
  51. package/src/empty-placeholder.ts +1 -0
  52. package/src/models.ts +6 -0
  53. package/src/tiles/grid/item-tile.ts +11 -4
  54. package/src/tiles/list/tile-list-compact.ts +16 -2
  55. package/src/tiles/list/tile-list.ts +12 -5
  56. package/src/utils/format-date.ts +4 -0
  57. package/src/utils/local-date-from-utc.ts +15 -0
  58. package/test/collection-browser.test.ts +57 -12
  59. package/test/collection-facets/facets-template.test.ts +98 -0
  60. package/test/tiles/grid/item-tile.test.ts +145 -3
  61. package/test/tiles/list/tile-list-compact.test.ts +70 -19
  62. package/test/tiles/list/tile-list.test.ts +118 -4
  63. package/test/utils/local-date-from-utc.test.ts +37 -0
@@ -82,6 +82,30 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
82
82
  * for the previous/next page, we'll fetch the next/previous page to populate it
83
83
  */
84
84
  this.dataSource = {};
85
+ /**
86
+ * Updates the height of the left column according to its position on the page.
87
+ * Arrow function ensures proper `this` binding.
88
+ */
89
+ this.updateLeftColumnHeight = () => {
90
+ var _a, _b, _c, _d, _e;
91
+ if (this.mobileView) {
92
+ (_b = (_a = this.leftColumn) === null || _a === void 0 ? void 0 : _a.style) === null || _b === void 0 ? void 0 : _b.removeProperty('height');
93
+ }
94
+ else {
95
+ const clientTop = (_c = this.leftColumn) === null || _c === void 0 ? void 0 : _c.getBoundingClientRect().top;
96
+ (_e = (_d = this.leftColumn) === null || _d === void 0 ? void 0 : _d.style) === null || _e === void 0 ? void 0 : _e.setProperty('height', `${window.innerHeight - (clientTop !== null && clientTop !== void 0 ? clientTop : 0) - 3}px`);
97
+ }
98
+ };
99
+ /**
100
+ * Toggles whether the fade-out is visible at the bottom of the facets.
101
+ * It should only be visible if the facets are not scrolled to the bottom.
102
+ * Arrow function ensures proper `this` binding.
103
+ */
104
+ this.updateFacetFadeOut = (entries) => {
105
+ var _a, _b;
106
+ const fadeElmt = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.getElementById('facets-bottom-fade');
107
+ fadeElmt === null || fadeElmt === void 0 ? void 0 : fadeElmt.classList.toggle('hidden', (_b = entries === null || entries === void 0 ? void 0 : entries[0]) === null || _b === void 0 ? void 0 : _b.isIntersecting);
108
+ };
85
109
  // we only want to scroll on the very first query change
86
110
  // so this keeps track of whether we've already set the initial query
87
111
  this.initialQueryChangeHappened = false;
@@ -150,8 +174,6 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
150
174
  if (letterFilters) {
151
175
  this.selectedTitleFilter = null;
152
176
  this.selectedCreatorFilter = null;
153
- this.titleQuery = undefined;
154
- this.creatorQuery = undefined;
155
177
  }
156
178
  if (sort) {
157
179
  this.sortParam = null;
@@ -193,8 +215,8 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
193
215
  if (!((_a = this.baseQuery) === null || _a === void 0 ? void 0 : _a.trim())) {
194
216
  this.placeholderType = 'empty-query';
195
217
  }
196
- if ((!this.searchResultsLoading && this.totalResults === 0) ||
197
- !this.searchService) {
218
+ else if (!this.searchResultsLoading &&
219
+ (this.totalResults === 0 || !this.searchService)) {
198
220
  this.placeholderType = 'null-result';
199
221
  }
200
222
  if (this.queryErrorMessage) {
@@ -218,7 +240,8 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
218
240
  const shouldShowSearching = this.searchResultsLoading || this.totalResults === undefined;
219
241
  const resultsCount = (_a = this.totalResults) === null || _a === void 0 ? void 0 : _a.toLocaleString();
220
242
  const resultsLabel = this.totalResults === 1 ? 'Result' : 'Results';
221
- return html `<div
243
+ return html ` <div id="left-column-scroll-sentinel"></div>
244
+ <div
222
245
  id="left-column"
223
246
  class="column${this.isResizeToMobile ? ' preload' : ''}"
224
247
  >
@@ -240,7 +263,9 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
240
263
  : ''}
241
264
  >
242
265
  ${this.facetsTemplate}
266
+ <div id="facets-scroll-sentinel"></div>
243
267
  </div>
268
+ ${this.mobileView ? nothing : html `<div id="facets-bottom-fade"></div>`}
244
269
  </div>
245
270
  <div id="right-column" class="column">
246
271
  ${this.sortFilterBarTemplate}
@@ -305,7 +330,6 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
305
330
  });
306
331
  }
307
332
  selectedSortChanged() {
308
- console.log('selectedSortChanged');
309
333
  if (this.selectedSort === 'relevance') {
310
334
  this.sortParam = null;
311
335
  return;
@@ -317,7 +341,6 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
317
341
  return;
318
342
  this.sortParam = { field: sortField, direction: this.sortDirection };
319
343
  // Lazy-load the alphabet counts for title/creator sort bar as needed
320
- console.log('will update prefix filters for current sort');
321
344
  this.updatePrefixFiltersForCurrentSort();
322
345
  }
323
346
  displayModeChanged(e) {
@@ -331,9 +354,28 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
331
354
  });
332
355
  }
333
356
  }
334
- /** Send Analytics when sorting by title's first letter
357
+ /**
358
+ * Returns a query clause identifying the currently selected title filter,
359
+ * e.g., `firstTitle:X`.
360
+ */
361
+ get titleQuery() {
362
+ return this.selectedTitleFilter
363
+ ? `firstTitle:${this.selectedTitleFilter}`
364
+ : undefined;
365
+ }
366
+ /**
367
+ * Returns a query clause identifying the currently selected creator filter,
368
+ * e.g., `firstCreator:X`.
369
+ */
370
+ get creatorQuery() {
371
+ return this.selectedCreatorFilter
372
+ ? `firstCreator:${this.selectedCreatorFilter}`
373
+ : undefined;
374
+ }
375
+ /**
376
+ * Send Analytics when sorting by title's first letter
335
377
  * labels: 'start-<ToLetter>' | 'clear-<FromLetter>' | '<FromLetter>-<ToLetter>'
336
- * */
378
+ */
337
379
  sendFilterByTitleAnalytics(prevSelectedLetter) {
338
380
  var _a;
339
381
  if (!prevSelectedLetter && !this.selectedTitleFilter) {
@@ -348,14 +390,10 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
348
390
  : `${prevSelectedLetter || 'start'}-${this.selectedTitleFilter}`,
349
391
  });
350
392
  }
351
- selectedTitleLetterChanged() {
352
- this.titleQuery = this.selectedTitleFilter
353
- ? `firstTitle:${this.selectedTitleFilter}`
354
- : undefined;
355
- }
356
- /** Send Analytics when filtering by creator's first letter
393
+ /**
394
+ * Send Analytics when filtering by creator's first letter
357
395
  * labels: 'start-<ToLetter>' | 'clear-<FromLetter>' | '<FromLetter>-<ToLetter>'
358
- * */
396
+ */
359
397
  sendFilterByCreatorAnalytics(prevSelectedLetter) {
360
398
  var _a;
361
399
  if (!prevSelectedLetter && !this.selectedCreatorFilter) {
@@ -370,20 +408,19 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
370
408
  : `${prevSelectedLetter || 'start'}-${this.selectedCreatorFilter}`,
371
409
  });
372
410
  }
373
- selectedCreatorLetterChanged() {
374
- this.creatorQuery = this.selectedCreatorFilter
375
- ? `firstCreator:${this.selectedCreatorFilter}`
376
- : undefined;
377
- }
411
+ /**
412
+ * Handler for changes to which letter is selected in the title alphabet bar.
413
+ */
378
414
  titleLetterSelected(e) {
379
415
  this.selectedCreatorFilter = null;
380
416
  this.selectedTitleFilter = e.detail.selectedLetter;
381
- this.selectedTitleLetterChanged();
382
417
  }
418
+ /**
419
+ * Handler for changes to which letter is selected in the creator alphabet bar.
420
+ */
383
421
  creatorLetterSelected(e) {
384
422
  this.selectedTitleFilter = null;
385
423
  this.selectedCreatorFilter = e.detail.selectedLetter;
386
- this.selectedCreatorLetterChanged();
387
424
  }
388
425
  get mobileFacetsTemplate() {
389
426
  return html `
@@ -424,13 +461,13 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
424
461
  .selectedFacets=${this.selectedFacets}
425
462
  .collectionNameCache=${this.collectionNameCache}
426
463
  .showHistogramDatePicker=${this.showHistogramDatePicker}
427
- .query=${this.filteredQuery}
464
+ .query=${this.baseQuery}
428
465
  .filterMap=${this.filterMap}
429
466
  .modalManager=${this.modalManager}
430
467
  ?collapsableFacets=${this.mobileView}
431
468
  ?facetsLoading=${this.facetsLoading}
432
469
  ?fullYearAggregationLoading=${this.facetsLoading}
433
- .onFacetClick=${this.facetClickHandler}
470
+ @facetClick=${this.facetClickHandler}
434
471
  .analyticsHandler=${this.analyticsHandler}
435
472
  >
436
473
  </collection-facets>
@@ -479,7 +516,15 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
479
516
  }
480
517
  updated(changed) {
481
518
  var _a;
482
- console.log('updated', changed, this.baseQuery, JSON.stringify(this.selectedFacets));
519
+ if (changed.has('placeholderType') && this.placeholderType === null) {
520
+ if (!this.leftColIntersectionObserver) {
521
+ this.setupLeftColumnScrollListeners();
522
+ }
523
+ if (!this.facetsIntersectionObserver) {
524
+ this.setupFacetsScrollListeners();
525
+ }
526
+ this.updateLeftColumnHeight();
527
+ }
483
528
  if (changed.has('displayMode') ||
484
529
  changed.has('baseNavigationUrl') ||
485
530
  changed.has('baseImageUrl') ||
@@ -524,11 +569,9 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
524
569
  }
525
570
  if (changed.has('selectedTitleFilter')) {
526
571
  this.sendFilterByTitleAnalytics(changed.get('selectedTitleFilter'));
527
- this.selectedTitleLetterChanged();
528
572
  }
529
573
  if (changed.has('selectedCreatorFilter')) {
530
574
  this.sendFilterByCreatorAnalytics(changed.get('selectedCreatorFilter'));
531
- this.selectedCreatorLetterChanged();
532
575
  }
533
576
  if (changed.has('baseQuery') ||
534
577
  changed.has('searchType') ||
@@ -554,12 +597,16 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
554
597
  }
555
598
  }
556
599
  disconnectedCallback() {
600
+ var _a, _b;
557
601
  if (this.resizeObserver) {
558
602
  this.disconnectResizeObserver(this.resizeObserver);
559
603
  }
560
604
  if (this.boundNavigationHandler) {
561
605
  window.removeEventListener('popstate', this.boundNavigationHandler);
562
606
  }
607
+ (_a = this.leftColIntersectionObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
608
+ (_b = this.facetsIntersectionObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
609
+ window.removeEventListener('resize', this.updateLeftColumnHeight);
563
610
  }
564
611
  handleResize(entry) {
565
612
  const previousView = this.mobileView;
@@ -570,6 +617,41 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
570
617
  this.isResizeToMobile = true;
571
618
  }
572
619
  }
620
+ // Ensure the facet sidebar remains sized correctly
621
+ this.updateLeftColumnHeight();
622
+ }
623
+ /**
624
+ * Sets up listeners for events that may require updating the left column height.
625
+ */
626
+ setupLeftColumnScrollListeners() {
627
+ var _a;
628
+ // We observe intersections between the left column's scroll sentinel and
629
+ // the viewport, so that we can ensure the left column is always sized to
630
+ // match the _available_ viewport height. This should generally be more
631
+ // performant than listening to scroll events on the page or column.
632
+ const leftColumnSentinel = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('#left-column-scroll-sentinel');
633
+ if (leftColumnSentinel) {
634
+ this.leftColIntersectionObserver = new IntersectionObserver(this.updateLeftColumnHeight, {
635
+ threshold: [...Array(101).keys()].map(n => n / 100), // Threshold every 1%
636
+ });
637
+ this.leftColIntersectionObserver.observe(leftColumnSentinel);
638
+ }
639
+ // We also listen for window resize events, as they are not always captured
640
+ // by the resize observer and can affect the desired height of the left column.
641
+ window.addEventListener('resize', this.updateLeftColumnHeight);
642
+ }
643
+ /**
644
+ * Sets up listeners to control whether the facet sidebar shows its bottom fade-out.
645
+ * Note this uses a separate IntersectionObserver from the left column, because we
646
+ * don't need granular intersection thresholds for this.
647
+ */
648
+ setupFacetsScrollListeners() {
649
+ var _a;
650
+ const facetsSentinel = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('#facets-scroll-sentinel');
651
+ if (facetsSentinel) {
652
+ this.facetsIntersectionObserver = new IntersectionObserver(this.updateFacetFadeOut);
653
+ this.facetsIntersectionObserver.observe(facetsSentinel);
654
+ }
573
655
  }
574
656
  emitBaseQueryChanged() {
575
657
  this.dispatchEvent(new CustomEvent('baseQueryChanged', {
@@ -706,6 +788,11 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
706
788
  await this.fetchPage(this.initialPageNumber);
707
789
  this.searchResultsLoading = false;
708
790
  }
791
+ /**
792
+ * Constructs a search service FilterMap object from the combination of
793
+ * all the currently-applied filters. This includes any facets, letter
794
+ * filters, and date range.
795
+ */
709
796
  get filterMap() {
710
797
  const builder = new FilterMapBuilder();
711
798
  // Add the date range, if applicable
@@ -733,20 +820,16 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
733
820
  }
734
821
  }
735
822
  }
823
+ // Add any letter filters
824
+ if (this.selectedTitleFilter) {
825
+ builder.addFilter('firstTitle', this.selectedTitleFilter, FilterConstraint.INCLUDE);
826
+ }
827
+ if (this.selectedCreatorFilter) {
828
+ builder.addFilter('firstCreator', this.selectedCreatorFilter, FilterConstraint.INCLUDE);
829
+ }
736
830
  const filterMap = builder.build();
737
831
  return filterMap;
738
832
  }
739
- /** The base query joined with any title/creator letter filters */
740
- get filteredQuery() {
741
- if (!this.baseQuery)
742
- return undefined;
743
- let filteredQuery = this.baseQuery.trim();
744
- const { sortFilterQueries } = this;
745
- if (sortFilterQueries) {
746
- filteredQuery += ` AND ${sortFilterQueries}`;
747
- }
748
- return filteredQuery.trim();
749
- }
750
833
  /** The full query, including year facets and date range clauses */
751
834
  get fullQuery() {
752
835
  if (!this.baseQuery)
@@ -764,20 +847,6 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
764
847
  }
765
848
  return fullQuery.trim();
766
849
  }
767
- /** The full query without any title/creator letter filters */
768
- get fullQueryWithoutAlphaFilters() {
769
- if (!this.baseQuery)
770
- return undefined;
771
- let fullQuery = this.baseQuery.trim();
772
- const { facetQuery, dateRangeQueryClause } = this;
773
- if (facetQuery) {
774
- fullQuery += ` AND ${facetQuery}`;
775
- }
776
- if (dateRangeQueryClause) {
777
- fullQuery += ` AND ${dateRangeQueryClause}`;
778
- }
779
- return fullQuery.trim();
780
- }
781
850
  /**
782
851
  * Generates a query string for the given facets
783
852
  *
@@ -849,33 +918,37 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
849
918
  facetsChanged(e) {
850
919
  this.selectedFacets = e.detail;
851
920
  }
852
- facetClickHandler(name, facetSelected, negative) {
921
+ facetClickHandler({ detail: { key, state: facetState, negative }, }) {
853
922
  var _a, _b;
854
923
  if (negative) {
855
924
  (_a = this.analyticsHandler) === null || _a === void 0 ? void 0 : _a.sendEvent({
856
925
  category: this.searchContext,
857
- action: facetSelected
926
+ action: facetState !== 'none'
858
927
  ? analyticsActions.facetNegativeSelected
859
928
  : analyticsActions.facetNegativeDeselected,
860
- label: name,
929
+ label: key,
861
930
  });
862
931
  }
863
932
  else {
864
933
  (_b = this.analyticsHandler) === null || _b === void 0 ? void 0 : _b.sendEvent({
865
934
  category: this.searchContext,
866
- action: facetSelected
935
+ action: facetState !== 'none'
867
936
  ? analyticsActions.facetSelected
868
937
  : analyticsActions.facetDeselected,
869
- label: name,
938
+ label: key,
870
939
  });
871
940
  }
872
941
  }
873
942
  async fetchFacets() {
874
943
  var _a, _b, _c, _d, _e, _f, _g, _h;
875
- if (!this.filteredQuery)
944
+ const trimmedQuery = (_a = this.baseQuery) === null || _a === void 0 ? void 0 : _a.trim();
945
+ if (!trimmedQuery)
876
946
  return;
947
+ if (!this.searchService)
948
+ return;
949
+ const { facetFetchQueryKey } = this;
877
950
  const params = {
878
- query: this.filteredQuery,
951
+ query: trimmedQuery,
879
952
  rows: 0,
880
953
  filters: this.filterMap,
881
954
  // Fetch a few extra buckets beyond the 6 we show, in case some get suppressed
@@ -885,9 +958,14 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
885
958
  uid: this.facetFetchQueryKey,
886
959
  };
887
960
  this.facetsLoading = true;
888
- const searchResponse = await ((_a = this.searchService) === null || _a === void 0 ? void 0 : _a.search(params, this.searchType));
961
+ const searchResponse = await this.searchService.search(params, this.searchType);
889
962
  const success = searchResponse === null || searchResponse === void 0 ? void 0 : searchResponse.success;
890
- this.facetsLoading = false;
963
+ // This is checking to see if the query has changed since the data was fetched.
964
+ // If so, we just want to discard this set of aggregations because they are
965
+ // likely no longer valid for the newer query.
966
+ const queryChangedSinceFetch = facetFetchQueryKey !== this.facetFetchQueryKey;
967
+ if (queryChangedSinceFetch)
968
+ return;
891
969
  if (!success) {
892
970
  const errorMsg = (_b = searchResponse === null || searchResponse === void 0 ? void 0 : searchResponse.error) === null || _b === void 0 ? void 0 : _b.message;
893
971
  const detailMsg = (_d = (_c = searchResponse === null || searchResponse === void 0 ? void 0 : searchResponse.error) === null || _c === void 0 ? void 0 : _c.details) === null || _d === void 0 ? void 0 : _d.message;
@@ -897,16 +975,10 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
897
975
  }
898
976
  return;
899
977
  }
900
- // This is checking to see if the query has changed since the data was fetched.
901
- // If so, we just want to discard this set of aggregations because they are
902
- // likely no longer valid for the newer query.
903
- const returnedUid = success.request.clientParameters.uid;
904
- const queryChangedSinceFetch = returnedUid !== this.facetFetchQueryKey;
905
- if (queryChangedSinceFetch)
906
- return;
907
978
  this.aggregations = success === null || success === void 0 ? void 0 : success.response.aggregations;
908
979
  this.fullYearsHistogramAggregation =
909
980
  (_h = (_g = success === null || success === void 0 ? void 0 : success.response) === null || _g === void 0 ? void 0 : _g.aggregations) === null || _h === void 0 ? void 0 : _h.year_histogram;
981
+ this.facetsLoading = false;
910
982
  }
911
983
  scrollToPage(pageNumber) {
912
984
  return new Promise(resolve => {
@@ -957,8 +1029,11 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
957
1029
  return `${this.fullQuery}-${this.searchType}`;
958
1030
  }
959
1031
  async fetchPage(pageNumber) {
960
- var _a, _b, _c, _d, _e, _f, _g, _h;
961
- if (!this.filteredQuery)
1032
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
1033
+ const trimmedQuery = (_a = this.baseQuery) === null || _a === void 0 ? void 0 : _a.trim();
1034
+ if (!trimmedQuery)
1035
+ return;
1036
+ if (!this.searchService)
962
1037
  return;
963
1038
  // if we already have data, don't fetch again
964
1039
  if (this.dataSource[pageNumber])
@@ -967,14 +1042,14 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
967
1042
  return;
968
1043
  // if a fetch is already in progress for this query and page, don't fetch again
969
1044
  const { pageFetchQueryKey } = this;
970
- const pageFetches = (_a = this.pageFetchesInProgress[pageFetchQueryKey]) !== null && _a !== void 0 ? _a : new Set();
1045
+ const pageFetches = (_b = this.pageFetchesInProgress[pageFetchQueryKey]) !== null && _b !== void 0 ? _b : new Set();
971
1046
  if (pageFetches.has(pageNumber))
972
1047
  return;
973
1048
  pageFetches.add(pageNumber);
974
1049
  this.pageFetchesInProgress[pageFetchQueryKey] = pageFetches;
975
1050
  const sortParams = this.sortParam ? [this.sortParam] : [];
976
1051
  const params = {
977
- query: this.filteredQuery,
1052
+ query: trimmedQuery,
978
1053
  page: pageNumber,
979
1054
  rows: this.pageSize,
980
1055
  sort: sortParams,
@@ -982,8 +1057,14 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
982
1057
  aggregations: { omit: true },
983
1058
  uid: this.pageFetchQueryKey,
984
1059
  };
985
- const searchResponse = await ((_b = this.searchService) === null || _b === void 0 ? void 0 : _b.search(params, this.searchType));
1060
+ const searchResponse = await this.searchService.search(params, this.searchType);
986
1061
  const success = searchResponse === null || searchResponse === void 0 ? void 0 : searchResponse.success;
1062
+ // This is checking to see if the query has changed since the data was fetched.
1063
+ // If so, we just want to discard the data since there should be a new query
1064
+ // right behind it.
1065
+ const queryChangedSinceFetch = pageFetchQueryKey !== this.pageFetchQueryKey;
1066
+ if (queryChangedSinceFetch)
1067
+ return;
987
1068
  if (!success) {
988
1069
  const errorMsg = (_c = searchResponse === null || searchResponse === void 0 ? void 0 : searchResponse.error) === null || _c === void 0 ? void 0 : _c.message;
989
1070
  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;
@@ -993,15 +1074,10 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
993
1074
  // @ts-ignore: Property 'Sentry' does not exist on type 'Window & typeof globalThis'
994
1075
  (_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, this.queryErrorMessage, 'error');
995
1076
  }
1077
+ (_h = this.pageFetchesInProgress[pageFetchQueryKey]) === null || _h === void 0 ? void 0 : _h.delete(pageNumber);
1078
+ this.searchResultsLoading = false;
996
1079
  return;
997
1080
  }
998
- // This is checking to see if the query has changed since the data was fetched.
999
- // If so, we just want to discard the data since there should be a new query
1000
- // right behind it.
1001
- const returnedUid = success.request.clientParameters.uid;
1002
- const queryChangedSinceFetch = returnedUid !== this.pageFetchQueryKey;
1003
- if (queryChangedSinceFetch)
1004
- return;
1005
1081
  this.totalResults = success.response.totalResults;
1006
1082
  const { results } = success.response;
1007
1083
  if (results && results.length > 0) {
@@ -1017,7 +1093,7 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
1017
1093
  this.infiniteScroller.itemCount = this.totalResults;
1018
1094
  }
1019
1095
  }
1020
- (_h = this.pageFetchesInProgress[pageFetchQueryKey]) === null || _h === void 0 ? void 0 : _h.delete(pageNumber);
1096
+ (_j = this.pageFetchesInProgress[pageFetchQueryKey]) === null || _j === void 0 ? void 0 : _j.delete(pageNumber);
1021
1097
  this.searchResultsLoading = false;
1022
1098
  }
1023
1099
  preloadCollectionNames(results) {
@@ -1119,29 +1195,32 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
1119
1195
  }
1120
1196
  /** Fetches the aggregation buckets for the given prefix filter type. */
1121
1197
  async fetchPrefixFilterBuckets(filterType) {
1122
- var _a, _b, _c, _d, _e, _f;
1123
- console.log('fetchPrefixFilterBuckets', this.fullQueryWithoutAlphaFilters);
1124
- if (!this.fullQueryWithoutAlphaFilters)
1198
+ var _a, _b, _c, _d, _e, _f, _g;
1199
+ const trimmedQuery = (_a = this.baseQuery) === null || _a === void 0 ? void 0 : _a.trim();
1200
+ if (!trimmedQuery)
1125
1201
  return [];
1126
1202
  const filterAggregationKey = prefixFilterAggregationKeys[filterType];
1127
1203
  const params = {
1128
- query: this.fullQueryWithoutAlphaFilters,
1204
+ query: trimmedQuery,
1129
1205
  rows: 0,
1206
+ filters: this.filterMap,
1130
1207
  // Only fetch the firstTitle or firstCreator aggregation
1131
1208
  aggregations: { simpleParams: [filterAggregationKey] },
1132
1209
  // Fetch all 26 letter buckets
1133
1210
  aggregationsSize: 26,
1134
1211
  };
1135
- console.log('sending prefix filter search request');
1136
- const searchResponse = await ((_a = this.searchService) === null || _a === void 0 ? void 0 : _a.search(params, this.searchType));
1137
- console.log('response', searchResponse);
1138
- return ((_f = (_e = (_d = (_c = (_b = searchResponse === null || searchResponse === void 0 ? void 0 : searchResponse.success) === null || _b === void 0 ? void 0 : _b.response) === null || _c === void 0 ? void 0 : _c.aggregations) === null || _d === void 0 ? void 0 : _d[filterAggregationKey]) === null || _e === void 0 ? void 0 : _e.buckets) !== null && _f !== void 0 ? _f : []);
1212
+ const searchResponse = await ((_b = this.searchService) === null || _b === void 0 ? void 0 : _b.search(params, this.searchType));
1213
+ 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 : []);
1139
1214
  }
1140
1215
  /** Fetches and caches the prefix filter counts for the given filter type. */
1141
1216
  async updatePrefixFilterCounts(filterType) {
1142
- console.log('updatePrefixFilterCounts');
1217
+ const { facetFetchQueryKey } = this;
1143
1218
  const buckets = await this.fetchPrefixFilterBuckets(filterType);
1144
- console.log('buckets', buckets);
1219
+ // Don't update the filter counts for an outdated query (if it has been changed
1220
+ // since we sent the request)
1221
+ const queryChangedSinceFetch = facetFetchQueryKey !== this.facetFetchQueryKey;
1222
+ if (queryChangedSinceFetch)
1223
+ return;
1145
1224
  // Unpack the aggregation buckets into a simple map like { 'A': 50, 'B': 25, ... }
1146
1225
  this.prefixFilterCountMap = { ...this.prefixFilterCountMap }; // Clone the object to trigger an update
1147
1226
  this.prefixFilterCountMap[filterType] = buckets.reduce((acc, bucket) => {
@@ -1154,12 +1233,9 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
1154
1233
  * provided it is one that permits prefix filtering. (If not, this does nothing).
1155
1234
  */
1156
1235
  async updatePrefixFiltersForCurrentSort() {
1157
- console.log('updatePrefixFiltersForCurrentSort');
1158
1236
  if (['title', 'creator'].includes(this.selectedSort)) {
1159
- console.log('sort is title or creator - will update');
1160
1237
  const filterType = this.selectedSort;
1161
1238
  if (!this.prefixFilterCountMap[filterType]) {
1162
- console.log('need new filters, updating');
1163
1239
  this.updatePrefixFilterCounts(filterType);
1164
1240
  }
1165
1241
  }
@@ -1172,7 +1248,6 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
1172
1248
  * Call this whenever the counts are invalidated (e.g., by a query change).
1173
1249
  */
1174
1250
  refreshLetterCounts() {
1175
- console.log('refreshLetterCounts');
1176
1251
  if (Object.keys(this.prefixFilterCountMap).length > 0) {
1177
1252
  this.prefixFilterCountMap = {};
1178
1253
  }
@@ -1229,6 +1304,9 @@ let CollectionBrowser = class CollectionBrowser extends LitElement {
1229
1304
  CollectionBrowser.styles = css `
1230
1305
  :host {
1231
1306
  display: block;
1307
+
1308
+ --leftColumnWidth: 18rem;
1309
+ --leftColumnPaddingRight: 2.5rem;
1232
1310
  }
1233
1311
 
1234
1312
  /**
@@ -1289,15 +1367,91 @@ CollectionBrowser.styles = css `
1289
1367
  }
1290
1368
 
1291
1369
  #left-column {
1292
- width: 18rem;
1293
- min-width: 18rem; /* Prevents Safari from shrinking col at first draw */
1294
- padding-right: 12px;
1295
- padding-right: 2.5rem;
1370
+ width: var(--leftColumnWidth, 18rem);
1371
+ /* Prevents Safari from shrinking col at first draw */
1372
+ min-width: var(--leftColumnWidth, 18rem);
1373
+ padding-top: 0;
1374
+ /* Reduced padding by 0.2rem to add the invisible border in the rule below */
1375
+ padding-right: calc(var(--leftColumnPaddingRight, 2.5rem) - 0.2rem);
1376
+ border-right: 0.2rem solid transparent; /* Pads to the right of the scrollbar a bit */
1296
1377
  z-index: 1;
1297
1378
  }
1298
1379
 
1380
+ .desktop #left-column {
1381
+ top: 0;
1382
+ position: sticky;
1383
+ height: calc(100vh - 2rem);
1384
+ max-height: calc(100vh - 2rem);
1385
+ overflow-x: hidden;
1386
+ overflow-y: scroll;
1387
+
1388
+ /*
1389
+ * Firefox doesn't support any of the -webkit-scrollbar stuff below, but
1390
+ * does at least give us a tiny bit of control over width & color.
1391
+ */
1392
+ scrollbar-width: thin;
1393
+ scrollbar-color: transparent transparent;
1394
+ }
1395
+ .desktop #left-column:hover {
1396
+ scrollbar-color: auto;
1397
+ }
1299
1398
  .desktop #left-column::-webkit-scrollbar {
1300
- display: none;
1399
+ appearance: none;
1400
+ width: 6px;
1401
+ }
1402
+ .desktop #left-column::-webkit-scrollbar-button {
1403
+ height: 3px;
1404
+ background: transparent;
1405
+ }
1406
+ .desktop #left-column::-webkit-scrollbar-corner {
1407
+ background: transparent;
1408
+ }
1409
+ .desktop #left-column::-webkit-scrollbar-thumb {
1410
+ border-radius: 4px;
1411
+ }
1412
+ .desktop #left-column:hover::-webkit-scrollbar-thumb {
1413
+ background: rgba(0, 0, 0, 0.15);
1414
+ }
1415
+ .desktop #left-column:hover::-webkit-scrollbar-thumb:hover {
1416
+ background: rgba(0, 0, 0, 0.2);
1417
+ }
1418
+ .desktop #left-column:hover::-webkit-scrollbar-thumb:active {
1419
+ background: rgba(0, 0, 0, 0.3);
1420
+ }
1421
+
1422
+ #facets-bottom-fade {
1423
+ background: linear-gradient(
1424
+ to bottom,
1425
+ #f5f5f700 0%,
1426
+ #f5f5f7c0 50%,
1427
+ #f5f5f7 80%,
1428
+ #f5f5f7 100%
1429
+ );
1430
+ position: fixed;
1431
+ bottom: 0;
1432
+ height: 50px;
1433
+ /* Wide enough to cover the content, but leave the scrollbar uncovered */
1434
+ width: calc(
1435
+ var(--leftColumnWidth) + var(--leftColumnPaddingRight) - 10px
1436
+ );
1437
+ z-index: 2;
1438
+ pointer-events: none;
1439
+ transition: height 0.1s ease;
1440
+ }
1441
+ #facets-bottom-fade.hidden {
1442
+ height: 0;
1443
+ }
1444
+
1445
+ .desktop #left-column-scroll-sentinel {
1446
+ width: 1px;
1447
+ height: 100vh;
1448
+ background: transparent;
1449
+ }
1450
+
1451
+ .desktop #facets-scroll-sentinel {
1452
+ width: 1px;
1453
+ height: 1px;
1454
+ background: transparent;
1301
1455
  }
1302
1456
 
1303
1457
  .mobile #left-column {
@@ -1305,21 +1459,16 @@ CollectionBrowser.styles = css `
1305
1459
  padding: 0;
1306
1460
  }
1307
1461
 
1308
- .desktop #left-column {
1309
- top: 0;
1310
- position: sticky;
1311
- max-height: 100vh;
1312
- overflow: scroll;
1313
- -ms-overflow-style: none; /* hide scrollbar IE and Edge */
1314
- scrollbar-width: none; /* hide scrollbar Firefox */
1315
- }
1316
-
1317
1462
  #mobile-header-container {
1318
1463
  display: flex;
1319
1464
  justify-content: space-between;
1320
1465
  align-items: center;
1321
1466
  }
1322
1467
 
1468
+ .desktop #mobile-header-container {
1469
+ padding-top: 2rem;
1470
+ }
1471
+
1323
1472
  #facets-container {
1324
1473
  position: relative;
1325
1474
  max-height: 0;
@@ -1493,12 +1642,6 @@ __decorate([
1493
1642
  __decorate([
1494
1643
  property({ type: Object })
1495
1644
  ], CollectionBrowser.prototype, "resizeObserver", void 0);
1496
- __decorate([
1497
- property({ type: String })
1498
- ], CollectionBrowser.prototype, "titleQuery", void 0);
1499
- __decorate([
1500
- property({ type: String })
1501
- ], CollectionBrowser.prototype, "creatorQuery", void 0);
1502
1645
  __decorate([
1503
1646
  property({ type: Number })
1504
1647
  ], CollectionBrowser.prototype, "currentPage", void 0);
@@ -1583,6 +1726,9 @@ __decorate([
1583
1726
  __decorate([
1584
1727
  query('#content-container')
1585
1728
  ], CollectionBrowser.prototype, "contentContainer", void 0);
1729
+ __decorate([
1730
+ query('#left-column')
1731
+ ], CollectionBrowser.prototype, "leftColumn", void 0);
1586
1732
  __decorate([
1587
1733
  property({ type: Object, attribute: false })
1588
1734
  ], CollectionBrowser.prototype, "analyticsHandler", void 0);