@internetarchive/collection-browser 4.6.0 → 4.7.1-alpha-webdev9189.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 (468) hide show
  1. package/.github/workflows/ci.yml +5 -3
  2. package/.github/workflows/gh-pages-main.yml +5 -3
  3. package/.github/workflows/npm-publish.yml +7 -4
  4. package/.github/workflows/pr-preview.yml +5 -3
  5. package/README.md +7 -23
  6. package/dist/src/app-root.d.ts +1 -1
  7. package/dist/src/assets/img/icons/arrow-left.d.ts +1 -1
  8. package/dist/src/assets/img/icons/arrow-right.d.ts +1 -1
  9. package/dist/src/assets/img/icons/chevron.d.ts +1 -1
  10. package/dist/src/assets/img/icons/close-circle-dark.d.ts +1 -1
  11. package/dist/src/assets/img/icons/contract.d.ts +1 -1
  12. package/dist/src/assets/img/icons/empty-query.d.ts +1 -1
  13. package/dist/src/assets/img/icons/expand.d.ts +1 -1
  14. package/dist/src/assets/img/icons/eye-closed.d.ts +1 -1
  15. package/dist/src/assets/img/icons/eye.d.ts +1 -1
  16. package/dist/src/assets/img/icons/favorite-filled.d.ts +1 -1
  17. package/dist/src/assets/img/icons/favorite-unfilled.d.ts +1 -1
  18. package/dist/src/assets/img/icons/filter.d.ts +1 -1
  19. package/dist/src/assets/img/icons/login-required.d.ts +1 -1
  20. package/dist/src/assets/img/icons/mediatype/account.d.ts +1 -1
  21. package/dist/src/assets/img/icons/mediatype/audio.d.ts +1 -1
  22. package/dist/src/assets/img/icons/mediatype/collection.d.ts +1 -1
  23. package/dist/src/assets/img/icons/mediatype/data.d.ts +1 -1
  24. package/dist/src/assets/img/icons/mediatype/etree.d.ts +1 -1
  25. package/dist/src/assets/img/icons/mediatype/film.d.ts +1 -1
  26. package/dist/src/assets/img/icons/mediatype/images.d.ts +1 -1
  27. package/dist/src/assets/img/icons/mediatype/radio.d.ts +1 -1
  28. package/dist/src/assets/img/icons/mediatype/search.d.ts +1 -1
  29. package/dist/src/assets/img/icons/mediatype/software.d.ts +1 -1
  30. package/dist/src/assets/img/icons/mediatype/texts.d.ts +1 -1
  31. package/dist/src/assets/img/icons/mediatype/tv-commercial.d.ts +1 -1
  32. package/dist/src/assets/img/icons/mediatype/tv-fact-check.d.ts +1 -1
  33. package/dist/src/assets/img/icons/mediatype/tv-quote.d.ts +1 -1
  34. package/dist/src/assets/img/icons/mediatype/tv.d.ts +1 -1
  35. package/dist/src/assets/img/icons/mediatype/video.d.ts +1 -1
  36. package/dist/src/assets/img/icons/mediatype/web.d.ts +1 -1
  37. package/dist/src/assets/img/icons/null-result.d.ts +1 -1
  38. package/dist/src/assets/img/icons/quote.d.ts +1 -1
  39. package/dist/src/assets/img/icons/restricted.d.ts +1 -1
  40. package/dist/src/assets/img/icons/reviews.d.ts +1 -1
  41. package/dist/src/assets/img/icons/upload.d.ts +1 -1
  42. package/dist/src/assets/img/icons/views.d.ts +1 -1
  43. package/dist/src/circular-activity-indicator.d.ts +1 -1
  44. package/dist/src/collection-browser.js +24 -2
  45. package/dist/src/collection-browser.js.map +1 -1
  46. package/dist/src/collection-facets/facet-tombstone-row.d.ts +1 -1
  47. package/dist/src/collection-facets/smart-facets/smart-facet-button.d.ts +1 -1
  48. package/dist/src/collection-facets/smart-facets/smart-facet-dropdown.d.ts +1 -1
  49. package/dist/src/collection-facets/toggle-switch.d.ts +1 -1
  50. package/dist/src/collection-facets.d.ts +2 -2
  51. package/dist/src/collection-facets.js +5 -5
  52. package/dist/src/collection-facets.js.map +1 -1
  53. package/dist/src/expanded-date-picker.d.ts +2 -2
  54. package/dist/src/expanded-date-picker.js +3 -3
  55. package/dist/src/expanded-date-picker.js.map +1 -1
  56. package/dist/src/sort-filter-bar/alpha-bar-tooltip.d.ts +1 -1
  57. package/dist/src/sort-filter-bar/img/compact.d.ts +1 -1
  58. package/dist/src/sort-filter-bar/img/list.d.ts +1 -1
  59. package/dist/src/sort-filter-bar/img/sort-toggle-disabled.d.ts +1 -1
  60. package/dist/src/sort-filter-bar/img/sort-toggle-down.d.ts +1 -1
  61. package/dist/src/sort-filter-bar/img/sort-toggle-up.d.ts +1 -1
  62. package/dist/src/sort-filter-bar/img/sort-triangle.d.ts +1 -1
  63. package/dist/src/sort-filter-bar/img/tile.d.ts +1 -1
  64. package/dist/src/sort-filter-bar/sort-filter-bar.js +1 -0
  65. package/dist/src/sort-filter-bar/sort-filter-bar.js.map +1 -1
  66. package/dist/src/tiles/collection-browser-loading-tile.d.ts +1 -1
  67. package/dist/src/tiles/image-block.d.ts +1 -1
  68. package/dist/src/tiles/item-image.d.ts +1 -1
  69. package/dist/src/tiles/item-image.js +1 -1
  70. package/dist/src/tiles/item-image.js.map +1 -1
  71. package/dist/src/tiles/list/tile-list-compact-header.d.ts +1 -1
  72. package/dist/src/tiles/list/tile-list-compact.d.ts +1 -1
  73. package/dist/src/tiles/tile-dispatcher.d.ts +1 -1
  74. package/dist/src/tiles/tile-mediatype-icon.d.ts +1 -1
  75. package/dist/test/collection-browser.test.js +38 -4
  76. package/dist/test/collection-browser.test.js.map +1 -1
  77. package/dist/test/collection-facets.test.js +2 -2
  78. package/dist/test/collection-facets.test.js.map +1 -1
  79. package/dist/test/expanded-date-picker.test.js.map +1 -1
  80. package/dist/test/sort-filter-bar/sort-filter-bar.test.js +22 -0
  81. package/dist/test/sort-filter-bar/sort-filter-bar.test.js.map +1 -1
  82. package/package.json +18 -10
  83. package/{.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/pnpm-workspace.yaml → pnpm-workspace.yaml} +0 -16
  84. package/src/collection-browser.ts +26 -4
  85. package/src/collection-facets.ts +6 -6
  86. package/src/expanded-date-picker.ts +4 -4
  87. package/src/sort-filter-bar/sort-filter-bar.ts +1 -0
  88. package/src/tiles/item-image.ts +1 -1
  89. package/test/collection-browser.test.ts +64 -9
  90. package/test/collection-facets.test.ts +2 -2
  91. package/test/expanded-date-picker.test.ts +3 -3
  92. package/test/sort-filter-bar/sort-filter-bar.test.ts +29 -0
  93. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/.editorconfig +0 -29
  94. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/.github/workflows/ci.yml +0 -27
  95. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/.github/workflows/gh-pages-main.yml +0 -39
  96. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/.github/workflows/npm-publish.yml +0 -39
  97. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/.github/workflows/pr-preview.yml +0 -38
  98. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/.husky/pre-commit +0 -1
  99. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/.prettierignore +0 -1
  100. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/LICENSE +0 -661
  101. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/README.md +0 -84
  102. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/eslint.config.mjs +0 -53
  103. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/index.html +0 -24
  104. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/index.ts +0 -29
  105. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/local.archive.org.cert +0 -86
  106. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/local.archive.org.key +0 -27
  107. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/package.json +0 -120
  108. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/renovate.json +0 -6
  109. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/app-root.ts +0 -1284
  110. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/arrow-left.ts +0 -10
  111. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/arrow-right.ts +0 -10
  112. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/chevron.ts +0 -4
  113. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/close-circle-dark.ts +0 -5
  114. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/contract.ts +0 -9
  115. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/empty-query.ts +0 -5
  116. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/expand.ts +0 -9
  117. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/eye-closed.ts +0 -5
  118. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/eye.ts +0 -5
  119. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/favorite-filled.ts +0 -10
  120. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/favorite-unfilled.ts +0 -9
  121. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/filter.ts +0 -10
  122. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/login-required.ts +0 -18
  123. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/account.ts +0 -14
  124. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/audio.ts +0 -14
  125. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/collection.ts +0 -12
  126. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/data.ts +0 -15
  127. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/etree.ts +0 -14
  128. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/film.ts +0 -14
  129. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/images.ts +0 -13
  130. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/radio.ts +0 -15
  131. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/search.ts +0 -14
  132. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/software.ts +0 -13
  133. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/texts.ts +0 -13
  134. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/tv-commercial.ts +0 -12
  135. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/tv-fact-check.ts +0 -12
  136. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/tv-quote.ts +0 -12
  137. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/tv.ts +0 -14
  138. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/video.ts +0 -14
  139. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/mediatype/web.ts +0 -13
  140. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/null-result.ts +0 -5
  141. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/quote.ts +0 -7
  142. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/restricted.ts +0 -13
  143. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/reviews.ts +0 -11
  144. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/upload.ts +0 -12
  145. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/assets/img/icons/views.ts +0 -11
  146. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/circular-activity-indicator.ts +0 -64
  147. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-browser.ts +0 -3165
  148. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/facet-row.ts +0 -309
  149. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/facet-tombstone-row.ts +0 -40
  150. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/facets-template.ts +0 -85
  151. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/models.ts +0 -10
  152. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/more-facets-content.ts +0 -644
  153. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/more-facets-pagination.ts +0 -294
  154. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/dedupe.ts +0 -44
  155. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/heuristics/browser-language/browser-language-heuristic.ts +0 -27
  156. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/heuristics/index.ts +0 -3
  157. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/heuristics/query-keywords/query-keywords-heuristic.ts +0 -17
  158. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/heuristics/query-keywords/query-keywords-map.ts +0 -70
  159. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-entity-map.ts +0 -79
  160. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-heuristic.ts +0 -93
  161. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/models.ts +0 -36
  162. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/smart-facet-bar.ts +0 -437
  163. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/smart-facet-button.ts +0 -145
  164. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/smart-facet-dropdown.ts +0 -185
  165. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/smart-facet-equals.ts +0 -16
  166. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/smart-facets/smart-facet-heuristics.ts +0 -26
  167. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets/toggle-switch.ts +0 -174
  168. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/collection-facets.ts +0 -1013
  169. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/data-source/collection-browser-data-source-interface.ts +0 -351
  170. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/data-source/collection-browser-data-source.ts +0 -1474
  171. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/data-source/collection-browser-query-state.ts +0 -60
  172. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/data-source/models.ts +0 -56
  173. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/empty-placeholder.ts +0 -192
  174. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/expanded-date-picker.ts +0 -191
  175. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/language-code-handler/language-code-handler.ts +0 -64
  176. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/language-code-handler/language-code-mapping.ts +0 -564
  177. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/manage/manage-bar.ts +0 -276
  178. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/manage/remove-items-modal-content.ts +0 -102
  179. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/mediatype/mediatype-config.ts +0 -146
  180. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/models.ts +0 -895
  181. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/restoration-state-handler.ts +0 -550
  182. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/alpha-bar-tooltip.ts +0 -53
  183. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/alpha-bar.ts +0 -252
  184. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/img/compact.ts +0 -5
  185. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/img/list.ts +0 -5
  186. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/img/sort-toggle-disabled.ts +0 -15
  187. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/img/sort-toggle-down.ts +0 -17
  188. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/img/sort-toggle-up.ts +0 -17
  189. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/img/sort-triangle.ts +0 -5
  190. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/img/tile.ts +0 -5
  191. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/sort-filter-bar/sort-filter-bar.ts +0 -733
  192. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/styles/ia-button.ts +0 -139
  193. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/styles/item-image-styles.ts +0 -124
  194. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/styles/sr-only.ts +0 -18
  195. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/styles/tile-action-styles.ts +0 -59
  196. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/base-tile-component.ts +0 -124
  197. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/collection-browser-loading-tile.ts +0 -26
  198. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/grid/account-tile.ts +0 -113
  199. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/grid/collection-tile.ts +0 -184
  200. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/grid/item-tile.ts +0 -347
  201. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/grid/search-tile.ts +0 -90
  202. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/grid/styles/tile-grid-shared-styles.ts +0 -130
  203. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/grid/tile-stats.ts +0 -211
  204. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/hover/hover-pane-controller.ts +0 -638
  205. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/hover/tile-hover-pane.ts +0 -184
  206. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/image-block.ts +0 -162
  207. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/item-image.ts +0 -214
  208. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/list/tile-list-compact-header.ts +0 -112
  209. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/list/tile-list-compact.ts +0 -278
  210. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/list/tile-list.ts +0 -718
  211. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/models.ts +0 -21
  212. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/overlay/icon-overlay.ts +0 -57
  213. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/overlay/text-overlay.ts +0 -79
  214. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/review-block.ts +0 -130
  215. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/text-snippet-block.ts +0 -132
  216. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/tile-dispatcher.ts +0 -637
  217. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/tile-display-value-provider.ts +0 -133
  218. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/tiles/tile-mediatype-icon.ts +0 -133
  219. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/analytics-events.ts +0 -29
  220. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/array-equals.ts +0 -8
  221. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/collapse-repeated-quotes.ts +0 -13
  222. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/date-filter-field.ts +0 -11
  223. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/facet-utils.ts +0 -183
  224. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/format-count.ts +0 -95
  225. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/format-date.ts +0 -62
  226. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/format-unit-size.ts +0 -43
  227. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/local-date-from-utc.ts +0 -15
  228. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/log.ts +0 -14
  229. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/resolve-mediatype.ts +0 -26
  230. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/src/utils/sha1.ts +0 -9
  231. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/collection-browser.test.ts +0 -2639
  232. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/collection-facets/facet-row.test.ts +0 -421
  233. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/collection-facets/facets-template.test.ts +0 -139
  234. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/collection-facets/more-facets-content.test.ts +0 -231
  235. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/collection-facets/more-facets-pagination.test.ts +0 -201
  236. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/collection-facets/toggle-switch.test.ts +0 -164
  237. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/collection-facets.test.ts +0 -928
  238. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/data-source/collection-browser-data-source.test.ts +0 -193
  239. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/empty-placeholder.test.ts +0 -88
  240. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/expanded-date-picker.test.ts +0 -201
  241. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/icon-overlay.test.ts +0 -38
  242. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/image-block.test.ts +0 -247
  243. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/item-image.test.ts +0 -220
  244. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/manage/manage-bar.test.ts +0 -347
  245. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/manage/remove-items-modal-content.test.ts +0 -81
  246. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/mediatype-config.test.ts +0 -11
  247. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/mocks/mock-analytics-handler.ts +0 -30
  248. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/mocks/mock-search-responses.ts +0 -1364
  249. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/mocks/mock-search-service.ts +0 -134
  250. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/restoration-state-handler.test.ts +0 -480
  251. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/review-block.test.ts +0 -62
  252. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/sort-filter-bar/alpha-bar-tooltip.test.ts +0 -17
  253. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/sort-filter-bar/alpha-bar.test.ts +0 -101
  254. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/sort-filter-bar/sort-filter-bar.test.ts +0 -443
  255. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/text-overlay.test.ts +0 -55
  256. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/text-snippet-block.test.ts +0 -85
  257. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tile-stats.test.ts +0 -191
  258. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/grid/account-tile.test.ts +0 -121
  259. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/grid/collection-tile.test.ts +0 -114
  260. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/grid/item-tile.test.ts +0 -520
  261. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/grid/search-tile.test.ts +0 -75
  262. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/hover/hover-pane-controller.test.ts +0 -482
  263. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/hover/tile-hover-pane.test.ts +0 -80
  264. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/list/tile-list-compact-header.test.ts +0 -43
  265. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/list/tile-list-compact.test.ts +0 -282
  266. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/list/tile-list.test.ts +0 -576
  267. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/tile-dispatcher.test.ts +0 -320
  268. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/tile-display-value-provider.test.ts +0 -172
  269. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/tiles/tile-mediatype-icon.test.ts +0 -160
  270. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/utils/array-equals.test.ts +0 -31
  271. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/utils/format-count.test.ts +0 -32
  272. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/utils/format-date.test.ts +0 -89
  273. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/utils/format-unit-size.test.ts +0 -21
  274. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/test/utils/local-date-from-utc.test.ts +0 -37
  275. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/tsconfig.json +0 -25
  276. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/types/dompurify.d.ts +0 -1
  277. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/vite.config.ts +0 -29
  278. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/web-dev-server.config.mjs +0 -30
  279. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/web-test-runner.config.mjs +0 -52
  280. package/.claude/worktrees/WEBDEV-8677-bump-field-parsers/yarn.lock +0 -5965
  281. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/.editorconfig +0 -29
  282. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/.github/workflows/ci.yml +0 -29
  283. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/.github/workflows/gh-pages-main.yml +0 -41
  284. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/.github/workflows/npm-publish.yml +0 -42
  285. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/.github/workflows/pr-preview.yml +0 -40
  286. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/.husky/pre-commit +0 -1
  287. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/.prettierignore +0 -1
  288. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/LICENSE +0 -661
  289. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/README.md +0 -68
  290. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/eslint.config.mjs +0 -53
  291. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/index.html +0 -24
  292. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/index.ts +0 -29
  293. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/local.archive.org.cert +0 -86
  294. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/local.archive.org.key +0 -27
  295. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/package.json +0 -129
  296. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/pnpm-lock.yaml +0 -7366
  297. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/renovate.json +0 -6
  298. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/app-root.ts +0 -1284
  299. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/arrow-left.ts +0 -10
  300. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/arrow-right.ts +0 -10
  301. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/chevron.ts +0 -4
  302. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/close-circle-dark.ts +0 -5
  303. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/contract.ts +0 -9
  304. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/empty-query.ts +0 -5
  305. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/expand.ts +0 -9
  306. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/eye-closed.ts +0 -5
  307. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/eye.ts +0 -5
  308. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/favorite-filled.ts +0 -10
  309. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/favorite-unfilled.ts +0 -9
  310. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/filter.ts +0 -10
  311. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/login-required.ts +0 -18
  312. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/mediatype/account.ts +0 -14
  313. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/mediatype/audio.ts +0 -14
  314. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/mediatype/collection.ts +0 -12
  315. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/mediatype/data.ts +0 -15
  316. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/mediatype/etree.ts +0 -14
  317. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/mediatype/film.ts +0 -14
  318. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/mediatype/images.ts +0 -13
  319. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/mediatype/radio.ts +0 -15
  320. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/mediatype/search.ts +0 -14
  321. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/mediatype/software.ts +0 -13
  322. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/mediatype/texts.ts +0 -13
  323. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/mediatype/tv-commercial.ts +0 -12
  324. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/mediatype/tv-fact-check.ts +0 -12
  325. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/mediatype/tv-quote.ts +0 -12
  326. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/mediatype/tv.ts +0 -14
  327. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/mediatype/video.ts +0 -14
  328. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/mediatype/web.ts +0 -13
  329. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/null-result.ts +0 -5
  330. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/quote.ts +0 -7
  331. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/restricted.ts +0 -13
  332. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/reviews.ts +0 -11
  333. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/upload.ts +0 -12
  334. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/assets/img/icons/views.ts +0 -11
  335. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/circular-activity-indicator.ts +0 -64
  336. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-browser.ts +0 -3165
  337. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/facet-row.ts +0 -309
  338. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/facet-tombstone-row.ts +0 -40
  339. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/facets-template.ts +0 -85
  340. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/models.ts +0 -10
  341. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/more-facets-content.ts +0 -644
  342. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/more-facets-pagination.ts +0 -294
  343. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/smart-facets/dedupe.ts +0 -44
  344. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/smart-facets/heuristics/browser-language/browser-language-heuristic.ts +0 -27
  345. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/smart-facets/heuristics/index.ts +0 -3
  346. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/smart-facets/heuristics/query-keywords/query-keywords-heuristic.ts +0 -17
  347. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/smart-facets/heuristics/query-keywords/query-keywords-map.ts +0 -70
  348. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-entity-map.ts +0 -79
  349. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-heuristic.ts +0 -93
  350. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/smart-facets/models.ts +0 -36
  351. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/smart-facets/smart-facet-bar.ts +0 -437
  352. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/smart-facets/smart-facet-button.ts +0 -145
  353. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/smart-facets/smart-facet-dropdown.ts +0 -185
  354. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/smart-facets/smart-facet-equals.ts +0 -16
  355. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/smart-facets/smart-facet-heuristics.ts +0 -26
  356. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets/toggle-switch.ts +0 -174
  357. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/collection-facets.ts +0 -1013
  358. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/data-source/collection-browser-data-source-interface.ts +0 -351
  359. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/data-source/collection-browser-data-source.ts +0 -1474
  360. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/data-source/collection-browser-query-state.ts +0 -60
  361. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/data-source/models.ts +0 -56
  362. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/empty-placeholder.ts +0 -192
  363. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/expanded-date-picker.ts +0 -191
  364. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/language-code-handler/language-code-handler.ts +0 -64
  365. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/language-code-handler/language-code-mapping.ts +0 -564
  366. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/manage/manage-bar.ts +0 -276
  367. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/manage/remove-items-modal-content.ts +0 -102
  368. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/mediatype/mediatype-config.ts +0 -146
  369. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/models.ts +0 -895
  370. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/restoration-state-handler.ts +0 -550
  371. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/sort-filter-bar/alpha-bar-tooltip.ts +0 -53
  372. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/sort-filter-bar/alpha-bar.ts +0 -252
  373. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/sort-filter-bar/img/compact.ts +0 -5
  374. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/sort-filter-bar/img/list.ts +0 -5
  375. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/sort-filter-bar/img/sort-toggle-disabled.ts +0 -15
  376. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/sort-filter-bar/img/sort-toggle-down.ts +0 -17
  377. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/sort-filter-bar/img/sort-toggle-up.ts +0 -17
  378. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/sort-filter-bar/img/sort-triangle.ts +0 -5
  379. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/sort-filter-bar/img/tile.ts +0 -5
  380. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/sort-filter-bar/sort-filter-bar.ts +0 -733
  381. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/styles/ia-button.ts +0 -139
  382. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/styles/item-image-styles.ts +0 -124
  383. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/styles/sr-only.ts +0 -18
  384. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/styles/tile-action-styles.ts +0 -59
  385. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/base-tile-component.ts +0 -124
  386. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/collection-browser-loading-tile.ts +0 -26
  387. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/grid/account-tile.ts +0 -113
  388. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/grid/collection-tile.ts +0 -184
  389. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/grid/item-tile.ts +0 -347
  390. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/grid/search-tile.ts +0 -90
  391. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/grid/styles/tile-grid-shared-styles.ts +0 -130
  392. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/grid/tile-stats.ts +0 -211
  393. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/hover/hover-pane-controller.ts +0 -638
  394. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/hover/tile-hover-pane.ts +0 -184
  395. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/image-block.ts +0 -162
  396. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/item-image.ts +0 -214
  397. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/list/tile-list-compact-header.ts +0 -112
  398. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/list/tile-list-compact.ts +0 -278
  399. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/list/tile-list.ts +0 -718
  400. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/models.ts +0 -21
  401. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/overlay/icon-overlay.ts +0 -57
  402. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/overlay/text-overlay.ts +0 -79
  403. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/review-block.ts +0 -130
  404. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/text-snippet-block.ts +0 -132
  405. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/tile-dispatcher.ts +0 -637
  406. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/tile-display-value-provider.ts +0 -133
  407. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/tiles/tile-mediatype-icon.ts +0 -133
  408. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/utils/analytics-events.ts +0 -29
  409. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/utils/array-equals.ts +0 -8
  410. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/utils/collapse-repeated-quotes.ts +0 -13
  411. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/utils/date-filter-field.ts +0 -11
  412. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/utils/facet-utils.ts +0 -183
  413. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/utils/format-count.ts +0 -95
  414. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/utils/format-date.ts +0 -62
  415. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/utils/format-unit-size.ts +0 -43
  416. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/utils/local-date-from-utc.ts +0 -15
  417. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/utils/log.ts +0 -14
  418. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/utils/resolve-mediatype.ts +0 -26
  419. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/src/utils/sha1.ts +0 -9
  420. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/collection-browser.test.ts +0 -2639
  421. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/collection-facets/facet-row.test.ts +0 -421
  422. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/collection-facets/facets-template.test.ts +0 -139
  423. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/collection-facets/more-facets-content.test.ts +0 -231
  424. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/collection-facets/more-facets-pagination.test.ts +0 -201
  425. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/collection-facets/toggle-switch.test.ts +0 -164
  426. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/collection-facets.test.ts +0 -928
  427. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/data-source/collection-browser-data-source.test.ts +0 -193
  428. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/empty-placeholder.test.ts +0 -88
  429. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/expanded-date-picker.test.ts +0 -201
  430. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/icon-overlay.test.ts +0 -38
  431. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/image-block.test.ts +0 -247
  432. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/item-image.test.ts +0 -220
  433. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/manage/manage-bar.test.ts +0 -347
  434. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/manage/remove-items-modal-content.test.ts +0 -81
  435. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/mediatype-config.test.ts +0 -11
  436. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/mocks/mock-analytics-handler.ts +0 -30
  437. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/mocks/mock-search-responses.ts +0 -1364
  438. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/mocks/mock-search-service.ts +0 -134
  439. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/restoration-state-handler.test.ts +0 -480
  440. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/review-block.test.ts +0 -62
  441. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/sort-filter-bar/alpha-bar-tooltip.test.ts +0 -17
  442. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/sort-filter-bar/alpha-bar.test.ts +0 -101
  443. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/sort-filter-bar/sort-filter-bar.test.ts +0 -443
  444. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/text-overlay.test.ts +0 -55
  445. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/text-snippet-block.test.ts +0 -85
  446. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/tile-stats.test.ts +0 -191
  447. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/tiles/grid/account-tile.test.ts +0 -121
  448. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/tiles/grid/collection-tile.test.ts +0 -114
  449. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/tiles/grid/item-tile.test.ts +0 -520
  450. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/tiles/grid/search-tile.test.ts +0 -75
  451. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/tiles/hover/hover-pane-controller.test.ts +0 -482
  452. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/tiles/hover/tile-hover-pane.test.ts +0 -80
  453. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/tiles/list/tile-list-compact-header.test.ts +0 -43
  454. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/tiles/list/tile-list-compact.test.ts +0 -282
  455. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/tiles/list/tile-list.test.ts +0 -576
  456. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/tiles/tile-dispatcher.test.ts +0 -320
  457. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/tiles/tile-display-value-provider.test.ts +0 -172
  458. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/tiles/tile-mediatype-icon.test.ts +0 -160
  459. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/utils/array-equals.test.ts +0 -31
  460. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/utils/format-count.test.ts +0 -32
  461. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/utils/format-date.test.ts +0 -89
  462. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/utils/format-unit-size.test.ts +0 -21
  463. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/test/utils/local-date-from-utc.test.ts +0 -37
  464. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/tsconfig.json +0 -25
  465. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/types/dompurify.d.ts +0 -1
  466. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/vite.config.ts +0 -29
  467. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/web-dev-server.config.mjs +0 -30
  468. package/.claude/worktrees/WEBDEV-9119-migrate-to-pnpm/web-test-runner.config.mjs +0 -52
@@ -1,2639 +0,0 @@
1
- import { aTimeout, expect, fixture } from '@open-wc/testing';
2
- import { html } from 'lit';
3
- import sinon from 'sinon';
4
- import type { InfiniteScroller } from '@internetarchive/infinite-scroller';
5
- import { FilterConstraint, SearchType } from '@internetarchive/search-service';
6
- import type { HistogramDateRange } from '@internetarchive/histogram-date-range';
7
- import type { CollectionBrowser } from '../src/collection-browser';
8
- import '../src/collection-browser';
9
- import {
10
- getDefaultSelectedFacets,
11
- FacetBucket,
12
- SelectedFacets,
13
- SortField,
14
- } from '../src/models';
15
- import { MockSearchService } from './mocks/mock-search-service';
16
- import { MockAnalyticsHandler } from './mocks/mock-analytics-handler';
17
- import {
18
- analyticsActions,
19
- analyticsCategories,
20
- } from '../src/utils/analytics-events';
21
- import type { TileDispatcher } from '../src/tiles/tile-dispatcher';
22
- import type { CollectionFacets } from '../src/collection-facets';
23
- import type { EmptyPlaceholder } from '../src/empty-placeholder';
24
- import type { SortFilterBar } from '../src/sort-filter-bar/sort-filter-bar';
25
-
26
- /**
27
- * Wait for the next tick of the event loop.
28
- *
29
- * This is necessary in some of the tests because certain collection browser
30
- * updates take more than one tick to render (e.g., date picker & query changes).
31
- * These delays are non-ideal and should eventually be investigated and fixed,
32
- * but they are minor enough that waiting for the next tick is a reasonable
33
- * testing solution for now.
34
- */
35
- const nextTick = () => aTimeout(0);
36
-
37
- describe('Collection Browser', () => {
38
- beforeEach(async () => {
39
- // Apparently query params set by one test can bleed into other tests.
40
- // Since collection browser restores its state from certain query params, we need
41
- // to clear these before each test to ensure they run in isolation from one another.
42
- const url = new URL(window.location.href);
43
- const { searchParams } = url;
44
- searchParams.delete('sin');
45
- searchParams.delete('sort');
46
- searchParams.delete('query');
47
- searchParams.delete('page');
48
- searchParams.delete('and[]');
49
- searchParams.delete('not[]');
50
- window.history.replaceState({}, '', url);
51
- });
52
-
53
- it('clears selected facets when requested', async () => {
54
- const selectedFacets = getDefaultSelectedFacets();
55
- selectedFacets.creator.foo = { count: 1, key: 'foo', state: 'selected' };
56
- const el = await fixture<CollectionBrowser>(
57
- html`<collection-browser></collection-browser>`,
58
- );
59
-
60
- el.selectedFacets = selectedFacets;
61
- await el.updateComplete;
62
- el.clearFilters(); // By default, sort is not cleared
63
-
64
- expect(el.selectedFacets).to.deep.equal(getDefaultSelectedFacets());
65
- });
66
-
67
- it('clears existing filters but not sort by default', async () => {
68
- const el = await fixture<CollectionBrowser>(
69
- html`<collection-browser></collection-browser>`,
70
- );
71
-
72
- el.selectedSort = 'title' as SortField;
73
- el.sortDirection = 'asc';
74
- await el.updateComplete;
75
- el.clearFilters(); // By default, sort is not cleared
76
-
77
- expect(el.selectedFacets).to.deep.equal(getDefaultSelectedFacets());
78
- expect(el.selectedSort).to.equal('title');
79
- expect(el.sortDirection).to.equal('asc');
80
- expect(el.sortParam).to.deep.equal({
81
- field: 'titleSorter',
82
- direction: 'asc',
83
- });
84
- expect(el.selectedCreatorFilter).to.be.null;
85
- expect(el.selectedTitleFilter).to.be.null;
86
- });
87
-
88
- it('clears existing filters for facets & sort via option', async () => {
89
- const el = await fixture<CollectionBrowser>(
90
- html`<collection-browser></collection-browser>`,
91
- );
92
-
93
- el.selectedSort = 'title' as SortField;
94
- await el.updateComplete;
95
- el.clearFilters({ sort: true }); // Sort is reset too due to the option
96
-
97
- expect(el.selectedFacets).to.deep.equal(getDefaultSelectedFacets());
98
- expect(el.selectedSort).to.equal(SortField.default);
99
- expect(el.sortDirection).to.be.null;
100
- expect(el.sortParam).to.be.null;
101
- expect(el.selectedCreatorFilter).to.be.null;
102
- expect(el.selectedTitleFilter).to.be.null;
103
- });
104
-
105
- it('filterBy creator with analytics', async () => {
106
- const mockAnalyticsHandler = new MockAnalyticsHandler();
107
- const el = await fixture<CollectionBrowser>(
108
- html`<collection-browser .analyticsHandler=${mockAnalyticsHandler}>
109
- </collection-browser>`,
110
- );
111
-
112
- el.searchContext = 'betaSearchService';
113
- el.selectedSort = 'creator' as SortField;
114
- el.sortDirection = 'asc';
115
- el.selectedCreatorFilter = 'A';
116
- await el.updateComplete;
117
-
118
- expect(mockAnalyticsHandler.callCategory).to.equal('betaSearchService');
119
- expect(mockAnalyticsHandler.callAction).to.equal('filterByCreator');
120
- expect(mockAnalyticsHandler.callLabel).to.equal('start-A');
121
-
122
- el.clearFilters();
123
- await el.updateComplete;
124
-
125
- expect(el.selectedTitleFilter).to.be.null;
126
- expect(mockAnalyticsHandler.callCategory).to.equal('betaSearchService');
127
- expect(mockAnalyticsHandler.callAction).to.equal('filterByCreator');
128
- expect(mockAnalyticsHandler.callLabel).to.equal('clear-A');
129
- });
130
-
131
- it('filterBy title with analytics', async () => {
132
- const mockAnalyticsHandler = new MockAnalyticsHandler();
133
- const el = await fixture<CollectionBrowser>(
134
- html`<collection-browser .analyticsHandler=${mockAnalyticsHandler}>
135
- </collection-browser>`,
136
- );
137
-
138
- el.searchContext = 'beta-search-service';
139
- el.selectedSort = 'title' as SortField;
140
- el.sortDirection = 'asc';
141
- el.selectedTitleFilter = 'A';
142
- await el.updateComplete;
143
-
144
- expect(mockAnalyticsHandler.callCategory).to.equal('beta-search-service');
145
- expect(mockAnalyticsHandler.callAction).to.equal('filterByTitle');
146
- expect(mockAnalyticsHandler.callLabel).to.equal('start-A');
147
-
148
- el.clearFilters();
149
- await el.updateComplete;
150
-
151
- expect(el.selectedTitleFilter).to.be.null;
152
- expect(mockAnalyticsHandler.callCategory).to.equal('beta-search-service');
153
- expect(mockAnalyticsHandler.callAction).to.equal('filterByTitle');
154
- expect(mockAnalyticsHandler.callLabel).to.equal('clear-A');
155
- });
156
-
157
- it('selected facets with analytics - not negative facets', async () => {
158
- const mockAnalyticsHandler = new MockAnalyticsHandler();
159
- const mediaTypeBucket = { count: 123, state: 'selected' } as FacetBucket;
160
- const mockedSelectedFacets: SelectedFacets = {
161
- subject: {},
162
- lending: {},
163
- mediatype: { data: mediaTypeBucket },
164
- language: {},
165
- creator: {},
166
- collection: {},
167
- year: {},
168
- };
169
-
170
- const el = await fixture<CollectionBrowser>(
171
- html`<collection-browser .analyticsHandler=${mockAnalyticsHandler}>
172
- </collection-browser>`,
173
- );
174
-
175
- el.searchContext = 'search-service';
176
- el.selectedFacets = mockedSelectedFacets;
177
- await el.updateComplete;
178
-
179
- el.facetClickHandler(
180
- new CustomEvent('facetClick', {
181
- detail: {
182
- facetType: 'mediatype',
183
- bucket: {
184
- key: '',
185
- state: 'selected',
186
- count: 123,
187
- },
188
- negative: false,
189
- },
190
- }),
191
- );
192
- expect(mockAnalyticsHandler.callCategory).to.equal('search-service');
193
- expect(mockAnalyticsHandler.callAction).to.equal('facetSelected');
194
- expect(mockAnalyticsHandler.callLabel).to.equal('mediatype');
195
-
196
- el.facetClickHandler(
197
- new CustomEvent('facetClick', {
198
- detail: {
199
- facetType: 'mediatype',
200
- bucket: {
201
- key: '',
202
- state: 'none',
203
- count: 123,
204
- },
205
- negative: false,
206
- },
207
- }),
208
- );
209
- expect(el.selectedFacets).to.equal(mockedSelectedFacets);
210
- expect(mockAnalyticsHandler.callCategory).to.equal('search-service');
211
- expect(mockAnalyticsHandler.callAction).to.equal('facetDeselected');
212
- expect(mockAnalyticsHandler.callLabel).to.equal('mediatype');
213
- });
214
-
215
- it('selected facets with analytics - negative facets', async () => {
216
- const mockAnalyticsHandler = new MockAnalyticsHandler();
217
- const mediaTypeBucket = { count: 123, state: 'selected' } as FacetBucket;
218
- const mockedSelectedFacets: SelectedFacets = {
219
- subject: {},
220
- lending: {},
221
- mediatype: { data: mediaTypeBucket },
222
- language: {},
223
- creator: {},
224
- collection: {},
225
- year: {},
226
- };
227
-
228
- const el = await fixture<CollectionBrowser>(
229
- html`<collection-browser .analyticsHandler=${mockAnalyticsHandler}>
230
- </collection-browser>`,
231
- );
232
-
233
- el.searchContext = 'beta-search-service';
234
- el.selectedFacets = mockedSelectedFacets;
235
- await el.updateComplete;
236
-
237
- el.facetClickHandler(
238
- new CustomEvent('facetClick', {
239
- detail: {
240
- facetType: 'mediatype',
241
- bucket: {
242
- key: '',
243
- state: 'hidden',
244
- count: 123,
245
- },
246
- negative: true,
247
- },
248
- }),
249
- );
250
- expect(mockAnalyticsHandler.callCategory).to.equal('beta-search-service');
251
- expect(mockAnalyticsHandler.callAction).to.equal('facetNegativeSelected');
252
- expect(mockAnalyticsHandler.callLabel).to.equal('mediatype');
253
-
254
- el.facetClickHandler(
255
- new CustomEvent('facetClick', {
256
- detail: {
257
- facetType: 'mediatype',
258
- bucket: {
259
- key: '',
260
- state: 'none',
261
- count: 123,
262
- },
263
- negative: true,
264
- },
265
- }),
266
- );
267
- expect(el.selectedFacets).to.equal(mockedSelectedFacets);
268
- expect(mockAnalyticsHandler.callCategory).to.equal('beta-search-service');
269
- expect(mockAnalyticsHandler.callAction).to.equal('facetNegativeDeselected');
270
- expect(mockAnalyticsHandler.callLabel).to.equal('mediatype');
271
- });
272
-
273
- it('should render with a sort bar, facets, and infinite scroller', async () => {
274
- const searchService = new MockSearchService();
275
-
276
- const el = await fixture<CollectionBrowser>(
277
- html`<collection-browser .searchService=${searchService}>
278
- </collection-browser>`,
279
- );
280
-
281
- el.baseQuery = 'hello';
282
- await el.updateComplete;
283
- await nextTick();
284
-
285
- const facets = el.shadowRoot?.querySelector('collection-facets');
286
- const sortBar = el.shadowRoot?.querySelector('sort-filter-bar');
287
- const infiniteScroller = el.shadowRoot?.querySelector('infinite-scroller');
288
- expect(facets, 'facets').to.exist;
289
- expect(sortBar, 'sort bar').to.exist;
290
- expect(infiniteScroller, 'infinite scroller').to.exist;
291
- });
292
-
293
- it('queries the search service when given a base query', async () => {
294
- const searchService = new MockSearchService();
295
-
296
- const el = await fixture<CollectionBrowser>(
297
- html`<collection-browser .searchService=${searchService}>
298
- </collection-browser>`,
299
- );
300
-
301
- el.baseQuery = 'collection:foo';
302
- await el.updateComplete;
303
- await el.initialSearchComplete;
304
-
305
- expect(searchService.searchParams?.query).to.equal('collection:foo');
306
- expect(
307
- el.shadowRoot?.querySelector('#big-results-label')?.textContent,
308
- ).to.contains('Results');
309
- });
310
-
311
- it('queries the search service when given a list of identifiers and no query', async () => {
312
- const searchService = new MockSearchService();
313
-
314
- const el = await fixture<CollectionBrowser>(
315
- html`<collection-browser .searchService=${searchService}>
316
- </collection-browser>`,
317
- );
318
-
319
- el.identifiers = ['foo', 'bar'];
320
- await el.updateComplete;
321
- await el.initialSearchComplete;
322
-
323
- expect(searchService.searchParams?.identifiers).to.deep.equal([
324
- 'foo',
325
- 'bar',
326
- ]);
327
- expect(
328
- el.shadowRoot?.querySelector('#big-results-label')?.textContent,
329
- ).to.contains('Results');
330
- });
331
-
332
- it('queries the search service when given a list of identifiers with a query', async () => {
333
- const searchService = new MockSearchService();
334
-
335
- const el = await fixture<CollectionBrowser>(
336
- html`<collection-browser .searchService=${searchService}>
337
- </collection-browser>`,
338
- );
339
-
340
- el.baseQuery = 'collection:foo';
341
- el.identifiers = ['foo', 'bar'];
342
- await el.updateComplete;
343
- await el.initialSearchComplete;
344
-
345
- expect(searchService.searchParams?.query).to.equal('collection:foo');
346
- expect(searchService.searchParams?.identifiers).to.deep.equal([
347
- 'foo',
348
- 'bar',
349
- ]);
350
- expect(
351
- el.shadowRoot?.querySelector('#big-results-label')?.textContent,
352
- ).to.contains('Results');
353
- });
354
-
355
- it('queries the search service with a metadata search', async () => {
356
- const searchService = new MockSearchService();
357
-
358
- const el = await fixture<CollectionBrowser>(
359
- html` <collection-browser .searchService=${searchService}>
360
- </collection-browser>`,
361
- );
362
-
363
- el.searchType = SearchType.METADATA;
364
- await el.updateComplete;
365
-
366
- el.baseQuery = 'collection:foo';
367
- await el.updateComplete;
368
- await el.initialSearchComplete;
369
-
370
- expect(searchService.searchParams?.query).to.equal('collection:foo');
371
- expect(searchService.searchType).to.equal(SearchType.METADATA);
372
- expect(
373
- el.shadowRoot?.querySelector('#big-results-label')?.textContent,
374
- ).to.contains('Results');
375
- });
376
-
377
- it('can change search type', async () => {
378
- const searchService = new MockSearchService();
379
- const el = await fixture<CollectionBrowser>(
380
- html`<collection-browser .searchService=${searchService}>
381
- </collection-browser>`,
382
- );
383
-
384
- el.baseQuery = 'collection:foo';
385
- await el.updateComplete;
386
-
387
- el.searchType = SearchType.FULLTEXT;
388
- await el.updateComplete;
389
- await el.initialSearchComplete;
390
-
391
- expect(searchService.searchType).to.equal(SearchType.FULLTEXT);
392
- });
393
-
394
- it('queries the search service with a fulltext search', async () => {
395
- const searchService = new MockSearchService();
396
-
397
- const el = await fixture<CollectionBrowser>(
398
- html` <collection-browser .searchService=${searchService}>
399
- </collection-browser>`,
400
- );
401
-
402
- el.searchType = SearchType.FULLTEXT;
403
- await el.updateComplete;
404
-
405
- el.baseQuery = 'collection:foo';
406
- await el.updateComplete;
407
- await el.initialSearchComplete;
408
-
409
- expect(searchService.searchParams?.query).to.equal('collection:foo');
410
- expect(searchService.searchType).to.equal(SearchType.FULLTEXT);
411
- expect(
412
- el.shadowRoot?.querySelector('#big-results-label')?.textContent,
413
- ).to.contains('Results');
414
- });
415
-
416
- it('queries the search service with a radio search', async () => {
417
- const searchService = new MockSearchService();
418
-
419
- const el = await fixture<CollectionBrowser>(
420
- html` <collection-browser .searchService=${searchService}>
421
- </collection-browser>`,
422
- );
423
-
424
- el.searchType = SearchType.RADIO;
425
- await el.updateComplete;
426
-
427
- el.baseQuery = 'collection:foo';
428
- await el.updateComplete;
429
- await el.initialSearchComplete;
430
-
431
- expect(searchService.searchParams?.query).to.equal('collection:foo');
432
- expect(searchService.searchType).to.equal(SearchType.RADIO);
433
- expect(
434
- el.shadowRoot?.querySelector('#big-results-label')?.textContent,
435
- ).to.contains('Results');
436
- });
437
-
438
- it('queries the search service with a TV search', async () => {
439
- const searchService = new MockSearchService();
440
-
441
- const el = await fixture<CollectionBrowser>(
442
- html` <collection-browser .searchService=${searchService}>
443
- </collection-browser>`,
444
- );
445
-
446
- el.searchType = SearchType.TV;
447
- await el.updateComplete;
448
-
449
- el.baseQuery = 'collection:foo';
450
- await el.updateComplete;
451
- await el.initialSearchComplete;
452
-
453
- expect(searchService.searchParams?.query).to.equal('collection:foo');
454
- expect(searchService.searchType).to.equal(SearchType.TV);
455
- expect(
456
- el.shadowRoot?.querySelector('#big-results-label')?.textContent,
457
- ).to.contains('Results');
458
- });
459
-
460
- it('queries the search service with facets selected/negated', async () => {
461
- const searchService = new MockSearchService();
462
- const selectedFacets: SelectedFacets = {
463
- subject: {
464
- foo: {
465
- key: 'foo',
466
- count: 1,
467
- state: 'selected',
468
- },
469
- bar: {
470
- key: 'bar',
471
- count: 2,
472
- state: 'hidden',
473
- },
474
- },
475
- lending: {},
476
- mediatype: {},
477
- language: {
478
- en: {
479
- key: 'en',
480
- count: 1,
481
- state: 'selected',
482
- },
483
- },
484
- creator: {},
485
- collection: {},
486
- year: {},
487
- };
488
-
489
- const el = await fixture<CollectionBrowser>(
490
- html`<collection-browser .searchService=${searchService}>
491
- </collection-browser>`,
492
- );
493
-
494
- el.baseQuery = 'collection:foo';
495
- el.selectedFacets = selectedFacets;
496
- await el.updateComplete;
497
- await el.initialSearchComplete;
498
-
499
- expect(searchService.searchParams?.query).to.equal('collection:foo');
500
- expect(searchService.searchParams?.filters).to.deep.equal({
501
- subject: {
502
- foo: 'inc',
503
- bar: 'exc',
504
- },
505
- language: {
506
- en: 'inc',
507
- },
508
- });
509
- });
510
-
511
- it('fails gracefully if no search service provided', async () => {
512
- const el = await fixture<CollectionBrowser>(
513
- html`<collection-browser></collection-browser>`,
514
- );
515
-
516
- el.baseQuery = 'collection:foo';
517
- await el.updateComplete;
518
-
519
- // This shouldn't throw an error
520
- expect(el.dataSource.fetchPage(3)).to.exist;
521
-
522
- // Should continue showing the empty placeholder
523
- expect(el.shadowRoot?.querySelector('empty-placeholder')).to.exist;
524
- });
525
-
526
- it('restores search type from URL param', async () => {
527
- // Add a sin=TXT param to the URL
528
- const url = new URL(window.location.href);
529
- url.searchParams.append('sin', 'TXT');
530
- window.history.replaceState({}, '', url);
531
-
532
- const searchService = new MockSearchService();
533
-
534
- const el = await fixture<CollectionBrowser>(
535
- html`<collection-browser .searchService=${searchService}>
536
- </collection-browser>`,
537
- );
538
-
539
- expect(el.searchType).to.equal(SearchType.FULLTEXT);
540
- });
541
-
542
- it('does not persist or restore search type from URL param if suppressed', async () => {
543
- // Add a sin=TXT param to the URL
544
- let url = new URL(window.location.href);
545
- url.searchParams.append('sin', 'TXT');
546
- window.history.replaceState({}, '', url);
547
-
548
- const searchService = new MockSearchService();
549
-
550
- const el = await fixture<CollectionBrowser>(
551
- html`<collection-browser
552
- .searchService=${searchService}
553
- suppressURLSinParam
554
- >
555
- </collection-browser>`,
556
- );
557
-
558
- url = new URL(window.location.href);
559
- expect(el.searchType).to.equal(SearchType.DEFAULT);
560
- expect(url.searchParams.has('sin')).to.be.false; // Removes existing sin param
561
-
562
- el.searchType = SearchType.RADIO;
563
- await el.updateComplete;
564
-
565
- url = new URL(window.location.href);
566
- expect(url.searchParams.has('sin')).to.be.false; // Doesn't add sin param
567
- });
568
-
569
- it('can construct tile models with many fields present', async () => {
570
- const searchService = new MockSearchService();
571
-
572
- const el = await fixture<CollectionBrowser>(
573
- html`<collection-browser .searchService=${searchService}>
574
- </collection-browser>`,
575
- );
576
-
577
- el.baseQuery = 'many-fields';
578
- await el.updateComplete;
579
- await el.initialSearchComplete;
580
-
581
- const cellTemplate = el.cellForIndex(0);
582
- expect(cellTemplate).to.exist;
583
-
584
- const cell = await fixture<TileDispatcher>(cellTemplate!);
585
- expect(cell).to.exist;
586
- });
587
-
588
- it('emits empty results event when search fetches no results', async () => {
589
- const searchService = new MockSearchService();
590
- const emptyResultsSpy = sinon.spy();
591
-
592
- const el = await fixture<CollectionBrowser>(
593
- html`<collection-browser
594
- .searchService=${searchService}
595
- @emptyResults=${emptyResultsSpy}
596
- >
597
- </collection-browser>`,
598
- );
599
-
600
- el.baseQuery = 'no-results';
601
- await el.updateComplete;
602
- await el.initialSearchComplete;
603
-
604
- expect(emptyResultsSpy.callCount).to.equal(1);
605
- });
606
-
607
- it('emits searchError event when search results in an error', async () => {
608
- const searchService = new MockSearchService();
609
- const searchErrorSpy = sinon.spy();
610
-
611
- const el = await fixture<CollectionBrowser>(
612
- html`<collection-browser
613
- .searchService=${searchService}
614
- @searchError=${searchErrorSpy}
615
- >
616
- </collection-browser>`,
617
- );
618
-
619
- el.baseQuery = 'error';
620
- await el.updateComplete;
621
- await el.initialSearchComplete;
622
-
623
- expect(searchErrorSpy.callCount).to.equal(1);
624
- });
625
-
626
- it('applies loggedin flag to tile models if needed', async () => {
627
- const searchService = new MockSearchService();
628
-
629
- const el = await fixture<CollectionBrowser>(
630
- html`<collection-browser .searchService=${searchService}>
631
- </collection-browser>`,
632
- );
633
-
634
- el.baseQuery = 'loggedin';
635
- await el.updateComplete;
636
- await el.initialSearchComplete;
637
-
638
- const cellTemplate = el.cellForIndex(0);
639
- expect(cellTemplate).to.exist;
640
-
641
- const cell = await fixture<TileDispatcher>(cellTemplate!);
642
- expect(cell).to.exist;
643
-
644
- expect(cell.model?.loginRequired).to.be.true;
645
- });
646
-
647
- it('applies no-preview flag to tile models if needed', async () => {
648
- const searchService = new MockSearchService();
649
-
650
- const el = await fixture<CollectionBrowser>(
651
- html`<collection-browser .searchService=${searchService}>
652
- </collection-browser>`,
653
- );
654
-
655
- el.baseQuery = 'no-preview';
656
- await el.updateComplete;
657
- await el.initialSearchComplete;
658
-
659
- const cellTemplate = el.cellForIndex(0);
660
- expect(cellTemplate).to.exist;
661
-
662
- const cell = await fixture<TileDispatcher>(cellTemplate!);
663
- expect(cell).to.exist;
664
-
665
- expect(cell.model?.contentWarning).to.be.true;
666
- });
667
-
668
- it('both loggedin and no-preview flags can be set simultaneously', async () => {
669
- const searchService = new MockSearchService();
670
-
671
- const el = await fixture<CollectionBrowser>(
672
- html`<collection-browser .searchService=${searchService}>
673
- </collection-browser>`,
674
- );
675
-
676
- el.baseQuery = 'loggedin-no-preview';
677
- await el.updateComplete;
678
- await el.initialSearchComplete;
679
-
680
- const cellTemplate = el.cellForIndex(0);
681
- expect(cellTemplate).to.exist;
682
-
683
- const cell = await fixture<TileDispatcher>(cellTemplate!);
684
- expect(cell).to.exist;
685
-
686
- expect(cell.model?.loginRequired).to.be.true;
687
- expect(cell.model?.contentWarning).to.be.true;
688
- });
689
-
690
- it('joins full description array into a single string with line breaks', async () => {
691
- const searchService = new MockSearchService();
692
-
693
- const el = await fixture<CollectionBrowser>(
694
- html`<collection-browser .searchService=${searchService}>
695
- </collection-browser>`,
696
- );
697
-
698
- // This query receives an array description like ['line1', 'line2']
699
- el.baseQuery = 'multi-line-description';
700
- await el.updateComplete;
701
- await el.initialSearchComplete;
702
-
703
- const cellTemplate = el.cellForIndex(0);
704
- expect(cellTemplate).to.exist;
705
-
706
- const cell = await fixture<TileDispatcher>(cellTemplate!);
707
- expect(cell).to.exist;
708
-
709
- // Actual model description should be joined
710
- expect(cell.model?.description).to.equal('line1\nline2');
711
- });
712
-
713
- it('can change search type', async () => {
714
- const searchService = new MockSearchService();
715
-
716
- const el = await fixture<CollectionBrowser>(
717
- html`<collection-browser
718
- .searchService=${searchService}
719
- .searchType=${SearchType.METADATA}
720
- ></collection-browser>`,
721
- );
722
-
723
- el.baseQuery = 'collection:foo';
724
- el.searchType = SearchType.FULLTEXT;
725
- await el.updateComplete;
726
- await el.initialSearchComplete;
727
-
728
- expect(searchService.searchParams?.query).to.equal('collection:foo');
729
- expect(searchService.searchType).to.equal(SearchType.FULLTEXT);
730
- });
731
-
732
- it('trims queries of leading/trailing whitespace', async () => {
733
- const searchService = new MockSearchService();
734
- const el = await fixture<CollectionBrowser>(
735
- html`<collection-browser
736
- .searchService=${searchService}
737
- ></collection-browser>`,
738
- );
739
-
740
- el.baseQuery = ' collection:foo ';
741
- await el.updateComplete;
742
- await el.initialSearchComplete;
743
-
744
- expect(searchService.searchParams?.query).to.equal('collection:foo');
745
- });
746
-
747
- it('shows error message when error response received', async () => {
748
- const searchService = new MockSearchService();
749
- const el = await fixture<CollectionBrowser>(
750
- html`<collection-browser
751
- .searchService=${searchService}
752
- ></collection-browser>`,
753
- );
754
-
755
- el.baseQuery = 'error';
756
- await el.updateComplete;
757
- await el.initialSearchComplete;
758
-
759
- const errorPlaceholder = el.shadowRoot?.querySelector(
760
- 'empty-placeholder',
761
- ) as EmptyPlaceholder;
762
- const errorDetails = errorPlaceholder?.shadowRoot?.querySelector(
763
- '.error-details',
764
- ) as HTMLParagraphElement;
765
-
766
- expect(errorDetails).to.exist;
767
- expect(errorDetails.textContent).to.contain('foo');
768
- });
769
-
770
- it('shows error message when error response received for a collection', async () => {
771
- const searchService = new MockSearchService();
772
- const el = await fixture<CollectionBrowser>(
773
- html`<collection-browser
774
- .searchService=${searchService}
775
- ></collection-browser>`,
776
- );
777
-
778
- el.withinCollection = 'error';
779
- await el.updateComplete;
780
- await el.initialSearchComplete;
781
-
782
- const errorPlaceholder = el.shadowRoot?.querySelector(
783
- 'empty-placeholder',
784
- ) as EmptyPlaceholder;
785
- const errorDetails = errorPlaceholder?.shadowRoot?.querySelector(
786
- '.error-details',
787
- ) as HTMLParagraphElement;
788
-
789
- expect(errorDetails).to.exist;
790
- expect(errorDetails.textContent).to.contain('foo');
791
- });
792
-
793
- it('reports malformed response errors to Sentry', async () => {
794
- const sentrySpy = sinon.spy();
795
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
796
- (window as any).Sentry = { captureMessage: sentrySpy };
797
- const searchService = new MockSearchService();
798
- const el = await fixture<CollectionBrowser>(
799
- html`<collection-browser
800
- .searchService=${searchService}
801
- ></collection-browser>`,
802
- );
803
-
804
- el.baseQuery = 'malformed';
805
- await el.updateComplete;
806
- await el.initialSearchComplete;
807
-
808
- expect(sentrySpy.callCount).to.be.greaterThanOrEqual(1);
809
- });
810
-
811
- it('adds collection names to cache when present on response', async () => {
812
- const searchService = new MockSearchService();
813
-
814
- const el = await fixture<CollectionBrowser>(
815
- html`<collection-browser .searchService=${searchService}>
816
- </collection-browser>`,
817
- );
818
-
819
- el.baseQuery = 'collection-titles';
820
- await el.updateComplete;
821
- await el.initialSearchComplete;
822
-
823
- expect(el.dataSource.collectionTitles.get('foo')).to.equal(
824
- 'Foo Collection',
825
- );
826
- expect(el.dataSource.collectionTitles.get('bar')).to.equal(
827
- 'Bar Collection',
828
- );
829
- expect(el.dataSource.collectionTitles.get('baz')).to.equal(
830
- 'Baz Collection',
831
- );
832
- expect(el.dataSource.collectionTitles.get('boop')).to.equal(
833
- 'Boop Collection',
834
- );
835
- });
836
-
837
- it('adds tv channel aliases to cache when present on response', async () => {
838
- const searchService = new MockSearchService();
839
-
840
- const el = await fixture<CollectionBrowser>(
841
- html`<collection-browser .searchService=${searchService}>
842
- </collection-browser>`,
843
- );
844
-
845
- el.baseQuery = 'channel-aliases';
846
- await el.updateComplete;
847
- await el.initialSearchComplete;
848
-
849
- expect(el.dataSource.tvChannelAliases.get('foo')).to.equal('Foo Network');
850
- expect(el.dataSource.tvChannelAliases.get('bar')).to.equal('Bar Network');
851
- });
852
-
853
- it('keeps search results from fetch if no change to query or sort param', async () => {
854
- const resultsSpy = sinon.spy();
855
- const searchService = new MockSearchService({
856
- asyncResponse: true,
857
- resultsSpy,
858
- });
859
-
860
- const el = await fixture<CollectionBrowser>(
861
- html`<collection-browser .searchService=${searchService}>
862
- </collection-browser>`,
863
- );
864
-
865
- el.baseQuery = 'with-sort';
866
- el.selectedSort = SortField.date;
867
- el.sortDirection = 'asc';
868
- await el.updateComplete;
869
-
870
- await el.dataSource.fetchPage(3);
871
-
872
- // If there is no change to the query or sort param during the fetch, the results
873
- // should be read.
874
- expect(resultsSpy.callCount).to.be.greaterThanOrEqual(1);
875
- });
876
-
877
- it('discards obsolete search results if sort params changed before arrival', async () => {
878
- const resultsSpy = sinon.spy();
879
- const searchService = new MockSearchService({
880
- asyncResponse: true,
881
- resultsSpy,
882
- });
883
-
884
- const el = await fixture<CollectionBrowser>(
885
- html`<collection-browser .searchService=${searchService}>
886
- </collection-browser>`,
887
- );
888
-
889
- el.baseQuery = 'with-sort';
890
- el.selectedSort = SortField.date;
891
- el.sortDirection = 'asc';
892
- await el.updateComplete;
893
-
894
- // We want to spy exclusively on the first set of results, not the second
895
- searchService.asyncResponse = false;
896
- searchService.resultsSpy = () => {};
897
-
898
- el.sortDirection = 'desc';
899
- await el.updateComplete;
900
- await el.initialSearchComplete;
901
-
902
- // If the different sort param causes the results to be discarded,
903
- // the first results array should never be read.
904
- expect(resultsSpy.callCount).to.equal(0);
905
- });
906
-
907
- it('discards obsolete search results if sort param added before arrival', async () => {
908
- const resultsSpy = sinon.spy();
909
- const searchService = new MockSearchService({
910
- asyncResponse: true,
911
- resultsSpy,
912
- });
913
-
914
- const el = await fixture<CollectionBrowser>(
915
- html`<collection-browser .searchService=${searchService}>
916
- </collection-browser>`,
917
- );
918
-
919
- el.baseQuery = 'single-result';
920
- await el.updateComplete;
921
-
922
- // We want to spy exclusively on the first set of results, not the second
923
- searchService.asyncResponse = false;
924
- searchService.resultsSpy = () => {};
925
-
926
- el.selectedSort = SortField.date;
927
- el.sortDirection = 'asc';
928
- await el.updateComplete;
929
- await el.initialSearchComplete;
930
-
931
- // If the different sort param causes the results to be discarded,
932
- // the first results array should never be read.
933
- expect(resultsSpy.callCount).to.equal(0);
934
- });
935
-
936
- it('discards obsolete search results if sort param cleared before arrival', async () => {
937
- const resultsSpy = sinon.spy();
938
- const searchService = new MockSearchService({
939
- asyncResponse: true,
940
- resultsSpy,
941
- });
942
-
943
- const el = await fixture<CollectionBrowser>(
944
- html`<collection-browser .searchService=${searchService}>
945
- </collection-browser>`,
946
- );
947
-
948
- el.baseQuery = 'with-sort';
949
- el.selectedSort = SortField.date;
950
- el.sortDirection = 'asc';
951
- await el.updateComplete;
952
-
953
- // We want to spy exclusively on the first set of results, not the second
954
- searchService.asyncResponse = false;
955
- searchService.resultsSpy = () => {};
956
-
957
- el.selectedSort = SortField.default;
958
- await el.updateComplete;
959
- await el.initialSearchComplete;
960
-
961
- // If the different sort param causes the results to be discarded,
962
- // the first results array should never be read.
963
- expect(resultsSpy.callCount).to.equal(0);
964
- });
965
-
966
- it('sets sort properties when user changes sort', async () => {
967
- const searchService = new MockSearchService();
968
- const el = await fixture<CollectionBrowser>(
969
- html`<collection-browser .searchService=${searchService}>
970
- </collection-browser>`,
971
- );
972
-
973
- expect(el.selectedSort).to.equal(SortField.default);
974
-
975
- el.baseQuery = 'foo';
976
- await el.updateComplete;
977
- await nextTick();
978
-
979
- const sortBar = el.shadowRoot?.querySelector(
980
- '#content-container sort-filter-bar',
981
- ) as SortFilterBar;
982
- expect(sortBar, 'sort bar').to.exist;
983
-
984
- // Switch to title sort
985
- sortBar.setSelectedSort(SortField.title);
986
- await el.updateComplete;
987
- expect(el.selectedSort).to.equal(SortField.title);
988
- expect(el.sortDirection).to.equal('asc'); // Default for title sort
989
-
990
- // Switch to descending sort order
991
- sortBar.setSortDirection('desc');
992
- await el.updateComplete;
993
- expect(el.selectedSort).to.equal(SortField.title);
994
- expect(el.sortDirection).to.equal('desc');
995
- });
996
-
997
- it('sets sort filter properties when user selects title filter', async () => {
998
- const searchService = new MockSearchService();
999
- const el = await fixture<CollectionBrowser>(
1000
- html`<collection-browser .searchService=${searchService}>
1001
- </collection-browser>`,
1002
- );
1003
-
1004
- el.baseQuery = 'first-title';
1005
- el.selectedSort = 'title' as SortField;
1006
- el.sortDirection = 'asc';
1007
- el.selectedTitleFilter = 'X';
1008
- await el.updateComplete;
1009
- await el.initialSearchComplete;
1010
-
1011
- expect(searchService.searchParams?.query).to.equal('first-title');
1012
- expect(searchService.searchParams?.filters?.firstTitle?.X).to.equal(
1013
- FilterConstraint.INCLUDE,
1014
- );
1015
- });
1016
-
1017
- it('sets sort filter properties when user selects creator filter', async () => {
1018
- const searchService = new MockSearchService();
1019
- const el = await fixture<CollectionBrowser>(
1020
- html`<collection-browser .searchService=${searchService}>
1021
- </collection-browser>`,
1022
- );
1023
-
1024
- el.baseQuery = 'first-creator';
1025
- el.selectedSort = 'creator' as SortField;
1026
- el.sortDirection = 'asc';
1027
- el.selectedCreatorFilter = 'X';
1028
- await el.updateComplete;
1029
- await el.initialSearchComplete;
1030
-
1031
- expect(searchService.searchParams?.query).to.equal('first-creator');
1032
- expect(searchService.searchParams?.filters?.firstCreator?.X).to.equal(
1033
- FilterConstraint.INCLUDE,
1034
- );
1035
- });
1036
-
1037
- it('sets sort filter properties simultaneous with facets and date range', async () => {
1038
- const searchService = new MockSearchService();
1039
- const selectedFacets: SelectedFacets = {
1040
- collection: { foo: { key: 'foo', state: 'selected', count: 1 } },
1041
- creator: {},
1042
- language: {},
1043
- lending: {},
1044
- mediatype: {},
1045
- subject: {},
1046
- year: {},
1047
- };
1048
-
1049
- const el = await fixture<CollectionBrowser>(
1050
- html`<collection-browser .searchService=${searchService}>
1051
- </collection-browser>`,
1052
- );
1053
-
1054
- el.baseQuery = 'first-creator';
1055
- el.selectedSort = 'creator' as SortField;
1056
- el.selectedFacets = selectedFacets;
1057
- el.minSelectedDate = '1950';
1058
- el.maxSelectedDate = '1970';
1059
- el.sortDirection = 'asc';
1060
- el.selectedCreatorFilter = 'X';
1061
- await el.updateComplete;
1062
- await el.initialSearchComplete;
1063
-
1064
- expect(searchService.searchParams?.query).to.equal('first-creator');
1065
- expect(searchService.searchParams?.filters).to.deep.equal({
1066
- collection: {
1067
- foo: 'inc',
1068
- },
1069
- year: {
1070
- '1950': 'gte',
1071
- '1970': 'lte',
1072
- },
1073
- firstCreator: {
1074
- X: 'inc',
1075
- },
1076
- });
1077
- });
1078
-
1079
- it('applies correct TV search filter for commercials', async () => {
1080
- const searchService = new MockSearchService();
1081
- const el = await fixture<CollectionBrowser>(
1082
- html`<collection-browser .searchService=${searchService}>
1083
- </collection-browser>`,
1084
- );
1085
-
1086
- el.baseQuery = 'tv-fields';
1087
- el.searchType = SearchType.TV;
1088
- el.selectedFacets = {
1089
- clip_type: {
1090
- commercial: { key: 'commercial', count: 1, state: 'selected' },
1091
- },
1092
- };
1093
- await el.updateComplete;
1094
- await el.initialSearchComplete;
1095
-
1096
- expect(searchService.searchParams?.filters?.clip_type?.commercial).to.equal(
1097
- FilterConstraint.INCLUDE,
1098
- );
1099
- });
1100
-
1101
- it('applies correct TV search filter for fact checks', async () => {
1102
- const searchService = new MockSearchService();
1103
- const el = await fixture<CollectionBrowser>(
1104
- html`<collection-browser .searchService=${searchService}>
1105
- </collection-browser>`,
1106
- );
1107
-
1108
- el.baseQuery = 'tv-fields';
1109
- el.searchType = SearchType.TV;
1110
- el.selectedFacets = {
1111
- clip_type: {
1112
- 'fact check': { key: 'fact check', count: 1, state: 'selected' },
1113
- },
1114
- };
1115
- await el.updateComplete;
1116
- await el.initialSearchComplete;
1117
-
1118
- expect(
1119
- searchService.searchParams?.filters?.clip_type?.['fact check'],
1120
- ).to.equal(FilterConstraint.INCLUDE);
1121
- });
1122
-
1123
- it('applies correct TV search filter for quotes', async () => {
1124
- const searchService = new MockSearchService();
1125
- const el = await fixture<CollectionBrowser>(
1126
- html`<collection-browser .searchService=${searchService}>
1127
- </collection-browser>`,
1128
- );
1129
-
1130
- el.baseQuery = 'tv-fields';
1131
- el.searchType = SearchType.TV;
1132
- el.selectedFacets = {
1133
- clip_type: { quote: { key: 'quote', count: 1, state: 'selected' } },
1134
- };
1135
- await el.updateComplete;
1136
- await el.initialSearchComplete;
1137
-
1138
- expect(searchService.searchParams?.filters?.clip_type?.quote).to.equal(
1139
- FilterConstraint.INCLUDE,
1140
- );
1141
- });
1142
-
1143
- it('resets letter filters when query changes', async () => {
1144
- const searchService = new MockSearchService();
1145
- const el = await fixture<CollectionBrowser>(
1146
- html`<collection-browser .searchService=${searchService}>
1147
- </collection-browser>`,
1148
- );
1149
-
1150
- el.baseQuery = 'first-creator';
1151
- el.selectedSort = 'creator' as SortField;
1152
- el.sortDirection = 'asc';
1153
- el.selectedCreatorFilter = 'X';
1154
- await el.updateComplete;
1155
- await el.initialSearchComplete;
1156
- await nextTick();
1157
-
1158
- expect(searchService.searchParams?.query).to.equal('first-creator');
1159
- expect(searchService.searchParams?.filters?.firstCreator?.X).to.equal(
1160
- FilterConstraint.INCLUDE,
1161
- );
1162
-
1163
- el.baseQuery = 'collection:foo';
1164
- await el.updateComplete;
1165
- await nextTick();
1166
-
1167
- expect(searchService.searchParams?.query).to.equal('collection:foo');
1168
- expect(searchService.searchParams?.filters?.firstCreator).not.to.exist;
1169
- });
1170
-
1171
- it('sets date range query when date picker selection changed', async () => {
1172
- const searchService = new MockSearchService();
1173
- const mockAnalyticsHandler = new MockAnalyticsHandler();
1174
- const el = await fixture<CollectionBrowser>(
1175
- html`<collection-browser
1176
- .searchService=${searchService}
1177
- .analyticsHandler=${mockAnalyticsHandler}
1178
- .suppressPlaceholders=${true}
1179
- >
1180
- </collection-browser>`,
1181
- );
1182
-
1183
- el.baseQuery = 'years'; // Includes year_histogram aggregation in response
1184
- el.showHistogramDatePicker = true;
1185
- await el.updateComplete;
1186
-
1187
- const facets = el.shadowRoot?.querySelector(
1188
- 'collection-facets',
1189
- ) as CollectionFacets;
1190
- await facets?.updateComplete;
1191
-
1192
- // Wait for the date picker to be rendered (which may take until the next tick)
1193
- await nextTick();
1194
-
1195
- const histogram = facets?.shadowRoot?.querySelector(
1196
- 'histogram-date-range',
1197
- ) as HistogramDateRange;
1198
-
1199
- expect(histogram, 'histogram exists').to.exist;
1200
-
1201
- // Enter a new min date into the date picker
1202
- const minDateInput = histogram.shadowRoot?.querySelector(
1203
- '#date-min',
1204
- ) as HTMLInputElement;
1205
-
1206
- const pressEnterEvent = new KeyboardEvent('keyup', {
1207
- key: 'Enter',
1208
- });
1209
-
1210
- minDateInput.value = '1960';
1211
- minDateInput.dispatchEvent(pressEnterEvent);
1212
-
1213
- // Wait for the histogram's update delay
1214
- await aTimeout(histogram.updateDelay + 50);
1215
-
1216
- // Ensure that the histogram change propagated to the collection browser's
1217
- // date query correctly.
1218
- await el.updateComplete;
1219
- expect(el.minSelectedDate).to.equal('1960');
1220
- expect(el.maxSelectedDate).to.equal('2009');
1221
- });
1222
-
1223
- it('sets date range query when monthly date picker selection changed', async () => {
1224
- const searchService = new MockSearchService();
1225
- const el = await fixture<CollectionBrowser>(
1226
- html`<collection-browser
1227
- .searchService=${searchService}
1228
- .suppressPlaceholders=${true}
1229
- >
1230
- </collection-browser>`,
1231
- );
1232
-
1233
- el.baseQuery = 'months'; // Includes date_histogram aggregation in response
1234
- el.searchType = SearchType.TV;
1235
- el.showHistogramDatePicker = true;
1236
- await el.updateComplete;
1237
-
1238
- const facets = el.shadowRoot?.querySelector(
1239
- 'collection-facets',
1240
- ) as CollectionFacets;
1241
- await facets?.updateComplete;
1242
-
1243
- // Wait for the date picker to be rendered (which may take until the next tick)
1244
- await nextTick();
1245
-
1246
- const histogram = facets?.shadowRoot?.querySelector(
1247
- 'histogram-date-range',
1248
- ) as HistogramDateRange;
1249
-
1250
- expect(histogram, 'histogram exists').to.exist;
1251
-
1252
- // Enter a new min date into the date picker
1253
- const minDateInput = histogram.shadowRoot?.querySelector(
1254
- '#date-min',
1255
- ) as HTMLInputElement;
1256
-
1257
- const pressEnterEvent = new KeyboardEvent('keyup', {
1258
- key: 'Enter',
1259
- });
1260
-
1261
- minDateInput.value = '2001-02';
1262
- minDateInput.dispatchEvent(pressEnterEvent);
1263
-
1264
- // Wait for the histogram's update delay
1265
- await aTimeout(histogram.updateDelay + 50);
1266
-
1267
- // Ensure that the histogram change propagated to the collection browser's
1268
- // date query correctly.
1269
- await el.updateComplete;
1270
- expect(el.minSelectedDate).to.equal('2001-02');
1271
- expect(el.maxSelectedDate).to.equal('2002-12');
1272
- });
1273
-
1274
- it('emits event when results start and end loading', async () => {
1275
- const spy = sinon.spy();
1276
- const searchService = new MockSearchService();
1277
- const el = await fixture<CollectionBrowser>(
1278
- html`<collection-browser
1279
- .searchService=${searchService}
1280
- @searchResultsLoadingChanged=${spy}
1281
- ></collection-browser>`,
1282
- );
1283
- spy.resetHistory();
1284
-
1285
- el.baseQuery = 'collection:foo';
1286
- await el.updateComplete;
1287
- await el.initialSearchComplete;
1288
-
1289
- // Should initially emit loading=true, then later emit loading=false
1290
- expect(spy.callCount).to.equal(2);
1291
- expect(spy.firstCall.firstArg?.detail?.loading).to.equal(true);
1292
- expect(spy.secondCall.firstArg?.detail?.loading).to.equal(false);
1293
- });
1294
-
1295
- it('collapses extra set of quotes around href field', async () => {
1296
- const searchService = new MockSearchService();
1297
- const el = await fixture<CollectionBrowser>(
1298
- html`<collection-browser
1299
- .searchService=${searchService}
1300
- .baseNavigationUrl=${''}
1301
- ></collection-browser>`,
1302
- );
1303
-
1304
- el.baseQuery = 'extra-quoted-href';
1305
- await el.updateComplete;
1306
- await el.initialSearchComplete;
1307
- await el.updateComplete;
1308
- await aTimeout(50);
1309
-
1310
- // Original href q param starts/ends with %22%22, but should be collapsed to %22 before render
1311
- expect(el.dataSource.getTileModelAt(0)?.href).to.equal(
1312
- '/details/foo?q=%22quoted+query%22',
1313
- );
1314
- });
1315
-
1316
- it('sets default sort from collection metadata', async () => {
1317
- const searchService = new MockSearchService();
1318
- const el = await fixture<CollectionBrowser>(
1319
- html`<collection-browser
1320
- .searchService=${searchService}
1321
- .baseNavigationUrl=${''}
1322
- ></collection-browser>`,
1323
- );
1324
-
1325
- el.withinCollection = 'default-sort';
1326
- await el.updateComplete;
1327
- await el.initialSearchComplete;
1328
- await el.updateComplete;
1329
- await aTimeout(50);
1330
-
1331
- const sortBar = el.shadowRoot?.querySelector(
1332
- 'sort-filter-bar',
1333
- ) as SortFilterBar;
1334
- expect(sortBar).to.exist;
1335
- expect(sortBar.defaultSortField).to.equal(SortField.title);
1336
- expect(sortBar.defaultSortDirection).to.equal('asc');
1337
- expect(sortBar.selectedSort).to.equal(SortField.default);
1338
- expect(sortBar.sortDirection).to.be.null;
1339
- });
1340
-
1341
- it('sets default sort from collection metadata in "-field" format', async () => {
1342
- const searchService = new MockSearchService();
1343
- const el = await fixture<CollectionBrowser>(
1344
- html`<collection-browser
1345
- .searchService=${searchService}
1346
- .baseNavigationUrl=${''}
1347
- ></collection-browser>`,
1348
- );
1349
-
1350
- el.withinCollection = 'default-sort-concise';
1351
- await el.updateComplete;
1352
- await el.initialSearchComplete;
1353
- await el.updateComplete;
1354
- await aTimeout(50);
1355
-
1356
- const sortBar = el.shadowRoot?.querySelector(
1357
- 'sort-filter-bar',
1358
- ) as SortFilterBar;
1359
- expect(sortBar).to.exist;
1360
- expect(sortBar.defaultSortField).to.equal(SortField.dateadded);
1361
- expect(sortBar.defaultSortDirection).to.equal('desc');
1362
- expect(sortBar.selectedSort).to.equal(SortField.default);
1363
- expect(sortBar.sortDirection).to.be.null;
1364
- });
1365
-
1366
- it('falls back to weekly views default sorting on profiles when tab not set', async () => {
1367
- const el = await fixture<CollectionBrowser>(
1368
- html`<collection-browser
1369
- .withinProfile=${'@foobar'}
1370
- ></collection-browser>`,
1371
- );
1372
-
1373
- el.applyDefaultProfileSort();
1374
- expect(el.defaultSortParam).to.deep.equal({
1375
- field: 'week',
1376
- direction: 'desc',
1377
- });
1378
- });
1379
-
1380
- it('uses relevance sort as default when a query is set', async () => {
1381
- const searchService = new MockSearchService();
1382
- const el = await fixture<CollectionBrowser>(
1383
- html`<collection-browser
1384
- .searchService=${searchService}
1385
- .baseNavigationUrl=${''}
1386
- ></collection-browser>`,
1387
- );
1388
-
1389
- el.withinCollection = 'default-sort';
1390
- el.baseQuery = 'default-sort';
1391
- await el.updateComplete;
1392
- await el.initialSearchComplete;
1393
- await el.updateComplete;
1394
- await aTimeout(50);
1395
-
1396
- const sortBar = el.shadowRoot?.querySelector(
1397
- 'sort-filter-bar',
1398
- ) as SortFilterBar;
1399
- expect(sortBar).to.exist;
1400
- expect(sortBar.defaultSortField).to.equal(SortField.relevance);
1401
- expect(sortBar.defaultSortDirection).to.be.null;
1402
- expect(sortBar.selectedSort).to.equal(SortField.default);
1403
- expect(sortBar.sortDirection).to.be.null;
1404
- });
1405
-
1406
- it('uses date favorited sort as default when targeting fav- collection', async () => {
1407
- const searchService = new MockSearchService();
1408
- const el = await fixture<CollectionBrowser>(
1409
- html`<collection-browser
1410
- .searchService=${searchService}
1411
- .baseNavigationUrl=${''}
1412
- ></collection-browser>`,
1413
- );
1414
-
1415
- el.withinCollection = 'fav-sort';
1416
- await el.updateComplete;
1417
- await el.initialSearchComplete;
1418
- await el.updateComplete;
1419
- await aTimeout(50);
1420
-
1421
- const sortBar = el.shadowRoot?.querySelector(
1422
- 'sort-filter-bar',
1423
- ) as SortFilterBar;
1424
- expect(sortBar).to.exist;
1425
- expect(sortBar.defaultSortField).to.equal(SortField.datefavorited);
1426
- expect(sortBar.defaultSortDirection).to.equal('desc');
1427
- expect(sortBar.selectedSort).to.equal(SortField.default);
1428
- expect(sortBar.sortDirection).to.be.null;
1429
- });
1430
-
1431
- it('scrolls to page', async () => {
1432
- const searchService = new MockSearchService();
1433
- const el = await fixture<CollectionBrowser>(
1434
- html`<collection-browser .searchService=${searchService}>
1435
- </collection-browser>`,
1436
- );
1437
-
1438
- // Infinite scroller won't exist unless there's a base query.
1439
- // First ensure that we don't throw errors when it doesn't exist.
1440
- await el.goToPage(1);
1441
-
1442
- // And make sure it correctly calls scrollToCell when the
1443
- // infinite scroller does exist.
1444
- el.baseQuery = 'collection:foo';
1445
- await el.updateComplete;
1446
- await nextTick();
1447
-
1448
- const infiniteScroller = el.shadowRoot?.querySelector(
1449
- 'infinite-scroller',
1450
- ) as InfiniteScroller;
1451
- expect(infiniteScroller).to.exist;
1452
-
1453
- const oldScrollToCell = infiniteScroller.scrollToCell;
1454
- const spy = sinon.spy();
1455
- infiniteScroller.scrollToCell = spy;
1456
-
1457
- await el.goToPage(1);
1458
- expect(spy.callCount, 'scroll to page fires once').to.equal(1);
1459
-
1460
- infiniteScroller.scrollToCell = oldScrollToCell;
1461
- });
1462
-
1463
- it('shows mobile facets in mobile view', async () => {
1464
- const searchService = new MockSearchService();
1465
- const el = await fixture<CollectionBrowser>(
1466
- html`<collection-browser
1467
- .searchService=${searchService}
1468
- .mobileBreakpoint=${9999}
1469
- ></collection-browser>`,
1470
- );
1471
-
1472
- el.baseQuery = 'collection:foo';
1473
- await el.updateComplete;
1474
-
1475
- const contentContainer = el.shadowRoot?.querySelector(
1476
- '#content-container',
1477
- ) as HTMLElement;
1478
-
1479
- el.handleResize({
1480
- target: contentContainer,
1481
- contentRect: contentContainer.getBoundingClientRect(),
1482
- borderBoxSize: [],
1483
- contentBoxSize: [],
1484
- devicePixelContentBoxSize: [],
1485
- });
1486
- await el.updateComplete;
1487
-
1488
- const mobileFacets = el.shadowRoot?.querySelector(
1489
- '#mobile-filter-collapse',
1490
- );
1491
- expect(mobileFacets).to.exist;
1492
- });
1493
-
1494
- it('fires analytics when mobile facets toggled', async () => {
1495
- const searchService = new MockSearchService();
1496
- const analyticsHandler = new MockAnalyticsHandler();
1497
- const el = await fixture<CollectionBrowser>(
1498
- html`<collection-browser
1499
- .searchService=${searchService}
1500
- .analyticsHandler=${analyticsHandler}
1501
- .searchContext=${'foobar-context'}
1502
- .mobileBreakpoint=${9999}
1503
- ></collection-browser>`,
1504
- );
1505
-
1506
- el.baseQuery = 'collection:foo';
1507
- await el.updateComplete;
1508
-
1509
- const contentContainer = el.shadowRoot?.querySelector(
1510
- '#content-container',
1511
- ) as HTMLElement;
1512
-
1513
- el.handleResize({
1514
- target: contentContainer,
1515
- contentRect: contentContainer.getBoundingClientRect(),
1516
- borderBoxSize: [],
1517
- contentBoxSize: [],
1518
- devicePixelContentBoxSize: [],
1519
- });
1520
- await el.updateComplete;
1521
-
1522
- const mobileFacets = el.shadowRoot?.querySelector(
1523
- '#mobile-filter-collapse',
1524
- ) as HTMLDetailsElement;
1525
- expect(mobileFacets).to.exist;
1526
-
1527
- // We set up a Promise to wait for the 'toggle' event on the collapser,
1528
- // which is what triggers the analytics.
1529
- let facetsToggled = new Promise(resolve => {
1530
- mobileFacets.addEventListener('toggle', resolve);
1531
- });
1532
-
1533
- // Open the mobile facets accordion & check analytics
1534
- const mobileFacetsHeader = mobileFacets.querySelector('summary');
1535
- expect(mobileFacetsHeader).to.exist;
1536
- mobileFacetsHeader!.click();
1537
- await facetsToggled;
1538
- expect(analyticsHandler.callCategory).to.equal('foobar-context');
1539
- expect(analyticsHandler.callAction).to.equal(
1540
- analyticsActions.mobileFacetsToggled,
1541
- );
1542
- expect(analyticsHandler.callLabel).to.equal('open');
1543
-
1544
- // Close the mobile facets accordion & check analytics
1545
- facetsToggled = new Promise(resolve => {
1546
- mobileFacets.addEventListener('toggle', resolve);
1547
- });
1548
- mobileFacetsHeader!.click();
1549
- await facetsToggled;
1550
- expect(analyticsHandler.callCategory).to.equal('foobar-context');
1551
- expect(analyticsHandler.callAction).to.equal(
1552
- analyticsActions.mobileFacetsToggled,
1553
- );
1554
- expect(analyticsHandler.callLabel).to.equal('closed');
1555
- });
1556
-
1557
- it('sets parent collections to prop when searching a collection', async () => {
1558
- const searchService = new MockSearchService();
1559
- const el = await fixture<CollectionBrowser>(
1560
- html`<collection-browser
1561
- .searchService=${searchService}
1562
- .withinCollection=${'fake'}
1563
- ></collection-browser>`,
1564
- );
1565
-
1566
- el.baseQuery = 'parent-collections';
1567
- await el.updateComplete;
1568
- await el.initialSearchComplete;
1569
- await aTimeout(0);
1570
-
1571
- expect(el.dataSource.parentCollections).to.deep.equal(['foo', 'bar']);
1572
- });
1573
-
1574
- it('recognizes TV collections', async () => {
1575
- const searchService = new MockSearchService();
1576
- const el = await fixture<CollectionBrowser>(
1577
- html`<collection-browser
1578
- .searchService=${searchService}
1579
- .withinCollection=${'TV-FOO'}
1580
- ></collection-browser>`,
1581
- );
1582
-
1583
- el.baseQuery = 'tv-collection';
1584
- await el.updateComplete;
1585
- await el.initialSearchComplete;
1586
- await aTimeout(0);
1587
-
1588
- expect(el.isTVCollection).to.be.true;
1589
- });
1590
-
1591
- it('refreshes when certain properties change - with some analytics event sampling', async () => {
1592
- const mockAnalyticsHandler = new MockAnalyticsHandler();
1593
- const searchService = new MockSearchService();
1594
- const el = await fixture<CollectionBrowser>(
1595
- html`<collection-browser
1596
- .analyticsHandler=${mockAnalyticsHandler}
1597
- .searchService=${searchService}
1598
- ></collection-browser>`,
1599
- );
1600
- const infiniteScrollerRefreshSpy = sinon.spy();
1601
-
1602
- // Infinite scroller won't exist unless there's a base query
1603
- el.baseQuery = 'collection:foo';
1604
- await el.updateComplete;
1605
- await nextTick();
1606
-
1607
- const infiniteScroller = el.shadowRoot?.querySelector('infinite-scroller');
1608
- (infiniteScroller as InfiniteScroller).reload = infiniteScrollerRefreshSpy;
1609
- expect(infiniteScrollerRefreshSpy.called).to.be.false;
1610
- expect(infiniteScrollerRefreshSpy.callCount).to.equal(0);
1611
-
1612
- // testing: `loggedIn`
1613
- el.loggedIn = true;
1614
- await el.updateComplete;
1615
-
1616
- expect(infiniteScrollerRefreshSpy.called, 'Infinite Scroller Refresh').to.be
1617
- .true;
1618
- expect(
1619
- infiniteScrollerRefreshSpy.callCount,
1620
- 'Infinite Scroller Refresh call count',
1621
- ).to.equal(1);
1622
-
1623
- el.loggedIn = false;
1624
- await el.updateComplete;
1625
-
1626
- expect(
1627
- infiniteScrollerRefreshSpy.callCount,
1628
- '2nd Infinite Scroller Refresh',
1629
- ).to.equal(2);
1630
-
1631
- // testing: `displayMode`
1632
- el.displayMode = 'list-compact';
1633
- el.searchContext = 'beta-search';
1634
- await el.updateComplete;
1635
- expect(
1636
- infiniteScrollerRefreshSpy.callCount,
1637
- '3rd Infinite Scroller Refresh',
1638
- ).to.equal(3);
1639
-
1640
- expect(mockAnalyticsHandler.callCategory).to.equal('beta-search');
1641
- expect(mockAnalyticsHandler.callAction).to.equal('displayMode');
1642
- expect(mockAnalyticsHandler.callLabel).to.equal('list-compact');
1643
-
1644
- el.displayMode = 'list-detail';
1645
- await el.updateComplete;
1646
- expect(
1647
- infiniteScrollerRefreshSpy.callCount,
1648
- '4th Infinite Scroller Refresh',
1649
- ).to.equal(4);
1650
-
1651
- expect(mockAnalyticsHandler.callCategory).to.equal('beta-search');
1652
- expect(mockAnalyticsHandler.callAction).to.equal('displayMode');
1653
- expect(mockAnalyticsHandler.callLabel).to.equal('list-detail');
1654
-
1655
- // testing: `baseNavigationUrl`
1656
- el.baseNavigationUrl = 'https://funtestsite.com';
1657
- await el.updateComplete;
1658
- expect(
1659
- infiniteScrollerRefreshSpy.callCount,
1660
- '5th Infinite Scroller Refresh',
1661
- ).to.equal(5);
1662
-
1663
- // testing: `baseImageUrl`
1664
- el.baseImageUrl = 'https://funtestsiteforimages.com';
1665
- await el.updateComplete;
1666
- expect(
1667
- infiniteScrollerRefreshSpy.callCount,
1668
- '6th Infinite Scroller Refresh',
1669
- ).to.equal(6);
1670
- });
1671
-
1672
- it('query the search service for single result', async () => {
1673
- const searchService = new MockSearchService();
1674
-
1675
- const el = await fixture<CollectionBrowser>(
1676
- html`<collection-browser .searchService=${searchService}>
1677
- </collection-browser>`,
1678
- );
1679
-
1680
- el.baseQuery = 'single-result';
1681
- await el.updateComplete;
1682
- await el.initialSearchComplete;
1683
-
1684
- expect(
1685
- el.shadowRoot?.querySelector('#big-results-label')?.textContent,
1686
- ).to.contains('Result');
1687
- });
1688
-
1689
- it('`searchContext` prop helps describe where component is being used', async () => {
1690
- const el = await fixture<CollectionBrowser>(
1691
- html`<collection-browser></collection-browser>`,
1692
- );
1693
-
1694
- expect(el.searchContext).to.equal(analyticsCategories.default);
1695
-
1696
- el.searchContext = 'unicorn-search';
1697
- await el.updateComplete;
1698
-
1699
- expect(el.searchContext).to.equal('unicorn-search');
1700
-
1701
- // property is reflected as attribute
1702
- expect(el.getAttribute('searchcontext')).to.equal('unicorn-search');
1703
- });
1704
-
1705
- it('respects the initial set of URL parameters for a general search', async () => {
1706
- const url = new URL(window.location.href);
1707
- const { searchParams } = url;
1708
- searchParams.set('query', 'foo');
1709
- searchParams.set('sin', 'TXT');
1710
- searchParams.set('sort', 'title');
1711
- searchParams.append('not[]', 'mediatype:"data"');
1712
- searchParams.append('and[]', 'subject:"baz"');
1713
- searchParams.append('and[]', 'firstTitle:X');
1714
- searchParams.append('and[]', 'year:[2000 TO 2010]');
1715
- window.history.replaceState({}, '', url);
1716
-
1717
- const searchService = new MockSearchService();
1718
- const el = await fixture<CollectionBrowser>(
1719
- html`<collection-browser .searchService=${searchService}>
1720
- </collection-browser>`,
1721
- );
1722
-
1723
- await el.initialSearchComplete;
1724
- await el.updateComplete;
1725
-
1726
- expect(el.baseQuery).to.equal('foo');
1727
- expect(el.searchType).to.equal(SearchType.FULLTEXT);
1728
- expect(el.selectedSort).to.equal(SortField.title);
1729
- expect(el.selectedFacets?.mediatype?.data?.state).to.equal('hidden');
1730
- expect(el.selectedFacets?.subject?.baz?.state).to.equal('selected');
1731
- expect(el.selectedTitleFilter).to.equal('X');
1732
- expect(el.minSelectedDate).to.equal('2000');
1733
- expect(el.maxSelectedDate).to.equal('2010');
1734
- });
1735
-
1736
- it('respects the initial set of URL parameters within a collection', async () => {
1737
- const url = new URL(window.location.href);
1738
- const { searchParams } = url;
1739
- searchParams.set('query', 'foo');
1740
- searchParams.set('sin', 'TXT');
1741
- searchParams.set('sort', 'title');
1742
- searchParams.append('not[]', 'mediatype:"data"');
1743
- searchParams.append('and[]', 'subject:"baz"');
1744
- searchParams.append('and[]', 'firstTitle:X');
1745
- searchParams.append('and[]', 'year:[2000 TO 2010]');
1746
- window.history.replaceState({}, '', url);
1747
-
1748
- const searchService = new MockSearchService();
1749
- const el = await fixture<CollectionBrowser>(
1750
- html`<collection-browser
1751
- .searchService=${searchService}
1752
- .withinCollection=${'foobar'}
1753
- >
1754
- </collection-browser>`,
1755
- );
1756
-
1757
- await el.initialSearchComplete;
1758
- await el.updateComplete;
1759
-
1760
- expect(el.withinCollection).to.equal('foobar');
1761
- expect(el.baseQuery).to.equal('foo');
1762
- expect(el.searchType).to.equal(SearchType.FULLTEXT);
1763
- expect(el.selectedSort).to.equal(SortField.title);
1764
- expect(el.selectedFacets?.mediatype?.data?.state).to.equal('hidden');
1765
- expect(el.selectedFacets?.subject?.baz?.state).to.equal('selected');
1766
- expect(el.selectedTitleFilter).to.equal('X');
1767
- expect(el.minSelectedDate).to.equal('2000');
1768
- expect(el.maxSelectedDate).to.equal('2010');
1769
- });
1770
-
1771
- it('respects the initial set of URL parameters within a profile page', async () => {
1772
- const url = new URL(window.location.href);
1773
- const { searchParams } = url;
1774
- searchParams.set('query', 'foo');
1775
- searchParams.append('not[]', 'mediatype:"data"');
1776
- searchParams.append('and[]', 'subject:"baz"');
1777
- searchParams.append('and[]', 'firstTitle:X');
1778
- searchParams.append('and[]', 'year:[2000 TO 2010]');
1779
- window.history.replaceState({}, '', url);
1780
-
1781
- const searchService = new MockSearchService();
1782
- const el = await fixture<CollectionBrowser>(
1783
- html`<collection-browser
1784
- .searchService=${searchService}
1785
- .withinProfile=${'@foobar'}
1786
- .profileElement=${'uploads'}
1787
- >
1788
- </collection-browser>`,
1789
- );
1790
-
1791
- await el.initialSearchComplete;
1792
- await el.updateComplete;
1793
-
1794
- expect(el.withinProfile).to.equal('@foobar');
1795
- expect(el.profileElement).to.equal('uploads');
1796
- expect(el.baseQuery).to.equal('foo');
1797
- expect(el.searchType).to.equal(SearchType.DEFAULT);
1798
- expect(el.selectedFacets?.mediatype?.data?.state).to.equal('hidden');
1799
- expect(el.selectedFacets?.subject?.baz?.state).to.equal('selected');
1800
- expect(el.selectedTitleFilter).to.equal('X');
1801
- expect(el.minSelectedDate).to.equal('2000');
1802
- expect(el.maxSelectedDate).to.equal('2010');
1803
- });
1804
-
1805
- it('clears filters except sort when query changes for a general search', async () => {
1806
- const url = new URL(window.location.href);
1807
- const { searchParams } = url;
1808
- searchParams.set('query', 'foo');
1809
- searchParams.set('sin', 'TXT');
1810
- searchParams.set('sort', 'title');
1811
- searchParams.append('not[]', 'mediatype:"data"');
1812
- searchParams.append('and[]', 'subject:"baz"');
1813
- searchParams.append('and[]', 'firstTitle:X');
1814
- searchParams.append('and[]', 'year:[2000 TO 2010]');
1815
- window.history.replaceState({}, '', url);
1816
-
1817
- const searchService = new MockSearchService();
1818
- const el = await fixture<CollectionBrowser>(
1819
- html`<collection-browser .searchService=${searchService}>
1820
- </collection-browser>`,
1821
- );
1822
-
1823
- await el.initialSearchComplete;
1824
- await el.updateComplete;
1825
-
1826
- el.baseQuery = 'bar';
1827
- await el.updateComplete;
1828
-
1829
- expect(el.baseQuery).to.equal('bar');
1830
- expect(el.searchType).to.equal(SearchType.FULLTEXT);
1831
- expect(el.selectedSort).to.equal(SortField.title);
1832
- expect(el.selectedFacets?.mediatype?.data).not.to.exist;
1833
- expect(el.selectedFacets?.subject?.baz).not.to.exist;
1834
- expect(el.selectedTitleFilter).not.to.exist;
1835
- expect(el.minSelectedDate).not.to.exist;
1836
- expect(el.maxSelectedDate).not.to.exist;
1837
- });
1838
-
1839
- it('clears filters except sort when query changes within a collection', async () => {
1840
- const url = new URL(window.location.href);
1841
- const { searchParams } = url;
1842
- searchParams.set('query', 'foo');
1843
- searchParams.set('sin', 'TXT');
1844
- searchParams.set('sort', 'title');
1845
- searchParams.append('not[]', 'mediatype:"data"');
1846
- searchParams.append('and[]', 'subject:"baz"');
1847
- searchParams.append('and[]', 'firstTitle:X');
1848
- searchParams.append('and[]', 'year:[2000 TO 2010]');
1849
- window.history.replaceState({}, '', url);
1850
-
1851
- const searchService = new MockSearchService();
1852
- const el = await fixture<CollectionBrowser>(
1853
- html`<collection-browser
1854
- .searchService=${searchService}
1855
- .withinCollection=${'foobar'}
1856
- >
1857
- </collection-browser>`,
1858
- );
1859
-
1860
- el.baseQuery = 'bar';
1861
- await el.updateComplete;
1862
-
1863
- expect(el.withinCollection).to.equal('foobar');
1864
- expect(el.baseQuery).to.equal('bar');
1865
- expect(el.searchType).to.equal(SearchType.FULLTEXT);
1866
- expect(el.selectedSort).to.equal(SortField.title);
1867
- expect(el.selectedFacets?.mediatype?.data).not.to.exist;
1868
- expect(el.selectedFacets?.subject?.baz).not.to.exist;
1869
- expect(el.selectedTitleFilter).not.to.exist;
1870
- expect(el.minSelectedDate).not.to.exist;
1871
- expect(el.maxSelectedDate).not.to.exist;
1872
- });
1873
-
1874
- it('clears filters *including* sort when target collection changes', async () => {
1875
- const url = new URL(window.location.href);
1876
- const { searchParams } = url;
1877
- searchParams.set('query', 'foo');
1878
- searchParams.set('sin', 'TXT');
1879
- searchParams.set('sort', 'title');
1880
- searchParams.append('not[]', 'mediatype:"data"');
1881
- searchParams.append('and[]', 'subject:"baz"');
1882
- searchParams.append('and[]', 'firstTitle:X');
1883
- searchParams.append('and[]', 'year:[2000 TO 2010]');
1884
- window.history.replaceState({}, '', url);
1885
-
1886
- const searchService = new MockSearchService();
1887
- const el = await fixture<CollectionBrowser>(
1888
- html`<collection-browser
1889
- .searchService=${searchService}
1890
- .withinCollection=${'foobar'}
1891
- >
1892
- </collection-browser>`,
1893
- );
1894
-
1895
- el.withinCollection = 'bar';
1896
- await el.updateComplete;
1897
-
1898
- expect(el.withinCollection).to.equal('bar');
1899
- expect(el.baseQuery).to.equal('foo');
1900
- expect(el.searchType).to.equal(SearchType.FULLTEXT);
1901
- expect(el.selectedSort).to.equal(SortField.default);
1902
- expect(el.selectedFacets?.mediatype?.data).not.to.exist;
1903
- expect(el.selectedFacets?.subject?.baz).not.to.exist;
1904
- expect(el.selectedTitleFilter).not.to.exist;
1905
- expect(el.minSelectedDate).not.to.exist;
1906
- expect(el.maxSelectedDate).not.to.exist;
1907
- });
1908
-
1909
- it('does not include stale facets in the search request when query changes', async () => {
1910
- const searchService = new MockSearchService();
1911
- const el = await fixture<CollectionBrowser>(
1912
- html`<collection-browser .searchService=${searchService}>
1913
- </collection-browser>`,
1914
- );
1915
-
1916
- // Perform an initial search with a facet applied
1917
- const selectedFacets = getDefaultSelectedFacets();
1918
- selectedFacets.collection.radio = {
1919
- count: 1,
1920
- key: 'radio',
1921
- state: 'selected',
1922
- } as FacetBucket;
1923
- el.baseQuery = 'cookies';
1924
- el.selectedFacets = selectedFacets;
1925
- await el.updateComplete;
1926
- await el.initialSearchComplete;
1927
-
1928
- // The initial search should include the facet filter
1929
- expect(searchService.searchParams?.filters?.collection?.radio).to.equal(
1930
- FilterConstraint.INCLUDE,
1931
- );
1932
-
1933
- // Ensure that the first search after the query change doesn't have stale facets
1934
- const searchSpy = sinon.spy(searchService, 'search');
1935
- el.baseQuery = 'cookies AND NOT collection:radio';
1936
- await el.updateComplete;
1937
- await el.initialSearchComplete;
1938
-
1939
- const firstCall = searchSpy.firstCall;
1940
- expect(firstCall.args[0].query).to.equal(
1941
- 'cookies AND NOT collection:radio',
1942
- );
1943
- expect(firstCall.args[0].filters?.collection).not.to.exist;
1944
-
1945
- searchSpy.restore();
1946
- });
1947
-
1948
- it('does not include stale date range in the search request when query changes', async () => {
1949
- const searchService = new MockSearchService();
1950
- const el = await fixture<CollectionBrowser>(
1951
- html`<collection-browser .searchService=${searchService}>
1952
- </collection-browser>`,
1953
- );
1954
-
1955
- // Perform an initial search with a date range applied
1956
- el.baseQuery = 'foo';
1957
- el.minSelectedDate = '2000';
1958
- el.maxSelectedDate = '2010';
1959
- await el.updateComplete;
1960
- await el.initialSearchComplete;
1961
-
1962
- expect(searchService.searchParams?.filters?.year?.['2000']).to.equal(
1963
- FilterConstraint.GREATER_OR_EQUAL,
1964
- );
1965
- expect(searchService.searchParams?.filters?.year?.['2010']).to.equal(
1966
- FilterConstraint.LESS_OR_EQUAL,
1967
- );
1968
-
1969
- // Change the query, which should clear the date range before searching
1970
- el.baseQuery = 'bar';
1971
- await el.updateComplete;
1972
- await el.initialSearchComplete;
1973
-
1974
- expect(searchService.searchParams?.filters?.year).not.to.exist;
1975
- expect(el.minSelectedDate).not.to.exist;
1976
- expect(el.maxSelectedDate).not.to.exist;
1977
- });
1978
-
1979
- it('does not include stale letter filters in the search request when query changes', async () => {
1980
- const searchService = new MockSearchService();
1981
- const el = await fixture<CollectionBrowser>(
1982
- html`<collection-browser .searchService=${searchService}>
1983
- </collection-browser>`,
1984
- );
1985
-
1986
- // Perform an initial search with a letter filter applied
1987
- el.baseQuery = 'first-creator';
1988
- el.selectedSort = 'creator' as SortField;
1989
- el.sortDirection = 'asc';
1990
- el.selectedCreatorFilter = 'X';
1991
- await el.updateComplete;
1992
- await el.initialSearchComplete;
1993
- await nextTick();
1994
-
1995
- expect(searchService.searchParams?.filters?.firstCreator?.X).to.equal(
1996
- FilterConstraint.INCLUDE,
1997
- );
1998
-
1999
- // Change the query, which should clear the letter filter before searching.
2000
- // Check the first search call to ensure stale filters aren't sent initially.
2001
- const searchSpy = sinon.spy(searchService, 'search');
2002
- el.baseQuery = 'bar';
2003
- await el.updateComplete;
2004
- await el.initialSearchComplete;
2005
- await nextTick();
2006
-
2007
- // The very first search after the query change should not include the old filter
2008
- const firstCall = searchSpy.firstCall;
2009
- expect(firstCall.args[0].filters?.firstCreator).not.to.exist;
2010
-
2011
- searchSpy.restore();
2012
- });
2013
-
2014
- it('correctly retrieves web archive hits', async () => {
2015
- const searchService = new MockSearchService();
2016
- const el = await fixture<CollectionBrowser>(
2017
- html`<collection-browser
2018
- .searchService=${searchService}
2019
- .withinProfile=${'@foo'}
2020
- .profileElement=${'web_archives'}
2021
- >
2022
- </collection-browser>`,
2023
- );
2024
-
2025
- el.baseQuery = 'web-archive';
2026
- await el.updateComplete;
2027
- await el.initialSearchComplete;
2028
- await nextTick();
2029
-
2030
- console.log(
2031
- '\n\n*****\n\n*****\n\n',
2032
- el.dataSource.getAllPages(),
2033
- '\n\n*****\n\n*****\n\n',
2034
- );
2035
- expect(el.dataSource.totalResults, 'total results').to.equal(1);
2036
- expect(el.dataSource.getTileModelAt(0)?.title).to.equal(
2037
- 'https://example.com',
2038
- );
2039
- expect(
2040
- el.dataSource.getTileModelAt(0)?.captureDates?.length,
2041
- 'capture dates',
2042
- ).to.equal(1);
2043
- });
2044
-
2045
- it('shows dropdown accordion in facet sidebar when opt-in strategy is specified', async () => {
2046
- const searchService = new MockSearchService();
2047
- const el = await fixture<CollectionBrowser>(
2048
- html`<collection-browser
2049
- .searchService=${searchService}
2050
- facetLoadStrategy=${'opt-in'}
2051
- >
2052
- </collection-browser>`,
2053
- );
2054
-
2055
- el.baseQuery = 'foo';
2056
- await el.updateComplete;
2057
- await el.initialSearchComplete;
2058
-
2059
- const facetsDropdown = el.shadowRoot?.querySelector(
2060
- '.desktop-facets-dropdown',
2061
- );
2062
- expect(facetsDropdown).to.exist;
2063
- });
2064
-
2065
- it('shows temporarily unavailable message when facets suppressed', async () => {
2066
- const searchService = new MockSearchService();
2067
- const el = await fixture<CollectionBrowser>(
2068
- html`<collection-browser
2069
- .searchService=${searchService}
2070
- facetLoadStrategy=${'off'}
2071
- >
2072
- </collection-browser>`,
2073
- );
2074
-
2075
- el.baseQuery = 'foo';
2076
- await el.updateComplete;
2077
- await el.initialSearchComplete;
2078
-
2079
- const facetsMsg = el.shadowRoot?.querySelector('.facets-message');
2080
- expect(facetsMsg).to.exist;
2081
- expect(facetsMsg?.textContent?.trim()).to.equal(
2082
- 'Facets are temporarily unavailable.',
2083
- );
2084
- });
2085
-
2086
- it('shows manage bar interface instead of sort bar when in manage view', async () => {
2087
- const searchService = new MockSearchService();
2088
- const el = await fixture<CollectionBrowser>(
2089
- html`<collection-browser .searchService=${searchService}>
2090
- </collection-browser>`,
2091
- );
2092
-
2093
- el.baseQuery = 'foo';
2094
- await el.updateComplete;
2095
- await el.initialSearchComplete;
2096
-
2097
- el.isManageView = true;
2098
- await el.updateComplete;
2099
-
2100
- expect(el.shadowRoot?.querySelector('manage-bar')).to.exist;
2101
- expect(el.shadowRoot?.querySelector('sort-filter-bar')).not.to.exist;
2102
-
2103
- el.isManageView = false;
2104
- await el.updateComplete;
2105
-
2106
- expect(el.shadowRoot?.querySelector('manage-bar')).not.to.exist;
2107
- expect(el.shadowRoot?.querySelector('sort-filter-bar')).to.exist;
2108
- });
2109
-
2110
- it('switches to grid display mode when manage view activated', async () => {
2111
- const searchService = new MockSearchService();
2112
- const el = await fixture<CollectionBrowser>(
2113
- html`<collection-browser
2114
- .searchService=${searchService}
2115
- .baseQuery=${'foo'}
2116
- .displayMode=${'list-detail'}
2117
- >
2118
- </collection-browser>`,
2119
- );
2120
-
2121
- el.isManageView = true;
2122
- await el.updateComplete;
2123
-
2124
- expect(el.displayMode).to.equal('grid');
2125
- });
2126
-
2127
- it('can remove all checked tiles', async () => {
2128
- const searchService = new MockSearchService();
2129
- const el = await fixture<CollectionBrowser>(
2130
- html`<collection-browser
2131
- .searchService=${searchService}
2132
- .baseNavigationUrl=${''}
2133
- >
2134
- </collection-browser>`,
2135
- );
2136
-
2137
- el.baseQuery = 'foo';
2138
- el.pageSize = 1; // To hit the edge case of a page break while offsetting tiles
2139
- await el.updateComplete;
2140
- await el.initialSearchComplete;
2141
-
2142
- el.isManageView = true;
2143
- await el.updateComplete;
2144
-
2145
- const infiniteScroller = el.shadowRoot?.querySelector('infinite-scroller');
2146
- expect(infiniteScroller).to.exist;
2147
-
2148
- let tiles =
2149
- infiniteScroller!.shadowRoot?.querySelectorAll('tile-dispatcher');
2150
- expect(tiles).to.exist;
2151
- expect(tiles?.length).to.equal(2);
2152
-
2153
- const firstTile = tiles![0] as TileDispatcher;
2154
- const firstTileLink = firstTile.shadowRoot?.querySelector(
2155
- 'a[href]',
2156
- ) as HTMLAnchorElement;
2157
- expect(firstTile.model?.identifier).to.equal('foo');
2158
- expect(firstTileLink).to.exist;
2159
-
2160
- // No effect if no tiles checked
2161
- el.removeCheckedTiles();
2162
- await el.updateComplete;
2163
- tiles = infiniteScroller!.shadowRoot?.querySelectorAll('tile-dispatcher');
2164
- expect(tiles).to.exist;
2165
- expect(tiles?.length).to.equal(2);
2166
-
2167
- // Check the first tile
2168
- firstTileLink!.click();
2169
- expect(firstTile.model?.checked).to.be.true;
2170
-
2171
- // Remove checked tiles and verify that we only kept the second tile
2172
- el.removeCheckedTiles();
2173
- await el.updateComplete;
2174
- expect(el?.dataSource?.size, 'data source count').to.equal(1);
2175
-
2176
- tiles = el.shadowRoot
2177
- ?.querySelector('infinite-scroller')!
2178
- .shadowRoot?.querySelectorAll('tile-dispatcher');
2179
- expect(tiles).to.exist;
2180
- expect(
2181
- tiles!.length,
2182
- 'tile count after `el.removeCheckedTiles()`',
2183
- ).to.equal(1);
2184
- });
2185
-
2186
- it('can check/uncheck all tiles', async () => {
2187
- const searchService = new MockSearchService();
2188
- const el = await fixture<CollectionBrowser>(
2189
- html`<collection-browser
2190
- .searchService=${searchService}
2191
- .baseNavigationUrl=${''}
2192
- >
2193
- </collection-browser>`,
2194
- );
2195
-
2196
- el.baseQuery = 'foo';
2197
- await el.updateComplete;
2198
- await el.initialSearchComplete;
2199
-
2200
- el.isManageView = true;
2201
- await el.updateComplete;
2202
-
2203
- expect(el.dataSource.checkedTileModels.length).to.equal(0);
2204
- expect(el.dataSource.uncheckedTileModels.length).to.equal(2);
2205
-
2206
- el.dataSource.checkAllTiles();
2207
- expect(el.dataSource.checkedTileModels.length).to.equal(2);
2208
- expect(el.dataSource.uncheckedTileModels.length).to.equal(0);
2209
-
2210
- el.dataSource.uncheckAllTiles();
2211
- expect(el.dataSource.checkedTileModels.length).to.equal(0);
2212
- expect(el.dataSource.uncheckedTileModels.length).to.equal(2);
2213
- });
2214
-
2215
- it('emits event when manage view state changes', async () => {
2216
- const spy = sinon.spy();
2217
- const searchService = new MockSearchService();
2218
- const el = await fixture<CollectionBrowser>(
2219
- html`<collection-browser
2220
- .searchService=${searchService}
2221
- .baseNavigationUrl=${''}
2222
- @manageModeChanged=${spy}
2223
- ></collection-browser>`,
2224
- );
2225
-
2226
- el.isManageView = true;
2227
- await el.updateComplete;
2228
-
2229
- expect(spy.callCount).to.equal(1);
2230
- expect(spy.args[0][0]?.detail).to.be.true;
2231
-
2232
- el.isManageView = false;
2233
- await el.updateComplete;
2234
-
2235
- expect(spy.callCount).to.equal(2);
2236
- expect(spy.args[1][0]?.detail).to.be.false;
2237
- });
2238
-
2239
- it('emits event when item removal requested', async () => {
2240
- const spy = sinon.spy();
2241
- const searchService = new MockSearchService();
2242
- const el = await fixture<CollectionBrowser>(
2243
- html`<collection-browser
2244
- .searchService=${searchService}
2245
- .baseNavigationUrl=${''}
2246
- @itemRemovalRequested=${spy}
2247
- >
2248
- </collection-browser>`,
2249
- );
2250
-
2251
- el.baseQuery = 'foo';
2252
- await el.updateComplete;
2253
- await el.initialSearchComplete;
2254
-
2255
- el.isManageView = true;
2256
- await el.updateComplete;
2257
-
2258
- const infiniteScroller = el.shadowRoot?.querySelector('infinite-scroller');
2259
- expect(infiniteScroller).to.exist;
2260
-
2261
- const tiles =
2262
- infiniteScroller!.shadowRoot?.querySelectorAll('tile-dispatcher');
2263
- expect(tiles).to.exist.and.have.length(2);
2264
-
2265
- const firstTile = tiles![0] as TileDispatcher;
2266
- const firstTileLink = firstTile.shadowRoot?.querySelector(
2267
- 'a[href]',
2268
- ) as HTMLAnchorElement;
2269
- expect(firstTile.model?.identifier).to.equal('foo');
2270
- expect(firstTileLink).to.exist;
2271
-
2272
- // Check the first tile
2273
- firstTileLink!.click();
2274
- await el.updateComplete;
2275
-
2276
- const manageBar = el.shadowRoot?.querySelector('manage-bar');
2277
- expect(manageBar).to.exist;
2278
-
2279
- // Emit remove event from manage bar
2280
- manageBar!.dispatchEvent(new CustomEvent('removeItems'));
2281
-
2282
- await el.updateComplete;
2283
- expect(spy.callCount).to.equal(1);
2284
- expect(spy.args[0].length).to.equal(1);
2285
- expect(spy.args[0][0].detail.items[0]).to.equal('foo');
2286
- });
2287
-
2288
- it('disables manage view when manage bar cancelled', async () => {
2289
- const searchService = new MockSearchService();
2290
- const el = await fixture<CollectionBrowser>(
2291
- html`<collection-browser
2292
- .searchService=${searchService}
2293
- .baseNavigationUrl=${''}
2294
- >
2295
- </collection-browser>`,
2296
- );
2297
-
2298
- el.baseQuery = 'foo';
2299
- await el.updateComplete;
2300
- await el.initialSearchComplete;
2301
-
2302
- el.isManageView = true;
2303
- await el.updateComplete;
2304
-
2305
- const manageBar = el.shadowRoot?.querySelector('manage-bar');
2306
- expect(manageBar).to.exist;
2307
-
2308
- // Emit remove event from manage bar
2309
- manageBar!.dispatchEvent(new CustomEvent('cancel'));
2310
-
2311
- await el.updateComplete;
2312
- expect(el.isManageView).to.be.false;
2313
- });
2314
-
2315
- it('enable/disable manage view delete button when you selectAll/unselectAll', async () => {
2316
- const searchService = new MockSearchService();
2317
- const el = await fixture<CollectionBrowser>(
2318
- html`<collection-browser .searchService=${searchService}>
2319
- </collection-browser>`,
2320
- );
2321
-
2322
- el.baseQuery = 'foo';
2323
- await el.updateComplete;
2324
- await el.initialSearchComplete;
2325
-
2326
- el.isManageView = true;
2327
- await el.updateComplete;
2328
-
2329
- const manageBar = el.shadowRoot?.querySelector('manage-bar');
2330
- expect(manageBar).to.exist;
2331
-
2332
- // disable button exists
2333
- expect(manageBar?.shadowRoot?.querySelector('.danger:disabled')).to.be
2334
- .exist;
2335
-
2336
- // Emit remove event from manage bar
2337
- manageBar!.dispatchEvent(new CustomEvent('selectAll'));
2338
- await el.updateComplete;
2339
-
2340
- // disable button does not exists
2341
- expect(manageBar?.shadowRoot?.querySelector('.danger:disabled')).to.be.not
2342
- .exist;
2343
-
2344
- // Emit remove event from manage bar
2345
- manageBar!.dispatchEvent(new CustomEvent('unselectAll'));
2346
- await el.updateComplete;
2347
-
2348
- // disable button exists again
2349
- expect(manageBar?.shadowRoot?.querySelector('.danger:disabled')).to.be
2350
- .exist;
2351
- });
2352
-
2353
- it('shows Blurring checkbox for admin users', async () => {
2354
- const searchService = new MockSearchService();
2355
- const el = await fixture<CollectionBrowser>(
2356
- html`<collection-browser
2357
- .baseNavigationUrl=${''}
2358
- .searchService=${searchService}
2359
- >
2360
- </collection-browser>`,
2361
- );
2362
-
2363
- el.baseQuery = 'archive-org-user-loggedin';
2364
- await el.updateComplete;
2365
- await el.initialSearchComplete;
2366
-
2367
- const blurringCheck = el.shadowRoot?.querySelector(
2368
- '#tile-blur-check',
2369
- ) as HTMLInputElement;
2370
- expect(blurringCheck).to.exist;
2371
- expect(blurringCheck.checked).to.be.true;
2372
- });
2373
-
2374
- it('unchecks Blurring checkbox for admin users with blurring preference off', async () => {
2375
- const searchService = new MockSearchService();
2376
- const el = await fixture<CollectionBrowser>(
2377
- html`<collection-browser
2378
- .baseNavigationUrl=${''}
2379
- .searchService=${searchService}
2380
- >
2381
- </collection-browser>`,
2382
- );
2383
-
2384
- el.baseQuery = 'archive-org-user-loggedin-noblur';
2385
- await el.updateComplete;
2386
- await el.initialSearchComplete;
2387
-
2388
- const blurringCheck = el.shadowRoot?.querySelector(
2389
- '#tile-blur-check',
2390
- ) as HTMLInputElement;
2391
- expect(blurringCheck).to.exist;
2392
- expect(blurringCheck.checked).to.be.false;
2393
- });
2394
-
2395
- it('toggles blur state when Blurring checkbox is toggled', async () => {
2396
- const searchService = new MockSearchService();
2397
- const el = await fixture<CollectionBrowser>(
2398
- html`<collection-browser
2399
- .baseNavigationUrl=${''}
2400
- .searchService=${searchService}
2401
- >
2402
- </collection-browser>`,
2403
- );
2404
-
2405
- el.baseQuery = 'archive-org-user-loggedin';
2406
- await el.updateComplete;
2407
- await el.initialSearchComplete;
2408
-
2409
- const blurringCheck = el.shadowRoot?.querySelector(
2410
- '#tile-blur-check',
2411
- ) as HTMLInputElement;
2412
- expect(blurringCheck).to.exist;
2413
-
2414
- blurringCheck.dispatchEvent(new PointerEvent('click'));
2415
- await el.updateComplete;
2416
-
2417
- const infiniteScroller = el.shadowRoot?.querySelector(
2418
- 'infinite-scroller',
2419
- ) as InfiniteScroller;
2420
- const firstTile = infiniteScroller?.shadowRoot?.querySelector(
2421
- 'tile-dispatcher',
2422
- ) as TileDispatcher;
2423
- expect(firstTile.suppressBlurring).to.be.true;
2424
- });
2425
-
2426
- it('applies loans tab properties to sort bar', async () => {
2427
- const searchService = new MockSearchService();
2428
- const el = await fixture<CollectionBrowser>(
2429
- html`<collection-browser
2430
- .baseNavigationUrl=${''}
2431
- .searchService=${searchService}
2432
- .enableSortOptionsSlot=${true}
2433
- >
2434
- </collection-browser>`,
2435
- );
2436
-
2437
- el.baseQuery = 'collection:foo';
2438
- await el.updateComplete;
2439
- await aTimeout(10);
2440
-
2441
- const sortBar = el.shadowRoot?.querySelector(
2442
- 'sort-filter-bar',
2443
- ) as SortFilterBar;
2444
- expect(sortBar?.enableSortOptionsSlot, 'show loans in sort bar').to.be.true;
2445
- expect(el.enableSortOptionsSlot, 'collection browser is loans tab').to.be
2446
- .true;
2447
-
2448
- const loansTabSlot = sortBar.querySelector('slot[name="sort-options"]');
2449
- expect(loansTabSlot).to.exist;
2450
- });
2451
-
2452
- it('can suppress presence of result count', async () => {
2453
- const searchService = new MockSearchService();
2454
- const el = await fixture<CollectionBrowser>(
2455
- html`<collection-browser
2456
- .searchService=${searchService}
2457
- suppressResultCount
2458
- ></collection-browser>`,
2459
- );
2460
-
2461
- el.baseQuery = 'collection:foo';
2462
- await el.updateComplete;
2463
- await el.initialSearchComplete;
2464
-
2465
- const resultCount = el.shadowRoot?.querySelector('#results-total');
2466
- expect(resultCount).not.to.exist;
2467
- });
2468
-
2469
- it('can suppress presence of result tiles', async () => {
2470
- const searchService = new MockSearchService();
2471
- const el = await fixture<CollectionBrowser>(
2472
- html`<collection-browser
2473
- .searchService=${searchService}
2474
- suppressResultTiles
2475
- ></collection-browser>`,
2476
- );
2477
-
2478
- el.baseQuery = 'collection:foo';
2479
- await el.updateComplete;
2480
-
2481
- const infiniteScroller = el.shadowRoot?.querySelector('infinite-scroller');
2482
- expect(infiniteScroller).not.to.exist;
2483
- });
2484
-
2485
- it('fetch larger result on search page for admin user to manage items', async () => {
2486
- const resultsSpy = sinon.spy();
2487
- const searchService = new MockSearchService({
2488
- asyncResponse: true,
2489
- resultsSpy,
2490
- });
2491
-
2492
- const el = await fixture<CollectionBrowser>(
2493
- html`<collection-browser .searchService=${searchService}>
2494
- </collection-browser>`,
2495
- );
2496
-
2497
- const numberOfPages = 15;
2498
-
2499
- el.baseQuery = 'jack';
2500
- el.isManageView = true;
2501
- await el.dataSource.fetchPage(1, numberOfPages);
2502
- await el.updateComplete;
2503
-
2504
- const initialResults = el.dataSource.getAllPages();
2505
- expect(Object.keys(initialResults).length).to.deep.equal(numberOfPages);
2506
- });
2507
-
2508
- it('uses date filter field for YYYY-MM selected dates', async () => {
2509
- const searchService = new MockSearchService();
2510
- const el = await fixture<CollectionBrowser>(
2511
- html`<collection-browser .searchService=${searchService}>
2512
- </collection-browser>`,
2513
- );
2514
-
2515
- el.baseQuery = 'months';
2516
- el.searchType = SearchType.TV;
2517
- el.minSelectedDate = '2001-02';
2518
- el.maxSelectedDate = '2002-12';
2519
- await el.updateComplete;
2520
- await el.initialSearchComplete;
2521
-
2522
- expect(searchService.searchParams?.filters?.date?.['2001-02']).to.equal(
2523
- FilterConstraint.GREATER_OR_EQUAL,
2524
- );
2525
- expect(searchService.searchParams?.filters?.date?.['2002-12']).to.equal(
2526
- FilterConstraint.LESS_OR_EQUAL,
2527
- );
2528
- expect(searchService.searchParams?.filters?.year).not.to.exist;
2529
- });
2530
-
2531
- it('still uses year filter field for YYYY selected dates', async () => {
2532
- const searchService = new MockSearchService();
2533
- const el = await fixture<CollectionBrowser>(
2534
- html`<collection-browser .searchService=${searchService}>
2535
- </collection-browser>`,
2536
- );
2537
-
2538
- el.baseQuery = 'years';
2539
- el.minSelectedDate = '1950';
2540
- el.maxSelectedDate = '1970';
2541
- await el.updateComplete;
2542
- await el.initialSearchComplete;
2543
-
2544
- expect(searchService.searchParams?.filters?.year?.['1950']).to.equal(
2545
- FilterConstraint.GREATER_OR_EQUAL,
2546
- );
2547
- expect(searchService.searchParams?.filters?.year?.['1970']).to.equal(
2548
- FilterConstraint.LESS_OR_EQUAL,
2549
- );
2550
- expect(searchService.searchParams?.filters?.date).not.to.exist;
2551
- });
2552
-
2553
- it('selects date_histogram for isTVCollection even with metadata searchType', async () => {
2554
- const searchService = new MockSearchService();
2555
- const el = await fixture<CollectionBrowser>(
2556
- html`<collection-browser
2557
- .searchService=${searchService}
2558
- .suppressPlaceholders=${true}
2559
- >
2560
- </collection-browser>`,
2561
- );
2562
-
2563
- el.baseQuery = 'months';
2564
- el.isTVCollection = true;
2565
- el.showHistogramDatePicker = true;
2566
- await el.updateComplete;
2567
- await el.initialSearchComplete;
2568
- await nextTick();
2569
-
2570
- const facets = el.shadowRoot?.querySelector(
2571
- 'collection-facets',
2572
- ) as CollectionFacets;
2573
- await facets?.updateComplete;
2574
- await nextTick();
2575
-
2576
- const histogram = facets?.shadowRoot?.querySelector(
2577
- 'histogram-date-range',
2578
- ) as HistogramDateRange;
2579
-
2580
- expect(histogram, 'histogram exists').to.exist;
2581
- });
2582
-
2583
- it('uses date: query clause for YYYY-MM date ranges', async () => {
2584
- const searchService = new MockSearchService();
2585
- const mockAnalyticsHandler = new MockAnalyticsHandler();
2586
- const el = await fixture<CollectionBrowser>(
2587
- html`<collection-browser
2588
- .searchService=${searchService}
2589
- .analyticsHandler=${mockAnalyticsHandler}
2590
- .suppressPlaceholders=${true}
2591
- >
2592
- </collection-browser>`,
2593
- );
2594
-
2595
- el.baseQuery = 'months';
2596
- el.searchType = SearchType.TV;
2597
- el.showHistogramDatePicker = true;
2598
- await el.updateComplete;
2599
-
2600
- const facets = el.shadowRoot?.querySelector(
2601
- 'collection-facets',
2602
- ) as CollectionFacets;
2603
- await facets?.updateComplete;
2604
-
2605
- await nextTick();
2606
-
2607
- const histogram = facets?.shadowRoot?.querySelector(
2608
- 'histogram-date-range',
2609
- ) as HistogramDateRange;
2610
-
2611
- expect(histogram, 'histogram exists').to.exist;
2612
-
2613
- // Enter a new min date into the date picker
2614
- const minDateInput = histogram.shadowRoot?.querySelector(
2615
- '#date-min',
2616
- ) as HTMLInputElement;
2617
-
2618
- const pressEnterEvent = new KeyboardEvent('keyup', {
2619
- key: 'Enter',
2620
- });
2621
-
2622
- minDateInput.value = '2001-02';
2623
- minDateInput.dispatchEvent(pressEnterEvent);
2624
-
2625
- // Wait for the histogram's update delay
2626
- await aTimeout(histogram.updateDelay + 50);
2627
-
2628
- await el.updateComplete;
2629
- expect(el.minSelectedDate).to.equal('2001-02');
2630
- expect(el.maxSelectedDate).to.equal('2002-12');
2631
-
2632
- // Verify the analytics event used date: not year:
2633
- expect(mockAnalyticsHandler.callAction).to.equal(
2634
- analyticsActions.histogramChanged,
2635
- );
2636
- expect(mockAnalyticsHandler.callLabel).to.include('date:');
2637
- expect(mockAnalyticsHandler.callLabel).not.to.include('year:');
2638
- });
2639
- });