@internetarchive/collection-browser 1.14.14-alpha.1 → 1.14.16-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +1 -0
  3. package/dist/index.js.map +1 -1
  4. package/dist/src/app-root.d.ts +0 -2
  5. package/dist/src/app-root.js +0 -8
  6. package/dist/src/app-root.js.map +1 -1
  7. package/dist/src/collection-browser.d.ts +24 -169
  8. package/dist/src/collection-browser.js +68 -684
  9. package/dist/src/collection-browser.js.map +1 -1
  10. package/dist/src/collection-facets/facet-row.d.ts +2 -2
  11. package/dist/src/collection-facets/facet-row.js +5 -10
  12. package/dist/src/collection-facets/facet-row.js.map +1 -1
  13. package/dist/src/collection-facets/facets-template.d.ts +2 -2
  14. package/dist/src/collection-facets/facets-template.js +2 -2
  15. package/dist/src/collection-facets/facets-template.js.map +1 -1
  16. package/dist/src/collection-facets/more-facets-content.d.ts +2 -9
  17. package/dist/src/collection-facets/more-facets-content.js +13 -18
  18. package/dist/src/collection-facets/more-facets-content.js.map +1 -1
  19. package/dist/src/collection-facets.d.ts +2 -3
  20. package/dist/src/collection-facets.js +5 -9
  21. package/dist/src/collection-facets.js.map +1 -1
  22. package/dist/src/data-source/collection-browser-data-source.d.ts +402 -0
  23. package/dist/src/data-source/collection-browser-data-source.js +742 -0
  24. package/dist/src/data-source/collection-browser-data-source.js.map +1 -0
  25. package/dist/src/data-source/models.d.ts +35 -0
  26. package/dist/src/data-source/models.js +2 -0
  27. package/dist/src/data-source/models.js.map +1 -0
  28. package/dist/src/tiles/hover/hover-pane-controller.d.ts +2 -2
  29. package/dist/src/tiles/hover/hover-pane-controller.js +1 -1
  30. package/dist/src/tiles/hover/hover-pane-controller.js.map +1 -1
  31. package/dist/src/tiles/hover/tile-hover-pane.d.ts +2 -2
  32. package/dist/src/tiles/hover/tile-hover-pane.js +2 -2
  33. package/dist/src/tiles/hover/tile-hover-pane.js.map +1 -1
  34. package/dist/src/tiles/list/tile-list.d.ts +3 -3
  35. package/dist/src/tiles/list/tile-list.js +7 -13
  36. package/dist/src/tiles/list/tile-list.js.map +1 -1
  37. package/dist/src/tiles/tile-dispatcher.d.ts +2 -2
  38. package/dist/src/tiles/tile-dispatcher.js +2 -3
  39. package/dist/src/tiles/tile-dispatcher.js.map +1 -1
  40. package/dist/test/collection-browser.test.js +43 -67
  41. package/dist/test/collection-browser.test.js.map +1 -1
  42. package/dist/test/collection-facets/facet-row.test.js +6 -17
  43. package/dist/test/collection-facets/facet-row.test.js.map +1 -1
  44. package/dist/test/collection-facets.test.js +0 -5
  45. package/dist/test/collection-facets.test.js.map +1 -1
  46. package/dist/test/tiles/list/tile-list.test.js +0 -5
  47. package/dist/test/tiles/list/tile-list.test.js.map +1 -1
  48. package/index.ts +4 -0
  49. package/package.json +3 -3
  50. package/src/app-root.ts +0 -10
  51. package/src/collection-browser.ts +79 -841
  52. package/src/collection-facets/facet-row.ts +4 -9
  53. package/src/collection-facets/facets-template.ts +3 -3
  54. package/src/collection-facets/more-facets-content.ts +15 -20
  55. package/src/collection-facets.ts +5 -10
  56. package/src/data-source/collection-browser-data-source.ts +1133 -0
  57. package/src/data-source/models.ts +45 -0
  58. package/src/tiles/hover/hover-pane-controller.ts +3 -3
  59. package/src/tiles/hover/tile-hover-pane.ts +3 -3
  60. package/src/tiles/list/tile-list.ts +13 -18
  61. package/src/tiles/tile-dispatcher.ts +3 -4
  62. package/test/collection-browser.test.ts +57 -79
  63. package/test/collection-facets/facet-row.test.ts +5 -18
  64. package/test/collection-facets.test.ts +0 -5
  65. package/test/tiles/list/tile-list.test.ts +0 -5
  66. package/dist/test/mocks/mock-collection-name-cache.d.ts +0 -9
  67. package/dist/test/mocks/mock-collection-name-cache.js +0 -18
  68. package/dist/test/mocks/mock-collection-name-cache.js.map +0 -1
  69. package/test/mocks/mock-collection-name-cache.ts +0 -24
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collection-browser-data-source.js","sourceRoot":"","sources":["../../../src/data-source/collection-browser-data-source.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from 'lit';\nimport {\n Aggregation,\n Bucket,\n CollectionExtraInfo,\n FilterConstraint,\n FilterMap,\n FilterMapBuilder,\n PageType,\n SearchParams,\n SearchResult,\n SearchType,\n} from '@internetarchive/search-service';\nimport type { MediaType } from '@internetarchive/field-parsers';\nimport {\n prefixFilterAggregationKeys,\n type FacetBucket,\n type PrefixFilterType,\n type TileModel,\n PrefixFilterCounts,\n} from '../models';\nimport type { CollectionBrowserSearchState } from './models';\nimport { sha1 } from '../utils/sha1';\n\ntype RequestKind = 'full' | 'hits' | 'aggregations';\n\nexport interface CollectionBrowserDataSourceInterface\n extends ReactiveController {\n /**\n * How many tile models are present in this data source\n */\n readonly size: number;\n\n /**\n * Whether the host has a valid set of properties for performing a search.\n * For instance, on the search page this requires a valid search service and a\n * non-empty query, while collection pages allow searching with an empty query\n * for MDS but not FTS.\n */\n readonly canPerformSearch: boolean;\n\n /**\n * A string key compactly representing the current full search state, which can\n * be used to determine, e.g., when a new search is required or whether an arriving\n * response is outdated.\n */\n readonly pageFetchQueryKey: string;\n\n /**\n * Similar to `pageFetchQueryKey`, but excluding properties that do not affect\n * the validity of a set of facets (e.g., sort).\n */\n readonly facetFetchQueryKey: string;\n\n /**\n * An object representing any collection-specific properties to be passed along\n * to the search service.\n */\n readonly collectionParams: {\n pageType: PageType;\n pageTarget: string;\n } | null;\n\n /**\n * A FilterMap object representing all filters applied to the current search,\n * including any facets, letter filters, and date ranges.\n */\n readonly filterMap: FilterMap;\n\n /**\n * The full set of aggregations retrieved for the current search.\n */\n readonly aggregations?: Record<string, Aggregation>;\n\n /**\n * The `year_histogram` aggregation retrieved for the current search.\n */\n readonly yearHistogramAggregation?: Aggregation;\n\n /**\n * A map from collection identifiers that appear on hits or aggregations for the\n * current search, to their human-readable collection titles.\n */\n readonly collectionTitles: Map<string, string>;\n\n /**\n * The \"extra info\" package provided by the PPS for collection pages, including details\n * used to populate the target collection header & About tab content.\n */\n readonly collectionExtraInfo?: CollectionExtraInfo;\n\n /**\n * An array of the current target collection's parent collections. Should include *all*\n * ancestors in the collection hierarchy, not just the immediate parent.\n */\n readonly parentCollections?: string[];\n\n /**\n * An object storing result counts for the current search bucketed by letter prefix.\n * Keys are the result field on which the prefixes are considered (e.g., title/creator)\n * and values are a Record mapping letters to their counts.\n */\n readonly prefixFilterCountMap: Partial<\n Record<PrefixFilterType, PrefixFilterCounts>\n >;\n\n /**\n * An array of all the tile models whose management checkboxes are checked\n */\n readonly checkedTileModels: TileModel[];\n\n /**\n * An array of all the tile models whose management checkboxes are unchecked\n */\n readonly uncheckedTileModels: TileModel[];\n\n /**\n * Adds the given page of tile models to the data source.\n * If the given page number already exists, that page will be overwritten.\n * @param pageNum Which page number to add (indexed starting from 1)\n * @param pageTiles The array of tile models for the new page\n */\n addPage(pageNum: number, pageTiles: TileModel[]): void;\n\n /**\n * Returns the given page of tile models from the data source.\n * @param pageNum Which page number to get (indexed starting from 1)\n */\n getPage(pageNum: number): TileModel[];\n\n /**\n * Whether the data source contains any tiles for the given page number.\n * @param pageNum Which page number to query (indexed starting from 1)\n */\n hasPage(pageNum: number): boolean;\n\n /**\n * Returns the single tile model appearing at the given index in the\n * data source, with respect to the current page size. Returns `undefined` if\n * the corresponding page is not present on the data source or if it does not\n * contain a tile model at the corresponding index.\n * @param index The 0-based index (within the full data source) of the tile to get\n */\n getTileModelAt(index: number): TileModel | undefined;\n\n /**\n * Requests that the data source fire a backend request for the given page of results.\n * @param pageNum Which page number to fetch results for\n * @param numInitialPages How many pages should be batched together on an initial fetch\n */\n fetchPage(pageNum: number, numInitialPages?: number): Promise<void>;\n\n /**\n * Requests that the data source update its prefix bucket result counts for the given\n * type of prefix filter.\n * @param filterType Which prefixable field to update the buckets for (e.g., title/creator)\n */\n updatePrefixFilterCounts(filterType: PrefixFilterType): Promise<void>;\n\n /**\n * Changes the page size used by the data source, discarding any previously-fetched pages.\n *\n * **Note: this operation will reset any data stored in the data source!**\n * @param pageSize\n */\n setPageSize(pageSize: number): void;\n\n /**\n * Resets the data source to its empty state, with no result pages, aggregations, etc.\n */\n reset(): void;\n\n /**\n * Notifies the data source that a query change has occurred, which may trigger a data\n * reset & new fetches.\n */\n handleQueryChange(): void;\n\n /**\n * Applies the given map function to all of the tile models in every page of the data\n * source.\n * @param callback A callback function to apply on each tile model, as with Array.map\n */\n map(\n callback: (model: TileModel, index: number, array: TileModel[]) => TileModel\n ): void;\n\n /**\n * Checks every tile's management checkbox\n */\n checkAllTiles(): void;\n\n /**\n * Unchecks every tile's management checkbox\n */\n uncheckAllTiles(): void;\n\n /**\n * Removes all tile models that are currently checked & adjusts the paging\n * of the data source to account for any new gaps in the data.\n */\n removeCheckedTiles(): void;\n}\n\nexport class CollectionBrowserDataSource\n implements CollectionBrowserDataSourceInterface\n{\n private pages: Record<string, TileModel[]> = {};\n\n private offset = 0;\n\n private numTileModels = 0;\n\n /**\n * Maps the full query key to the pages being fetched for that query\n */\n private pageFetchesInProgress: Record<string, Set<number>> = {};\n\n totalResults = 0;\n\n endOfDataReached = false;\n\n /**\n * @inheritdoc\n */\n aggregations?: Record<string, Aggregation>;\n\n /**\n * @inheritdoc\n */\n yearHistogramAggregation?: Aggregation;\n\n /**\n * @inheritdoc\n */\n collectionTitles = new Map<string, string>();\n\n /**\n * @inheritdoc\n */\n collectionExtraInfo?: CollectionExtraInfo;\n\n /**\n * @inheritdoc\n */\n parentCollections?: string[] = [];\n\n /**\n * @inheritdoc\n */\n prefixFilterCountMap: Partial<Record<PrefixFilterType, PrefixFilterCounts>> =\n {};\n\n constructor(\n /** The host element to which this controller should attach listeners */\n private readonly host: ReactiveControllerHost &\n CollectionBrowserSearchState,\n /** Default size of result pages */\n private pageSize: number\n ) {\n this.host.addController(this as CollectionBrowserDataSourceInterface);\n }\n\n /**\n * @inheritdoc\n */\n get size(): number {\n return this.numTileModels;\n }\n\n /**\n * @inheritdoc\n */\n addPage(pageNum: number, pageTiles: TileModel[]): void {\n this.pages[pageNum] = pageTiles;\n this.numTileModels += pageTiles.length;\n this.host.requestUpdate();\n }\n\n /**\n * @inheritdoc\n */\n getPage(pageNum: number): TileModel[] {\n return this.pages[pageNum];\n }\n\n /**\n * @inheritdoc\n */\n hasPage(pageNum: number): boolean {\n return !!this.pages[pageNum];\n }\n\n /**\n * @inheritdoc\n */\n getTileModelAt(index: number): TileModel | undefined {\n const pageNum = Math.floor(index / this.pageSize) + 1;\n const indexOnPage = index % this.pageSize;\n return this.pages[pageNum]?.[indexOnPage];\n }\n\n /**\n * @inheritdoc\n */\n setPageSize(pageSize: number): void {\n this.reset();\n this.pageSize = pageSize;\n }\n\n /**\n * @inheritdoc\n */\n reset(): void {\n this.pages = {};\n this.aggregations = {};\n this.yearHistogramAggregation = undefined;\n this.pageFetchesInProgress = {};\n\n this.offset = 0;\n this.numTileModels = 0;\n this.totalResults = 0;\n\n this.host.requestUpdate();\n }\n\n /**\n * @inheritdoc\n */\n async handleQueryChange(): Promise<void> {\n this.reset();\n await Promise.all([\n this.doInitialPageFetch(),\n this.host.suppressFacets ? null : this.fetchFacets(),\n ]);\n }\n\n /**\n * @inheritdoc\n */\n map(\n callback: (model: TileModel, index: number, array: TileModel[]) => TileModel\n ): void {\n this.pages = Object.fromEntries(\n Object.entries(this.pages).map(([page, tileModels]) => [\n page,\n tileModels.map((model, index, array) =>\n model ? callback(model, index, array) : model\n ),\n ])\n );\n this.host.requestUpdate();\n }\n\n /**\n * @inheritdoc\n */\n checkAllTiles(): void {\n this.map(model => ({ ...model, checked: true }));\n }\n\n /**\n * @inheritdoc\n */\n uncheckAllTiles(): void {\n this.map(model => ({ ...model, checked: false }));\n }\n\n /**\n * @inheritdoc\n */\n removeCheckedTiles(): void {\n // To make sure our data source remains page-aligned, we will offset our data source by\n // the number of removed tiles, so that we can just add the offset when the infinite\n // scroller queries for cell contents.\n // This only matters while we're still viewing the same set of results. If the user changes\n // their query/filters/sort, then the data source is overwritten and the offset cleared.\n const { checkedTileModels, uncheckedTileModels } = this;\n const numChecked = checkedTileModels.length;\n if (numChecked === 0) return;\n this.offset += numChecked;\n const newPages: typeof this.pages = {};\n\n // Which page the remaining tile models start on, post-offset\n let offsetPageNumber = Math.floor(this.offset / this.pageSize) + 1;\n let indexOnPage = this.offset % this.pageSize;\n\n // Fill the pages up to that point with empty models\n for (let page = 1; page <= offsetPageNumber; page += 1) {\n const remainingHidden = this.offset - this.pageSize * (page - 1);\n const offsetCellsOnPage = Math.min(this.pageSize, remainingHidden);\n newPages[page] = Array(offsetCellsOnPage).fill(undefined);\n }\n\n // Shift all the remaining tiles into their new positions in the data source\n for (const model of uncheckedTileModels) {\n if (!newPages[offsetPageNumber]) newPages[offsetPageNumber] = [];\n newPages[offsetPageNumber].push(model);\n indexOnPage += 1;\n if (indexOnPage >= this.pageSize) {\n offsetPageNumber += 1;\n indexOnPage = 0;\n }\n }\n\n // Swap in the new pages\n this.pages = newPages;\n this.numTileModels -= numChecked;\n this.host.requestUpdate();\n }\n\n /**\n * @inheritdoc\n */\n get checkedTileModels(): TileModel[] {\n return this.getFilteredTileModels(model => model.checked);\n }\n\n /**\n * @inheritdoc\n */\n get uncheckedTileModels(): TileModel[] {\n return this.getFilteredTileModels(model => !model.checked);\n }\n\n /**\n * Returns a flattened, filtered array of all the tile models in the data source\n * for which the given predicate returns a truthy value.\n *\n * @param predicate A callback function to apply on each tile model, as with Array.filter\n * @returns A filtered array of tile models satisfying the predicate\n */\n private getFilteredTileModels(\n predicate: (model: TileModel, index: number, array: TileModel[]) => unknown\n ): TileModel[] {\n return Object.values(this.pages)\n .flat()\n .filter((model, index, array) =>\n model ? predicate(model, index, array) : false\n );\n }\n\n // DATA FETCHES\n\n /**\n * @inheritdoc\n */\n get canPerformSearch(): boolean {\n if (!this.host.searchService) return false;\n\n const trimmedQuery = this.host.baseQuery?.trim();\n const hasNonEmptyQuery = !!trimmedQuery;\n const isCollectionSearch = !!this.host.withinCollection;\n const isMetadataSearch = this.host.searchType === SearchType.METADATA;\n\n // Metadata searches within a collection are allowed to have no query.\n // Otherwise, a non-empty query must be set.\n return hasNonEmptyQuery || (isCollectionSearch && isMetadataSearch);\n }\n\n /**\n * The query key is a string that uniquely identifies the current search.\n * It consists of:\n * - The current base query\n * - The current collection\n * - The current search type\n * - Any currently-applied facets\n * - Any currently-applied date range\n * - Any currently-applied prefix filters\n * - The current sort options\n *\n * This lets us keep track of queries so we don't persist data that's\n * no longer relevant.\n */\n get pageFetchQueryKey(): string {\n const sortField = this.host.sortParam?.field ?? 'none';\n const sortDirection = this.host.sortParam?.direction ?? 'none';\n return `${this.fullQuery}-${this.host.withinCollection}-${this.host.searchType}-${sortField}-${sortDirection}`;\n }\n\n /**\n * Similar to `pageFetchQueryKey` above, but excludes sort fields since they\n * are not relevant in determining aggregation queries.\n */\n get facetFetchQueryKey(): string {\n return `${this.fullQuery}-${this.host.withinCollection}-${this.host.searchType}`;\n }\n\n /**\n * Constructs a search service FilterMap object from the combination of\n * all the currently-applied filters. This includes any facets, letter\n * filters, and date range.\n */\n get filterMap(): FilterMap {\n const builder = new FilterMapBuilder();\n\n // Add the date range, if applicable\n if (this.host.minSelectedDate) {\n builder.addFilter(\n 'year',\n this.host.minSelectedDate,\n FilterConstraint.GREATER_OR_EQUAL\n );\n }\n if (this.host.maxSelectedDate) {\n builder.addFilter(\n 'year',\n this.host.maxSelectedDate,\n FilterConstraint.LESS_OR_EQUAL\n );\n }\n\n // Add any selected facets\n if (this.host.selectedFacets) {\n for (const [facetName, facetValues] of Object.entries(\n this.host.selectedFacets\n )) {\n const { name, values } = this.prepareFacetForFetch(\n facetName,\n facetValues\n );\n for (const [value, bucket] of Object.entries(values)) {\n let constraint;\n if (bucket.state === 'selected') {\n constraint = FilterConstraint.INCLUDE;\n } else if (bucket.state === 'hidden') {\n constraint = FilterConstraint.EXCLUDE;\n }\n\n if (constraint) {\n builder.addFilter(name, value, constraint);\n }\n }\n }\n }\n\n // Add any letter filters\n if (this.host.selectedTitleFilter) {\n builder.addFilter(\n 'firstTitle',\n this.host.selectedTitleFilter,\n FilterConstraint.INCLUDE\n );\n }\n if (this.host.selectedCreatorFilter) {\n builder.addFilter(\n 'firstCreator',\n this.host.selectedCreatorFilter,\n FilterConstraint.INCLUDE\n );\n }\n\n const filterMap = builder.build();\n return filterMap;\n }\n\n /**\n * Produces a compact unique ID for a search request that can help with debugging\n * on the backend by making related requests easier to trace through different services.\n * (e.g., tying the hits/aggregations requests for the same page back to a single hash).\n *\n * @param params The search service parameters for the request\n * @param kind The kind of request (hits-only, aggregations-only, or both)\n * @returns A Promise resolving to the uid to apply to the request\n */\n private async requestUID(\n params: SearchParams,\n kind: RequestKind\n ): Promise<string> {\n const paramsToHash = JSON.stringify({\n pageType: params.pageType,\n pageTarget: params.pageTarget,\n query: params.query,\n fields: params.fields,\n filters: params.filters,\n sort: params.sort,\n searchType: this.host.searchType,\n });\n\n const fullQueryHash = (await sha1(paramsToHash)).slice(0, 20); // First 80 bits of SHA-1 are plenty for this\n const sessionId = (await this.host.getSessionId()).slice(0, 20); // Likewise\n const page = params.page ?? 0;\n const kindPrefix = kind.charAt(0); // f = full, h = hits, a = aggregations\n const currentTime = Date.now();\n\n return `R:${fullQueryHash}-S:${sessionId}-P:${page}-K:${kindPrefix}-T:${currentTime}`;\n }\n\n /**\n * @inheritdoc\n */\n get collectionParams(): {\n pageType: PageType;\n pageTarget: string;\n } | null {\n return this.host.withinCollection\n ? {\n pageType: 'collection_details',\n pageTarget: this.host.withinCollection,\n }\n : null;\n }\n\n /**\n * The full query, including year facets and date range clauses\n */\n private get fullQuery(): string | undefined {\n let fullQuery = this.host.baseQuery?.trim() ?? '';\n\n const { facetQuery, dateRangeQueryClause, sortFilterQueries } = this;\n\n if (facetQuery) {\n fullQuery += ` AND ${facetQuery}`;\n }\n if (dateRangeQueryClause) {\n fullQuery += ` AND ${dateRangeQueryClause}`;\n }\n if (sortFilterQueries) {\n fullQuery += ` AND ${sortFilterQueries}`;\n }\n return fullQuery.trim();\n }\n\n /**\n * Generates a query string representing the current set of applied facets\n *\n * Example: `mediatype:(\"collection\" OR \"audio\" OR -\"etree\") AND year:(\"2000\" OR \"2001\")`\n */\n private get facetQuery(): string | undefined {\n if (!this.host.selectedFacets) return undefined;\n const facetClauses = [];\n for (const [facetName, facetValues] of Object.entries(\n this.host.selectedFacets\n )) {\n facetClauses.push(this.buildFacetClause(facetName, facetValues));\n }\n return this.joinFacetClauses(facetClauses)?.trim();\n }\n\n private get dateRangeQueryClause(): string | undefined {\n if (!this.host.minSelectedDate || !this.host.maxSelectedDate) {\n return undefined;\n }\n\n return `year:[${this.host.minSelectedDate} TO ${this.host.maxSelectedDate}]`;\n }\n\n private get sortFilterQueries(): string {\n const queries = [this.titleQuery, this.creatorQuery];\n return queries.filter(q => q).join(' AND ');\n }\n\n /**\n * Returns a query clause identifying the currently selected title filter,\n * e.g., `firstTitle:X`.\n */\n private get titleQuery(): string | undefined {\n return this.host.selectedTitleFilter\n ? `firstTitle:${this.host.selectedTitleFilter}`\n : undefined;\n }\n\n /**\n * Returns a query clause identifying the currently selected creator filter,\n * e.g., `firstCreator:X`.\n */\n private get creatorQuery(): string | undefined {\n return this.host.selectedCreatorFilter\n ? `firstCreator:${this.host.selectedCreatorFilter}`\n : undefined;\n }\n\n /**\n * Builds an OR-joined facet clause for the given facet name and values.\n *\n * E.g., for name `subject` and values\n * `{ foo: { state: 'selected' }, bar: { state: 'hidden' } }`\n * this will produce the clause\n * `subject:(\"foo\" OR -\"bar\")`.\n *\n * @param facetName The facet type (e.g., 'collection')\n * @param facetValues The facet buckets, mapped by their keys\n */\n private buildFacetClause(\n facetName: string,\n facetValues: Record<string, FacetBucket>\n ): string {\n const { name: facetQueryName, values } = this.prepareFacetForFetch(\n facetName,\n facetValues\n );\n const facetEntries = Object.entries(values);\n if (facetEntries.length === 0) return '';\n\n const facetValuesArray: string[] = [];\n for (const [key, facetData] of facetEntries) {\n const plusMinusPrefix = facetData.state === 'hidden' ? '-' : '';\n facetValuesArray.push(`${plusMinusPrefix}\"${key}\"`);\n }\n\n const valueQuery = facetValuesArray.join(` OR `);\n return `${facetQueryName}:(${valueQuery})`;\n }\n\n /**\n * Handles some special pre-request normalization steps for certain facet types\n * that require them.\n *\n * @param facetName The name of the facet type (e.g., 'language')\n * @param facetValues An array of values for that facet type\n */\n private prepareFacetForFetch(\n facetName: string,\n facetValues: Record<string, FacetBucket>\n ): { name: string; values: Record<string, FacetBucket> } {\n // eslint-disable-next-line prefer-const\n let [normalizedName, normalizedValues] = [facetName, facetValues];\n\n // The full \"search engine\" name of the lending field is \"lending___status\"\n if (facetName === 'lending') {\n normalizedName = 'lending___status';\n }\n\n return {\n name: normalizedName,\n values: normalizedValues,\n };\n }\n\n /**\n * Takes an array of facet clauses, and combines them into a\n * full AND-joined facet query string. Empty clauses are ignored.\n */\n private joinFacetClauses(facetClauses: string[]): string | undefined {\n const nonEmptyFacetClauses = facetClauses.filter(\n clause => clause.length > 0\n );\n return nonEmptyFacetClauses.length > 0\n ? `(${nonEmptyFacetClauses.join(' AND ')})`\n : undefined;\n }\n\n /**\n * Fires a backend request to fetch a set of aggregations (representing UI facets) for\n * the current search state.\n */\n private async fetchFacets(): Promise<void> {\n const trimmedQuery = this.host.baseQuery?.trim();\n if (!this.canPerformSearch) return;\n\n const { facetFetchQueryKey } = this;\n\n const sortParams = this.host.sortParam ? [this.host.sortParam] : [];\n const params: SearchParams = {\n ...this.collectionParams,\n query: trimmedQuery || '',\n rows: 0,\n filters: this.filterMap,\n // Fetch a few extra buckets beyond the 6 we show, in case some get suppressed\n aggregationsSize: 10,\n // Note: we don't need an aggregations param to fetch the default aggregations from the PPS.\n // The default aggregations for the search_results page type should be what we need here.\n };\n params.uid = await this.requestUID(\n { ...params, sort: sortParams },\n 'aggregations'\n );\n\n this.host.setFacetsLoading(true);\n const searchResponse = await this.host.searchService?.search(\n params,\n this.host.searchType\n );\n const success = searchResponse?.success;\n\n // This is checking to see if the query has changed since the data was fetched.\n // If so, we just want to discard this set of aggregations because they are\n // likely no longer valid for the newer query.\n const queryChangedSinceFetch =\n facetFetchQueryKey !== this.facetFetchQueryKey;\n if (queryChangedSinceFetch) return;\n\n if (!success) {\n const errorMsg = searchResponse?.error?.message;\n const detailMsg = searchResponse?.error?.details?.message;\n\n if (!errorMsg && !detailMsg) {\n // @ts-ignore: Property 'Sentry' does not exist on type 'Window & typeof globalThis'\n window?.Sentry?.captureMessage?.(\n 'Missing or malformed facet response from backend',\n 'error'\n );\n }\n\n return;\n }\n\n const { aggregations, collectionTitles } = success.response;\n this.aggregations = aggregations;\n\n if (collectionTitles) {\n for (const [id, title] of Object.entries(collectionTitles)) {\n this.collectionTitles.set(id, title);\n }\n }\n\n this.yearHistogramAggregation =\n success?.response?.aggregations?.year_histogram;\n\n this.host.setFacetsLoading(false);\n }\n\n /**\n * Performs the initial page fetch(es) for the current search state.\n */\n private async doInitialPageFetch(): Promise<void> {\n this.host.setSearchResultsLoading(true);\n // Try to batch 2 initial page requests when possible\n await this.fetchPage(this.host.initialPageNumber, 2);\n this.host.setSearchResultsLoading(false);\n }\n\n /**\n * Fetches one or more pages of results and updates the data source.\n *\n * @param pageNumber The page number to fetch\n * @param numInitialPages If this is an initial page fetch (`pageNumber = 1`),\n * specifies how many pages to batch together in one request. Ignored\n * if `pageNumber != 1`, defaulting to a single page.\n */\n async fetchPage(pageNumber: number, numInitialPages = 1): Promise<void> {\n const trimmedQuery = this.host.baseQuery?.trim();\n if (!this.canPerformSearch) return;\n\n // if we already have data, don't fetch again\n if (this.hasPage(pageNumber)) return;\n\n if (this.endOfDataReached) return;\n\n // Batch multiple initial page requests together if needed (e.g., can request\n // pages 1 and 2 together in a single request).\n const numPages = pageNumber === 1 ? numInitialPages : 1;\n const numRows = this.pageSize * numPages;\n\n // if a fetch is already in progress for this query and page, don't fetch again\n const { pageFetchQueryKey } = this;\n const pageFetches =\n this.pageFetchesInProgress[pageFetchQueryKey] ?? new Set();\n if (pageFetches.has(pageNumber)) return;\n for (let i = 0; i < numPages; i += 1) {\n pageFetches.add(pageNumber + i);\n }\n this.pageFetchesInProgress[pageFetchQueryKey] = pageFetches;\n\n const sortParams = this.host.sortParam ? [this.host.sortParam] : [];\n const params: SearchParams = {\n ...this.collectionParams,\n query: trimmedQuery || '',\n page: pageNumber,\n rows: numRows,\n sort: sortParams,\n filters: this.filterMap,\n aggregations: { omit: true },\n };\n params.uid = await this.requestUID(params, 'hits');\n\n const searchResponse = await this.host.searchService?.search(\n params,\n this.host.searchType\n );\n const success = searchResponse?.success;\n\n // This is checking to see if the query has changed since the data was fetched.\n // If so, we just want to discard the data since there should be a new query\n // right behind it.\n const queryChangedSinceFetch = pageFetchQueryKey !== this.pageFetchQueryKey;\n if (queryChangedSinceFetch) return;\n\n if (!success) {\n const errorMsg = searchResponse?.error?.message;\n const detailMsg = searchResponse?.error?.details?.message;\n\n this.host.queryErrorMessage = `${errorMsg ?? ''}${\n detailMsg ? `; ${detailMsg}` : ''\n }`;\n\n if (!this.host.queryErrorMessage) {\n this.host.queryErrorMessage =\n 'Missing or malformed response from backend';\n // @ts-ignore: Property 'Sentry' does not exist on type 'Window & typeof globalThis'\n window?.Sentry?.captureMessage?.(this.queryErrorMessage, 'error');\n }\n\n for (let i = 0; i < numPages; i += 1) {\n this.pageFetchesInProgress[pageFetchQueryKey]?.delete(pageNumber + i);\n }\n\n this.host.setSearchResultsLoading(false);\n return;\n }\n\n this.totalResults = success.response.totalResults - this.offset;\n\n // display event to offshoot when result count is zero.\n if (this.totalResults === 0) {\n this.host.emitEmptyResults();\n }\n\n if (this.host.withinCollection) {\n this.collectionExtraInfo = success.response.collectionExtraInfo;\n\n // For collections, we want the UI to respect the default sort option\n // which can be specified in metadata, or otherwise assumed to be week:desc\n this.host.applyDefaultCollectionSort(this.collectionExtraInfo);\n\n if (this.collectionExtraInfo) {\n this.parentCollections = [].concat(\n this.collectionExtraInfo.public_metadata?.collection ?? []\n );\n }\n }\n\n const { results, collectionTitles } = success.response;\n if (results && results.length > 0) {\n // Load any collection titles present on the response into the cache,\n // or queue up preload fetches for them if none were present.\n if (collectionTitles) {\n for (const [id, title] of Object.entries(collectionTitles)) {\n this.collectionTitles.set(id, title);\n }\n }\n\n // Update the data source for each returned page\n for (let i = 0; i < numPages; i += 1) {\n const pageStartIndex = this.pageSize * i;\n this.addTilesToDataSource(\n pageNumber + i,\n results.slice(pageStartIndex, pageStartIndex + this.pageSize)\n );\n }\n }\n\n // When we reach the end of the data, we can set the infinite scroller's\n // item count to the real total number of results (rather than the\n // temporary estimates based on pages rendered so far).\n const resultCountDiscrepancy = numRows - results.length;\n if (resultCountDiscrepancy > 0) {\n this.endOfDataReached = true;\n this.host.setTotalResultCount(this.totalResults);\n }\n\n for (let i = 0; i < numPages; i += 1) {\n this.pageFetchesInProgress[pageFetchQueryKey]?.delete(pageNumber + i);\n }\n }\n\n /**\n * Update the datasource from the fetch response\n *\n * @param pageNumber\n * @param results\n */\n private addTilesToDataSource(\n pageNumber: number,\n results: SearchResult[]\n ): void {\n // copy our existing datasource so when we set it below, it gets set\n // instead of modifying the existing dataSource since object changes\n // don't trigger a re-render\n // const datasource = { ...this.dataSource };\n const tiles: TileModel[] = [];\n results?.forEach(result => {\n if (!result.identifier) return;\n\n let loginRequired = false;\n let contentWarning = false;\n // Check if item and item in \"modifying\" collection, setting above flags\n if (\n result.collection?.values.length &&\n result.mediatype?.value !== 'collection'\n ) {\n for (const collection of result.collection?.values ?? []) {\n if (collection === 'loggedin') {\n loginRequired = true;\n if (contentWarning) break;\n }\n if (collection === 'no-preview') {\n contentWarning = true;\n if (loginRequired) break;\n }\n }\n }\n\n tiles.push({\n averageRating: result.avg_rating?.value,\n checked: false,\n collections: result.collection?.values ?? [],\n collectionFilesCount: result.collection_files_count?.value ?? 0,\n collectionSize: result.collection_size?.value ?? 0,\n commentCount: result.num_reviews?.value ?? 0,\n creator: result.creator?.value,\n creators: result.creator?.values ?? [],\n dateAdded: result.addeddate?.value,\n dateArchived: result.publicdate?.value,\n datePublished: result.date?.value,\n dateReviewed: result.reviewdate?.value,\n description: result.description?.values.join('\\n'),\n favCount: result.num_favorites?.value ?? 0,\n href: this.collapseRepeatedQuotes(result.__href__?.value),\n identifier: result.identifier,\n issue: result.issue?.value,\n itemCount: result.item_count?.value ?? 0,\n mediatype: this.getMediatype(result),\n snippets: result.highlight?.values ?? [],\n source: result.source?.value,\n subjects: result.subject?.values ?? [],\n title: result.title?.value ?? '',\n volume: result.volume?.value,\n viewCount: result.downloads?.value ?? 0,\n weeklyViewCount: result.week?.value,\n loginRequired,\n contentWarning,\n });\n });\n this.addPage(pageNumber, tiles);\n const visiblePages = this.host.currentVisiblePageNumbers;\n const needsReload = visiblePages.includes(pageNumber);\n if (needsReload) {\n this.host.refreshVisibleResults();\n }\n }\n\n /**\n * Returns the mediatype string for the given search result, taking into account\n * the special `favorited_search` hit type.\n * @param result The search result to extract a mediatype from\n */\n private getMediatype(result: SearchResult): MediaType {\n /**\n * hit_type == 'favorited_search' is basically a new hit_type\n * - we are getting from PPS.\n * - which gives response for fav- collection\n * - having favorited items like account/collection/item etc..\n * - as user can also favorite a search result (a search page)\n * - so we need to have response (having fav- items and fav- search results)\n *\n * if backend hit_type == 'favorited_search'\n * - let's assume a \"search\" as new mediatype\n */\n if (result?.rawMetadata?.hit_type === 'favorited_search') {\n return 'search';\n }\n\n return result.mediatype?.value ?? 'data';\n }\n\n /**\n * Returns the input string, but removing one set of quotes from all instances of\n * \"\"clauses wrapped in two sets of quotes\"\". This assumes the quotes are already\n * URL-encoded.\n *\n * This should be a temporary measure to address the fact that the __href__ field\n * sometimes acquires extra quotation marks during query rewriting. Once there is a\n * full Lucene parser in place that handles quoted queries correctly, this can likely\n * be removed.\n */\n private collapseRepeatedQuotes(str?: string): string | undefined {\n return str?.replace(/%22%22(?!%22%22)(.+?)%22%22/g, '%22$1%22');\n }\n\n /**\n * Fetches the aggregation buckets for the given prefix filter type.\n */\n private async fetchPrefixFilterBuckets(\n filterType: PrefixFilterType\n ): Promise<Bucket[]> {\n const trimmedQuery = this.host.baseQuery?.trim();\n if (!this.canPerformSearch) return [];\n\n const filterAggregationKey = prefixFilterAggregationKeys[filterType];\n const sortParams = this.host.sortParam ? [this.host.sortParam] : [];\n\n const params: SearchParams = {\n ...this.collectionParams,\n query: trimmedQuery || '',\n rows: 0,\n filters: this.filterMap,\n // Only fetch the firstTitle or firstCreator aggregation\n aggregations: { simpleParams: [filterAggregationKey] },\n // Fetch all 26 letter buckets\n aggregationsSize: 26,\n };\n params.uid = await this.requestUID(\n { ...params, sort: sortParams },\n 'aggregations'\n );\n\n const searchResponse = await this.host.searchService?.search(\n params,\n this.host.searchType\n );\n\n return (searchResponse?.success?.response?.aggregations?.[\n filterAggregationKey\n ]?.buckets ?? []) as Bucket[];\n }\n\n /**\n * Fetches and caches the prefix filter counts for the given filter type.\n */\n async updatePrefixFilterCounts(filterType: PrefixFilterType): Promise<void> {\n const { facetFetchQueryKey } = this;\n const buckets = await this.fetchPrefixFilterBuckets(filterType);\n\n // Don't update the filter counts for an outdated query (if it has been changed\n // since we sent the request)\n const queryChangedSinceFetch =\n facetFetchQueryKey !== this.facetFetchQueryKey;\n if (queryChangedSinceFetch) return;\n\n // Unpack the aggregation buckets into a simple map like { 'A': 50, 'B': 25, ... }\n this.prefixFilterCountMap = { ...this.prefixFilterCountMap }; // Clone the object to trigger an update\n this.prefixFilterCountMap[filterType] = buckets.reduce(\n (acc: Record<string, number>, bucket: Bucket) => {\n acc[(bucket.key as string).toUpperCase()] = bucket.doc_count;\n return acc;\n },\n {}\n );\n\n this.host.requestUpdate();\n }\n}\n"]}
@@ -0,0 +1,35 @@
1
+ import type { CollectionExtraInfo, SearchServiceInterface, SearchType, SortDirection, SortParam } from '@internetarchive/search-service';
2
+ import type { SelectedFacets, SortField } from '../models';
3
+ /**
4
+ * A Map from collection identifiers to their corresponding collection titles.
5
+ */
6
+ export declare type CollectionTitles = Map<string, string>;
7
+ /**
8
+ * Interface representing search-related state and operations required by the
9
+ * data source on its host component.
10
+ */
11
+ export interface CollectionBrowserSearchState {
12
+ baseQuery?: string;
13
+ withinCollection?: string;
14
+ searchType: SearchType;
15
+ selectedFacets?: SelectedFacets;
16
+ minSelectedDate?: string;
17
+ maxSelectedDate?: string;
18
+ selectedSort?: SortField;
19
+ sortDirection: SortDirection | null;
20
+ readonly sortParam: SortParam | null;
21
+ selectedTitleFilter: string | null;
22
+ selectedCreatorFilter: string | null;
23
+ searchService?: SearchServiceInterface;
24
+ readonly suppressFacets?: boolean;
25
+ readonly initialPageNumber: number;
26
+ readonly currentVisiblePageNumbers: number[];
27
+ queryErrorMessage?: string;
28
+ getSessionId(): Promise<string>;
29
+ setSearchResultsLoading(loading: boolean): void;
30
+ setFacetsLoading(loading: boolean): void;
31
+ setTotalResultCount(count: number): void;
32
+ applyDefaultCollectionSort(collectionInfo?: CollectionExtraInfo): void;
33
+ emitEmptyResults(): void;
34
+ refreshVisibleResults(): void;
35
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../../../src/data-source/models.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n CollectionExtraInfo,\n SearchServiceInterface,\n SearchType,\n SortDirection,\n SortParam,\n} from '@internetarchive/search-service';\nimport type { SelectedFacets, SortField } from '../models';\n\n/**\n * A Map from collection identifiers to their corresponding collection titles.\n */\nexport type CollectionTitles = Map<string, string>;\n\n/**\n * Interface representing search-related state and operations required by the\n * data source on its host component.\n */\nexport interface CollectionBrowserSearchState {\n baseQuery?: string;\n withinCollection?: string;\n searchType: SearchType;\n selectedFacets?: SelectedFacets;\n minSelectedDate?: string;\n maxSelectedDate?: string;\n selectedSort?: SortField;\n sortDirection: SortDirection | null;\n readonly sortParam: SortParam | null;\n selectedTitleFilter: string | null;\n selectedCreatorFilter: string | null;\n searchService?: SearchServiceInterface;\n\n readonly suppressFacets?: boolean;\n readonly initialPageNumber: number;\n readonly currentVisiblePageNumbers: number[];\n queryErrorMessage?: string;\n\n getSessionId(): Promise<string>;\n setSearchResultsLoading(loading: boolean): void;\n setFacetsLoading(loading: boolean): void;\n setTotalResultCount(count: number): void;\n applyDefaultCollectionSort(collectionInfo?: CollectionExtraInfo): void;\n emitEmptyResults(): void;\n refreshVisibleResults(): void;\n}\n"]}
@@ -1,14 +1,14 @@
1
- import type { CollectionNameCacheInterface } from '@internetarchive/collection-name-cache';
2
1
  import type { SortParam } from '@internetarchive/search-service';
3
2
  import { HTMLTemplateResult, nothing, ReactiveController, ReactiveControllerHost } from 'lit';
4
3
  import type { TileModel } from '../../models';
4
+ import type { CollectionTitles } from '../../data-source/models';
5
5
  export interface HoverPaneProperties {
6
6
  model?: TileModel;
7
7
  baseNavigationUrl?: string;
8
8
  baseImageUrl?: string;
9
9
  loggedIn: boolean;
10
10
  sortParam: SortParam | null;
11
- collectionNameCache?: CollectionNameCacheInterface;
11
+ collectionTitles?: CollectionTitles;
12
12
  }
13
13
  export interface HoverPaneControllerOptions {
14
14
  offsetX?: number;
@@ -177,7 +177,7 @@ export class HoverPaneController {
177
177
  .baseImageUrl=${(_c = this.hoverPaneProps) === null || _c === void 0 ? void 0 : _c.baseImageUrl}
178
178
  .loggedIn=${(_d = this.hoverPaneProps) === null || _d === void 0 ? void 0 : _d.loggedIn}
179
179
  .sortParam=${(_e = this.hoverPaneProps) === null || _e === void 0 ? void 0 : _e.sortParam}
180
- .collectionNameCache=${(_f = this.hoverPaneProps) === null || _f === void 0 ? void 0 : _f.collectionNameCache}
180
+ .collectionTitles=${(_f = this.hoverPaneProps) === null || _f === void 0 ? void 0 : _f.collectionTitles}
181
181
  ></tile-hover-pane>`
182
182
  : nothing;
183
183
  }
@@ -1 +1 @@
1
- {"version":3,"file":"hover-pane-controller.js","sourceRoot":"","sources":["../../../../src/tiles/hover/hover-pane-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CollectionNameCacheInterface } from '@internetarchive/collection-name-cache';\nimport type { SortParam } from '@internetarchive/search-service';\nimport {\n html,\n HTMLTemplateResult,\n nothing,\n ReactiveController,\n ReactiveControllerHost,\n} from 'lit';\nimport type { TileModel } from '../../models';\n\ntype HoverPaneState = 'hidden' | 'shown' | 'fading-out';\n\nexport interface HoverPaneProperties {\n model?: TileModel;\n baseNavigationUrl?: string;\n baseImageUrl?: string;\n loggedIn: boolean;\n sortParam: SortParam | null;\n collectionNameCache?: CollectionNameCacheInterface;\n}\n\nexport interface HoverPaneControllerOptions {\n offsetX?: number;\n offsetY?: number;\n enableLongPress?: boolean;\n showDelay?: number;\n hideDelay?: number;\n longPressDelay?: number;\n mobileBreakpoint?: number;\n}\n\n/** A common interface for providing a hover pane element. */\nexport interface HoverPaneProviderInterface {\n /** Returns the provider's currently rendered hover pane element. */\n getHoverPane(): HTMLElement | undefined;\n /** Returns properties that should be passed to the hover pane. */\n getHoverPaneProps(): HoverPaneProperties;\n}\n\nexport interface ToggleHoverPaneOptions {\n coords: { x: number; y: number };\n enableTouchBackdrop?: boolean;\n}\n\n/**\n * An interface for interacting with hover pane controllers (e.g.,\n * to retrieve their current hover pane template).\n */\nexport interface HoverPaneControllerInterface extends ReactiveController {\n /**\n * Returns the hover pane template to render based on this controller's\n * current state. The returned template may be `nothing` if the hover\n * pane should not currently be rendered.\n */\n getTemplate(): HTMLTemplateResult | typeof nothing;\n\n /**\n * Requests to manually toggle the state of the hover pane.\n * If the hover pane is already shown, it will begin fading out and then\n * subsequently be hidden and removed. If the hover pane is already fading\n * out or hidden, it will fade back in and be shown.\n */\n toggleHoverPane(options: ToggleHoverPaneOptions): void;\n}\n\nconst clamp = (val: number, min = -Infinity, max = Infinity) =>\n Math.max(min, Math.min(val, max));\n\nexport class HoverPaneController implements HoverPaneControllerInterface {\n /**\n * The hover pane element attached to this controller's host.\n */\n private hoverPane?: HTMLElement;\n\n /**\n * The properties to be passed to the hover pane element\n */\n private hoverPaneProps?: HoverPaneProperties;\n\n /**\n * The breakpoint (in pixels) below which the mobile interface should be used.\n */\n private mobileBreakpoint?: number = 600;\n\n /**\n * The number of horizontal pixels the hover pane should be offset from the\n * pointer position.\n */\n private offsetX: number = -10;\n\n /**\n * The number of vertical pixels the hover pane should be offset from the\n * pointer position.\n */\n private offsetY: number = 15;\n\n /**\n * The delay between the mouse idling within the host element and when the hover\n * pane should begin fading in (in milliseconds).\n */\n private showDelay: number = 300;\n\n /**\n * The delay between when the mouse leaves the host element and when the hover\n * pane should begin fading out (in milliseconds).\n */\n private hideDelay: number = 100;\n\n /**\n * The delay between when a touch event begins on the host element and when the\n * hover pane should begin fading in (in milliseconds).\n */\n private longPressDelay: number = 600;\n\n /**\n * Whether long press interactions should cause the hover pane to appear (when\n * below the mobile breakpoint).\n */\n private enableLongPress: boolean = false;\n\n /**\n * Used to control the current state of this provider's hover pane.\n * - `'hidden'` => The hover pane is not present at all.\n * - `'shown'` => The hover pane is either fading in or fully visible.\n * - `'fading-out'` => The hover pane is fading out and about to be removed.\n */\n private hoverPaneState: HoverPaneState = 'hidden';\n\n /** The timer ID for showing the hover pane */\n private showTimer?: number;\n\n /** The timer ID for hiding the hover pane */\n private hideTimer?: number;\n\n /** The timer ID for recognizing a long press event */\n private longPressTimer?: number;\n\n /**\n * Whether the touch backdrop should currently be rendered irrespective of other touch\n * interactions being enabled.\n */\n private forceTouchBackdrop: boolean = false;\n\n /** A record of the last mouse position on the host element, for positioning the hover pane */\n private lastPointerClientPos = { x: 0, y: 0 };\n\n constructor(\n /** The host element to which this controller should attach listeners */\n private readonly host: ReactiveControllerHost &\n HoverPaneProviderInterface &\n HTMLElement,\n /** Options for adjusting the hover pane behavior (offsets, delays, etc.) */\n options: HoverPaneControllerOptions = {}\n ) {\n this.mobileBreakpoint = options.mobileBreakpoint ?? this.mobileBreakpoint;\n this.offsetX = options.offsetX ?? this.offsetX;\n this.offsetY = options.offsetY ?? this.offsetY;\n this.showDelay = options.showDelay ?? this.showDelay;\n this.hideDelay = options.hideDelay ?? this.hideDelay;\n this.longPressDelay = options.longPressDelay ?? this.longPressDelay;\n this.enableLongPress = options.enableLongPress ?? this.enableLongPress;\n\n this.host.addController(this);\n }\n\n hostConnected(): void {\n this.attachListeners();\n }\n\n hostDisconnected(): void {\n this.detachListeners();\n }\n\n hostUpdated(): void {\n this.hoverPane = this.host.getHoverPane();\n this.hoverPaneProps = this.host.getHoverPaneProps();\n }\n\n /** @inheritdoc */\n getTemplate(): HTMLTemplateResult | typeof nothing {\n return this.shouldRenderHoverPane\n ? html` ${this.touchBackdropTemplate}\n <tile-hover-pane\n .model=${this.hoverPaneProps?.model}\n .baseNavigationUrl=${this.hoverPaneProps?.baseNavigationUrl}\n .baseImageUrl=${this.hoverPaneProps?.baseImageUrl}\n .loggedIn=${this.hoverPaneProps?.loggedIn}\n .sortParam=${this.hoverPaneProps?.sortParam}\n .collectionNameCache=${this.hoverPaneProps?.collectionNameCache}\n ></tile-hover-pane>`\n : nothing;\n }\n\n /** @inheritdoc */\n toggleHoverPane(options: ToggleHoverPaneOptions): void {\n if (this.hoverPaneState === 'shown') {\n this.fadeOutHoverPane();\n this.forceTouchBackdrop = false;\n } else {\n this.lastPointerClientPos = options.coords;\n this.forceTouchBackdrop = options.enableTouchBackdrop ?? false;\n this.showHoverPane();\n }\n }\n\n /**\n * Produces a template for the invisible touch capture backdrop that\n * is used to cancel the hover pane on touch devices. We want any\n * touch interaction on the backdrop to remove the hover pane, and\n * we don't want to bubble up mouse events that would otherwise\n * affect the state of the hover pane (e.g., fading it back in).\n */\n private get touchBackdropTemplate(): HTMLTemplateResult | typeof nothing {\n return this.showTouchBackdrop\n ? html`<div\n id=\"touch-backdrop\"\n @touchstart=${this.handleBackdropInteraction}\n @touchmove=${this.handleBackdropInteraction}\n @touchend=${this.handleBackdropInteraction}\n @touchcancel=${this.handleBackdropInteraction}\n @mouseenter=${(e: MouseEvent) => e.stopPropagation()}\n @mousemove=${(e: MouseEvent) => e.stopPropagation()}\n @mouseleave=${(e: MouseEvent) => e.stopPropagation()}\n ></div>`\n : nothing;\n }\n\n private get showTouchBackdrop(): boolean {\n return (\n (this.isTouchEnabled && this.enableLongPress) || this.forceTouchBackdrop\n );\n }\n\n /** Whether to use the mobile layout */\n private get isMobileView(): boolean {\n return !!this.mobileBreakpoint && window.innerWidth < this.mobileBreakpoint;\n }\n\n private get isHoverEnabled(): boolean {\n return window.matchMedia('(hover: hover)').matches;\n }\n\n private get isTouchEnabled(): boolean {\n return (\n 'ontouchstart' in window &&\n window.matchMedia('(any-pointer: coarse)').matches\n );\n }\n\n /** Whether this controller should currently render its hover pane. */\n private get shouldRenderHoverPane(): boolean {\n return this.hoverPaneState !== 'hidden';\n }\n\n /**\n * Returns the desired top/left offsets (in pixels) for this tile's hover pane.\n * The desired offsets balance positioning the hover pane under the primary pointer\n * while preventing it from flowing outside the viewport. The returned offsets are\n * given relative to this tile's content box.\n *\n * These offsets are only valid if the hover pane is already rendered with its\n * correct width and height. If the hover pane is not present, the returned offsets\n * will simply represent the current pointer position.\n */\n private get hoverPaneDesiredOffsets(): { top: number; left: number } {\n // Try to find offsets for the hover pane that:\n // (a) cause it to lie entirely within the viewport, and\n // (b) to the extent possible, minimize the distance between the\n // nearest corner of the hover pane and the mouse position\n // (with some additional offsets applied after the fact).\n\n let [left, top] = [\n this.lastPointerClientPos.x,\n this.lastPointerClientPos.y,\n ];\n\n // Flip the hover pane according to which quadrant of the viewport the mouse is in.\n // (Similar to how Wikipedia's link hover panes work)\n const flipHorizontal = this.lastPointerClientPos.x > window.innerWidth / 2;\n const flipVertical = this.lastPointerClientPos.y > window.innerHeight / 2;\n\n const hoverPaneRect = this.hoverPane?.getBoundingClientRect();\n if (hoverPaneRect) {\n // If we need to flip the hover pane, do so by subtracting its width/height from left/top\n if (flipHorizontal) {\n left -= hoverPaneRect.width;\n }\n if (flipVertical) {\n top -= hoverPaneRect.height;\n }\n\n // Apply desired offsets from the mouse position\n left += (flipHorizontal ? -1 : 1) * this.offsetX;\n top += (flipVertical ? -1 : 1) * this.offsetY;\n\n // On mobile view, shunt the hover pane to avoid overflowing the viewport\n if (this.isMobileView) {\n left = clamp(left, 20, window.innerWidth - hoverPaneRect.width - 20);\n top = clamp(top, 20, window.innerHeight - hoverPaneRect.height - 20);\n }\n }\n\n // Subtract off the tile's own offsets\n const hostRect = this.host.getBoundingClientRect();\n left -= hostRect.left;\n top -= hostRect.top;\n\n return { left, top };\n }\n\n /**\n * Adds to the host element all the listeners necessary to make the\n * hover pane functional.\n */\n private attachListeners(): void {\n if (this.isHoverEnabled) {\n this.host.addEventListener('mouseenter', this.handleMouseEnter);\n this.host.addEventListener('mousemove', this.handleMouseMove);\n this.host.addEventListener('mouseleave', this.handleMouseLeave);\n }\n\n if (this.isTouchEnabled && this.enableLongPress) {\n this.host.addEventListener('touchstart', this.handleTouchStart);\n this.host.addEventListener('touchmove', this.handleLongPressCancel);\n this.host.addEventListener('touchend', this.handleLongPressCancel);\n this.host.addEventListener('touchcancel', this.handleLongPressCancel);\n this.host.addEventListener('contextmenu', this.handleContextMenu);\n }\n }\n\n /**\n * Removes all the hover pane listeners from the host element.\n */\n private detachListeners(): void {\n this.host.removeEventListener('mouseenter', this.handleMouseEnter);\n this.host.removeEventListener('mousemove', this.handleMouseMove);\n this.host.removeEventListener('mouseleave', this.handleMouseLeave);\n this.host.removeEventListener('touchstart', this.handleTouchStart);\n this.host.removeEventListener('touchmove', this.handleLongPressCancel);\n this.host.removeEventListener('touchend', this.handleLongPressCancel);\n this.host.removeEventListener('touchcancel', this.handleLongPressCancel);\n this.host.removeEventListener('contextmenu', this.handleContextMenu);\n }\n\n /**\n * Handler for the mouseenter event on the host element.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleMouseEnter = (e: MouseEvent): void => {\n // Delegate to the mousemove handler, as they are currently processed identically\n this.handleMouseMove(e);\n };\n\n /**\n * Handler for the mousemove event on the host element.\n * Aborts any pending hide/fade-out for the hover pane, and restarts the\n * timer to show it.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleMouseMove = (e: MouseEvent): void => {\n // The mouse is within the tile, so abort any pending removal of the hover pane\n clearTimeout(this.hideTimer);\n\n // If the hover pane is currently fading out, just make it fade back in where it is\n if (this.hoverPaneState === 'fading-out') {\n this.hoverPaneState = 'shown';\n this.hoverPane?.classList.add('fade-in');\n }\n\n // Restart the timer to show the hover pane anytime the mouse moves within the tile\n if (this.hoverPaneState === 'hidden') {\n this.restartShowHoverPaneTimer();\n this.lastPointerClientPos = { x: e.clientX, y: e.clientY };\n }\n };\n\n /**\n * Handler for the mouseleave event on the host element.\n * Hides the hover pane if present, and aborts the timer for showing it.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleMouseLeave = (): void => {\n // Abort any timer to show the hover pane, as the mouse has left the tile\n clearTimeout(this.showTimer);\n\n // Hide the hover pane if it's already been shown\n clearTimeout(this.hideTimer);\n if (this.hoverPaneState !== 'hidden') {\n this.hideTimer = window.setTimeout(() => {\n this.fadeOutHoverPane();\n }, this.hideDelay);\n }\n };\n\n /**\n * Handler for the touchstart event on the host element.\n * Begins the timer for recognizing a long press event.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleTouchStart = (e: TouchEvent): void => {\n clearTimeout(this.longPressTimer);\n\n if (e.touches.length === 1) {\n this.longPressTimer = window.setTimeout(() => {\n if (this.hoverPaneState === 'hidden') {\n this.showHoverPane();\n }\n }, this.longPressDelay);\n\n this.lastPointerClientPos = {\n x: e.touches[0].clientX,\n y: e.touches[0].clientY,\n };\n }\n };\n\n /**\n * Handler for events that should cancel a pending long press event\n * (touchmove, touchend, touchcancel). Aborts the timer for recognizing\n * a long press.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleLongPressCancel = (): void => {\n clearTimeout(this.longPressTimer);\n };\n\n /**\n * Handler for the contextmenu event, which should be suppressed during\n * mobile long-press events on the host element.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleContextMenu = (e: Event): void => {\n e.preventDefault();\n };\n\n /**\n * Immediately causes the hover pane to begin fading out, if it is present.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleBackdropInteraction = (e: Event): void => {\n if (this.hoverPaneState !== 'hidden') {\n this.fadeOutHoverPane();\n }\n e.stopPropagation();\n };\n\n /**\n * Aborts and restarts the timer for showing the hover pane.\n */\n private restartShowHoverPaneTimer(): void {\n clearTimeout(this.showTimer);\n this.showTimer = window.setTimeout(() => {\n this.showHoverPane();\n }, this.showDelay);\n }\n\n /**\n * Causes this tile's hover pane to be rendered, positioned, and made visible.\n */\n private async showHoverPane(): Promise<void> {\n this.hoverPaneState = 'shown';\n this.host.requestUpdate();\n\n // Wait for the state update to render the hover pane\n await this.host.updateComplete;\n await new Promise(resolve => {\n // Pane sizes aren't accurate until next frame\n requestAnimationFrame(resolve);\n });\n\n // Apply the correct positioning to the hover pane\n this.repositionHoverPane();\n\n // The hover pane is initially not visible (to avoid it shifting around\n // while being positioned). Since it now has the correct positioning, we\n // can make it visible and begin its fade-in animation.\n this.hoverPane?.classList.add('visible', 'fade-in');\n }\n\n /**\n * Causes this tile's hover pane to begin fading out and starts\n * the timer for it to be removed.\n */\n private fadeOutHoverPane(): void {\n this.hoverPaneState = 'fading-out';\n this.hoverPane?.classList.remove('fade-in');\n\n clearTimeout(this.hideTimer);\n this.hideTimer = window.setTimeout(() => {\n this.hoverPaneState = 'hidden';\n this.host.requestUpdate();\n }, 100);\n }\n\n /**\n * Positions the hover pane with the correct offsets.\n */\n private repositionHoverPane(): void {\n if (!this.hoverPane) return;\n\n const { top, left } = this.hoverPaneDesiredOffsets;\n this.hoverPane.style.top = `${top}px`;\n this.hoverPane.style.left = `${left}px`;\n }\n}\n"]}
1
+ {"version":3,"file":"hover-pane-controller.js","sourceRoot":"","sources":["../../../../src/tiles/hover/hover-pane-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SortParam } from '@internetarchive/search-service';\nimport {\n html,\n HTMLTemplateResult,\n nothing,\n ReactiveController,\n ReactiveControllerHost,\n} from 'lit';\nimport type { TileModel } from '../../models';\nimport type { CollectionTitles } from '../../data-source/models';\n\ntype HoverPaneState = 'hidden' | 'shown' | 'fading-out';\n\nexport interface HoverPaneProperties {\n model?: TileModel;\n baseNavigationUrl?: string;\n baseImageUrl?: string;\n loggedIn: boolean;\n sortParam: SortParam | null;\n collectionTitles?: CollectionTitles;\n}\n\nexport interface HoverPaneControllerOptions {\n offsetX?: number;\n offsetY?: number;\n enableLongPress?: boolean;\n showDelay?: number;\n hideDelay?: number;\n longPressDelay?: number;\n mobileBreakpoint?: number;\n}\n\n/** A common interface for providing a hover pane element. */\nexport interface HoverPaneProviderInterface {\n /** Returns the provider's currently rendered hover pane element. */\n getHoverPane(): HTMLElement | undefined;\n /** Returns properties that should be passed to the hover pane. */\n getHoverPaneProps(): HoverPaneProperties;\n}\n\nexport interface ToggleHoverPaneOptions {\n coords: { x: number; y: number };\n enableTouchBackdrop?: boolean;\n}\n\n/**\n * An interface for interacting with hover pane controllers (e.g.,\n * to retrieve their current hover pane template).\n */\nexport interface HoverPaneControllerInterface extends ReactiveController {\n /**\n * Returns the hover pane template to render based on this controller's\n * current state. The returned template may be `nothing` if the hover\n * pane should not currently be rendered.\n */\n getTemplate(): HTMLTemplateResult | typeof nothing;\n\n /**\n * Requests to manually toggle the state of the hover pane.\n * If the hover pane is already shown, it will begin fading out and then\n * subsequently be hidden and removed. If the hover pane is already fading\n * out or hidden, it will fade back in and be shown.\n */\n toggleHoverPane(options: ToggleHoverPaneOptions): void;\n}\n\nconst clamp = (val: number, min = -Infinity, max = Infinity) =>\n Math.max(min, Math.min(val, max));\n\nexport class HoverPaneController implements HoverPaneControllerInterface {\n /**\n * The hover pane element attached to this controller's host.\n */\n private hoverPane?: HTMLElement;\n\n /**\n * The properties to be passed to the hover pane element\n */\n private hoverPaneProps?: HoverPaneProperties;\n\n /**\n * The breakpoint (in pixels) below which the mobile interface should be used.\n */\n private mobileBreakpoint?: number = 600;\n\n /**\n * The number of horizontal pixels the hover pane should be offset from the\n * pointer position.\n */\n private offsetX: number = -10;\n\n /**\n * The number of vertical pixels the hover pane should be offset from the\n * pointer position.\n */\n private offsetY: number = 15;\n\n /**\n * The delay between the mouse idling within the host element and when the hover\n * pane should begin fading in (in milliseconds).\n */\n private showDelay: number = 300;\n\n /**\n * The delay between when the mouse leaves the host element and when the hover\n * pane should begin fading out (in milliseconds).\n */\n private hideDelay: number = 100;\n\n /**\n * The delay between when a touch event begins on the host element and when the\n * hover pane should begin fading in (in milliseconds).\n */\n private longPressDelay: number = 600;\n\n /**\n * Whether long press interactions should cause the hover pane to appear (when\n * below the mobile breakpoint).\n */\n private enableLongPress: boolean = false;\n\n /**\n * Used to control the current state of this provider's hover pane.\n * - `'hidden'` => The hover pane is not present at all.\n * - `'shown'` => The hover pane is either fading in or fully visible.\n * - `'fading-out'` => The hover pane is fading out and about to be removed.\n */\n private hoverPaneState: HoverPaneState = 'hidden';\n\n /** The timer ID for showing the hover pane */\n private showTimer?: number;\n\n /** The timer ID for hiding the hover pane */\n private hideTimer?: number;\n\n /** The timer ID for recognizing a long press event */\n private longPressTimer?: number;\n\n /**\n * Whether the touch backdrop should currently be rendered irrespective of other touch\n * interactions being enabled.\n */\n private forceTouchBackdrop: boolean = false;\n\n /** A record of the last mouse position on the host element, for positioning the hover pane */\n private lastPointerClientPos = { x: 0, y: 0 };\n\n constructor(\n /** The host element to which this controller should attach listeners */\n private readonly host: ReactiveControllerHost &\n HoverPaneProviderInterface &\n HTMLElement,\n /** Options for adjusting the hover pane behavior (offsets, delays, etc.) */\n options: HoverPaneControllerOptions = {}\n ) {\n this.mobileBreakpoint = options.mobileBreakpoint ?? this.mobileBreakpoint;\n this.offsetX = options.offsetX ?? this.offsetX;\n this.offsetY = options.offsetY ?? this.offsetY;\n this.showDelay = options.showDelay ?? this.showDelay;\n this.hideDelay = options.hideDelay ?? this.hideDelay;\n this.longPressDelay = options.longPressDelay ?? this.longPressDelay;\n this.enableLongPress = options.enableLongPress ?? this.enableLongPress;\n\n this.host.addController(this);\n }\n\n hostConnected(): void {\n this.attachListeners();\n }\n\n hostDisconnected(): void {\n this.detachListeners();\n }\n\n hostUpdated(): void {\n this.hoverPane = this.host.getHoverPane();\n this.hoverPaneProps = this.host.getHoverPaneProps();\n }\n\n /** @inheritdoc */\n getTemplate(): HTMLTemplateResult | typeof nothing {\n return this.shouldRenderHoverPane\n ? html` ${this.touchBackdropTemplate}\n <tile-hover-pane\n .model=${this.hoverPaneProps?.model}\n .baseNavigationUrl=${this.hoverPaneProps?.baseNavigationUrl}\n .baseImageUrl=${this.hoverPaneProps?.baseImageUrl}\n .loggedIn=${this.hoverPaneProps?.loggedIn}\n .sortParam=${this.hoverPaneProps?.sortParam}\n .collectionTitles=${this.hoverPaneProps?.collectionTitles}\n ></tile-hover-pane>`\n : nothing;\n }\n\n /** @inheritdoc */\n toggleHoverPane(options: ToggleHoverPaneOptions): void {\n if (this.hoverPaneState === 'shown') {\n this.fadeOutHoverPane();\n this.forceTouchBackdrop = false;\n } else {\n this.lastPointerClientPos = options.coords;\n this.forceTouchBackdrop = options.enableTouchBackdrop ?? false;\n this.showHoverPane();\n }\n }\n\n /**\n * Produces a template for the invisible touch capture backdrop that\n * is used to cancel the hover pane on touch devices. We want any\n * touch interaction on the backdrop to remove the hover pane, and\n * we don't want to bubble up mouse events that would otherwise\n * affect the state of the hover pane (e.g., fading it back in).\n */\n private get touchBackdropTemplate(): HTMLTemplateResult | typeof nothing {\n return this.showTouchBackdrop\n ? html`<div\n id=\"touch-backdrop\"\n @touchstart=${this.handleBackdropInteraction}\n @touchmove=${this.handleBackdropInteraction}\n @touchend=${this.handleBackdropInteraction}\n @touchcancel=${this.handleBackdropInteraction}\n @mouseenter=${(e: MouseEvent) => e.stopPropagation()}\n @mousemove=${(e: MouseEvent) => e.stopPropagation()}\n @mouseleave=${(e: MouseEvent) => e.stopPropagation()}\n ></div>`\n : nothing;\n }\n\n private get showTouchBackdrop(): boolean {\n return (\n (this.isTouchEnabled && this.enableLongPress) || this.forceTouchBackdrop\n );\n }\n\n /** Whether to use the mobile layout */\n private get isMobileView(): boolean {\n return !!this.mobileBreakpoint && window.innerWidth < this.mobileBreakpoint;\n }\n\n private get isHoverEnabled(): boolean {\n return window.matchMedia('(hover: hover)').matches;\n }\n\n private get isTouchEnabled(): boolean {\n return (\n 'ontouchstart' in window &&\n window.matchMedia('(any-pointer: coarse)').matches\n );\n }\n\n /** Whether this controller should currently render its hover pane. */\n private get shouldRenderHoverPane(): boolean {\n return this.hoverPaneState !== 'hidden';\n }\n\n /**\n * Returns the desired top/left offsets (in pixels) for this tile's hover pane.\n * The desired offsets balance positioning the hover pane under the primary pointer\n * while preventing it from flowing outside the viewport. The returned offsets are\n * given relative to this tile's content box.\n *\n * These offsets are only valid if the hover pane is already rendered with its\n * correct width and height. If the hover pane is not present, the returned offsets\n * will simply represent the current pointer position.\n */\n private get hoverPaneDesiredOffsets(): { top: number; left: number } {\n // Try to find offsets for the hover pane that:\n // (a) cause it to lie entirely within the viewport, and\n // (b) to the extent possible, minimize the distance between the\n // nearest corner of the hover pane and the mouse position\n // (with some additional offsets applied after the fact).\n\n let [left, top] = [\n this.lastPointerClientPos.x,\n this.lastPointerClientPos.y,\n ];\n\n // Flip the hover pane according to which quadrant of the viewport the mouse is in.\n // (Similar to how Wikipedia's link hover panes work)\n const flipHorizontal = this.lastPointerClientPos.x > window.innerWidth / 2;\n const flipVertical = this.lastPointerClientPos.y > window.innerHeight / 2;\n\n const hoverPaneRect = this.hoverPane?.getBoundingClientRect();\n if (hoverPaneRect) {\n // If we need to flip the hover pane, do so by subtracting its width/height from left/top\n if (flipHorizontal) {\n left -= hoverPaneRect.width;\n }\n if (flipVertical) {\n top -= hoverPaneRect.height;\n }\n\n // Apply desired offsets from the mouse position\n left += (flipHorizontal ? -1 : 1) * this.offsetX;\n top += (flipVertical ? -1 : 1) * this.offsetY;\n\n // On mobile view, shunt the hover pane to avoid overflowing the viewport\n if (this.isMobileView) {\n left = clamp(left, 20, window.innerWidth - hoverPaneRect.width - 20);\n top = clamp(top, 20, window.innerHeight - hoverPaneRect.height - 20);\n }\n }\n\n // Subtract off the tile's own offsets\n const hostRect = this.host.getBoundingClientRect();\n left -= hostRect.left;\n top -= hostRect.top;\n\n return { left, top };\n }\n\n /**\n * Adds to the host element all the listeners necessary to make the\n * hover pane functional.\n */\n private attachListeners(): void {\n if (this.isHoverEnabled) {\n this.host.addEventListener('mouseenter', this.handleMouseEnter);\n this.host.addEventListener('mousemove', this.handleMouseMove);\n this.host.addEventListener('mouseleave', this.handleMouseLeave);\n }\n\n if (this.isTouchEnabled && this.enableLongPress) {\n this.host.addEventListener('touchstart', this.handleTouchStart);\n this.host.addEventListener('touchmove', this.handleLongPressCancel);\n this.host.addEventListener('touchend', this.handleLongPressCancel);\n this.host.addEventListener('touchcancel', this.handleLongPressCancel);\n this.host.addEventListener('contextmenu', this.handleContextMenu);\n }\n }\n\n /**\n * Removes all the hover pane listeners from the host element.\n */\n private detachListeners(): void {\n this.host.removeEventListener('mouseenter', this.handleMouseEnter);\n this.host.removeEventListener('mousemove', this.handleMouseMove);\n this.host.removeEventListener('mouseleave', this.handleMouseLeave);\n this.host.removeEventListener('touchstart', this.handleTouchStart);\n this.host.removeEventListener('touchmove', this.handleLongPressCancel);\n this.host.removeEventListener('touchend', this.handleLongPressCancel);\n this.host.removeEventListener('touchcancel', this.handleLongPressCancel);\n this.host.removeEventListener('contextmenu', this.handleContextMenu);\n }\n\n /**\n * Handler for the mouseenter event on the host element.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleMouseEnter = (e: MouseEvent): void => {\n // Delegate to the mousemove handler, as they are currently processed identically\n this.handleMouseMove(e);\n };\n\n /**\n * Handler for the mousemove event on the host element.\n * Aborts any pending hide/fade-out for the hover pane, and restarts the\n * timer to show it.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleMouseMove = (e: MouseEvent): void => {\n // The mouse is within the tile, so abort any pending removal of the hover pane\n clearTimeout(this.hideTimer);\n\n // If the hover pane is currently fading out, just make it fade back in where it is\n if (this.hoverPaneState === 'fading-out') {\n this.hoverPaneState = 'shown';\n this.hoverPane?.classList.add('fade-in');\n }\n\n // Restart the timer to show the hover pane anytime the mouse moves within the tile\n if (this.hoverPaneState === 'hidden') {\n this.restartShowHoverPaneTimer();\n this.lastPointerClientPos = { x: e.clientX, y: e.clientY };\n }\n };\n\n /**\n * Handler for the mouseleave event on the host element.\n * Hides the hover pane if present, and aborts the timer for showing it.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleMouseLeave = (): void => {\n // Abort any timer to show the hover pane, as the mouse has left the tile\n clearTimeout(this.showTimer);\n\n // Hide the hover pane if it's already been shown\n clearTimeout(this.hideTimer);\n if (this.hoverPaneState !== 'hidden') {\n this.hideTimer = window.setTimeout(() => {\n this.fadeOutHoverPane();\n }, this.hideDelay);\n }\n };\n\n /**\n * Handler for the touchstart event on the host element.\n * Begins the timer for recognizing a long press event.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleTouchStart = (e: TouchEvent): void => {\n clearTimeout(this.longPressTimer);\n\n if (e.touches.length === 1) {\n this.longPressTimer = window.setTimeout(() => {\n if (this.hoverPaneState === 'hidden') {\n this.showHoverPane();\n }\n }, this.longPressDelay);\n\n this.lastPointerClientPos = {\n x: e.touches[0].clientX,\n y: e.touches[0].clientY,\n };\n }\n };\n\n /**\n * Handler for events that should cancel a pending long press event\n * (touchmove, touchend, touchcancel). Aborts the timer for recognizing\n * a long press.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleLongPressCancel = (): void => {\n clearTimeout(this.longPressTimer);\n };\n\n /**\n * Handler for the contextmenu event, which should be suppressed during\n * mobile long-press events on the host element.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleContextMenu = (e: Event): void => {\n e.preventDefault();\n };\n\n /**\n * Immediately causes the hover pane to begin fading out, if it is present.\n */\n // NB: Arrow function so 'this' remains bound to the controller\n private handleBackdropInteraction = (e: Event): void => {\n if (this.hoverPaneState !== 'hidden') {\n this.fadeOutHoverPane();\n }\n e.stopPropagation();\n };\n\n /**\n * Aborts and restarts the timer for showing the hover pane.\n */\n private restartShowHoverPaneTimer(): void {\n clearTimeout(this.showTimer);\n this.showTimer = window.setTimeout(() => {\n this.showHoverPane();\n }, this.showDelay);\n }\n\n /**\n * Causes this tile's hover pane to be rendered, positioned, and made visible.\n */\n private async showHoverPane(): Promise<void> {\n this.hoverPaneState = 'shown';\n this.host.requestUpdate();\n\n // Wait for the state update to render the hover pane\n await this.host.updateComplete;\n await new Promise(resolve => {\n // Pane sizes aren't accurate until next frame\n requestAnimationFrame(resolve);\n });\n\n // Apply the correct positioning to the hover pane\n this.repositionHoverPane();\n\n // The hover pane is initially not visible (to avoid it shifting around\n // while being positioned). Since it now has the correct positioning, we\n // can make it visible and begin its fade-in animation.\n this.hoverPane?.classList.add('visible', 'fade-in');\n }\n\n /**\n * Causes this tile's hover pane to begin fading out and starts\n * the timer for it to be removed.\n */\n private fadeOutHoverPane(): void {\n this.hoverPaneState = 'fading-out';\n this.hoverPane?.classList.remove('fade-in');\n\n clearTimeout(this.hideTimer);\n this.hideTimer = window.setTimeout(() => {\n this.hoverPaneState = 'hidden';\n this.host.requestUpdate();\n }, 100);\n }\n\n /**\n * Positions the hover pane with the correct offsets.\n */\n private repositionHoverPane(): void {\n if (!this.hoverPane) return;\n\n const { top, left } = this.hoverPaneDesiredOffsets;\n this.hoverPane.style.top = `${top}px`;\n this.hoverPane.style.left = `${left}px`;\n }\n}\n"]}
@@ -1,7 +1,7 @@
1
- import type { CollectionNameCacheInterface } from '@internetarchive/collection-name-cache';
2
1
  import type { SortParam } from '@internetarchive/search-service';
3
2
  import { CSSResultGroup, LitElement, TemplateResult } from 'lit';
4
3
  import type { TileModel } from '../../models';
4
+ import type { CollectionTitles } from '../../data-source/models';
5
5
  import '../list/tile-list';
6
6
  export declare class TileHoverPane extends LitElement {
7
7
  model?: TileModel;
@@ -9,7 +9,7 @@ export declare class TileHoverPane extends LitElement {
9
9
  baseImageUrl?: string;
10
10
  loggedIn: boolean;
11
11
  sortParam?: SortParam;
12
- collectionNameCache?: CollectionNameCacheInterface;
12
+ collectionTitles?: CollectionTitles;
13
13
  protected render(): TemplateResult;
14
14
  static get styles(): CSSResultGroup;
15
15
  }
@@ -16,7 +16,7 @@ let TileHoverPane = class TileHoverPane extends LitElement {
16
16
  .baseImageUrl=${this.baseImageUrl}
17
17
  .loggedIn=${this.loggedIn}
18
18
  .sortParam=${this.sortParam}
19
- .collectionNameCache=${this.collectionNameCache}
19
+ .collectionTitles=${this.collectionTitles}
20
20
  ></tile-list>
21
21
  </div>
22
22
  `;
@@ -80,7 +80,7 @@ __decorate([
80
80
  ], TileHoverPane.prototype, "sortParam", void 0);
81
81
  __decorate([
82
82
  property({ type: Object })
83
- ], TileHoverPane.prototype, "collectionNameCache", void 0);
83
+ ], TileHoverPane.prototype, "collectionTitles", void 0);
84
84
  TileHoverPane = __decorate([
85
85
  customElement('tile-hover-pane')
86
86
  ], TileHoverPane);
@@ -1 +1 @@
1
- {"version":3,"file":"tile-hover-pane.js","sourceRoot":"","sources":["../../../../src/tiles/hover/tile-hover-pane.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,GAAG,EAAkB,IAAI,EAAE,UAAU,EAAkB,MAAM,KAAK,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,mBAAmB,CAAC;AAG3B,IAAa,aAAa,GAA1B,MAAa,aAAc,SAAQ,UAAU;IAA7C;;QAO+B,aAAQ,GAAY,KAAK,CAAC;IA+DzD,CAAC;IAxDW,MAAM;QACd,OAAO,IAAI,CAAA;;;mBAGI,IAAI,CAAC,KAAK;+BACE,IAAI,CAAC,iBAAiB;0BAC3B,IAAI,CAAC,YAAY;sBACrB,IAAI,CAAC,QAAQ;uBACZ,IAAI,CAAC,SAAS;iCACJ,IAAI,CAAC,mBAAmB;;;KAGpD,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,MAAM;QACf,OAAO,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAsCT,CAAC;IACJ,CAAC;CACF,CAAA;AArE6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;4CAAmB;AAElB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wDAA4B;AAE3B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;mDAAuB;AAErB;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;+CAA2B;AAE3B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gDAAuB;AAGlD;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;0DACwB;AAZxC,aAAa;IADzB,aAAa,CAAC,iBAAiB,CAAC;GACpB,aAAa,CAsEzB;SAtEY,aAAa","sourcesContent":["import type { CollectionNameCacheInterface } from '@internetarchive/collection-name-cache';\nimport type { SortParam } from '@internetarchive/search-service';\nimport { css, CSSResultGroup, html, LitElement, TemplateResult } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type { TileModel } from '../../models';\nimport '../list/tile-list';\n\n@customElement('tile-hover-pane')\nexport class TileHoverPane extends LitElement {\n @property({ type: Object }) model?: TileModel;\n\n @property({ type: String }) baseNavigationUrl?: string;\n\n @property({ type: String }) baseImageUrl?: string;\n\n @property({ type: Boolean }) loggedIn: boolean = false;\n\n @property({ type: Object }) sortParam?: SortParam;\n\n @property({ type: Object })\n collectionNameCache?: CollectionNameCacheInterface;\n\n protected render(): TemplateResult {\n return html`\n <div id=\"container\">\n <tile-list\n .model=${this.model}\n .baseNavigationUrl=${this.baseNavigationUrl}\n .baseImageUrl=${this.baseImageUrl}\n .loggedIn=${this.loggedIn}\n .sortParam=${this.sortParam}\n .collectionNameCache=${this.collectionNameCache}\n ></tile-list>\n </div>\n `;\n }\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n visibility: hidden;\n opacity: 0;\n transform: translateY(8px);\n transition: opacity 0.1s ease-in, transform 0.1s ease-in;\n }\n\n :host(.visible) {\n visibility: visible;\n }\n\n :host(.fade-in) {\n opacity: 1;\n transform: translateY(0);\n }\n\n @media (prefers-reduced-motion: reduce) {\n :host {\n transition-duration: 0.001s !important; /* Imperceptibly fast */\n }\n }\n\n #container {\n width: max-content;\n max-width: min(45vw, 600px);\n padding: 10px;\n border: 1px solid #ddd;\n border-radius: 4px;\n box-shadow: 4px 4px 8px 0 rgba(0, 0, 0, 0.8);\n background: white;\n }\n\n @media screen and (max-width: 600px) {\n #container {\n max-width: 80vw;\n }\n }\n `;\n }\n}\n"]}
1
+ {"version":3,"file":"tile-hover-pane.js","sourceRoot":"","sources":["../../../../src/tiles/hover/tile-hover-pane.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAkB,IAAI,EAAE,UAAU,EAAkB,MAAM,KAAK,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAG5D,OAAO,mBAAmB,CAAC;AAG3B,IAAa,aAAa,GAA1B,MAAa,aAAc,SAAQ,UAAU;IAA7C;;QAO+B,aAAQ,GAAY,KAAK,CAAC;IA+DzD,CAAC;IAxDW,MAAM;QACd,OAAO,IAAI,CAAA;;;mBAGI,IAAI,CAAC,KAAK;+BACE,IAAI,CAAC,iBAAiB;0BAC3B,IAAI,CAAC,YAAY;sBACrB,IAAI,CAAC,QAAQ;uBACZ,IAAI,CAAC,SAAS;8BACP,IAAI,CAAC,gBAAgB;;;KAG9C,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,MAAM;QACf,OAAO,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAsCT,CAAC;IACJ,CAAC;CACF,CAAA;AArE6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;4CAAmB;AAElB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wDAA4B;AAE3B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;mDAAuB;AAErB;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;+CAA2B;AAE3B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gDAAuB;AAGlD;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;uDACS;AAZzB,aAAa;IADzB,aAAa,CAAC,iBAAiB,CAAC;GACpB,aAAa,CAsEzB;SAtEY,aAAa","sourcesContent":["import type { SortParam } from '@internetarchive/search-service';\nimport { css, CSSResultGroup, html, LitElement, TemplateResult } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type { TileModel } from '../../models';\nimport type { CollectionTitles } from '../../data-source/models';\nimport '../list/tile-list';\n\n@customElement('tile-hover-pane')\nexport class TileHoverPane extends LitElement {\n @property({ type: Object }) model?: TileModel;\n\n @property({ type: String }) baseNavigationUrl?: string;\n\n @property({ type: String }) baseImageUrl?: string;\n\n @property({ type: Boolean }) loggedIn: boolean = false;\n\n @property({ type: Object }) sortParam?: SortParam;\n\n @property({ type: Object })\n collectionTitles?: CollectionTitles;\n\n protected render(): TemplateResult {\n return html`\n <div id=\"container\">\n <tile-list\n .model=${this.model}\n .baseNavigationUrl=${this.baseNavigationUrl}\n .baseImageUrl=${this.baseImageUrl}\n .loggedIn=${this.loggedIn}\n .sortParam=${this.sortParam}\n .collectionTitles=${this.collectionTitles}\n ></tile-list>\n </div>\n `;\n }\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n visibility: hidden;\n opacity: 0;\n transform: translateY(8px);\n transition: opacity 0.1s ease-in, transform 0.1s ease-in;\n }\n\n :host(.visible) {\n visibility: visible;\n }\n\n :host(.fade-in) {\n opacity: 1;\n transform: translateY(0);\n }\n\n @media (prefers-reduced-motion: reduce) {\n :host {\n transition-duration: 0.001s !important; /* Imperceptibly fast */\n }\n }\n\n #container {\n width: max-content;\n max-width: min(45vw, 600px);\n padding: 10px;\n border: 1px solid #ddd;\n border-radius: 4px;\n box-shadow: 4px 4px 8px 0 rgba(0, 0, 0, 0.8);\n background: white;\n }\n\n @media screen and (max-width: 600px) {\n #container {\n max-width: 80vw;\n }\n }\n `;\n }\n}\n"]}
@@ -1,10 +1,10 @@
1
1
  import { PropertyValues, TemplateResult } from 'lit';
2
- import type { CollectionNameCacheInterface } from '@internetarchive/collection-name-cache';
2
+ import type { CollectionTitles } from '../../data-source/models';
3
3
  import { BaseTileComponent } from '../base-tile-component';
4
4
  import '../image-block';
5
5
  import '../mediatype-icon';
6
6
  export declare class TileList extends BaseTileComponent {
7
- collectionNameCache?: CollectionNameCacheInterface;
7
+ collectionTitles?: CollectionTitles;
8
8
  private collectionLinks;
9
9
  render(): TemplateResult<1>;
10
10
  /**
@@ -38,7 +38,7 @@ export declare class TileList extends BaseTileComponent {
38
38
  /** The URL of this item's mediatype collection, if defined. */
39
39
  private get mediatypeURL();
40
40
  protected updated(changed: PropertyValues): void;
41
- private fetchCollectionNames;
41
+ private buildCollectionLinks;
42
42
  private get date();
43
43
  private get classSize();
44
44
  private get formatSize();
@@ -316,32 +316,26 @@ let TileList = class TileList extends BaseTileComponent {
316
316
  }
317
317
  }
318
318
  updated(changed) {
319
- if (changed.has('model')) {
320
- this.fetchCollectionNames();
319
+ if (changed.has('model') || changed.has('collectionTitles')) {
320
+ this.buildCollectionLinks();
321
321
  }
322
322
  }
323
- async fetchCollectionNames() {
324
- var _a, _b;
325
- if (!((_a = this.model) === null || _a === void 0 ? void 0 : _a.collections) ||
326
- this.model.collections.length === 0 ||
327
- !this.collectionNameCache) {
323
+ async buildCollectionLinks() {
324
+ var _a, _b, _c;
325
+ if (!((_a = this.model) === null || _a === void 0 ? void 0 : _a.collections) || this.model.collections.length === 0) {
328
326
  return;
329
327
  }
330
328
  // Note: quirk of Lit: need to replace collectionLinks array,
331
329
  // otherwise it will not re-render. Can't simply alter the array.
332
330
  this.collectionLinks = [];
333
331
  const newCollectionLinks = [];
334
- const promises = [];
335
332
  for (const collection of this.model.collections) {
336
333
  // Don't include favorites or collections that are meant to be suppressed
337
334
  if (!suppressedCollections[collection] &&
338
335
  !collection.startsWith('fav-')) {
339
- promises.push((_b = this.collectionNameCache) === null || _b === void 0 ? void 0 : _b.collectionNameFor(collection).then(name => {
340
- newCollectionLinks.push(this.detailsLink(collection, name !== null && name !== void 0 ? name : collection, true));
341
- }));
336
+ newCollectionLinks.push(this.detailsLink(collection, (_c = (_b = this.collectionTitles) === null || _b === void 0 ? void 0 : _b.get(collection)) !== null && _c !== void 0 ? _c : collection, true));
342
337
  }
343
338
  }
344
- await Promise.all(promises);
345
339
  this.collectionLinks = newCollectionLinks;
346
340
  }
347
341
  /*
@@ -554,7 +548,7 @@ let TileList = class TileList extends BaseTileComponent {
554
548
  };
555
549
  __decorate([
556
550
  property({ type: Object })
557
- ], TileList.prototype, "collectionNameCache", void 0);
551
+ ], TileList.prototype, "collectionTitles", void 0);
558
552
  __decorate([
559
553
  state()
560
554
  ], TileList.prototype, "collectionLinks", void 0);