@internetarchive/collection-browser 4.8.0 → 4.8.1-webdev-9227.2

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 (401) hide show
  1. package/README.md +33 -0
  2. package/dist/src/collection-browser.d.ts +2 -1
  3. package/dist/src/collection-browser.js +7 -7
  4. package/dist/src/collection-browser.js.map +1 -1
  5. package/dist/src/collection-facets/facet-row-template.d.ts +1 -1
  6. package/dist/src/collection-facets/facet-row-template.js +10 -6
  7. package/dist/src/collection-facets/facet-row-template.js.map +1 -1
  8. package/dist/src/collection-facets/facet-row.js +3 -1
  9. package/dist/src/collection-facets/facet-row.js.map +1 -1
  10. package/dist/src/collection-facets/more-facets-content.js +6 -5
  11. package/dist/src/collection-facets/more-facets-content.js.map +1 -1
  12. package/dist/src/collection-facets/more-facets-scroller.js +3 -2
  13. package/dist/src/collection-facets/more-facets-scroller.js.map +1 -1
  14. package/dist/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-entity-map.js +13 -4
  15. package/dist/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-entity-map.js.map +1 -1
  16. package/dist/src/collection-facets/smart-facets/smart-facet-bar.js +6 -2
  17. package/dist/src/collection-facets/smart-facets/smart-facet-bar.js.map +1 -1
  18. package/dist/src/collection-facets.js +6 -5
  19. package/dist/src/collection-facets.js.map +1 -1
  20. package/dist/src/empty-placeholder.d.ts +7 -7
  21. package/dist/src/empty-placeholder.js +29 -15
  22. package/dist/src/empty-placeholder.js.map +1 -1
  23. package/dist/src/expanded-date-picker.js +3 -2
  24. package/dist/src/expanded-date-picker.js.map +1 -1
  25. package/dist/src/locales/es.d.ts +205 -0
  26. package/dist/src/locales/es.js +220 -0
  27. package/dist/src/locales/es.js.map +1 -0
  28. package/dist/src/manage/manage-bar.d.ts +3 -2
  29. package/dist/src/manage/manage-bar.js +15 -16
  30. package/dist/src/manage/manage-bar.js.map +1 -1
  31. package/dist/src/manage/remove-items-modal-content.js +3 -2
  32. package/dist/src/manage/remove-items-modal-content.js.map +1 -1
  33. package/dist/src/mediatype/mediatype-config.js +55 -18
  34. package/dist/src/mediatype/mediatype-config.js.map +1 -1
  35. package/dist/src/models.js +120 -40
  36. package/dist/src/models.js.map +1 -1
  37. package/dist/src/sort-filter-bar/alpha-bar-tooltip.js +6 -2
  38. package/dist/src/sort-filter-bar/alpha-bar-tooltip.js.map +1 -1
  39. package/dist/src/sort-filter-bar/alpha-bar.js +5 -2
  40. package/dist/src/sort-filter-bar/alpha-bar.js.map +1 -1
  41. package/dist/src/sort-filter-bar/sort-filter-bar.js +9 -8
  42. package/dist/src/sort-filter-bar/sort-filter-bar.js.map +1 -1
  43. package/dist/src/tiles/grid/account-tile.js +3 -2
  44. package/dist/src/tiles/grid/account-tile.js.map +1 -1
  45. package/dist/src/tiles/grid/collection-tile.js +9 -6
  46. package/dist/src/tiles/grid/collection-tile.js.map +1 -1
  47. package/dist/src/tiles/grid/item-tile.js +8 -7
  48. package/dist/src/tiles/grid/item-tile.js.map +1 -1
  49. package/dist/src/tiles/grid/tile-stats.js +6 -3
  50. package/dist/src/tiles/grid/tile-stats.js.map +1 -1
  51. package/dist/src/tiles/list/tile-list-compact-header.js +3 -2
  52. package/dist/src/tiles/list/tile-list-compact-header.js.map +1 -1
  53. package/dist/src/tiles/list/tile-list-compact.js +3 -1
  54. package/dist/src/tiles/list/tile-list-compact.js.map +1 -1
  55. package/dist/src/tiles/list/tile-list.js +4 -3
  56. package/dist/src/tiles/list/tile-list.js.map +1 -1
  57. package/dist/src/tiles/overlay/text-overlay.js +3 -1
  58. package/dist/src/tiles/overlay/text-overlay.js.map +1 -1
  59. package/dist/src/tiles/review-block.js +3 -2
  60. package/dist/src/tiles/review-block.js.map +1 -1
  61. package/dist/src/tiles/tile-dispatcher.d.ts +2 -1
  62. package/dist/src/tiles/tile-dispatcher.js +6 -5
  63. package/dist/src/tiles/tile-dispatcher.js.map +1 -1
  64. package/dist/src/tiles/tile-mediatype-icon.js +3 -1
  65. package/dist/src/tiles/tile-mediatype-icon.js.map +1 -1
  66. package/dist/src/utils/format-unit-size.d.ts +1 -1
  67. package/dist/src/utils/format-unit-size.js +20 -18
  68. package/dist/src/utils/format-unit-size.js.map +1 -1
  69. package/locales/es.d.ts +1 -0
  70. package/locales/es.js +1 -0
  71. package/package.json +13 -1
  72. package/.editorconfig +0 -29
  73. package/.github/workflows/ci.yml +0 -29
  74. package/.github/workflows/gh-pages-main.yml +0 -41
  75. package/.github/workflows/npm-publish.yml +0 -42
  76. package/.github/workflows/pr-preview.yml +0 -40
  77. package/.husky/pre-commit +0 -1
  78. package/.prettierignore +0 -1
  79. package/dist/test/collection-browser.test.d.ts +0 -1
  80. package/dist/test/collection-browser.test.js +0 -1815
  81. package/dist/test/collection-browser.test.js.map +0 -1
  82. package/dist/test/collection-facets/facet-row.test.d.ts +0 -1
  83. package/dist/test/collection-facets/facet-row.test.js +0 -291
  84. package/dist/test/collection-facets/facet-row.test.js.map +0 -1
  85. package/dist/test/collection-facets/facets-template.test.d.ts +0 -1
  86. package/dist/test/collection-facets/facets-template.test.js +0 -95
  87. package/dist/test/collection-facets/facets-template.test.js.map +0 -1
  88. package/dist/test/collection-facets/more-facets-content.test.d.ts +0 -1
  89. package/dist/test/collection-facets/more-facets-content.test.js +0 -509
  90. package/dist/test/collection-facets/more-facets-content.test.js.map +0 -1
  91. package/dist/test/collection-facets/more-facets-scroller.test.d.ts +0 -1
  92. package/dist/test/collection-facets/more-facets-scroller.test.js +0 -288
  93. package/dist/test/collection-facets/more-facets-scroller.test.js.map +0 -1
  94. package/dist/test/collection-facets/page-window.test.d.ts +0 -1
  95. package/dist/test/collection-facets/page-window.test.js +0 -175
  96. package/dist/test/collection-facets/page-window.test.js.map +0 -1
  97. package/dist/test/collection-facets/toggle-switch.test.d.ts +0 -1
  98. package/dist/test/collection-facets/toggle-switch.test.js +0 -99
  99. package/dist/test/collection-facets/toggle-switch.test.js.map +0 -1
  100. package/dist/test/collection-facets.test.d.ts +0 -2
  101. package/dist/test/collection-facets.test.js +0 -728
  102. package/dist/test/collection-facets.test.js.map +0 -1
  103. package/dist/test/data-source/collection-browser-data-source.test.d.ts +0 -1
  104. package/dist/test/data-source/collection-browser-data-source.test.js +0 -154
  105. package/dist/test/data-source/collection-browser-data-source.test.js.map +0 -1
  106. package/dist/test/empty-placeholder.test.d.ts +0 -1
  107. package/dist/test/empty-placeholder.test.js +0 -57
  108. package/dist/test/empty-placeholder.test.js.map +0 -1
  109. package/dist/test/expanded-date-picker.test.d.ts +0 -1
  110. package/dist/test/expanded-date-picker.test.js +0 -124
  111. package/dist/test/expanded-date-picker.test.js.map +0 -1
  112. package/dist/test/icon-overlay.test.d.ts +0 -1
  113. package/dist/test/icon-overlay.test.js +0 -31
  114. package/dist/test/icon-overlay.test.js.map +0 -1
  115. package/dist/test/image-block.test.d.ts +0 -1
  116. package/dist/test/image-block.test.js +0 -208
  117. package/dist/test/image-block.test.js.map +0 -1
  118. package/dist/test/item-image.test.d.ts +0 -1
  119. package/dist/test/item-image.test.js +0 -187
  120. package/dist/test/item-image.test.js.map +0 -1
  121. package/dist/test/manage/manage-bar.test.d.ts +0 -3
  122. package/dist/test/manage/manage-bar.test.js +0 -216
  123. package/dist/test/manage/manage-bar.test.js.map +0 -1
  124. package/dist/test/manage/remove-items-modal-content.test.d.ts +0 -1
  125. package/dist/test/manage/remove-items-modal-content.test.js +0 -60
  126. package/dist/test/manage/remove-items-modal-content.test.js.map +0 -1
  127. package/dist/test/mediatype-config.test.d.ts +0 -1
  128. package/dist/test/mediatype-config.test.js +0 -11
  129. package/dist/test/mediatype-config.test.js.map +0 -1
  130. package/dist/test/mocks/mock-analytics-handler.d.ts +0 -10
  131. package/dist/test/mocks/mock-analytics-handler.js +0 -16
  132. package/dist/test/mocks/mock-analytics-handler.js.map +0 -1
  133. package/dist/test/mocks/mock-search-responses.d.ts +0 -37
  134. package/dist/test/mocks/mock-search-responses.js +0 -1293
  135. package/dist/test/mocks/mock-search-responses.js.map +0 -1
  136. package/dist/test/mocks/mock-search-service.d.ts +0 -16
  137. package/dist/test/mocks/mock-search-service.js +0 -65
  138. package/dist/test/mocks/mock-search-service.js.map +0 -1
  139. package/dist/test/restoration-state-handler.test.d.ts +0 -1
  140. package/dist/test/restoration-state-handler.test.js +0 -335
  141. package/dist/test/restoration-state-handler.test.js.map +0 -1
  142. package/dist/test/review-block.test.d.ts +0 -1
  143. package/dist/test/review-block.test.js +0 -46
  144. package/dist/test/review-block.test.js.map +0 -1
  145. package/dist/test/sort-filter-bar/alpha-bar-tooltip.test.d.ts +0 -1
  146. package/dist/test/sort-filter-bar/alpha-bar-tooltip.test.js +0 -12
  147. package/dist/test/sort-filter-bar/alpha-bar-tooltip.test.js.map +0 -1
  148. package/dist/test/sort-filter-bar/alpha-bar.test.d.ts +0 -1
  149. package/dist/test/sort-filter-bar/alpha-bar.test.js +0 -68
  150. package/dist/test/sort-filter-bar/alpha-bar.test.js.map +0 -1
  151. package/dist/test/sort-filter-bar/sort-filter-bar.test.d.ts +0 -1
  152. package/dist/test/sort-filter-bar/sort-filter-bar.test.js +0 -304
  153. package/dist/test/sort-filter-bar/sort-filter-bar.test.js.map +0 -1
  154. package/dist/test/text-overlay.test.d.ts +0 -1
  155. package/dist/test/text-overlay.test.js +0 -43
  156. package/dist/test/text-overlay.test.js.map +0 -1
  157. package/dist/test/text-snippet-block.test.d.ts +0 -1
  158. package/dist/test/text-snippet-block.test.js +0 -58
  159. package/dist/test/text-snippet-block.test.js.map +0 -1
  160. package/dist/test/tile-stats.test.d.ts +0 -1
  161. package/dist/test/tile-stats.test.js +0 -167
  162. package/dist/test/tile-stats.test.js.map +0 -1
  163. package/dist/test/tiles/grid/account-tile.test.d.ts +0 -1
  164. package/dist/test/tiles/grid/account-tile.test.js +0 -96
  165. package/dist/test/tiles/grid/account-tile.test.js.map +0 -1
  166. package/dist/test/tiles/grid/collection-tile.test.d.ts +0 -1
  167. package/dist/test/tiles/grid/collection-tile.test.js +0 -90
  168. package/dist/test/tiles/grid/collection-tile.test.js.map +0 -1
  169. package/dist/test/tiles/grid/item-tile.test.d.ts +0 -1
  170. package/dist/test/tiles/grid/item-tile.test.js +0 -400
  171. package/dist/test/tiles/grid/item-tile.test.js.map +0 -1
  172. package/dist/test/tiles/grid/search-tile.test.d.ts +0 -1
  173. package/dist/test/tiles/grid/search-tile.test.js +0 -62
  174. package/dist/test/tiles/grid/search-tile.test.js.map +0 -1
  175. package/dist/test/tiles/hover/hover-pane-controller.test.d.ts +0 -1
  176. package/dist/test/tiles/hover/hover-pane-controller.test.js +0 -351
  177. package/dist/test/tiles/hover/hover-pane-controller.test.js.map +0 -1
  178. package/dist/test/tiles/hover/tile-hover-pane.test.d.ts +0 -1
  179. package/dist/test/tiles/hover/tile-hover-pane.test.js +0 -53
  180. package/dist/test/tiles/hover/tile-hover-pane.test.js.map +0 -1
  181. package/dist/test/tiles/list/tile-list-compact-header.test.d.ts +0 -1
  182. package/dist/test/tiles/list/tile-list-compact-header.test.js +0 -36
  183. package/dist/test/tiles/list/tile-list-compact-header.test.js.map +0 -1
  184. package/dist/test/tiles/list/tile-list-compact.test.d.ts +0 -1
  185. package/dist/test/tiles/list/tile-list-compact.test.js +0 -237
  186. package/dist/test/tiles/list/tile-list-compact.test.js.map +0 -1
  187. package/dist/test/tiles/list/tile-list.test.d.ts +0 -1
  188. package/dist/test/tiles/list/tile-list.test.js +0 -460
  189. package/dist/test/tiles/list/tile-list.test.js.map +0 -1
  190. package/dist/test/tiles/tile-dispatcher.test.d.ts +0 -1
  191. package/dist/test/tiles/tile-dispatcher.test.js +0 -246
  192. package/dist/test/tiles/tile-dispatcher.test.js.map +0 -1
  193. package/dist/test/tiles/tile-display-value-provider.test.d.ts +0 -1
  194. package/dist/test/tiles/tile-display-value-provider.test.js +0 -142
  195. package/dist/test/tiles/tile-display-value-provider.test.js.map +0 -1
  196. package/dist/test/tiles/tile-mediatype-icon.test.d.ts +0 -1
  197. package/dist/test/tiles/tile-mediatype-icon.test.js +0 -133
  198. package/dist/test/tiles/tile-mediatype-icon.test.js.map +0 -1
  199. package/dist/test/utils/array-equals.test.d.ts +0 -1
  200. package/dist/test/utils/array-equals.test.js +0 -27
  201. package/dist/test/utils/array-equals.test.js.map +0 -1
  202. package/dist/test/utils/format-count.test.d.ts +0 -1
  203. package/dist/test/utils/format-count.test.js +0 -24
  204. package/dist/test/utils/format-count.test.js.map +0 -1
  205. package/dist/test/utils/format-date.test.d.ts +0 -1
  206. package/dist/test/utils/format-date.test.js +0 -61
  207. package/dist/test/utils/format-date.test.js.map +0 -1
  208. package/dist/test/utils/format-unit-size.test.d.ts +0 -1
  209. package/dist/test/utils/format-unit-size.test.js +0 -18
  210. package/dist/test/utils/format-unit-size.test.js.map +0 -1
  211. package/dist/test/utils/local-date-from-utc.test.d.ts +0 -1
  212. package/dist/test/utils/local-date-from-utc.test.js +0 -27
  213. package/dist/test/utils/local-date-from-utc.test.js.map +0 -1
  214. package/dist/test/utils/normalize-filter-text.test.d.ts +0 -1
  215. package/dist/test/utils/normalize-filter-text.test.js +0 -69
  216. package/dist/test/utils/normalize-filter-text.test.js.map +0 -1
  217. package/docs/design/column-virtualization.md +0 -214
  218. package/eslint.config.mjs +0 -53
  219. package/index.html +0 -24
  220. package/index.ts +0 -29
  221. package/local.archive.org.cert +0 -86
  222. package/local.archive.org.key +0 -27
  223. package/pnpm-workspace.yaml +0 -30
  224. package/renovate.json +0 -6
  225. package/src/app-root.ts +0 -1282
  226. package/src/assets/img/icons/arrow-left.ts +0 -10
  227. package/src/assets/img/icons/arrow-right.ts +0 -10
  228. package/src/assets/img/icons/check.ts +0 -5
  229. package/src/assets/img/icons/chevron.ts +0 -4
  230. package/src/assets/img/icons/close-circle-dark.ts +0 -5
  231. package/src/assets/img/icons/contract.ts +0 -9
  232. package/src/assets/img/icons/empty-query.ts +0 -5
  233. package/src/assets/img/icons/expand.ts +0 -9
  234. package/src/assets/img/icons/eye-closed.ts +0 -5
  235. package/src/assets/img/icons/eye.ts +0 -5
  236. package/src/assets/img/icons/favorite-filled.ts +0 -10
  237. package/src/assets/img/icons/favorite-unfilled.ts +0 -9
  238. package/src/assets/img/icons/filter.ts +0 -10
  239. package/src/assets/img/icons/login-required.ts +0 -18
  240. package/src/assets/img/icons/mediatype/account.ts +0 -14
  241. package/src/assets/img/icons/mediatype/audio.ts +0 -14
  242. package/src/assets/img/icons/mediatype/collection.ts +0 -12
  243. package/src/assets/img/icons/mediatype/data.ts +0 -15
  244. package/src/assets/img/icons/mediatype/etree.ts +0 -14
  245. package/src/assets/img/icons/mediatype/film.ts +0 -14
  246. package/src/assets/img/icons/mediatype/images.ts +0 -13
  247. package/src/assets/img/icons/mediatype/radio.ts +0 -15
  248. package/src/assets/img/icons/mediatype/search.ts +0 -14
  249. package/src/assets/img/icons/mediatype/software.ts +0 -13
  250. package/src/assets/img/icons/mediatype/texts.ts +0 -13
  251. package/src/assets/img/icons/mediatype/tv-commercial.ts +0 -12
  252. package/src/assets/img/icons/mediatype/tv-fact-check.ts +0 -12
  253. package/src/assets/img/icons/mediatype/tv-quote.ts +0 -12
  254. package/src/assets/img/icons/mediatype/tv.ts +0 -14
  255. package/src/assets/img/icons/mediatype/video.ts +0 -14
  256. package/src/assets/img/icons/mediatype/web.ts +0 -13
  257. package/src/assets/img/icons/null-result.ts +0 -5
  258. package/src/assets/img/icons/quote.ts +0 -7
  259. package/src/assets/img/icons/restricted.ts +0 -13
  260. package/src/assets/img/icons/reviews.ts +0 -11
  261. package/src/assets/img/icons/upload.ts +0 -12
  262. package/src/assets/img/icons/views.ts +0 -11
  263. package/src/circular-activity-indicator.ts +0 -64
  264. package/src/collection-browser.ts +0 -3165
  265. package/src/collection-facets/facet-row-template.ts +0 -242
  266. package/src/collection-facets/facet-row.ts +0 -122
  267. package/src/collection-facets/facet-tombstone-row.ts +0 -40
  268. package/src/collection-facets/facets-template.ts +0 -85
  269. package/src/collection-facets/models.ts +0 -16
  270. package/src/collection-facets/more-facets-content.ts +0 -951
  271. package/src/collection-facets/more-facets-scroller.ts +0 -485
  272. package/src/collection-facets/page-window.ts +0 -247
  273. package/src/collection-facets/smart-facets/dedupe.ts +0 -44
  274. package/src/collection-facets/smart-facets/heuristics/browser-language/browser-language-heuristic.ts +0 -27
  275. package/src/collection-facets/smart-facets/heuristics/index.ts +0 -3
  276. package/src/collection-facets/smart-facets/heuristics/query-keywords/query-keywords-heuristic.ts +0 -17
  277. package/src/collection-facets/smart-facets/heuristics/query-keywords/query-keywords-map.ts +0 -70
  278. package/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-entity-map.ts +0 -79
  279. package/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-heuristic.ts +0 -93
  280. package/src/collection-facets/smart-facets/models.ts +0 -36
  281. package/src/collection-facets/smart-facets/smart-facet-bar.ts +0 -437
  282. package/src/collection-facets/smart-facets/smart-facet-button.ts +0 -145
  283. package/src/collection-facets/smart-facets/smart-facet-dropdown.ts +0 -185
  284. package/src/collection-facets/smart-facets/smart-facet-equals.ts +0 -16
  285. package/src/collection-facets/smart-facets/smart-facet-heuristics.ts +0 -26
  286. package/src/collection-facets/toggle-switch.ts +0 -175
  287. package/src/collection-facets.ts +0 -1013
  288. package/src/data-source/collection-browser-data-source-interface.ts +0 -351
  289. package/src/data-source/collection-browser-data-source.ts +0 -1474
  290. package/src/data-source/collection-browser-query-state.ts +0 -60
  291. package/src/data-source/models.ts +0 -56
  292. package/src/empty-placeholder.ts +0 -192
  293. package/src/expanded-date-picker.ts +0 -191
  294. package/src/language-code-handler/language-code-handler.ts +0 -64
  295. package/src/language-code-handler/language-code-mapping.ts +0 -564
  296. package/src/manage/manage-bar.ts +0 -276
  297. package/src/manage/remove-items-modal-content.ts +0 -102
  298. package/src/mediatype/mediatype-config.ts +0 -146
  299. package/src/models.ts +0 -912
  300. package/src/restoration-state-handler.ts +0 -550
  301. package/src/sort-filter-bar/alpha-bar-tooltip.ts +0 -53
  302. package/src/sort-filter-bar/alpha-bar.ts +0 -252
  303. package/src/sort-filter-bar/img/compact.ts +0 -5
  304. package/src/sort-filter-bar/img/list.ts +0 -5
  305. package/src/sort-filter-bar/img/sort-toggle-disabled.ts +0 -15
  306. package/src/sort-filter-bar/img/sort-toggle-down.ts +0 -17
  307. package/src/sort-filter-bar/img/sort-toggle-up.ts +0 -17
  308. package/src/sort-filter-bar/img/sort-triangle.ts +0 -5
  309. package/src/sort-filter-bar/img/tile.ts +0 -5
  310. package/src/sort-filter-bar/sort-filter-bar.ts +0 -733
  311. package/src/styles/ia-button.ts +0 -139
  312. package/src/styles/item-image-styles.ts +0 -124
  313. package/src/styles/sr-only.ts +0 -18
  314. package/src/styles/tile-action-styles.ts +0 -59
  315. package/src/tiles/base-tile-component.ts +0 -124
  316. package/src/tiles/collection-browser-loading-tile.ts +0 -26
  317. package/src/tiles/grid/account-tile.ts +0 -113
  318. package/src/tiles/grid/collection-tile.ts +0 -184
  319. package/src/tiles/grid/item-tile.ts +0 -347
  320. package/src/tiles/grid/search-tile.ts +0 -90
  321. package/src/tiles/grid/styles/tile-grid-shared-styles.ts +0 -130
  322. package/src/tiles/grid/tile-stats.ts +0 -211
  323. package/src/tiles/hover/hover-pane-controller.ts +0 -638
  324. package/src/tiles/hover/tile-hover-pane.ts +0 -184
  325. package/src/tiles/image-block.ts +0 -162
  326. package/src/tiles/item-image.ts +0 -214
  327. package/src/tiles/list/tile-list-compact-header.ts +0 -112
  328. package/src/tiles/list/tile-list-compact.ts +0 -278
  329. package/src/tiles/list/tile-list.ts +0 -718
  330. package/src/tiles/models.ts +0 -21
  331. package/src/tiles/overlay/icon-overlay.ts +0 -57
  332. package/src/tiles/overlay/text-overlay.ts +0 -79
  333. package/src/tiles/review-block.ts +0 -130
  334. package/src/tiles/text-snippet-block.ts +0 -132
  335. package/src/tiles/tile-dispatcher.ts +0 -637
  336. package/src/tiles/tile-display-value-provider.ts +0 -133
  337. package/src/tiles/tile-mediatype-icon.ts +0 -133
  338. package/src/utils/analytics-events.ts +0 -29
  339. package/src/utils/array-equals.ts +0 -8
  340. package/src/utils/collapse-repeated-quotes.ts +0 -13
  341. package/src/utils/date-filter-field.ts +0 -11
  342. package/src/utils/facet-utils.ts +0 -183
  343. package/src/utils/format-count.ts +0 -95
  344. package/src/utils/format-date.ts +0 -62
  345. package/src/utils/format-unit-size.ts +0 -43
  346. package/src/utils/local-date-from-utc.ts +0 -15
  347. package/src/utils/log.ts +0 -14
  348. package/src/utils/normalize-filter-text.ts +0 -54
  349. package/src/utils/resolve-mediatype.ts +0 -26
  350. package/src/utils/sha1.ts +0 -9
  351. package/test/collection-browser.test.ts +0 -2639
  352. package/test/collection-facets/facet-row.test.ts +0 -421
  353. package/test/collection-facets/facets-template.test.ts +0 -139
  354. package/test/collection-facets/more-facets-content.test.ts +0 -716
  355. package/test/collection-facets/more-facets-scroller.test.ts +0 -401
  356. package/test/collection-facets/page-window.test.ts +0 -208
  357. package/test/collection-facets/toggle-switch.test.ts +0 -164
  358. package/test/collection-facets.test.ts +0 -928
  359. package/test/data-source/collection-browser-data-source.test.ts +0 -193
  360. package/test/empty-placeholder.test.ts +0 -88
  361. package/test/expanded-date-picker.test.ts +0 -201
  362. package/test/icon-overlay.test.ts +0 -38
  363. package/test/image-block.test.ts +0 -247
  364. package/test/item-image.test.ts +0 -220
  365. package/test/manage/manage-bar.test.ts +0 -347
  366. package/test/manage/remove-items-modal-content.test.ts +0 -81
  367. package/test/mediatype-config.test.ts +0 -11
  368. package/test/mocks/mock-analytics-handler.ts +0 -30
  369. package/test/mocks/mock-search-responses.ts +0 -1420
  370. package/test/mocks/mock-search-service.ts +0 -136
  371. package/test/restoration-state-handler.test.ts +0 -480
  372. package/test/review-block.test.ts +0 -62
  373. package/test/sort-filter-bar/alpha-bar-tooltip.test.ts +0 -17
  374. package/test/sort-filter-bar/alpha-bar.test.ts +0 -101
  375. package/test/sort-filter-bar/sort-filter-bar.test.ts +0 -443
  376. package/test/text-overlay.test.ts +0 -55
  377. package/test/text-snippet-block.test.ts +0 -85
  378. package/test/tile-stats.test.ts +0 -191
  379. package/test/tiles/grid/account-tile.test.ts +0 -121
  380. package/test/tiles/grid/collection-tile.test.ts +0 -114
  381. package/test/tiles/grid/item-tile.test.ts +0 -520
  382. package/test/tiles/grid/search-tile.test.ts +0 -75
  383. package/test/tiles/hover/hover-pane-controller.test.ts +0 -482
  384. package/test/tiles/hover/tile-hover-pane.test.ts +0 -80
  385. package/test/tiles/list/tile-list-compact-header.test.ts +0 -43
  386. package/test/tiles/list/tile-list-compact.test.ts +0 -282
  387. package/test/tiles/list/tile-list.test.ts +0 -576
  388. package/test/tiles/tile-dispatcher.test.ts +0 -320
  389. package/test/tiles/tile-display-value-provider.test.ts +0 -172
  390. package/test/tiles/tile-mediatype-icon.test.ts +0 -160
  391. package/test/utils/array-equals.test.ts +0 -31
  392. package/test/utils/format-count.test.ts +0 -32
  393. package/test/utils/format-date.test.ts +0 -89
  394. package/test/utils/format-unit-size.test.ts +0 -21
  395. package/test/utils/local-date-from-utc.test.ts +0 -37
  396. package/test/utils/normalize-filter-text.test.ts +0 -87
  397. package/tsconfig.json +0 -25
  398. package/types/dompurify.d.ts +0 -1
  399. package/vite.config.ts +0 -29
  400. package/web-dev-server.config.mjs +0 -30
  401. package/web-test-runner.config.mjs +0 -57
@@ -1,951 +0,0 @@
1
- import {
2
- css,
3
- CSSResultGroup,
4
- html,
5
- LitElement,
6
- nothing,
7
- PropertyValues,
8
- TemplateResult,
9
- } from 'lit';
10
- import { customElement, property, query, state } from 'lit/decorators.js';
11
- import { ifDefined } from 'lit/directives/if-defined.js';
12
- import { repeat } from 'lit/directives/repeat.js';
13
- import { when } from 'lit/directives/when.js';
14
- import {
15
- Aggregation,
16
- Bucket,
17
- SearchServiceInterface,
18
- SearchParams,
19
- SearchType,
20
- AggregationSortType,
21
- FilterMap,
22
- PageType,
23
- } from '@internetarchive/search-service';
24
- import type { ModalManagerInterface } from '@internetarchive/modal-manager';
25
- import type { AnalyticsManagerInterface } from '@internetarchive/analytics-manager';
26
- import { msg, str } from '@lit/localize';
27
- import {
28
- SelectedFacets,
29
- FacetGroup,
30
- FacetBucket,
31
- FacetOption,
32
- facetTitles,
33
- facetPluralTitles,
34
- suppressedCollections,
35
- valueFacetSort,
36
- defaultFacetSort,
37
- getDefaultSelectedFacets,
38
- FacetEventDetails,
39
- tvMoreFacetSort,
40
- } from '../models';
41
- import type {
42
- CollectionTitles,
43
- PageSpecifierParams,
44
- TVChannelAliases,
45
- } from '../data-source/models';
46
- import '@internetarchive/elements/ia-status-indicator/ia-status-indicator';
47
- import '@internetarchive/ia-clearable-text-input';
48
- import './more-facets-scroller';
49
- import type { MoreFacetsScroller } from './more-facets-scroller';
50
- import {
51
- analyticsActions,
52
- analyticsCategories,
53
- } from '../utils/analytics-events';
54
- import './toggle-switch';
55
- import { srOnlyStyle } from '../styles/sr-only';
56
- import checkIcon from '../assets/img/icons/check';
57
- import eyeClosedIcon from '../assets/img/icons/eye-closed';
58
- import closeCircleDark from '../assets/img/icons/close-circle-dark';
59
- import {
60
- mergeSelectedFacets,
61
- updateSelectedFacetBucket,
62
- } from '../utils/facet-utils';
63
- import {
64
- filterTextIncludes,
65
- normalizeFilterText,
66
- type NormalizedFilterText,
67
- } from '../utils/normalize-filter-text';
68
- import { log } from '../utils/log';
69
- import { MORE_FACETS__MAX_AGGREGATIONS } from './models';
70
-
71
- @customElement('more-facets-content')
72
- export class MoreFacetsContent extends LitElement {
73
- @property({ type: String }) facetKey?: FacetOption;
74
-
75
- @property({ type: String }) query?: string;
76
-
77
- @property({ type: Array }) identifiers?: string[];
78
-
79
- @property({ type: Object }) filterMap?: FilterMap;
80
-
81
- @property({ type: Number }) searchType?: SearchType;
82
-
83
- @property({ type: Object }) pageSpecifierParams?: PageSpecifierParams;
84
-
85
- @property({ type: Object })
86
- collectionTitles?: CollectionTitles;
87
-
88
- @property({ type: Object })
89
- tvChannelAliases?: TVChannelAliases;
90
-
91
- /**
92
- * Whether we are waiting for facet data to load.
93
- * We begin with this set to true so that we show an initial loading indicator.
94
- */
95
- @property({ type: Boolean }) facetsLoading = true;
96
-
97
- /**
98
- * The set of pre-existing facet selections (including both selected & negated facets).
99
- */
100
- @property({ type: Object }) selectedFacets?: SelectedFacets;
101
-
102
- @property({ type: Number }) sortedBy: AggregationSortType =
103
- AggregationSortType.COUNT;
104
-
105
- @property({ type: Boolean }) isTvSearch = false;
106
-
107
- @property({ type: Object }) modalManager?: ModalManagerInterface;
108
-
109
- @property({ type: Object }) searchService?: SearchServiceInterface;
110
-
111
- @property({ type: Object, attribute: false })
112
- analyticsHandler?: AnalyticsManagerInterface;
113
-
114
- /**
115
- * The full set of aggregations received from the search service
116
- */
117
- @state() private aggregations?: Record<string, Aggregation>;
118
-
119
- /**
120
- * A FacetGroup storing the full set of facet buckets to be shown on the dialog.
121
- */
122
- @state() private facetGroup?: FacetGroup;
123
-
124
- /**
125
- * An object holding any changes the patron has made to their facet selections
126
- * within the modal dialog but which they have not yet applied. These are
127
- * eventually merged into the existing `selectedFacets` when the patron applies
128
- * their changes, or discarded if they cancel/close the dialog.
129
- */
130
- @state() private unappliedFacetChanges: SelectedFacets =
131
- getDefaultSelectedFacets();
132
-
133
- /**
134
- * Text the patron has entered to narrow down the facet values shown.
135
- */
136
- @state() private filterText = '';
137
-
138
- /**
139
- * Whether the search for this facet's values failed, either with an error
140
- * result or by throwing.
141
- */
142
- @state() private loadFailed = false;
143
-
144
- /**
145
- * The buckets from `facetGroup` that match `filterText`, in display order.
146
- * Derived in `willUpdate`.
147
- */
148
- private filteredBuckets: FacetBucket[] = [];
149
-
150
- /**
151
- * Each bucket's display text in the normalized form that filtering compares
152
- * against, keyed by bucket key. Filled lazily so that each value is only
153
- * normalized once, however many times the filter text changes.
154
- */
155
- private filterKeys = new Map<string, NormalizedFilterText>();
156
-
157
- /**
158
- * The values currently selected or hidden, in the order they were selected.
159
- * Shown as chiclets above the list. Derived in `willUpdate`.
160
- */
161
- private chosenBuckets: FacetBucket[] = [];
162
-
163
- /**
164
- * Position of a chiclet that was just removed, whose neighbor should get
165
- * focus once it's gone.
166
- */
167
- private chicletFocusIndex?: number;
168
-
169
- @query('more-facets-scroller')
170
- private scroller?: MoreFacetsScroller;
171
-
172
- @query('ia-clearable-text-input')
173
- private filterInput?: HTMLElement;
174
-
175
- willUpdate(changed: PropertyValues): void {
176
- if (changed.has('aggregations')) {
177
- this.filterKeys.clear();
178
- }
179
-
180
- const facetGroupChanged =
181
- changed.has('aggregations') ||
182
- changed.has('sortedBy') ||
183
- changed.has('selectedFacets') ||
184
- changed.has('unappliedFacetChanges');
185
- if (facetGroupChanged) {
186
- // Convert the merged selected facets & aggregations into a facet group
187
- this.facetGroup = this.mergedFacets;
188
- this.chosenBuckets = this.listChosenBuckets();
189
- }
190
-
191
- if (facetGroupChanged || changed.has('filterText')) {
192
- this.filteredBuckets = this.filterBuckets();
193
- }
194
-
195
- // If any of the search properties change, it triggers a facet fetch
196
- if (
197
- changed.has('facetKey') ||
198
- changed.has('query') ||
199
- changed.has('searchType') ||
200
- changed.has('filterMap')
201
- ) {
202
- this.facetsLoading = true;
203
- this.loadFailed = false;
204
- this.sortedBy =
205
- this.searchType === SearchType.TV
206
- ? tvMoreFacetSort[this.facetKey as FacetOption]
207
- : defaultFacetSort[this.facetKey as FacetOption];
208
-
209
- this.updateSpecificFacets();
210
- }
211
- }
212
-
213
- updated(changed: PropertyValues): void {
214
- // A new filter or sort order shows different values, so start over from
215
- // the first page rather than somewhere in the middle of them.
216
- if (changed.has('filterText') || changed.has('sortedBy')) {
217
- this.scroller?.scrollToPage(0);
218
- }
219
-
220
- // A removed chiclet took its focused button with it; move focus to the
221
- // chiclet that took its place, or back to the filter field if none are left.
222
- if (this.chicletFocusIndex !== undefined) {
223
- const buttons =
224
- this.shadowRoot?.querySelectorAll<HTMLElement>('.chiclet-remove') ?? [];
225
- const index = Math.min(this.chicletFocusIndex, buttons.length - 1);
226
- this.chicletFocusIndex = undefined;
227
- (buttons[index] ?? this.filterInput)?.focus();
228
- }
229
- }
230
-
231
- firstUpdated(): void {
232
- this.setupEscapeListeners();
233
- }
234
-
235
- disconnectedCallback(): void {
236
- super.disconnectedCallback();
237
- document.removeEventListener('keydown', this.escapeHandler);
238
- }
239
-
240
- /**
241
- * Close more facets modal on Escape click
242
- */
243
- private escapeHandler = (e: KeyboardEvent): void => {
244
- if (e.key === 'Escape') this.modalManager?.closeModal();
245
- };
246
-
247
- private setupEscapeListeners() {
248
- if (this.modalManager) {
249
- document.addEventListener('keydown', this.escapeHandler);
250
- }
251
- }
252
-
253
- /**
254
- * Whether facet requests are for the search_results page type (either defaulted or explicitly).
255
- */
256
- private get isSearchResultsPage(): boolean {
257
- // Default page type is search_results when none is specified, so we check
258
- // for undefined as well.
259
- const pageType: PageType | undefined = this.pageSpecifierParams?.pageType;
260
- return pageType === undefined || pageType === 'search_results';
261
- }
262
-
263
- /**
264
- * Get specific facets data from search-service API based of currently query params
265
- * - this.aggregations - hold result of search service and being used for further processing.
266
- */
267
- async updateSpecificFacets(): Promise<void> {
268
- if (!this.facetKey) return; // Can't fetch facets if we don't know what type of facets we need!
269
-
270
- const trimmedQuery = this.query?.trim();
271
- if (!trimmedQuery && this.isSearchResultsPage) return; // The search page _requires_ a query
272
-
273
- const aggregations = {
274
- simpleParams: [this.facetKey],
275
- };
276
- const aggregationsSize = MORE_FACETS__MAX_AGGREGATIONS; // Only request the 10K highest-count facets
277
-
278
- const params: SearchParams = {
279
- ...this.pageSpecifierParams,
280
- query: trimmedQuery || '',
281
- identifiers: this.identifiers,
282
- filters: this.filterMap,
283
- aggregations,
284
- aggregationsSize,
285
- rows: 0, // todo - do we want server-side pagination with offset/page/limit flag?
286
- };
287
-
288
- try {
289
- const results = await this.searchService?.search(params, this.searchType);
290
- const response = results?.success?.response;
291
- if (!response) {
292
- log('More facets search failed', results?.error);
293
- this.loadFailed = true;
294
- this.aggregations = undefined;
295
- return;
296
- }
297
-
298
- // Record collection titles before the aggregations, so that they're
299
- // available for sorting & filtering once the facet group is built.
300
- const { collectionTitles } = response;
301
- if (collectionTitles) {
302
- for (const [id, title] of Object.entries(collectionTitles)) {
303
- this.collectionTitles?.set(id, title);
304
- }
305
- }
306
-
307
- this.aggregations = response.aggregations;
308
- } catch (err) {
309
- log('More facets search threw', err);
310
- this.loadFailed = true;
311
- this.aggregations = undefined;
312
- } finally {
313
- this.facetsLoading = false;
314
- }
315
- }
316
-
317
- /**
318
- * Combines the selected facets with the aggregations into the single list of
319
- * values the dialog shows. Selected and hidden values keep their place in the
320
- * current sort order rather than moving to the front; the chiclets above the
321
- * list are what call them out.
322
- */
323
- private get mergedFacets(): FacetGroup | undefined {
324
- if (!this.facetKey || !this.selectedFacets) return undefined;
325
-
326
- const { aggregationFacetGroup } = this;
327
-
328
- // If we don't have any aggregations, then there is nothing to show yet
329
- if (!aggregationFacetGroup) return undefined;
330
-
331
- const selections = this.currentSelections;
332
-
333
- // Mark each aggregated value with its selection state, if it has one
334
- const buckets = aggregationFacetGroup.buckets.map(bucket => {
335
- const selection = selections[bucket.key];
336
- return selection ? { ...bucket, state: selection.state } : bucket;
337
- });
338
-
339
- // Values selected before the dialog opened can be missing from the
340
- // aggregations (a hidden value is excluded from the results it would be
341
- // counted in). Slot them in where the current sort puts them, so they can
342
- // still be changed from the list.
343
- const aggregatedKeys = new Set(buckets.map(b => b.key));
344
- const preexisting = this.selectedFacets[this.facetKey] ?? {};
345
- for (const [key, data] of Object.entries(preexisting)) {
346
- if (aggregatedKeys.has(key)) continue;
347
- this.insertInSortOrder(buckets, {
348
- displayText: this.displayTextFor(key),
349
- key,
350
- count: data.count,
351
- state: selections[key]?.state ?? data.state,
352
- });
353
- }
354
-
355
- // For TV creator facets, uppercase the display text
356
- if (this.facetKey === 'creator' && this.isTvSearch) {
357
- buckets.forEach(b => {
358
- b.displayText = (b.displayText ?? b.key)?.toLocaleUpperCase();
359
-
360
- const channelLabel = this.tvChannelAliases?.get(b.displayText);
361
- if (channelLabel && channelLabel !== b.displayText) {
362
- b.extraNote = `(${channelLabel})`;
363
- }
364
- });
365
- }
366
-
367
- return { ...aggregationFacetGroup, buckets };
368
- }
369
-
370
- /**
371
- * This facet type's selections: the ones made before the dialog opened,
372
- * overridden by any unapplied changes made in it. Values stay in the order
373
- * they were first selected, and cleared ones remain with state `'none'`.
374
- */
375
- private get currentSelections(): Record<string, FacetBucket> {
376
- if (!this.facetKey) return {};
377
- return {
378
- ...this.selectedFacets?.[this.facetKey],
379
- ...this.unappliedFacetChanges[this.facetKey],
380
- };
381
- }
382
-
383
- /**
384
- * The values that are currently selected or hidden, in the order they were
385
- * selected, as they appear in `facetGroup`.
386
- */
387
- private listChosenBuckets(): FacetBucket[] {
388
- const byKey = new Map(this.facetGroup?.buckets.map(b => [b.key, b]));
389
- // Without a list (e.g. the search failed), fall back on the selections
390
- // themselves, so they can still be seen and cleared.
391
- return Object.entries(this.currentSelections)
392
- .map(
393
- ([key, selection]) =>
394
- byKey.get(key) ?? {
395
- ...selection,
396
- displayText: this.displayTextFor(key),
397
- },
398
- )
399
- .filter(bucket => bucket.state !== 'none');
400
- }
401
-
402
- /**
403
- * Inserts `bucket` ahead of the first bucket that the current sort would put
404
- * after it.
405
- */
406
- private insertInSortOrder(buckets: FacetBucket[], bucket: FacetBucket): void {
407
- const index = buckets.findIndex(b => this.compareForSort(bucket, b) < 0);
408
- buckets.splice(index === -1 ? buckets.length : index, 0, bucket);
409
- }
410
-
411
- /**
412
- * Orders two buckets the way the aggregations are ordered for the current
413
- * sort (see `getSortedBuckets` in search-service).
414
- */
415
- private compareForSort(a: FacetBucket, b: FacetBucket): number {
416
- switch (this.sortedBy) {
417
- case AggregationSortType.ALPHABETICAL:
418
- return (a.displayText ?? a.key).localeCompare(b.displayText ?? b.key);
419
- case AggregationSortType.NUMERIC:
420
- return Number(b.key) - Number(a.key);
421
- default:
422
- return b.count - a.count;
423
- }
424
- }
425
-
426
- /**
427
- * The text patrons see for a bucket: the collection title for collections,
428
- * and the bucket key for everything else.
429
- */
430
- private displayTextFor(key: string): string {
431
- const collectionTitle =
432
- this.facetKey === 'collection'
433
- ? this.collectionTitles?.get(key)
434
- : undefined;
435
- return collectionTitle ?? key;
436
- }
437
-
438
- /**
439
- * Converts the raw `aggregations` for the current facet key to a `FacetGroup`,
440
- * which is easier to work with.
441
- */
442
- private get aggregationFacetGroup(): FacetGroup | undefined {
443
- if (!this.aggregations || !this.facetKey) return undefined;
444
-
445
- const currentAggregation = this.aggregations[this.facetKey];
446
- if (!currentAggregation) return undefined;
447
-
448
- const facetGroupTitle = facetTitles[this.facetKey];
449
-
450
- // Order the facets according to the current sort option
451
- let sortedBuckets = currentAggregation.getSortedBuckets(
452
- this.sortedBy,
453
- ) as Bucket[];
454
-
455
- if (this.facetKey === 'collection') {
456
- // we are not showing fav- collections or certain deemphasized collections in facets
457
- sortedBuckets = sortedBuckets?.filter(bucket => {
458
- const bucketKey = bucket?.key?.toString();
459
- return (
460
- !suppressedCollections[bucketKey] && !bucketKey?.startsWith('fav-')
461
- );
462
- });
463
- }
464
-
465
- // Construct the array of facet buckets from the aggregation buckets
466
- const facetBuckets: FacetBucket[] = sortedBuckets.map(bucket => {
467
- const bucketKeyStr = `${bucket.key}`;
468
- return {
469
- displayText: this.displayTextFor(bucketKeyStr),
470
- key: bucketKeyStr,
471
- count: bucket.doc_count,
472
- state: 'none',
473
- };
474
- });
475
-
476
- // Collections sorted alphabetically should be in order of the titles
477
- // patrons see, not of the identifiers that getSortedBuckets used.
478
- if (
479
- this.facetKey === 'collection' &&
480
- this.sortedBy === AggregationSortType.ALPHABETICAL
481
- ) {
482
- facetBuckets.sort((a, b) =>
483
- (a.displayText ?? a.key).localeCompare(b.displayText ?? b.key),
484
- );
485
- }
486
-
487
- return {
488
- title: facetGroupTitle,
489
- key: this.facetKey,
490
- buckets: facetBuckets,
491
- };
492
- }
493
-
494
- /**
495
- * The buckets whose visible text contains the filter text, ignoring case,
496
- * accents and punctuation.
497
- */
498
- private filterBuckets(): FacetBucket[] {
499
- const buckets = this.facetGroup?.buckets ?? [];
500
- const needle = normalizeFilterText(this.filterText);
501
- if (!needle.spaced) return buckets;
502
- return buckets.filter(bucket =>
503
- filterTextIncludes(this.filterKeyFor(bucket), needle),
504
- );
505
- }
506
-
507
- private filterKeyFor(bucket: FacetBucket): NormalizedFilterText {
508
- let filterKey = this.filterKeys.get(bucket.key);
509
- if (filterKey === undefined) {
510
- const visibleText = [bucket.displayText ?? bucket.key, bucket.extraNote]
511
- .filter(Boolean)
512
- .join(' ');
513
- filterKey = normalizeFilterText(visibleText);
514
- this.filterKeys.set(bucket.key, filterKey);
515
- }
516
- return filterKey;
517
- }
518
-
519
- /**
520
- * Whether the patron's filter text has ruled out every value
521
- */
522
- private get noValuesMatch(): boolean {
523
- const isFiltering = normalizeFilterText(this.filterText).spaced !== '';
524
- return isFiltering && this.filteredBuckets.length === 0;
525
- }
526
-
527
- private get moreFacetsTemplate(): TemplateResult {
528
- const valuesLabel = this.facetKey
529
- ? msg(str`${facetTitles[this.facetKey]} values`)
530
- : undefined;
531
- return html`
532
- <more-facets-scroller
533
- .facetType=${this.facetKey}
534
- .buckets=${this.filteredBuckets}
535
- .collectionTitles=${this.collectionTitles}
536
- ?omitHideButtons=${this.facetGroup?.buckets.length === 1}
537
- label=${ifDefined(valuesLabel)}
538
- @facetClick=${this.facetClicked}
539
- @pageChanged=${this.pageChanged}
540
- ></more-facets-scroller>
541
- ${when(
542
- this.loadFailed,
543
- () => this.loadErrorTemplate,
544
- () => when(this.noValuesMatch, () => this.noMatchesTemplate),
545
- )}
546
- `;
547
- }
548
-
549
- /**
550
- * A chiclet for each selected or hidden value, each with a button to clear it
551
- */
552
- private get chicletsTemplate(): TemplateResult {
553
- const valuesName = this.facetKey ? facetPluralTitles[this.facetKey] : '';
554
- return html`
555
- <ul class="chiclets" aria-label=${msg(str`Selected ${valuesName}`)}>
556
- ${repeat(
557
- this.chosenBuckets,
558
- bucket => bucket.key,
559
- (bucket, index) => this.chicletTemplate(bucket, index),
560
- )}
561
- </ul>
562
- `;
563
- }
564
-
565
- private chicletTemplate(bucket: FacetBucket, index: number): TemplateResult {
566
- const isHidden = bucket.state === 'hidden';
567
- const text = [bucket.displayText ?? bucket.key, bucket.extraNote]
568
- .filter(Boolean)
569
- .join(' ');
570
- const removeLabel = isHidden
571
- ? msg(str`Unhide ${text}`)
572
- : msg(str`Deselect ${text}`);
573
-
574
- return html`
575
- <li class="chiclet" title=${text}>
576
- <span class="chiclet-icon" aria-hidden="true"
577
- >${isHidden ? eyeClosedIcon : checkIcon}</span
578
- >
579
- <span class="sr-only"
580
- >${isHidden ? msg('Hidden:') : msg('Selected:')}</span
581
- >
582
- <span class="chiclet-text">${text}</span>
583
- <button
584
- type="button"
585
- class="chiclet-remove"
586
- aria-label=${removeLabel}
587
- @click=${() => this.chicletRemoved(bucket, index)}
588
- >
589
- ${closeCircleDark}
590
- </button>
591
- </li>
592
- `;
593
- }
594
-
595
- private get noMatchesTemplate(): TemplateResult {
596
- return html`<p class="facets-message no-matches" role="status">
597
- ${msg('No matching values found.')}
598
- </p>`;
599
- }
600
-
601
- private get loadErrorTemplate(): TemplateResult {
602
- return html`<p class="facets-message load-error" role="alert">
603
- ${msg('Sorry, these values couldn’t be loaded. Please try again later.')}
604
- </p>`;
605
- }
606
-
607
- private get loaderTemplate(): TemplateResult {
608
- return html`
609
- <ia-status-indicator
610
- class="facets-loader"
611
- mode="loading"
612
- ></ia-status-indicator>
613
- `;
614
- }
615
-
616
- private get footerTemplate(): TemplateResult {
617
- return html`
618
- <div class="footer">
619
- <button class="btn btn-cancel" type="button" @click=${this.cancelClick}>
620
- Cancel
621
- </button>
622
- <button
623
- class="btn btn-submit"
624
- type="button"
625
- @click=${this.applySearchFacetsClicked}
626
- >
627
- Apply filters
628
- </button>
629
- </div>
630
- `;
631
- }
632
-
633
- private sortFacetAggregation(facetSortType: AggregationSortType) {
634
- this.sortedBy = facetSortType;
635
- this.dispatchEvent(
636
- new CustomEvent('sortedFacets', { detail: this.sortedBy }),
637
- );
638
- }
639
-
640
- private get modalHeaderTemplate(): TemplateResult {
641
- const facetSort =
642
- this.sortedBy ?? defaultFacetSort[this.facetKey as FacetOption];
643
- const defaultSwitchSide =
644
- facetSort === AggregationSortType.COUNT ? 'left' : 'right';
645
- const valuesName = this.facetKey ? facetPluralTitles[this.facetKey] : '';
646
- // From the facet key rather than the facet group, which is missing
647
- // until the values load (or if they fail to)
648
- const title = this.facetKey ? facetTitles[this.facetKey] : '';
649
-
650
- return html`<span class="sr-only">${msg('More facets for:')}</span>
651
- <span class="title">${title}</span>
652
- <span class="header-controls">
653
- <span class="sort-controls">
654
- <label class="sort-label">${msg('Sort by:')}</label>
655
- ${this.facetKey
656
- ? html`<toggle-switch
657
- class="sort-toggle"
658
- leftValue=${AggregationSortType.COUNT}
659
- leftLabel="Count"
660
- rightValue=${valueFacetSort[this.facetKey]}
661
- .rightLabel=${title}
662
- side=${defaultSwitchSide}
663
- @change=${(e: CustomEvent<string>) => {
664
- this.sortFacetAggregation(
665
- Number(e.detail) as AggregationSortType,
666
- );
667
- }}
668
- ></toggle-switch>`
669
- : nothing}
670
- </span>
671
- <span class="filter-controls">
672
- <label class="filter-label">${msg('Filter by:')}</label>
673
- <ia-clearable-text-input
674
- class="filter-input"
675
- .value=${this.filterText}
676
- .placeholder=${msg(str`Search ${valuesName}…`)}
677
- .screenReaderLabel=${msg(str`Filter ${valuesName}`)}
678
- .clearButtonScreenReaderLabel=${msg('Clear filter')}
679
- @input=${this.filterTextChanged}
680
- ></ia-clearable-text-input>
681
- </span>
682
- </span>`;
683
- }
684
-
685
- render() {
686
- return html`
687
- ${this.facetsLoading
688
- ? this.loaderTemplate
689
- : html`
690
- <section id="more-facets">
691
- <div class="header-content">${this.modalHeaderTemplate}</div>
692
- ${when(this.chosenBuckets.length, () => this.chicletsTemplate)}
693
- <div class="facets-content">${this.moreFacetsTemplate}</div>
694
- ${this.footerTemplate}
695
- </section>
696
- `}
697
- `;
698
- }
699
-
700
- /**
701
- * Handler for typing in (or clearing) the filter text field
702
- */
703
- private filterTextChanged(e: Event): void {
704
- const input = e.target as HTMLElement & { value: string };
705
- this.filterText = input.value;
706
- }
707
-
708
- private facetClicked(e: CustomEvent<FacetEventDetails>): void {
709
- if (!this.facetKey) return;
710
- this.unappliedFacetChanges = updateSelectedFacetBucket(
711
- this.unappliedFacetChanges,
712
- this.facetKey,
713
- e.detail.bucket,
714
- );
715
- }
716
-
717
- /**
718
- * Clears the selection a chiclet stands for, which removes the chiclet and
719
- * unchecks the value in the list.
720
- */
721
- private chicletRemoved(bucket: FacetBucket, index: number): void {
722
- if (!this.facetKey) return;
723
- this.unappliedFacetChanges = updateSelectedFacetBucket(
724
- this.unappliedFacetChanges,
725
- this.facetKey,
726
- { ...bucket, state: 'none' },
727
- );
728
- this.chicletFocusIndex = index;
729
- }
730
-
731
- private pageChanged(e: CustomEvent<number>): void {
732
- this.analyticsHandler?.sendEvent({
733
- category: analyticsCategories.default,
734
- action: analyticsActions.moreFacetsPageChange,
735
- label: `${e.detail + 1}`,
736
- });
737
- }
738
-
739
- private applySearchFacetsClicked() {
740
- const mergedSelections = mergeSelectedFacets(
741
- this.selectedFacets,
742
- this.unappliedFacetChanges,
743
- );
744
-
745
- const event = new CustomEvent<SelectedFacets>('facetsChanged', {
746
- detail: mergedSelections,
747
- bubbles: true,
748
- composed: true,
749
- });
750
- this.dispatchEvent(event);
751
-
752
- // Reset the unapplied changes back to default, now that they have been applied
753
- this.unappliedFacetChanges = getDefaultSelectedFacets();
754
-
755
- this.modalManager?.closeModal();
756
- this.analyticsHandler?.sendEvent({
757
- category: analyticsCategories.default,
758
- action: `${analyticsActions.applyMoreFacetsModal}`,
759
- label: `${this.facetKey}`,
760
- });
761
- }
762
-
763
- private cancelClick() {
764
- // Reset the unapplied changes back to default
765
- this.unappliedFacetChanges = getDefaultSelectedFacets();
766
-
767
- this.modalManager?.closeModal();
768
- this.analyticsHandler?.sendEvent({
769
- category: analyticsCategories.default,
770
- action: analyticsActions.closeMoreFacetsModal,
771
- label: `${this.facetKey}`,
772
- });
773
- }
774
-
775
- static get styles(): CSSResultGroup {
776
- const modalSubmitButton = css`var(--primaryButtonBGColor, #194880)`;
777
-
778
- return [
779
- srOnlyStyle,
780
- css`
781
- section#more-facets {
782
- padding: 10px;
783
- }
784
-
785
- .header-content .title {
786
- display: block;
787
- text-align: left;
788
- font-size: 1.8rem;
789
- padding: 0 10px;
790
- font-weight: bold;
791
- }
792
-
793
- .header-controls {
794
- display: flex;
795
- flex-wrap: wrap;
796
- align-items: center;
797
- gap: 8px 20px;
798
- padding: 5px 10px 0;
799
- }
800
-
801
- /* Each label stays on the same line as its control when these wrap */
802
- .sort-controls,
803
- .filter-controls {
804
- display: inline-flex;
805
- align-items: center;
806
- gap: 5px;
807
- white-space: nowrap;
808
- }
809
-
810
- .sort-label,
811
- .filter-label {
812
- font-size: 1.3rem;
813
- }
814
-
815
- .sort-toggle {
816
- font-weight: normal;
817
- }
818
-
819
- .filter-input {
820
- --input-height: 2.5rem;
821
- --input-font-size: 1.3rem;
822
- --input-border-radius: 4px;
823
- --input-padding: 4px 8px;
824
- --input-focused-border-color: ${modalSubmitButton};
825
- width: 16rem;
826
- }
827
-
828
- .chiclets {
829
- display: flex;
830
- flex-wrap: wrap;
831
- gap: 6px;
832
- margin: 0;
833
- padding: 10px 10px 0;
834
- list-style: none;
835
- /* About three rows; any more scroll, so the values stay in view */
836
- max-height: 7.8rem;
837
- overflow-y: auto;
838
- }
839
-
840
- .chiclet {
841
- display: inline-flex;
842
- align-items: center;
843
- gap: 4px;
844
- max-width: 24rem;
845
- padding: 2px 3px 2px 6px;
846
- border: 1px solid ${modalSubmitButton};
847
- border-radius: 5px;
848
- background: #fff;
849
- color: #2c2c2c;
850
- font-size: 1.2rem;
851
- line-height: normal;
852
- }
853
-
854
- .chiclet-icon {
855
- display: flex;
856
- flex: none;
857
- }
858
-
859
- .chiclet-icon svg {
860
- width: 12px;
861
- height: 12px;
862
- }
863
-
864
- .chiclet-text {
865
- overflow: hidden;
866
- white-space: nowrap;
867
- text-overflow: ellipsis;
868
- }
869
-
870
- .chiclet-remove {
871
- display: flex;
872
- flex: none;
873
- padding: 2px;
874
- border: none;
875
- border-radius: 50%;
876
- background: none;
877
- cursor: pointer;
878
- }
879
-
880
- .chiclet-remove svg {
881
- width: 10px;
882
- height: 10px;
883
- opacity: 0.55;
884
- }
885
-
886
- .chiclet-remove:hover svg,
887
- .chiclet-remove:focus-visible svg {
888
- opacity: 1;
889
- }
890
-
891
- .facets-content {
892
- position: relative;
893
- font-size: 1.2rem;
894
- padding: 10px 0;
895
- }
896
-
897
- .facets-message {
898
- position: absolute;
899
- inset: 0;
900
- display: flex;
901
- align-items: center;
902
- justify-content: center;
903
- margin: 0;
904
- font-size: 1.4rem;
905
- color: #666;
906
- }
907
-
908
- .facets-loader {
909
- --icon-width: 70px;
910
- margin-bottom: 20px;
911
- display: block;
912
- margin-left: auto;
913
- margin-right: auto;
914
- }
915
- .btn {
916
- border: none;
917
- padding: 10px;
918
- margin-bottom: 10px;
919
- width: auto;
920
- border-radius: 4px;
921
- cursor: pointer;
922
- font-family: inherit;
923
- }
924
- .btn-cancel {
925
- background-color: #2c2c2c;
926
- color: white;
927
- }
928
- .btn-submit {
929
- background-color: ${modalSubmitButton};
930
- color: white;
931
- }
932
- .footer {
933
- text-align: center;
934
- }
935
-
936
- @media (max-width: 560px) {
937
- /* The filter gets a line of its own here, so let it fill that line */
938
- .filter-controls {
939
- flex: 1 1 auto;
940
- }
941
- .filter-input {
942
- flex: 1 1 auto;
943
- width: auto;
944
- min-width: 12rem;
945
- --input-font-size: 1.2rem;
946
- }
947
- }
948
- `,
949
- ];
950
- }
951
- }