@internetarchive/collection-browser 2.15.1-alpha-webdev7667.3 → 2.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/dist/src/collection-browser.d.ts +0 -17
  2. package/dist/src/collection-browser.js +3 -70
  3. package/dist/src/collection-browser.js.map +1 -1
  4. package/dist/src/collection-facets/more-facets-content.d.ts +2 -1
  5. package/dist/src/collection-facets/more-facets-content.js +6 -3
  6. package/dist/src/collection-facets/more-facets-content.js.map +1 -1
  7. package/dist/src/collection-facets/smart-facets/smart-facet-bar.js +1 -1
  8. package/dist/src/collection-facets/smart-facets/smart-facet-bar.js.map +1 -1
  9. package/dist/src/collection-facets.d.ts +9 -3
  10. package/dist/src/collection-facets.js +85 -41
  11. package/dist/src/collection-facets.js.map +1 -1
  12. package/dist/src/data-source/collection-browser-data-source-interface.d.ts +8 -3
  13. package/dist/src/data-source/collection-browser-data-source-interface.js.map +1 -1
  14. package/dist/src/data-source/collection-browser-data-source.d.ts +5 -1
  15. package/dist/src/data-source/collection-browser-data-source.js +25 -8
  16. package/dist/src/data-source/collection-browser-data-source.js.map +1 -1
  17. package/dist/src/data-source/models.d.ts +4 -0
  18. package/dist/src/data-source/models.js.map +1 -1
  19. package/dist/src/expanded-date-picker.d.ts +4 -0
  20. package/dist/src/expanded-date-picker.js +10 -0
  21. package/dist/src/expanded-date-picker.js.map +1 -1
  22. package/dist/src/models.d.ts +0 -7
  23. package/dist/src/models.js +0 -31
  24. package/dist/src/models.js.map +1 -1
  25. package/dist/src/tiles/base-tile-component.d.ts +0 -1
  26. package/dist/src/tiles/base-tile-component.js +0 -4
  27. package/dist/src/tiles/base-tile-component.js.map +1 -1
  28. package/dist/src/tiles/grid/account-tile.js +0 -2
  29. package/dist/src/tiles/grid/account-tile.js.map +1 -1
  30. package/dist/src/tiles/grid/collection-tile.js +0 -2
  31. package/dist/src/tiles/grid/collection-tile.js.map +1 -1
  32. package/dist/src/tiles/grid/item-tile.js +0 -2
  33. package/dist/src/tiles/grid/item-tile.js.map +1 -1
  34. package/dist/src/tiles/grid/search-tile.js +0 -2
  35. package/dist/src/tiles/grid/search-tile.js.map +1 -1
  36. package/dist/src/tiles/hover/hover-pane-controller.d.ts +0 -1
  37. package/dist/src/tiles/hover/hover-pane-controller.js +12 -7
  38. package/dist/src/tiles/hover/hover-pane-controller.js.map +1 -1
  39. package/dist/src/tiles/hover/tile-hover-pane.d.ts +0 -1
  40. package/dist/src/tiles/hover/tile-hover-pane.js +0 -5
  41. package/dist/src/tiles/hover/tile-hover-pane.js.map +1 -1
  42. package/dist/src/tiles/image-block.d.ts +0 -1
  43. package/dist/src/tiles/image-block.js +0 -7
  44. package/dist/src/tiles/image-block.js.map +1 -1
  45. package/dist/src/tiles/item-image.d.ts +0 -1
  46. package/dist/src/tiles/item-image.js +2 -7
  47. package/dist/src/tiles/item-image.js.map +1 -1
  48. package/dist/src/tiles/list/tile-list-compact-header.js +0 -1
  49. package/dist/src/tiles/list/tile-list-compact-header.js.map +1 -1
  50. package/dist/src/tiles/list/tile-list-compact.js +0 -2
  51. package/dist/src/tiles/list/tile-list-compact.js.map +1 -1
  52. package/dist/src/tiles/list/tile-list.js +0 -2
  53. package/dist/src/tiles/list/tile-list.js.map +1 -1
  54. package/dist/src/tiles/tile-dispatcher.js +0 -7
  55. package/dist/src/tiles/tile-dispatcher.js.map +1 -1
  56. package/dist/test/collection-browser.test.js +44 -1
  57. package/dist/test/collection-browser.test.js.map +1 -1
  58. package/dist/test/collection-facets.test.js +24 -14
  59. package/dist/test/collection-facets.test.js.map +1 -1
  60. package/dist/test/mocks/mock-search-responses.d.ts +2 -0
  61. package/dist/test/mocks/mock-search-responses.js +92 -0
  62. package/dist/test/mocks/mock-search-responses.js.map +1 -1
  63. package/dist/test/mocks/mock-search-service.js +3 -1
  64. package/dist/test/mocks/mock-search-service.js.map +1 -1
  65. package/dist/test/tiles/hover/hover-pane-controller.test.js +0 -1
  66. package/dist/test/tiles/hover/hover-pane-controller.test.js.map +1 -1
  67. package/package.json +3 -3
  68. package/src/collection-browser.ts +3 -68
  69. package/src/collection-facets/more-facets-content.ts +5 -2
  70. package/src/collection-facets/smart-facets/smart-facet-bar.ts +2 -1
  71. package/src/collection-facets.ts +109 -40
  72. package/src/data-source/collection-browser-data-source-interface.ts +13 -3
  73. package/src/data-source/collection-browser-data-source.ts +30 -9
  74. package/src/data-source/models.ts +5 -0
  75. package/src/expanded-date-picker.ts +10 -0
  76. package/src/models.ts +0 -36
  77. package/src/tiles/base-tile-component.ts +0 -2
  78. package/src/tiles/grid/account-tile.ts +0 -2
  79. package/src/tiles/grid/collection-tile.ts +0 -2
  80. package/src/tiles/grid/item-tile.ts +0 -2
  81. package/src/tiles/grid/search-tile.ts +0 -2
  82. package/src/tiles/hover/hover-pane-controller.ts +7 -2
  83. package/src/tiles/hover/tile-hover-pane.ts +0 -3
  84. package/src/tiles/image-block.ts +0 -5
  85. package/src/tiles/item-image.ts +2 -6
  86. package/src/tiles/list/tile-list-compact-header.ts +0 -1
  87. package/src/tiles/list/tile-list-compact.ts +0 -2
  88. package/src/tiles/list/tile-list.ts +0 -2
  89. package/src/tiles/tile-dispatcher.ts +0 -7
  90. package/test/collection-browser.test.ts +68 -1
  91. package/test/collection-facets.test.ts +24 -14
  92. package/test/mocks/mock-search-responses.ts +100 -0
  93. package/test/mocks/mock-search-service.ts +4 -0
  94. package/test/tiles/hover/hover-pane-controller.test.ts +0 -1
@@ -29,6 +29,7 @@ import type { FeatureFeedbackServiceInterface } from '@internetarchive/feature-f
29
29
  import type { RecaptchaManagerInterface } from '@internetarchive/recaptcha-manager';
30
30
  import type { AnalyticsManagerInterface } from '@internetarchive/analytics-manager';
31
31
  import type { SharedResizeObserverInterface } from '@internetarchive/shared-resize-observer';
32
+ import type { BinSnappingInterval } from '@internetarchive/histogram-date-range';
32
33
  import chevronIcon from './assets/img/icons/chevron';
33
34
  import expandIcon from './assets/img/icons/expand';
34
35
  import {
@@ -44,16 +45,12 @@ import {
44
45
  suppressedCollections,
45
46
  defaultFacetSort,
46
47
  FacetEventDetails,
47
- tvChannelFacetLabels,
48
48
  } from './models';
49
49
  import type {
50
50
  CollectionTitles,
51
51
  PageSpecifierParams,
52
+ TVChannelAliases,
52
53
  } from './data-source/models';
53
- import './collection-facets/more-facets-content';
54
- import './collection-facets/facets-template';
55
- import './collection-facets/facet-tombstone-row';
56
- import './expanded-date-picker';
57
54
  import {
58
55
  analyticsActions,
59
56
  analyticsCategories,
@@ -65,6 +62,12 @@ import {
65
62
  updateSelectedFacetBucket,
66
63
  } from './utils/facet-utils';
67
64
 
65
+ import '@internetarchive/histogram-date-range';
66
+ import './collection-facets/more-facets-content';
67
+ import './collection-facets/facets-template';
68
+ import './collection-facets/facet-tombstone-row';
69
+ import './expanded-date-picker';
70
+
68
71
  @customElement('collection-facets')
69
72
  export class CollectionFacets extends LitElement {
70
73
  @property({ type: Object }) searchService?: SearchServiceInterface;
@@ -73,7 +76,7 @@ export class CollectionFacets extends LitElement {
73
76
 
74
77
  @property({ type: Object }) aggregations?: Record<string, Aggregation>;
75
78
 
76
- @property({ type: Object }) fullYearsHistogramAggregation?: Aggregation;
79
+ @property({ type: Object }) histogramAggregation?: Aggregation;
77
80
 
78
81
  @property({ type: String }) minSelectedDate?: string;
79
82
 
@@ -83,7 +86,7 @@ export class CollectionFacets extends LitElement {
83
86
 
84
87
  @property({ type: Boolean }) facetsLoading = false;
85
88
 
86
- @property({ type: Boolean }) fullYearAggregationLoading = false;
89
+ @property({ type: Boolean }) histogramAggregationLoading = false;
87
90
 
88
91
  @property({ type: Object }) selectedFacets?: SelectedFacets;
89
92
 
@@ -134,6 +137,9 @@ export class CollectionFacets extends LitElement {
134
137
  @property({ type: Object, attribute: false })
135
138
  collectionTitles?: CollectionTitles;
136
139
 
140
+ @property({ type: Object, attribute: false })
141
+ tvChannelAliases?: TVChannelAliases;
142
+
137
143
  @state() openFacets: Record<FacetOption, boolean> = {
138
144
  subject: false,
139
145
  lending: false,
@@ -164,7 +170,7 @@ export class CollectionFacets extends LitElement {
164
170
  return html`
165
171
  <div id="container" class=${containerClasses}>
166
172
  ${this.showHistogramDatePicker &&
167
- (this.fullYearsHistogramAggregation || this.fullYearAggregationLoading)
173
+ (this.histogramAggregation || this.histogramAggregationLoading)
168
174
  ? html`
169
175
  <section
170
176
  class="facet-group"
@@ -230,15 +236,63 @@ export class CollectionFacets extends LitElement {
230
236
  });
231
237
  }
232
238
 
239
+ /**
240
+ * Properties to pass into the date-picker histogram component
241
+ */
242
+ private get histogramProps() {
243
+ const { histogramAggregation: aggregation } = this;
244
+ if (!aggregation) return undefined;
245
+
246
+ // Normalize some properties from the raw aggregation
247
+ const firstYear =
248
+ aggregation.first_bucket_year ?? aggregation.first_bucket_key;
249
+ const lastYear =
250
+ aggregation.last_bucket_year ?? aggregation.last_bucket_key;
251
+ if (firstYear == null || lastYear == null) return undefined; // We at least need a start/end year defined
252
+
253
+ const firstMonth = aggregation.first_bucket_month ?? 1;
254
+ const lastMonth = aggregation.last_bucket_month ?? 12;
255
+
256
+ const yearInterval = aggregation.interval ?? 1;
257
+ const monthInterval = aggregation.interval_in_months ?? 12;
258
+
259
+ const zeroPadMonth = (month: number) => month.toString().padStart(2, '0');
260
+
261
+ // Format the min/max dates appropriately
262
+ const minDate = this.isTvSearch
263
+ ? `${firstYear}-${zeroPadMonth(firstMonth)}`
264
+ : `${firstYear}`;
265
+
266
+ const maxDate = this.isTvSearch
267
+ ? `${lastYear}-${zeroPadMonth(lastMonth + monthInterval - 1)}`
268
+ : `${lastYear + yearInterval - 1}`;
269
+
270
+ const hasMonths = this.isTvSearch && monthInterval < 12;
271
+ return {
272
+ buckets: aggregation.buckets as number[],
273
+ dateFormat: this.isTvSearch ? 'YYYY-MM' : 'YYYY',
274
+ tooltipDateFormat: hasMonths ? 'MMM YYYY' : 'YYYY',
275
+ binSnapping: (hasMonths ? 'month' : 'year') as BinSnappingInterval,
276
+ minDate,
277
+ maxDate,
278
+ };
279
+ }
280
+
233
281
  /**
234
282
  * Opens a modal dialog containing an enlarged version of the date picker.
235
283
  */
236
284
  private showDatePickerModal(): void {
237
- const { fullYearsHistogramAggregation } = this;
238
- const minDate = fullYearsHistogramAggregation?.first_bucket_key;
239
- const maxDate = fullYearsHistogramAggregation?.last_bucket_key;
240
- const buckets = fullYearsHistogramAggregation?.buckets as number[];
241
- const dateFormat = this.isTvSearch ? 'YYYY-MM' : 'YYYY';
285
+ const { histogramProps } = this;
286
+ if (!histogramProps) return;
287
+
288
+ const {
289
+ buckets,
290
+ dateFormat,
291
+ tooltipDateFormat,
292
+ binSnapping,
293
+ minDate,
294
+ maxDate,
295
+ } = histogramProps;
242
296
 
243
297
  // Because the modal manager does not clear its DOM content after being closed,
244
298
  // it may try to render the exact same date picker template when it is reopened.
@@ -264,6 +318,8 @@ export class CollectionFacets extends LitElement {
264
318
  .minSelectedDate=${this.minSelectedDate}
265
319
  .maxSelectedDate=${this.maxSelectedDate}
266
320
  .dateFormat=${dateFormat}
321
+ .tooltipDateFormat=${tooltipDateFormat}
322
+ .binSnapping=${binSnapping}
267
323
  .buckets=${buckets}
268
324
  .modalManager=${this.modalManager}
269
325
  .analyticsHandler=${this.analyticsHandler}
@@ -328,30 +384,42 @@ export class CollectionFacets extends LitElement {
328
384
  : nothing;
329
385
  }
330
386
 
331
- private get histogramTemplate() {
332
- const { fullYearsHistogramAggregation } = this;
333
- const minDate = fullYearsHistogramAggregation?.first_bucket_key;
334
- const maxDate = fullYearsHistogramAggregation?.last_bucket_key;
335
- const dateFormat = this.isTvSearch ? 'YYYY-MM' : 'YYYY';
336
- return this.fullYearAggregationLoading
337
- ? html`<div class="histogram-loading-indicator">&hellip;</div>` // Ellipsis block
338
- : html`
339
- <histogram-date-range
340
- class=${this.isTvSearch ? 'wide-inputs' : nothing}
341
- .minDate=${minDate}
342
- .maxDate=${maxDate}
343
- .minSelectedDate=${this.minSelectedDate ?? minDate}
344
- .maxSelectedDate=${this.maxSelectedDate ?? maxDate}
345
- .updateDelay=${100}
346
- .dateFormat=${dateFormat}
347
- missingDataMessage="..."
348
- .width=${this.collapsableFacets && this.contentWidth
349
- ? this.contentWidth
350
- : 180}
351
- .bins=${fullYearsHistogramAggregation?.buckets as number[]}
352
- @histogramDateRangeUpdated=${this.histogramDateRangeUpdated}
353
- ></histogram-date-range>
354
- `;
387
+ private get histogramTemplate(): TemplateResult | typeof nothing {
388
+ if (this.histogramAggregationLoading) {
389
+ return html` <div class="histogram-loading-indicator">&hellip;</div> `;
390
+ }
391
+
392
+ const { histogramProps } = this;
393
+ if (!histogramProps) return nothing;
394
+
395
+ const {
396
+ buckets,
397
+ dateFormat,
398
+ tooltipDateFormat,
399
+ binSnapping,
400
+ minDate,
401
+ maxDate,
402
+ } = histogramProps;
403
+
404
+ return html`
405
+ <histogram-date-range
406
+ class=${this.isTvSearch ? 'wide-inputs' : nothing}
407
+ .minDate=${minDate}
408
+ .maxDate=${maxDate}
409
+ .minSelectedDate=${this.minSelectedDate ?? minDate}
410
+ .maxSelectedDate=${this.maxSelectedDate ?? maxDate}
411
+ .updateDelay=${100}
412
+ .dateFormat=${dateFormat}
413
+ .tooltipDateFormat=${tooltipDateFormat}
414
+ .binSnapping=${binSnapping}
415
+ .bins=${buckets}
416
+ missingDataMessage="..."
417
+ .width=${this.collapsableFacets && this.contentWidth
418
+ ? this.contentWidth
419
+ : 180}
420
+ @histogramDateRangeUpdated=${this.histogramDateRangeUpdated}
421
+ ></histogram-date-range>
422
+ `;
355
423
  }
356
424
 
357
425
  /**
@@ -471,7 +539,7 @@ export class CollectionFacets extends LitElement {
471
539
  bucketsWithCount.forEach(b => {
472
540
  b.displayText = (b.displayText ?? b.key)?.toLocaleUpperCase();
473
541
 
474
- const channelLabel = tvChannelFacetLabels[b.displayText];
542
+ const channelLabel = this.tvChannelAliases?.get(b.displayText);
475
543
  if (channelLabel && channelLabel !== b.displayText) {
476
544
  b.extraNote = `(${channelLabel})`;
477
545
  }
@@ -533,8 +601,8 @@ export class CollectionFacets extends LitElement {
533
601
  private get aggregationFacetGroups(): FacetGroup[] {
534
602
  const facetGroups: FacetGroup[] = [];
535
603
  Object.entries(this.aggregations ?? []).forEach(([key, aggregation]) => {
536
- // the year_histogram data is in a different format so can't be handled here
537
- if (key === 'year_histogram') return;
604
+ // the year_histogram and date_histogram data is in a different format so can't be handled here
605
+ if (['year_histogram', 'date_histogram'].includes(key)) return;
538
606
 
539
607
  const option = key as FacetOption;
540
608
  const title = facetTitles[option];
@@ -707,6 +775,7 @@ export class CollectionFacets extends LitElement {
707
775
  .searchService=${this.searchService}
708
776
  .searchType=${this.searchType}
709
777
  .collectionTitles=${this.collectionTitles}
778
+ .tvChannelAliases=${this.tvChannelAliases}
710
779
  .selectedFacets=${this.selectedFacets}
711
780
  .sortedBy=${sortedBy}
712
781
  .isTvSearch=${this.isTvSearch}
@@ -12,7 +12,11 @@ import type {
12
12
  PrefixFilterCounts,
13
13
  TileModel,
14
14
  } from '../models';
15
- import type { PageSpecifierParams, CollectionTitles } from './models';
15
+ import type {
16
+ PageSpecifierParams,
17
+ CollectionTitles,
18
+ TVChannelAliases,
19
+ } from './models';
16
20
 
17
21
  export interface CollectionBrowserDataSourceInterface
18
22
  extends ReactiveController {
@@ -78,9 +82,9 @@ export interface CollectionBrowserDataSourceInterface
78
82
  readonly aggregations?: Record<string, Aggregation>;
79
83
 
80
84
  /**
81
- * The `year_histogram` aggregation retrieved for the current search.
85
+ * The `year_histogram` or `date_histogram` aggregation retrieved for the current search.
82
86
  */
83
- readonly yearHistogramAggregation?: Aggregation;
87
+ readonly histogramAggregation?: Aggregation;
84
88
 
85
89
  /**
86
90
  * A map from collection identifiers that appear on hits or aggregations for the
@@ -88,6 +92,12 @@ export interface CollectionBrowserDataSourceInterface
88
92
  */
89
93
  readonly collectionTitles: CollectionTitles;
90
94
 
95
+ /**
96
+ * A map from TV channel names appearing in `creator` aggregations, to their
97
+ * more human-readable network names.
98
+ */
99
+ readonly tvChannelAliases: TVChannelAliases;
100
+
91
101
  /**
92
102
  * The "extra info" package provided by the PPS for collection pages, including details
93
103
  * used to populate the target collection header & About tab content.
@@ -114,13 +114,18 @@ export class CollectionBrowserDataSource
114
114
  /**
115
115
  * @inheritdoc
116
116
  */
117
- yearHistogramAggregation?: Aggregation;
117
+ histogramAggregation?: Aggregation;
118
118
 
119
119
  /**
120
120
  * @inheritdoc
121
121
  */
122
122
  collectionTitles = new Map<string, string>();
123
123
 
124
+ /**
125
+ * @inheritdoc
126
+ */
127
+ tvChannelAliases = new Map<string, string>();
128
+
124
129
  /**
125
130
  * @inheritdoc
126
131
  */
@@ -234,7 +239,7 @@ export class CollectionBrowserDataSource
234
239
  log('Resetting CB data source');
235
240
  this.pages = {};
236
241
  this.aggregations = {};
237
- this.yearHistogramAggregation = undefined;
242
+ this.histogramAggregation = undefined;
238
243
  this.pageElements = undefined;
239
244
  this.parentCollections = [];
240
245
  this.previousQueryKey = '';
@@ -700,16 +705,18 @@ export class CollectionBrowserDataSource
700
705
  selectedCreatorFilter,
701
706
  } = this.host;
702
707
 
708
+ const dateField = this.host.searchType === SearchType.TV ? 'date' : 'year';
709
+
703
710
  if (minSelectedDate) {
704
711
  builder.addFilter(
705
- 'year',
712
+ dateField,
706
713
  minSelectedDate,
707
714
  FilterConstraint.GREATER_OR_EQUAL,
708
715
  );
709
716
  }
710
717
  if (maxSelectedDate) {
711
718
  builder.addFilter(
712
- 'year',
719
+ dateField,
713
720
  maxSelectedDate,
714
721
  FilterConstraint.LESS_OR_EQUAL,
715
722
  );
@@ -1029,17 +1036,25 @@ export class CollectionBrowserDataSource
1029
1036
  return;
1030
1037
  }
1031
1038
 
1032
- const { aggregations, collectionTitles } = success.response;
1039
+ const { aggregations, collectionTitles, tvChannelAliases } =
1040
+ success.response;
1033
1041
  this.aggregations = aggregations;
1034
1042
 
1043
+ this.histogramAggregation =
1044
+ this.host.searchType === SearchType.TV
1045
+ ? aggregations?.date_histogram
1046
+ : aggregations?.year_histogram;
1047
+
1035
1048
  if (collectionTitles) {
1036
1049
  for (const [id, title] of Object.entries(collectionTitles)) {
1037
1050
  this.collectionTitles.set(id, title);
1038
1051
  }
1039
1052
  }
1040
-
1041
- this.yearHistogramAggregation =
1042
- success?.response?.aggregations?.year_histogram;
1053
+ if (tvChannelAliases) {
1054
+ for (const [channel, network] of Object.entries(tvChannelAliases)) {
1055
+ this.tvChannelAliases.set(channel, network);
1056
+ }
1057
+ }
1043
1058
 
1044
1059
  this.setFacetsLoading(false);
1045
1060
  this.requestHostUpdate();
@@ -1187,7 +1202,7 @@ export class CollectionBrowserDataSource
1187
1202
  this.pageElements = success.response.pageElements;
1188
1203
  }
1189
1204
 
1190
- const { results, collectionTitles } = success.response;
1205
+ const { results, collectionTitles, tvChannelAliases } = success.response;
1191
1206
  if (results && results.length > 0) {
1192
1207
  // Load any collection titles present on the response into the cache,
1193
1208
  // or queue up preload fetches for them if none were present.
@@ -1203,6 +1218,12 @@ export class CollectionBrowserDataSource
1203
1218
  }
1204
1219
  }
1205
1220
 
1221
+ if (tvChannelAliases) {
1222
+ for (const [channel, network] of Object.entries(tvChannelAliases)) {
1223
+ this.tvChannelAliases.set(channel, network);
1224
+ }
1225
+ }
1226
+
1206
1227
  // Update the data source for each returned page.
1207
1228
  // For loans and web archives, we must account for receiving more pages than we asked for.
1208
1229
  const isUnpagedElement = ['lending', 'web_archives'].includes(
@@ -8,6 +8,11 @@ import type {
8
8
  */
9
9
  export type CollectionTitles = Map<string, string>;
10
10
 
11
+ /**
12
+ * A Map from channel names to their corresponding, more human-readable network name.
13
+ */
14
+ export type TVChannelAliases = Map<string, string>;
15
+
11
16
  /**
12
17
  * The subset of search service params that uniquely specify the type of results
13
18
  * that are sought by an instance of collection browser.
@@ -1,13 +1,17 @@
1
1
  import { css, html, LitElement, CSSResultGroup, TemplateResult } from 'lit';
2
2
  import { customElement, property } from 'lit/decorators.js';
3
+ import { ifDefined } from 'lit/directives/if-defined.js';
3
4
  import { msg } from '@lit/localize';
4
5
  import type { ModalManagerInterface } from '@internetarchive/modal-manager';
5
6
  import type { AnalyticsManagerInterface } from '@internetarchive/analytics-manager';
7
+ import { BinSnappingInterval } from '@internetarchive/histogram-date-range';
6
8
  import {
7
9
  analyticsActions,
8
10
  analyticsCategories,
9
11
  } from './utils/analytics-events';
10
12
 
13
+ import '@internetarchive/histogram-date-range';
14
+
11
15
  @customElement('expanded-date-picker')
12
16
  export class ExpandedDatePicker extends LitElement {
13
17
  @property({ type: String }) minDate?: string;
@@ -22,6 +26,10 @@ export class ExpandedDatePicker extends LitElement {
22
26
 
23
27
  @property({ type: String }) dateFormat: string = 'YYYY';
24
28
 
29
+ @property({ type: String }) tooltipDateFormat?: string;
30
+
31
+ @property({ type: String }) binSnapping?: BinSnappingInterval;
32
+
25
33
  @property({ type: Object, attribute: false })
26
34
  modalManager?: ModalManagerInterface;
27
35
 
@@ -38,6 +46,8 @@ export class ExpandedDatePicker extends LitElement {
38
46
  .minSelectedDate=${this.minSelectedDate ?? this.minDate}
39
47
  .maxSelectedDate=${this.maxSelectedDate ?? this.maxDate}
40
48
  .dateFormat=${this.dateFormat}
49
+ tooltipDateFormat=${ifDefined(this.tooltipDateFormat)}
50
+ binSnapping=${ifDefined(this.binSnapping)}
41
51
  .updateDelay=${0}
42
52
  updateWhileFocused
43
53
  missingDataMessage="..."
package/src/models.ts CHANGED
@@ -750,42 +750,6 @@ export const valueFacetSort: Record<FacetOption, AggregationSortType> = {
750
750
  sponsor: AggregationSortType.ALPHABETICAL,
751
751
  };
752
752
 
753
- /**
754
- * Extra parenthesized labels to show next to certain TV channel facets
755
- *
756
- * TODO: This is only needed until we can receive the appropriate mapping via PPS,
757
- * and can be removed/replaced once that is set up.
758
- */
759
- export const tvChannelFacetLabels: Record<string, string> = Object.fromEntries(
760
- // prettier-ignore
761
- Object.entries({
762
- 'Al Jazeera' : ['ALJAZAM', 'ALJAZ'],
763
- 'Bloomberg' : ['BLOOMBERG'],
764
- 'BBC' : ['BBC', 'BBC1', 'BBC2'],
765
- 'BBC America' : ['BBCAMERICA'],
766
- 'BBC News' : ['BBCNEWS'],
767
- 'GB News' : ['GBN'],
768
- 'BET' : ['BETW'],
769
- 'CNBC' : ['CNBC'],
770
- 'CNN' : ['CNNW', 'CNN'],
771
- 'Comedy Central' : ['COM', 'COMW'],
772
- 'CSPAN' : ['CSPAN', 'CSPAN2', 'CSPAN3'],
773
- 'Current' : ['CURRENT'],
774
- 'Deutsche Welle' : ['DW'],
775
- 'France 24' : ['FRANCE24'],
776
- 'FOX Business' : ['FBC'],
777
- 'FOX News' : ['FOXNEWSW', 'FOXNEWS'],
778
- 'LINKTV' : ['LINKTV'],
779
- 'MSNBC' : ['MSNBCW', 'MSNBC'],
780
- 'NHK World' : ['NHK'],
781
- 'RT' : ['RT'],
782
- 'Sky News' : ['SKY'],
783
- }).reduce(
784
- (acc, [label, channels]) => acc.concat(channels.map(ch => [ch, label])),
785
- [] as [string, string][],
786
- ),
787
- );
788
-
789
753
  export type LendingFacetKey =
790
754
  | 'is_lendable'
791
755
  | 'is_borrowable'
@@ -27,8 +27,6 @@ export abstract class BaseTileComponent extends LitElement {
27
27
 
28
28
  @property({ type: Boolean }) loggedIn = false;
29
29
 
30
- @property({ type: Boolean }) suppressBlurring = false;
31
-
32
30
  protected displayValueProvider = new TileDisplayValueProvider();
33
31
 
34
32
  protected willUpdate(changed: PropertyValues<this>) {
@@ -21,7 +21,6 @@ export class AccountTile extends BaseTileComponent {
21
21
  * - creatorFilter?: string;
22
22
  * - mobileBreakpoint?: number;
23
23
  * - loggedIn = false;
24
- * - suppressBlurring = false;
25
24
  */
26
25
 
27
26
  @property({ type: Boolean }) showInfoButton = false;
@@ -47,7 +46,6 @@ export class AccountTile extends BaseTileComponent {
47
46
  .model=${this.model}
48
47
  .baseImageUrl=${this.baseImageUrl}
49
48
  .viewSize=${'grid'}
50
- .suppressBlurring=${this.suppressBlurring}
51
49
  >
52
50
  </image-block>
53
51
  `;
@@ -21,7 +21,6 @@ export class CollectionTile extends BaseTileComponent {
21
21
  * - creatorFilter?: string;
22
22
  * - mobileBreakpoint?: number;
23
23
  * - loggedIn = false;
24
- * - suppressBlurring = false;
25
24
  */
26
25
 
27
26
  @property({ type: Boolean }) showInfoButton = false;
@@ -47,7 +46,6 @@ export class CollectionTile extends BaseTileComponent {
47
46
  .model=${this.model}
48
47
  .baseImageUrl=${this.baseImageUrl}
49
48
  .viewSize=${'grid'}
50
- .suppressBlurring=${this.suppressBlurring}
51
49
  >
52
50
  </image-block>
53
51
  `;
@@ -33,7 +33,6 @@ export class ItemTile extends BaseTileComponent {
33
33
  * - creatorFilter?: string;
34
34
  * - mobileBreakpoint?: number;
35
35
  * - loggedIn = false;
36
- * - suppressBlurring = false;
37
36
  */
38
37
 
39
38
  @property({ type: Boolean }) showInfoButton = false;
@@ -99,7 +98,6 @@ export class ItemTile extends BaseTileComponent {
99
98
  .model=${this.model}
100
99
  .baseImageUrl=${this.baseImageUrl}
101
100
  .loggedIn=${this.loggedIn}
102
- .suppressBlurring=${this.suppressBlurring}
103
101
  .isCompactTile=${false}
104
102
  .isListTile=${false}
105
103
  .viewSize=${'grid'}
@@ -18,7 +18,6 @@ export class SearchTile extends BaseTileComponent {
18
18
  * - creatorFilter?: string;
19
19
  * - mobileBreakpoint?: number;
20
20
  * - loggedIn = false;
21
- * - suppressBlurring = false;
22
21
  */
23
22
 
24
23
  @property({ type: Boolean }) showInfoButton = false;
@@ -41,7 +40,6 @@ export class SearchTile extends BaseTileComponent {
41
40
  .model=${this.model}
42
41
  .baseImageUrl=${this.baseImageUrl}
43
42
  .viewSize=${'grid'}
44
- .suppressBlurring=${this.suppressBlurring}
45
43
  >
46
44
  </image-block>
47
45
  `;
@@ -16,7 +16,6 @@ export interface HoverPaneProperties {
16
16
  baseNavigationUrl?: string;
17
17
  baseImageUrl?: string;
18
18
  loggedIn: boolean;
19
- suppressBlurring: boolean;
20
19
  sortParam: SortParam | null;
21
20
  collectionTitles?: CollectionTitles;
22
21
  }
@@ -190,7 +189,6 @@ export class HoverPaneController implements HoverPaneControllerInterface {
190
189
  .baseNavigationUrl=${this.hoverPaneProps?.baseNavigationUrl}
191
190
  .baseImageUrl=${this.hoverPaneProps?.baseImageUrl}
192
191
  .loggedIn=${this.hoverPaneProps?.loggedIn}
193
- .suppressBlurring=${this.hoverPaneProps?.suppressBlurring}
194
192
  .sortParam=${this.hoverPaneProps?.sortParam}
195
193
  .collectionTitles=${this.hoverPaneProps?.collectionTitles}
196
194
  .mobileBreakpoint=${this.mobileBreakpoint}
@@ -308,6 +306,9 @@ export class HoverPaneController implements HoverPaneControllerInterface {
308
306
  }
309
307
  }
310
308
 
309
+ left += window.scrollX;
310
+ top += window.scrollY;
311
+
311
312
  return { left, top };
312
313
  }
313
314
 
@@ -467,6 +468,10 @@ export class HoverPaneController implements HoverPaneControllerInterface {
467
468
  // Wait for the state update to render the hover pane
468
469
  await this.host.updateComplete;
469
470
 
471
+ // Ensure the hover pane element is still in the document before showing,
472
+ // as it might have been removed by the previous update.
473
+ if (!this.hoverPane?.isConnected) return;
474
+
470
475
  this.hoverPane?.showPopover?.();
471
476
  await new Promise(resolve => {
472
477
  // Pane sizes aren't accurate until next frame
@@ -22,8 +22,6 @@ export class TileHoverPane extends LitElement {
22
22
 
23
23
  @property({ type: Boolean }) loggedIn: boolean = false;
24
24
 
25
- @property({ type: Boolean }) suppressBlurring: boolean = false;
26
-
27
25
  @property({ type: Object }) sortParam?: SortParam;
28
26
 
29
27
  @property({ type: Number }) mobileBreakpoint?: number;
@@ -43,7 +41,6 @@ export class TileHoverPane extends LitElement {
43
41
  .baseNavigationUrl=${this.baseNavigationUrl}
44
42
  .baseImageUrl=${this.baseImageUrl}
45
43
  .loggedIn=${this.loggedIn}
46
- .suppressBlurring=${this.suppressBlurring}
47
44
  .sortParam=${this.sortParam}
48
45
  .collectionTitles=${this.collectionTitles}
49
46
  .mobileBreakpoint=${this.mobileBreakpoint}
@@ -17,8 +17,6 @@ export class ImageBlock extends LitElement {
17
17
 
18
18
  @property({ type: Boolean }) loggedIn = false;
19
19
 
20
- @property({ type: Boolean }) suppressBlurring = false;
21
-
22
20
  @property({ type: Object }) model?: TileModel;
23
21
 
24
22
  @property({ type: String }) viewSize: string = 'desktop';
@@ -34,7 +32,6 @@ export class ImageBlock extends LitElement {
34
32
  .isListTile=${this.isListTile}
35
33
  .isCompactTile=${this.isCompactTile}
36
34
  .loggedIn=${this.loggedIn}
37
- .suppressBlurring=${this.suppressBlurring}
38
35
  style="--imgHeight: 100%; --imgWidth: 100%"
39
36
  >
40
37
  </item-image>
@@ -81,8 +78,6 @@ export class ImageBlock extends LitElement {
81
78
  }
82
79
 
83
80
  private get overlayType(): TileOverlayType | undefined {
84
- if (this.suppressBlurring) return undefined;
85
-
86
81
  // Prioritize showing the login-required overlay if needed.
87
82
  // Otherwise, if a content warning is required, show that overlay instead.
88
83
  // If neither flag is present, no overlay should be shown.
@@ -22,8 +22,6 @@ export class ItemImage extends LitElement {
22
22
 
23
23
  @property({ type: Boolean }) loggedIn = false;
24
24
 
25
- @property({ type: Boolean }) suppressBlurring = false;
26
-
27
25
  @state() private isWaveform = false;
28
26
 
29
27
  @state() private isNotFound = false;
@@ -113,14 +111,12 @@ export class ItemImage extends LitElement {
113
111
  }
114
112
 
115
113
  private get itemImageClass(): ClassInfo {
116
- const toBlur =
117
- !this.suppressBlurring &&
118
- !!(this.model?.contentWarning || this.model?.loginRequired);
114
+ const toBlur = this.model?.contentWarning || this.model?.loginRequired;
119
115
 
120
116
  return {
121
117
  contain: !this.isCompactTile && !this.isWaveform,
122
118
  cover: this.isCompactTile,
123
- blur: toBlur,
119
+ blur: toBlur || false,
124
120
  waveform: this.isWaveform,
125
121
  'account-image': this.isAccountImage, // for account tile image
126
122
  'collection-image': this.model?.mediatype === 'collection', // for collection tile image
@@ -17,7 +17,6 @@ export class TileListCompactHeader extends BaseTileComponent {
17
17
  * - creatorFilter?: string;
18
18
  * - mobileBreakpoint?: number;
19
19
  * - loggedIn = false;
20
- * - suppressBlurring = false;
21
20
  */
22
21
 
23
22
  render() {