@internetarchive/collection-browser 4.3.2-rc-webdev-8334.4 → 4.3.2-rc-webdev-8334.5

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.
@@ -122,25 +122,7 @@ let TileDispatcher = class TileDispatcher extends BaseTileComponent {
122
122
  // Use the server-specified href if available.
123
123
  // Otherwise, construct a details page URL from the item identifier.
124
124
  if (this.model.href) {
125
- // Backstop for legacy Wayback Machine URLs where the target URL was
126
- // erroneously percent-encoded by encodeURIComponent (the root cause in
127
- // tile-display-value-provider is fixed, but old stored data may still
128
- // carry encoded URLs). Decode only the target-URL segment after the
129
- // /web/{timestamp}/ prefix — decoding the full href risks corrupting the
130
- // Wayback prefix or intentional encoding elsewhere in the path.
131
- // %3A%2F%2F (encoded "://") is an unambiguous indicator the entire URL
132
- // was over-encoded; legitimate paths with %3A never appear next to %2F%2F.
133
- const href = this.model.href.replace(/(\/web\/\d+\/)(.+)/, (_, prefix, target) => {
134
- if (!/%3A%2F%2F/i.test(target))
135
- return `${prefix}${target}`;
136
- try {
137
- return `${prefix}${decodeURIComponent(target)}`;
138
- }
139
- catch {
140
- return `${prefix}${target}`;
141
- }
142
- });
143
- return `${this.baseNavigationUrl}${href}`;
125
+ return `${this.baseNavigationUrl}${this.model.href}`;
144
126
  }
145
127
  return this.displayValueProvider.itemPageUrl(this.model.identifier, this.model.mediatype === 'collection');
146
128
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tile-dispatcher.js","sourceRoot":"","sources":["../../../src/tiles/tile-dispatcher.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, nothing, PropertyValues } from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { msg } from '@lit/localize';\nimport type {\n SharedResizeObserverInterface,\n SharedResizeObserverResizeHandlerInterface,\n} from '@internetarchive/shared-resize-observer';\nimport type { TileDisplayMode } from '../models';\nimport type { CollectionTitles } from '../data-source/models';\nimport './grid/collection-tile';\nimport './grid/item-tile';\nimport './grid/account-tile';\nimport './grid/search-tile';\nimport './hover/tile-hover-pane';\nimport './list/tile-list';\nimport './list/tile-list-compact';\nimport './list/tile-list-compact-header';\nimport type { TileHoverPane } from './hover/tile-hover-pane';\nimport { BaseTileComponent } from './base-tile-component';\nimport { LayoutType } from './models';\nimport {\n HoverPaneController,\n HoverPaneControllerInterface,\n HoverPaneProperties,\n HoverPaneProviderInterface,\n} from './hover/hover-pane-controller';\nimport { srOnlyStyle } from '../styles/sr-only';\n\n@customElement('tile-dispatcher')\nexport class TileDispatcher\n extends BaseTileComponent\n implements\n SharedResizeObserverResizeHandlerInterface,\n HoverPaneProviderInterface\n{\n /*\n * Reactive properties inherited from BaseTileComponent:\n * - model?: TileModel;\n * - currentWidth?: number;\n * - currentHeight?: number;\n * - baseNavigationUrl?: string;\n * - baseImageUrl?: string;\n * - collectionPagePath?: string;\n * - sortParam: SortParam | null = null;\n * - defaultSortParam: SortParam | null = null;\n * - creatorFilter?: string;\n * - mobileBreakpoint?: number;\n * - loggedIn = false;\n * - suppressTileBlurring = false;\n * - useLocalTime = false;\n */\n\n @property({ type: String }) tileDisplayMode?: TileDisplayMode;\n\n @property({ type: Boolean }) isManageView = false;\n\n @property({ type: Object }) resizeObserver?: SharedResizeObserverInterface;\n\n @property({ type: Object })\n collectionTitles?: CollectionTitles;\n\n @property({ type: Boolean }) showTvClips = false;\n\n /** What type of simplified layout to use in grid mode, if any */\n @property({ type: String }) layoutType: LayoutType = 'default';\n\n /** Whether this tile should include a hover pane at all (for applicable tile modes) */\n @property({ type: Boolean }) enableHoverPane = false;\n\n @property({ type: String }) manageCheckTitle = msg(\n 'Remove this item from the list',\n );\n\n private hoverPaneController?: HoverPaneControllerInterface;\n\n @query('#container')\n private container!: HTMLDivElement;\n\n @query('tile-hover-pane')\n private hoverPane?: TileHoverPane;\n\n @query('.tile-link')\n private tileLinkElement?: HTMLAnchorElement;\n\n acquireFocus(): void {\n this.tileLinkElement?.focus();\n }\n\n releaseFocus(): void {\n this.tileLinkElement?.blur();\n }\n\n /** Maps each display mode to whether hover panes should appear in that mode */\n private static readonly HOVER_PANE_DISPLAY_MODES: Record<\n TileDisplayMode,\n boolean\n > = {\n grid: true,\n 'list-compact': true,\n 'list-detail': false,\n 'list-header': false,\n };\n\n render() {\n const isGridMode = this.tileDisplayMode === 'grid';\n const hoverPaneTemplate =\n this.hoverPaneController?.getTemplate() ?? nothing;\n return html`\n <div id=\"container\" class=${isGridMode ? 'hoverable' : ''}>\n ${this.tileDisplayMode === 'list-header'\n ? this.headerTemplate\n : this.tileTemplate}\n ${this.manageCheckTemplate} ${hoverPaneTemplate}\n </div>\n `;\n }\n\n protected firstUpdated(): void {\n if (this.shouldPrepareHoverPane) {\n this.hoverPaneController = new HoverPaneController(this, {\n mobileBreakpoint: this.mobileBreakpoint,\n enableLongPress: false,\n });\n }\n }\n\n private get headerTemplate() {\n const { currentWidth, sortParam, defaultSortParam, mobileBreakpoint } =\n this;\n return html`\n <tile-list-compact-header\n class=\"header\"\n .currentWidth=${currentWidth}\n .sortParam=${sortParam ?? defaultSortParam}\n .mobileBreakpoint=${mobileBreakpoint}\n >\n </tile-list-compact-header>\n `;\n }\n\n private get tileTemplate() {\n return html`\n ${this.tileDisplayMode === 'list-detail'\n ? this.tile\n : this.linkTileTemplate}\n `;\n }\n\n private get linkTileTemplate() {\n return html`\n <a\n href=${this.linkTileHref}\n aria-label=${this.model?.title ?? 'Untitled item'}\n aria-describedby=\"link-aria-description\"\n aria-haspopup=${this.shouldPrepareHoverPane ? 'dialog' : 'false'}\n title=${this.shouldPrepareHoverPane\n ? nothing // Don't show title tooltips when we have the tile info popups\n : ifDefined(this.model?.title)}\n @click=${this.handleLinkClicked}\n @contextmenu=${this.handleLinkContextMenu}\n class=\"tile-link\"\n >\n ${this.tile}\n </a>\n <div id=\"link-aria-description\" class=\"sr-only\">\n ${msg('Press Down Arrow to preview item details')}\n </div>\n `;\n }\n\n private get linkTileHref(): string | typeof nothing {\n if (!this.model?.identifier || this.baseNavigationUrl == null)\n return nothing;\n\n // Use the server-specified href if available.\n // Otherwise, construct a details page URL from the item identifier.\n if (this.model.href) {\n // Backstop for legacy Wayback Machine URLs where the target URL was\n // erroneously percent-encoded by encodeURIComponent (the root cause in\n // tile-display-value-provider is fixed, but old stored data may still\n // carry encoded URLs). Decode only the target-URL segment after the\n // /web/{timestamp}/ prefix — decoding the full href risks corrupting the\n // Wayback prefix or intentional encoding elsewhere in the path.\n // %3A%2F%2F (encoded \"://\") is an unambiguous indicator the entire URL\n // was over-encoded; legitimate paths with %3A never appear next to %2F%2F.\n const href = this.model.href.replace(\n /(\\/web\\/\\d+\\/)(.+)/,\n (_, prefix, target) => {\n if (!/%3A%2F%2F/i.test(target)) return `${prefix}${target}`;\n try {\n return `${prefix}${decodeURIComponent(target)}`;\n } catch {\n return `${prefix}${target}`;\n }\n },\n );\n return `${this.baseNavigationUrl}${href}`;\n }\n\n return this.displayValueProvider.itemPageUrl(\n this.model.identifier,\n this.model.mediatype === 'collection',\n );\n }\n\n private get manageCheckTemplate() {\n if (!this.isManageView || this.tileDisplayMode !== 'grid') return nothing;\n\n return html`\n <div class=\"manage-check\">\n <input\n type=\"checkbox\"\n title=${this.manageCheckTitle}\n ?checked=${this.model?.checked}\n @change=${this.handleLinkClicked}\n />\n </div>\n `;\n }\n\n /**\n * Whether hover pane behavior should be prepared for this tile\n * (e.g., whether mouse listeners should be attached, etc.)\n */\n private get shouldPrepareHoverPane(): boolean {\n return (\n this.enableHoverPane &&\n !!this.tileDisplayMode &&\n TileDispatcher.HOVER_PANE_DISPLAY_MODES[this.tileDisplayMode] &&\n this.model?.mediatype !== 'search' && // don't show hover panes on search tiles\n !this.model?.captureDates // don't show hover panes on web archive tiles\n );\n }\n\n private get isHoverEnabled(): boolean {\n return window.matchMedia('(hover: hover)').matches;\n }\n\n /**\n * Whether the info button should be shown on this tile.\n * Only shown on touch/non-hover devices where a hover pane is available,\n * so the button always has something to toggle.\n */\n private get shouldShowInfoButton(): boolean {\n return !this.isHoverEnabled && this.shouldPrepareHoverPane;\n }\n\n /** @inheritdoc */\n getHoverPane(): TileHoverPane | undefined {\n return this.hoverPane;\n }\n\n /** @inheritdoc */\n getHoverPaneProps(): HoverPaneProperties {\n return this;\n }\n\n handleResize(entry: ResizeObserverEntry): void {\n this.currentWidth = entry.contentRect.width;\n this.currentHeight = entry.contentRect.height;\n }\n\n disconnectedCallback(): void {\n this.stopResizeObservation(this.resizeObserver);\n }\n\n private stopResizeObservation(observer?: SharedResizeObserverInterface) {\n observer?.removeObserver({\n handler: this,\n target: this.container,\n });\n }\n\n private startResizeObservation() {\n this.stopResizeObservation(this.resizeObserver);\n this.resizeObserver?.addObserver({\n handler: this,\n target: this.container,\n });\n }\n\n updated(props: PropertyValues) {\n if (props.has('resizeObserver')) {\n const previousObserver = props.get(\n 'resizeObserver',\n ) as SharedResizeObserverInterface;\n this.stopResizeObservation(previousObserver);\n this.startResizeObservation();\n }\n }\n\n /**\n * Handler for when the tile link is left-clicked. Emits the `resultSelected` event.\n * In manage view, it also checks/unchecks the tile.\n */\n private handleLinkClicked(e: Event): void {\n if (this.isManageView) {\n e.preventDefault();\n if (this.model) this.model.checked = !this.model.checked;\n }\n\n this.dispatchEvent(\n new CustomEvent('resultSelected', { detail: this.model }),\n );\n }\n\n /**\n * Handler for when the tile link is right-clicked.\n * In manage view, it opens the item in a new tab. Otherwise, does nothing.\n */\n private handleLinkContextMenu(e: Event): void {\n if (this.isManageView && this.linkTileHref !== nothing) {\n e.preventDefault();\n window.open(this.linkTileHref, '_blank');\n }\n }\n\n private tileInfoButtonPressed(\n e: CustomEvent<{ x: number; y: number }>,\n ): void {\n this.hoverPaneController?.toggleHoverPane({\n coords: e.detail,\n enableTouchBackdrop: true,\n });\n }\n\n private get tile() {\n const {\n model,\n collectionPagePath,\n baseNavigationUrl,\n currentWidth,\n currentHeight,\n sortParam,\n creatorFilter,\n mobileBreakpoint,\n defaultSortParam,\n } = this;\n\n if (!model) return nothing;\n\n switch (this.tileDisplayMode) {\n case 'grid':\n switch (model.mediatype) {\n case 'collection':\n return html`<collection-tile\n .model=${model}\n .collectionPagePath=${collectionPagePath}\n .baseImageUrl=${this.baseImageUrl}\n .currentWidth=${currentWidth}\n .currentHeight=${currentHeight}\n .creatorFilter=${creatorFilter}\n .suppressBlurring=${this.suppressBlurring}\n .isManageView=${this.isManageView}\n .layoutType=${this.layoutType}\n ?showInfoButton=${this.shouldShowInfoButton}\n @infoButtonPressed=${this.tileInfoButtonPressed}\n >\n </collection-tile>`;\n case 'account':\n return html`<account-tile\n .model=${model}\n .collectionPagePath=${collectionPagePath}\n .baseImageUrl=${this.baseImageUrl}\n .currentWidth=${currentWidth}\n .currentHeight=${currentHeight}\n .creatorFilter=${creatorFilter}\n .suppressBlurring=${this.suppressBlurring}\n .isManageView=${this.isManageView}\n ?showInfoButton=${this.shouldShowInfoButton}\n @infoButtonPressed=${this.tileInfoButtonPressed}\n >\n </account-tile>`;\n case 'search':\n return html`<search-tile\n .model=${model}\n .collectionPagePath=${collectionPagePath}\n .baseImageUrl=${this.baseImageUrl}\n .currentWidth=${currentWidth}\n .currentHeight=${currentHeight}\n .creatorFilter=${creatorFilter}\n .suppressBlurring=${this.suppressBlurring}\n .isManageView=${this.isManageView}\n ?showInfoButton=${false}\n @infoButtonPressed=${this.tileInfoButtonPressed}\n >\n </search-tile>`;\n default:\n return html`<item-tile\n .model=${model}\n .collectionPagePath=${collectionPagePath}\n .currentWidth=${this.currentWidth}\n .currentHeight=${this.currentHeight}\n .baseImageUrl=${this.baseImageUrl}\n .sortParam=${sortParam}\n .defaultSortParam=${defaultSortParam}\n .creatorFilter=${creatorFilter}\n .loggedIn=${this.loggedIn}\n .suppressBlurring=${this.suppressBlurring}\n .isManageView=${this.isManageView}\n .layoutType=${this.layoutType}\n ?showTvClips=${this.showTvClips}\n ?showInfoButton=${this.shouldShowInfoButton}\n ?useLocalTime=${this.useLocalTime}\n @infoButtonPressed=${this.tileInfoButtonPressed}\n >\n </item-tile>`;\n }\n case 'list-compact':\n return html`<tile-list-compact\n .model=${model}\n .collectionPagePath=${collectionPagePath}\n .currentWidth=${currentWidth}\n .currentHeight=${currentHeight}\n .baseNavigationUrl=${baseNavigationUrl}\n .sortParam=${sortParam}\n .defaultSortParam=${defaultSortParam}\n .creatorFilter=${creatorFilter}\n .mobileBreakpoint=${mobileBreakpoint}\n .baseImageUrl=${this.baseImageUrl}\n .loggedIn=${this.loggedIn}\n .suppressBlurring=${this.suppressBlurring}\n ?useLocalTime=${this.useLocalTime}\n >\n </tile-list-compact>`;\n case 'list-detail':\n return html`<tile-list\n .model=${model}\n .collectionPagePath=${collectionPagePath}\n .collectionTitles=${this.collectionTitles}\n .currentWidth=${currentWidth}\n .currentHeight=${currentHeight}\n .baseNavigationUrl=${baseNavigationUrl}\n .sortParam=${sortParam}\n .defaultSortParam=${defaultSortParam}\n .creatorFilter=${creatorFilter}\n .mobileBreakpoint=${mobileBreakpoint}\n .baseImageUrl=${this.baseImageUrl}\n .loggedIn=${this.loggedIn}\n .suppressBlurring=${this.suppressBlurring}\n ?useLocalTime=${this.useLocalTime}\n >\n </tile-list>`;\n default:\n return nothing;\n }\n }\n\n static get styles() {\n return [\n srOnlyStyle,\n css`\n :host {\n display: block;\n height: 100%;\n }\n\n collection-tile {\n --tileBorderColor: #555555;\n --tileBackgroundColor: #666666;\n --imageBlockBackgroundColor: #666666;\n }\n\n account-tile {\n --tileBorderColor: #dddddd;\n --imageBlockBackgroundColor: #fcf5e6;\n }\n\n item-tile {\n --tileBorderColor: #dddddd;\n --imageBlockBackgroundColor: #f1f1f4;\n }\n\n search-tile {\n --tileBorderColor: #555555;\n --tileBackgroundColor: #666666;\n --imageBlockBackgroundColor: #666666;\n --iconFillColor: #2c2c2c;\n }\n\n #container {\n position: relative;\n height: 100%;\n border-radius: 4px;\n }\n\n #container.hoverable a:focus,\n #container.hoverable a:hover {\n box-shadow: var(\n --tileHoverBoxShadow,\n 0 0 6px 2px rgba(8, 8, 32, 0.8)\n );\n transition: box-shadow 0.1s ease;\n }\n\n a {\n display: block;\n height: 100%;\n color: unset;\n text-decoration: none;\n transition: transform 0.05s ease;\n border-radius: 4px;\n outline: none;\n }\n\n a :first-child {\n display: block;\n height: 100%;\n }\n\n .manage-check {\n position: absolute;\n right: 0;\n top: 0;\n border: 5px solid #2c2c2c;\n border-radius: 3px;\n background-color: #2c2c2c;\n z-index: 1;\n }\n\n .manage-check > input[type='checkbox'] {\n display: block;\n margin: 0;\n }\n\n #touch-backdrop {\n position: fixed;\n width: 100vw;\n height: 100vh;\n top: 0;\n left: 0;\n z-index: 2;\n background: transparent;\n }\n\n tile-hover-pane {\n position: absolute;\n top: 0;\n left: -9999px;\n z-index: 2;\n }\n `,\n ];\n }\n}\n"]}
1
+ {"version":3,"file":"tile-dispatcher.js","sourceRoot":"","sources":["../../../src/tiles/tile-dispatcher.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, nothing, PropertyValues } from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { msg } from '@lit/localize';\nimport type {\n SharedResizeObserverInterface,\n SharedResizeObserverResizeHandlerInterface,\n} from '@internetarchive/shared-resize-observer';\nimport type { TileDisplayMode } from '../models';\nimport type { CollectionTitles } from '../data-source/models';\nimport './grid/collection-tile';\nimport './grid/item-tile';\nimport './grid/account-tile';\nimport './grid/search-tile';\nimport './hover/tile-hover-pane';\nimport './list/tile-list';\nimport './list/tile-list-compact';\nimport './list/tile-list-compact-header';\nimport type { TileHoverPane } from './hover/tile-hover-pane';\nimport { BaseTileComponent } from './base-tile-component';\nimport { LayoutType } from './models';\nimport {\n HoverPaneController,\n HoverPaneControllerInterface,\n HoverPaneProperties,\n HoverPaneProviderInterface,\n} from './hover/hover-pane-controller';\nimport { srOnlyStyle } from '../styles/sr-only';\n\n@customElement('tile-dispatcher')\nexport class TileDispatcher\n extends BaseTileComponent\n implements\n SharedResizeObserverResizeHandlerInterface,\n HoverPaneProviderInterface\n{\n /*\n * Reactive properties inherited from BaseTileComponent:\n * - model?: TileModel;\n * - currentWidth?: number;\n * - currentHeight?: number;\n * - baseNavigationUrl?: string;\n * - baseImageUrl?: string;\n * - collectionPagePath?: string;\n * - sortParam: SortParam | null = null;\n * - defaultSortParam: SortParam | null = null;\n * - creatorFilter?: string;\n * - mobileBreakpoint?: number;\n * - loggedIn = false;\n * - suppressTileBlurring = false;\n * - useLocalTime = false;\n */\n\n @property({ type: String }) tileDisplayMode?: TileDisplayMode;\n\n @property({ type: Boolean }) isManageView = false;\n\n @property({ type: Object }) resizeObserver?: SharedResizeObserverInterface;\n\n @property({ type: Object })\n collectionTitles?: CollectionTitles;\n\n @property({ type: Boolean }) showTvClips = false;\n\n /** What type of simplified layout to use in grid mode, if any */\n @property({ type: String }) layoutType: LayoutType = 'default';\n\n /** Whether this tile should include a hover pane at all (for applicable tile modes) */\n @property({ type: Boolean }) enableHoverPane = false;\n\n @property({ type: String }) manageCheckTitle = msg(\n 'Remove this item from the list',\n );\n\n private hoverPaneController?: HoverPaneControllerInterface;\n\n @query('#container')\n private container!: HTMLDivElement;\n\n @query('tile-hover-pane')\n private hoverPane?: TileHoverPane;\n\n @query('.tile-link')\n private tileLinkElement?: HTMLAnchorElement;\n\n acquireFocus(): void {\n this.tileLinkElement?.focus();\n }\n\n releaseFocus(): void {\n this.tileLinkElement?.blur();\n }\n\n /** Maps each display mode to whether hover panes should appear in that mode */\n private static readonly HOVER_PANE_DISPLAY_MODES: Record<\n TileDisplayMode,\n boolean\n > = {\n grid: true,\n 'list-compact': true,\n 'list-detail': false,\n 'list-header': false,\n };\n\n render() {\n const isGridMode = this.tileDisplayMode === 'grid';\n const hoverPaneTemplate =\n this.hoverPaneController?.getTemplate() ?? nothing;\n return html`\n <div id=\"container\" class=${isGridMode ? 'hoverable' : ''}>\n ${this.tileDisplayMode === 'list-header'\n ? this.headerTemplate\n : this.tileTemplate}\n ${this.manageCheckTemplate} ${hoverPaneTemplate}\n </div>\n `;\n }\n\n protected firstUpdated(): void {\n if (this.shouldPrepareHoverPane) {\n this.hoverPaneController = new HoverPaneController(this, {\n mobileBreakpoint: this.mobileBreakpoint,\n enableLongPress: false,\n });\n }\n }\n\n private get headerTemplate() {\n const { currentWidth, sortParam, defaultSortParam, mobileBreakpoint } =\n this;\n return html`\n <tile-list-compact-header\n class=\"header\"\n .currentWidth=${currentWidth}\n .sortParam=${sortParam ?? defaultSortParam}\n .mobileBreakpoint=${mobileBreakpoint}\n >\n </tile-list-compact-header>\n `;\n }\n\n private get tileTemplate() {\n return html`\n ${this.tileDisplayMode === 'list-detail'\n ? this.tile\n : this.linkTileTemplate}\n `;\n }\n\n private get linkTileTemplate() {\n return html`\n <a\n href=${this.linkTileHref}\n aria-label=${this.model?.title ?? 'Untitled item'}\n aria-describedby=\"link-aria-description\"\n aria-haspopup=${this.shouldPrepareHoverPane ? 'dialog' : 'false'}\n title=${this.shouldPrepareHoverPane\n ? nothing // Don't show title tooltips when we have the tile info popups\n : ifDefined(this.model?.title)}\n @click=${this.handleLinkClicked}\n @contextmenu=${this.handleLinkContextMenu}\n class=\"tile-link\"\n >\n ${this.tile}\n </a>\n <div id=\"link-aria-description\" class=\"sr-only\">\n ${msg('Press Down Arrow to preview item details')}\n </div>\n `;\n }\n\n private get linkTileHref(): string | typeof nothing {\n if (!this.model?.identifier || this.baseNavigationUrl == null)\n return nothing;\n\n // Use the server-specified href if available.\n // Otherwise, construct a details page URL from the item identifier.\n if (this.model.href) {\n return `${this.baseNavigationUrl}${this.model.href}`;\n }\n\n return this.displayValueProvider.itemPageUrl(\n this.model.identifier,\n this.model.mediatype === 'collection',\n );\n }\n\n private get manageCheckTemplate() {\n if (!this.isManageView || this.tileDisplayMode !== 'grid') return nothing;\n\n return html`\n <div class=\"manage-check\">\n <input\n type=\"checkbox\"\n title=${this.manageCheckTitle}\n ?checked=${this.model?.checked}\n @change=${this.handleLinkClicked}\n />\n </div>\n `;\n }\n\n /**\n * Whether hover pane behavior should be prepared for this tile\n * (e.g., whether mouse listeners should be attached, etc.)\n */\n private get shouldPrepareHoverPane(): boolean {\n return (\n this.enableHoverPane &&\n !!this.tileDisplayMode &&\n TileDispatcher.HOVER_PANE_DISPLAY_MODES[this.tileDisplayMode] &&\n this.model?.mediatype !== 'search' && // don't show hover panes on search tiles\n !this.model?.captureDates // don't show hover panes on web archive tiles\n );\n }\n\n private get isHoverEnabled(): boolean {\n return window.matchMedia('(hover: hover)').matches;\n }\n\n /**\n * Whether the info button should be shown on this tile.\n * Only shown on touch/non-hover devices where a hover pane is available,\n * so the button always has something to toggle.\n */\n private get shouldShowInfoButton(): boolean {\n return !this.isHoverEnabled && this.shouldPrepareHoverPane;\n }\n\n /** @inheritdoc */\n getHoverPane(): TileHoverPane | undefined {\n return this.hoverPane;\n }\n\n /** @inheritdoc */\n getHoverPaneProps(): HoverPaneProperties {\n return this;\n }\n\n handleResize(entry: ResizeObserverEntry): void {\n this.currentWidth = entry.contentRect.width;\n this.currentHeight = entry.contentRect.height;\n }\n\n disconnectedCallback(): void {\n this.stopResizeObservation(this.resizeObserver);\n }\n\n private stopResizeObservation(observer?: SharedResizeObserverInterface) {\n observer?.removeObserver({\n handler: this,\n target: this.container,\n });\n }\n\n private startResizeObservation() {\n this.stopResizeObservation(this.resizeObserver);\n this.resizeObserver?.addObserver({\n handler: this,\n target: this.container,\n });\n }\n\n updated(props: PropertyValues) {\n if (props.has('resizeObserver')) {\n const previousObserver = props.get(\n 'resizeObserver',\n ) as SharedResizeObserverInterface;\n this.stopResizeObservation(previousObserver);\n this.startResizeObservation();\n }\n }\n\n /**\n * Handler for when the tile link is left-clicked. Emits the `resultSelected` event.\n * In manage view, it also checks/unchecks the tile.\n */\n private handleLinkClicked(e: Event): void {\n if (this.isManageView) {\n e.preventDefault();\n if (this.model) this.model.checked = !this.model.checked;\n }\n\n this.dispatchEvent(\n new CustomEvent('resultSelected', { detail: this.model }),\n );\n }\n\n /**\n * Handler for when the tile link is right-clicked.\n * In manage view, it opens the item in a new tab. Otherwise, does nothing.\n */\n private handleLinkContextMenu(e: Event): void {\n if (this.isManageView && this.linkTileHref !== nothing) {\n e.preventDefault();\n window.open(this.linkTileHref, '_blank');\n }\n }\n\n private tileInfoButtonPressed(\n e: CustomEvent<{ x: number; y: number }>,\n ): void {\n this.hoverPaneController?.toggleHoverPane({\n coords: e.detail,\n enableTouchBackdrop: true,\n });\n }\n\n private get tile() {\n const {\n model,\n collectionPagePath,\n baseNavigationUrl,\n currentWidth,\n currentHeight,\n sortParam,\n creatorFilter,\n mobileBreakpoint,\n defaultSortParam,\n } = this;\n\n if (!model) return nothing;\n\n switch (this.tileDisplayMode) {\n case 'grid':\n switch (model.mediatype) {\n case 'collection':\n return html`<collection-tile\n .model=${model}\n .collectionPagePath=${collectionPagePath}\n .baseImageUrl=${this.baseImageUrl}\n .currentWidth=${currentWidth}\n .currentHeight=${currentHeight}\n .creatorFilter=${creatorFilter}\n .suppressBlurring=${this.suppressBlurring}\n .isManageView=${this.isManageView}\n .layoutType=${this.layoutType}\n ?showInfoButton=${this.shouldShowInfoButton}\n @infoButtonPressed=${this.tileInfoButtonPressed}\n >\n </collection-tile>`;\n case 'account':\n return html`<account-tile\n .model=${model}\n .collectionPagePath=${collectionPagePath}\n .baseImageUrl=${this.baseImageUrl}\n .currentWidth=${currentWidth}\n .currentHeight=${currentHeight}\n .creatorFilter=${creatorFilter}\n .suppressBlurring=${this.suppressBlurring}\n .isManageView=${this.isManageView}\n ?showInfoButton=${this.shouldShowInfoButton}\n @infoButtonPressed=${this.tileInfoButtonPressed}\n >\n </account-tile>`;\n case 'search':\n return html`<search-tile\n .model=${model}\n .collectionPagePath=${collectionPagePath}\n .baseImageUrl=${this.baseImageUrl}\n .currentWidth=${currentWidth}\n .currentHeight=${currentHeight}\n .creatorFilter=${creatorFilter}\n .suppressBlurring=${this.suppressBlurring}\n .isManageView=${this.isManageView}\n ?showInfoButton=${false}\n @infoButtonPressed=${this.tileInfoButtonPressed}\n >\n </search-tile>`;\n default:\n return html`<item-tile\n .model=${model}\n .collectionPagePath=${collectionPagePath}\n .currentWidth=${this.currentWidth}\n .currentHeight=${this.currentHeight}\n .baseImageUrl=${this.baseImageUrl}\n .sortParam=${sortParam}\n .defaultSortParam=${defaultSortParam}\n .creatorFilter=${creatorFilter}\n .loggedIn=${this.loggedIn}\n .suppressBlurring=${this.suppressBlurring}\n .isManageView=${this.isManageView}\n .layoutType=${this.layoutType}\n ?showTvClips=${this.showTvClips}\n ?showInfoButton=${this.shouldShowInfoButton}\n ?useLocalTime=${this.useLocalTime}\n @infoButtonPressed=${this.tileInfoButtonPressed}\n >\n </item-tile>`;\n }\n case 'list-compact':\n return html`<tile-list-compact\n .model=${model}\n .collectionPagePath=${collectionPagePath}\n .currentWidth=${currentWidth}\n .currentHeight=${currentHeight}\n .baseNavigationUrl=${baseNavigationUrl}\n .sortParam=${sortParam}\n .defaultSortParam=${defaultSortParam}\n .creatorFilter=${creatorFilter}\n .mobileBreakpoint=${mobileBreakpoint}\n .baseImageUrl=${this.baseImageUrl}\n .loggedIn=${this.loggedIn}\n .suppressBlurring=${this.suppressBlurring}\n ?useLocalTime=${this.useLocalTime}\n >\n </tile-list-compact>`;\n case 'list-detail':\n return html`<tile-list\n .model=${model}\n .collectionPagePath=${collectionPagePath}\n .collectionTitles=${this.collectionTitles}\n .currentWidth=${currentWidth}\n .currentHeight=${currentHeight}\n .baseNavigationUrl=${baseNavigationUrl}\n .sortParam=${sortParam}\n .defaultSortParam=${defaultSortParam}\n .creatorFilter=${creatorFilter}\n .mobileBreakpoint=${mobileBreakpoint}\n .baseImageUrl=${this.baseImageUrl}\n .loggedIn=${this.loggedIn}\n .suppressBlurring=${this.suppressBlurring}\n ?useLocalTime=${this.useLocalTime}\n >\n </tile-list>`;\n default:\n return nothing;\n }\n }\n\n static get styles() {\n return [\n srOnlyStyle,\n css`\n :host {\n display: block;\n height: 100%;\n }\n\n collection-tile {\n --tileBorderColor: #555555;\n --tileBackgroundColor: #666666;\n --imageBlockBackgroundColor: #666666;\n }\n\n account-tile {\n --tileBorderColor: #dddddd;\n --imageBlockBackgroundColor: #fcf5e6;\n }\n\n item-tile {\n --tileBorderColor: #dddddd;\n --imageBlockBackgroundColor: #f1f1f4;\n }\n\n search-tile {\n --tileBorderColor: #555555;\n --tileBackgroundColor: #666666;\n --imageBlockBackgroundColor: #666666;\n --iconFillColor: #2c2c2c;\n }\n\n #container {\n position: relative;\n height: 100%;\n border-radius: 4px;\n }\n\n #container.hoverable a:focus,\n #container.hoverable a:hover {\n box-shadow: var(\n --tileHoverBoxShadow,\n 0 0 6px 2px rgba(8, 8, 32, 0.8)\n );\n transition: box-shadow 0.1s ease;\n }\n\n a {\n display: block;\n height: 100%;\n color: unset;\n text-decoration: none;\n transition: transform 0.05s ease;\n border-radius: 4px;\n outline: none;\n }\n\n a :first-child {\n display: block;\n height: 100%;\n }\n\n .manage-check {\n position: absolute;\n right: 0;\n top: 0;\n border: 5px solid #2c2c2c;\n border-radius: 3px;\n background-color: #2c2c2c;\n z-index: 1;\n }\n\n .manage-check > input[type='checkbox'] {\n display: block;\n margin: 0;\n }\n\n #touch-backdrop {\n position: fixed;\n width: 100vw;\n height: 100vh;\n top: 0;\n left: 0;\n z-index: 2;\n background: transparent;\n }\n\n tile-hover-pane {\n position: absolute;\n top: 0;\n left: -9999px;\n z-index: 2;\n }\n `,\n ];\n }\n}\n"]}
@@ -85,7 +85,7 @@ describe('Tile Dispatcher', () => {
85
85
  expect(spy.args[0][1]).to.equal('_blank');
86
86
  window.open = oldWindowOpen;
87
87
  });
88
- it('should use model href as-is when not percent-encoded', async () => {
88
+ it('should use model href as link href', async () => {
89
89
  const el = await fixture(html `
90
90
  <tile-dispatcher
91
91
  .model=${{
@@ -99,34 +99,6 @@ describe('Tile Dispatcher', () => {
99
99
  expect(tileLink).to.exist;
100
100
  expect(tileLink.getAttribute('href')).to.equal('https://web.archive.org/web/20180613065659/http://www.sankei.com/');
101
101
  });
102
- it('should decode percent-encoded model href before use', async () => {
103
- const el = await fixture(html `
104
- <tile-dispatcher
105
- .model=${{
106
- identifier: 'foo',
107
- href: 'https://web.archive.org/web/20180613065659/http%3A%2F%2Fwww.sankei.com%2F',
108
- }}
109
- .baseNavigationUrl=${''}
110
- ></tile-dispatcher>
111
- `);
112
- const tileLink = el.shadowRoot?.querySelector('a[href]');
113
- expect(tileLink).to.exist;
114
- expect(tileLink.getAttribute('href')).to.equal('https://web.archive.org/web/20180613065659/http://www.sankei.com/');
115
- });
116
- it('should not decode %3A in Wayback URL path when not an encoded scheme', async () => {
117
- // %3A in the path (e.g. /path/%3Asomething) is not a sign of over-encoding;
118
- // only %3A%2F%2F (encoded "://") is.
119
- const href = 'https://web.archive.org/web/20180613065659/https://example.com/path/%3Asomething';
120
- const el = await fixture(html `
121
- <tile-dispatcher
122
- .model=${{ identifier: 'foo', href }}
123
- .baseNavigationUrl=${''}
124
- ></tile-dispatcher>
125
- `);
126
- const tileLink = el.shadowRoot?.querySelector('a[href]');
127
- expect(tileLink).to.exist;
128
- expect(tileLink.getAttribute('href')).to.equal(href);
129
- });
130
102
  it('should toggle model checked state when manage check clicked', async () => {
131
103
  const el = await fixture(html `
132
104
  <tile-dispatcher
@@ -1 +1 @@
1
- {"version":3,"file":"tile-dispatcher.test.js","sourceRoot":"","sources":["../../../test/tiles/tile-dispatcher.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { aTimeout, expect, fixture } from '@open-wc/testing';\nimport { html } from 'lit';\nimport sinon from 'sinon';\nimport type { TileDispatcher } from '../../src/tiles/tile-dispatcher';\n\nimport '../../src/tiles/tile-dispatcher';\nimport type { ItemTile } from '../../src/tiles/grid/item-tile';\nimport { TileHoverPane } from '../../src/tiles/hover/tile-hover-pane';\nimport type { HoverPaneProperties } from '../../src/tiles/hover/hover-pane-controller';\n\ndescribe('Tile Dispatcher', () => {\n it('should render item-tile for grid mode by default', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'grid'}\n .model=${{ mediatype: 'texts' }}\n >\n </tile-dispatcher>\n `);\n\n const itemTile = el.shadowRoot?.querySelector('item-tile');\n expect(itemTile).to.exist;\n });\n\n it('should render collection-tile for grid mode and collection mediatype', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'grid'}\n .model=${{ mediatype: 'collection' }}\n >\n </tile-dispatcher>\n `);\n\n const collectionTile = el.shadowRoot?.querySelector('collection-tile');\n expect(collectionTile).to.exist;\n });\n\n it('should render account-tile for grid mode and account mediatype', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'grid'}\n .model=${{ mediatype: 'account' }}\n >\n </tile-dispatcher>\n `);\n\n const accountTile = el.shadowRoot?.querySelector('account-tile');\n expect(accountTile).to.exist;\n });\n\n it('should render search-tile for grid mode and search mediatype', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'grid'}\n .model=${{ mediatype: 'search' }}\n >\n </tile-dispatcher>\n `);\n\n const searchTile = el.shadowRoot?.querySelector('search-tile');\n expect(searchTile).to.exist;\n });\n\n it('should render tile-list for extended list mode', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher .tileDisplayMode=${'list-detail'} .model=${{}}>\n </tile-dispatcher>\n `);\n\n const listTile = el.shadowRoot?.querySelector('tile-list');\n expect(listTile).to.exist;\n });\n\n it('should render tile-list-compact for compact list mode', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher .tileDisplayMode=${'list-compact'} .model=${{}}>\n </tile-dispatcher>\n `);\n\n const compactListTile = el.shadowRoot?.querySelector('tile-list-compact');\n expect(compactListTile).to.exist;\n });\n\n it('should open item in new tab when right-clicked in manage mode', async () => {\n const oldWindowOpen = window.open;\n const spy = sinon.spy();\n window.open = spy;\n\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n isManageView\n .model=${{ identifier: 'foo', href: '/foo' }}\n .baseNavigationUrl=${''}\n >\n </tile-dispatcher>\n `);\n\n const tileLink = el.shadowRoot?.querySelector(\n 'a[href]',\n ) as HTMLAnchorElement;\n expect(tileLink).to.exist;\n\n tileLink.dispatchEvent(new Event('contextmenu'));\n await el.updateComplete;\n\n expect(spy.callCount).to.equal(1);\n expect(spy.args[0][0]).to.equal('/foo');\n expect(spy.args[0][1]).to.equal('_blank');\n\n window.open = oldWindowOpen;\n });\n\n it('should use model href as-is when not percent-encoded', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .model=${{\n identifier: 'foo',\n href: 'https://web.archive.org/web/20180613065659/http://www.sankei.com/',\n }}\n .baseNavigationUrl=${''}\n ></tile-dispatcher>\n `);\n\n const tileLink = el.shadowRoot?.querySelector(\n 'a[href]',\n ) as HTMLAnchorElement;\n expect(tileLink).to.exist;\n expect(tileLink.getAttribute('href')).to.equal(\n 'https://web.archive.org/web/20180613065659/http://www.sankei.com/',\n );\n });\n\n it('should decode percent-encoded model href before use', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .model=${{\n identifier: 'foo',\n href: 'https://web.archive.org/web/20180613065659/http%3A%2F%2Fwww.sankei.com%2F',\n }}\n .baseNavigationUrl=${''}\n ></tile-dispatcher>\n `);\n\n const tileLink = el.shadowRoot?.querySelector(\n 'a[href]',\n ) as HTMLAnchorElement;\n expect(tileLink).to.exist;\n expect(tileLink.getAttribute('href')).to.equal(\n 'https://web.archive.org/web/20180613065659/http://www.sankei.com/',\n );\n });\n\n it('should not decode %3A in Wayback URL path when not an encoded scheme', async () => {\n // %3A in the path (e.g. /path/%3Asomething) is not a sign of over-encoding;\n // only %3A%2F%2F (encoded \"://\") is.\n const href =\n 'https://web.archive.org/web/20180613065659/https://example.com/path/%3Asomething';\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .model=${{ identifier: 'foo', href }}\n .baseNavigationUrl=${''}\n ></tile-dispatcher>\n `);\n\n const tileLink = el.shadowRoot?.querySelector(\n 'a[href]',\n ) as HTMLAnchorElement;\n expect(tileLink).to.exist;\n expect(tileLink.getAttribute('href')).to.equal(href);\n });\n\n it('should toggle model checked state when manage check clicked', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n isManageView\n .model=${{ identifier: 'foo', href: '/foo' }}\n .tileDisplayMode=${'grid'}\n ></tile-dispatcher>\n `);\n\n const manageCheck = el.shadowRoot?.querySelector(\n '.manage-check > input[type=\"checkbox\"]',\n ) as HTMLButtonElement;\n\n manageCheck.click();\n await el.updateComplete;\n expect(el.model?.checked).to.be.true;\n\n manageCheck.click();\n await el.updateComplete;\n expect(el.model?.checked).to.be.false;\n });\n\n it('should return hover pane props', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher .model=${{ identifier: 'foo' }}> </tile-dispatcher>\n `);\n\n expect(el.getHoverPaneProps()).to.satisfy(\n (props: HoverPaneProperties) => props?.model?.identifier === 'foo',\n );\n });\n\n it('should focus the tile link when requested', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher .tileDisplayMode=${'grid'}> </tile-dispatcher>\n `);\n\n const tileLink = el.shadowRoot?.querySelector(\n '.tile-link',\n ) as HTMLAnchorElement;\n expect(tileLink).to.exist;\n\n const spyFocus = sinon.spy(tileLink, 'focus');\n el.acquireFocus();\n expect(spyFocus.callCount).to.equal(1);\n });\n\n it('should blur the tile link when requested', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher .tileDisplayMode=${'grid'}> </tile-dispatcher>\n `);\n\n const tileLink = el.shadowRoot?.querySelector(\n '.tile-link',\n ) as HTMLAnchorElement;\n expect(tileLink).to.exist;\n\n const spyBlur = sinon.spy(tileLink, 'blur');\n el.releaseFocus();\n expect(spyBlur.callCount).to.equal(1);\n });\n\n describe('Hover pane info button behavior', () => {\n let oldMatchMedia: typeof window.matchMedia;\n\n before(() => {\n oldMatchMedia = window.matchMedia;\n // Pretend that there is no hover-capable input device\n window.matchMedia = () => ({ matches: false }) as MediaQueryList;\n });\n\n after(() => {\n window.matchMedia = oldMatchMedia;\n });\n\n it('should toggle hover pane when tile info button is pressed', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'grid'}\n .model=${{ mediatype: 'texts' }}\n .enableHoverPane=${true}\n >\n </tile-dispatcher>\n `);\n\n const itemTile = el.shadowRoot?.querySelector('item-tile') as ItemTile;\n expect(itemTile).to.exist;\n\n const infoButton = itemTile.shadowRoot?.querySelector(\n '.info-button',\n ) as HTMLButtonElement;\n expect(infoButton).to.exist;\n\n infoButton.click();\n await aTimeout(500);\n await el.updateComplete;\n expect(el.getHoverPane()).to.be.instanceOf(TileHoverPane);\n\n infoButton.click();\n await aTimeout(500);\n await el.updateComplete;\n expect(el.getHoverPane()).not.to.exist;\n });\n\n it('should not show info button when hover pane is not enabled', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'grid'}\n .model=${{ mediatype: 'texts' }}\n .enableHoverPane=${false}\n >\n </tile-dispatcher>\n `);\n\n const itemTile = el.shadowRoot?.querySelector('item-tile') as ItemTile;\n expect(itemTile).to.exist;\n\n const infoButton = itemTile.shadowRoot?.querySelector('.info-button');\n expect(infoButton).to.not.exist;\n });\n });\n\n describe('Accessibility', () => {\n it('should have proper aria-label on tile link', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'grid'}\n .model=${{\n title: 'Example Title',\n mediatype: 'texts',\n }}\n >\n </tile-dispatcher>\n `);\n\n const tileLink = el.shadowRoot?.querySelector(\n '.tile-link',\n ) as HTMLAnchorElement;\n expect(tileLink).to.exist;\n expect(tileLink.getAttribute('aria-label')).to.equal('Example Title');\n });\n\n it('should fallback to untitled aria-label on tile link when no title', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'grid'}\n .model=${{\n mediatype: 'texts',\n }}\n >\n </tile-dispatcher>\n `);\n\n const tileLink = el.shadowRoot?.querySelector(\n '.tile-link',\n ) as HTMLAnchorElement;\n expect(tileLink).to.exist;\n expect(tileLink.getAttribute('aria-label')).to.equal('Untitled item');\n });\n\n it('should have no accessibility violations in grid mode', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'grid'}\n .model=${{\n title: 'Example Title',\n mediatype: 'texts',\n }}\n >\n </tile-dispatcher>\n `);\n\n await expect(el).to.be.accessible();\n });\n\n it('should have no accessibility violations in list mode', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'list-detail'}\n .model=${{ mediatype: 'texts' }}\n >\n </tile-dispatcher>\n `);\n\n await expect(el).to.be.accessible();\n });\n });\n});\n"]}
1
+ {"version":3,"file":"tile-dispatcher.test.js","sourceRoot":"","sources":["../../../test/tiles/tile-dispatcher.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { aTimeout, expect, fixture } from '@open-wc/testing';\nimport { html } from 'lit';\nimport sinon from 'sinon';\nimport type { TileDispatcher } from '../../src/tiles/tile-dispatcher';\n\nimport '../../src/tiles/tile-dispatcher';\nimport type { ItemTile } from '../../src/tiles/grid/item-tile';\nimport { TileHoverPane } from '../../src/tiles/hover/tile-hover-pane';\nimport type { HoverPaneProperties } from '../../src/tiles/hover/hover-pane-controller';\n\ndescribe('Tile Dispatcher', () => {\n it('should render item-tile for grid mode by default', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'grid'}\n .model=${{ mediatype: 'texts' }}\n >\n </tile-dispatcher>\n `);\n\n const itemTile = el.shadowRoot?.querySelector('item-tile');\n expect(itemTile).to.exist;\n });\n\n it('should render collection-tile for grid mode and collection mediatype', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'grid'}\n .model=${{ mediatype: 'collection' }}\n >\n </tile-dispatcher>\n `);\n\n const collectionTile = el.shadowRoot?.querySelector('collection-tile');\n expect(collectionTile).to.exist;\n });\n\n it('should render account-tile for grid mode and account mediatype', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'grid'}\n .model=${{ mediatype: 'account' }}\n >\n </tile-dispatcher>\n `);\n\n const accountTile = el.shadowRoot?.querySelector('account-tile');\n expect(accountTile).to.exist;\n });\n\n it('should render search-tile for grid mode and search mediatype', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'grid'}\n .model=${{ mediatype: 'search' }}\n >\n </tile-dispatcher>\n `);\n\n const searchTile = el.shadowRoot?.querySelector('search-tile');\n expect(searchTile).to.exist;\n });\n\n it('should render tile-list for extended list mode', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher .tileDisplayMode=${'list-detail'} .model=${{}}>\n </tile-dispatcher>\n `);\n\n const listTile = el.shadowRoot?.querySelector('tile-list');\n expect(listTile).to.exist;\n });\n\n it('should render tile-list-compact for compact list mode', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher .tileDisplayMode=${'list-compact'} .model=${{}}>\n </tile-dispatcher>\n `);\n\n const compactListTile = el.shadowRoot?.querySelector('tile-list-compact');\n expect(compactListTile).to.exist;\n });\n\n it('should open item in new tab when right-clicked in manage mode', async () => {\n const oldWindowOpen = window.open;\n const spy = sinon.spy();\n window.open = spy;\n\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n isManageView\n .model=${{ identifier: 'foo', href: '/foo' }}\n .baseNavigationUrl=${''}\n >\n </tile-dispatcher>\n `);\n\n const tileLink = el.shadowRoot?.querySelector(\n 'a[href]',\n ) as HTMLAnchorElement;\n expect(tileLink).to.exist;\n\n tileLink.dispatchEvent(new Event('contextmenu'));\n await el.updateComplete;\n\n expect(spy.callCount).to.equal(1);\n expect(spy.args[0][0]).to.equal('/foo');\n expect(spy.args[0][1]).to.equal('_blank');\n\n window.open = oldWindowOpen;\n });\n\n it('should use model href as link href', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .model=${{\n identifier: 'foo',\n href: 'https://web.archive.org/web/20180613065659/http://www.sankei.com/',\n }}\n .baseNavigationUrl=${''}\n ></tile-dispatcher>\n `);\n\n const tileLink = el.shadowRoot?.querySelector(\n 'a[href]',\n ) as HTMLAnchorElement;\n expect(tileLink).to.exist;\n expect(tileLink.getAttribute('href')).to.equal(\n 'https://web.archive.org/web/20180613065659/http://www.sankei.com/',\n );\n });\n\n it('should toggle model checked state when manage check clicked', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n isManageView\n .model=${{ identifier: 'foo', href: '/foo' }}\n .tileDisplayMode=${'grid'}\n ></tile-dispatcher>\n `);\n\n const manageCheck = el.shadowRoot?.querySelector(\n '.manage-check > input[type=\"checkbox\"]',\n ) as HTMLButtonElement;\n\n manageCheck.click();\n await el.updateComplete;\n expect(el.model?.checked).to.be.true;\n\n manageCheck.click();\n await el.updateComplete;\n expect(el.model?.checked).to.be.false;\n });\n\n it('should return hover pane props', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher .model=${{ identifier: 'foo' }}> </tile-dispatcher>\n `);\n\n expect(el.getHoverPaneProps()).to.satisfy(\n (props: HoverPaneProperties) => props?.model?.identifier === 'foo',\n );\n });\n\n it('should focus the tile link when requested', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher .tileDisplayMode=${'grid'}> </tile-dispatcher>\n `);\n\n const tileLink = el.shadowRoot?.querySelector(\n '.tile-link',\n ) as HTMLAnchorElement;\n expect(tileLink).to.exist;\n\n const spyFocus = sinon.spy(tileLink, 'focus');\n el.acquireFocus();\n expect(spyFocus.callCount).to.equal(1);\n });\n\n it('should blur the tile link when requested', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher .tileDisplayMode=${'grid'}> </tile-dispatcher>\n `);\n\n const tileLink = el.shadowRoot?.querySelector(\n '.tile-link',\n ) as HTMLAnchorElement;\n expect(tileLink).to.exist;\n\n const spyBlur = sinon.spy(tileLink, 'blur');\n el.releaseFocus();\n expect(spyBlur.callCount).to.equal(1);\n });\n\n describe('Hover pane info button behavior', () => {\n let oldMatchMedia: typeof window.matchMedia;\n\n before(() => {\n oldMatchMedia = window.matchMedia;\n // Pretend that there is no hover-capable input device\n window.matchMedia = () => ({ matches: false }) as MediaQueryList;\n });\n\n after(() => {\n window.matchMedia = oldMatchMedia;\n });\n\n it('should toggle hover pane when tile info button is pressed', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'grid'}\n .model=${{ mediatype: 'texts' }}\n .enableHoverPane=${true}\n >\n </tile-dispatcher>\n `);\n\n const itemTile = el.shadowRoot?.querySelector('item-tile') as ItemTile;\n expect(itemTile).to.exist;\n\n const infoButton = itemTile.shadowRoot?.querySelector(\n '.info-button',\n ) as HTMLButtonElement;\n expect(infoButton).to.exist;\n\n infoButton.click();\n await aTimeout(500);\n await el.updateComplete;\n expect(el.getHoverPane()).to.be.instanceOf(TileHoverPane);\n\n infoButton.click();\n await aTimeout(500);\n await el.updateComplete;\n expect(el.getHoverPane()).not.to.exist;\n });\n\n it('should not show info button when hover pane is not enabled', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'grid'}\n .model=${{ mediatype: 'texts' }}\n .enableHoverPane=${false}\n >\n </tile-dispatcher>\n `);\n\n const itemTile = el.shadowRoot?.querySelector('item-tile') as ItemTile;\n expect(itemTile).to.exist;\n\n const infoButton = itemTile.shadowRoot?.querySelector('.info-button');\n expect(infoButton).to.not.exist;\n });\n });\n\n describe('Accessibility', () => {\n it('should have proper aria-label on tile link', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'grid'}\n .model=${{\n title: 'Example Title',\n mediatype: 'texts',\n }}\n >\n </tile-dispatcher>\n `);\n\n const tileLink = el.shadowRoot?.querySelector(\n '.tile-link',\n ) as HTMLAnchorElement;\n expect(tileLink).to.exist;\n expect(tileLink.getAttribute('aria-label')).to.equal('Example Title');\n });\n\n it('should fallback to untitled aria-label on tile link when no title', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'grid'}\n .model=${{\n mediatype: 'texts',\n }}\n >\n </tile-dispatcher>\n `);\n\n const tileLink = el.shadowRoot?.querySelector(\n '.tile-link',\n ) as HTMLAnchorElement;\n expect(tileLink).to.exist;\n expect(tileLink.getAttribute('aria-label')).to.equal('Untitled item');\n });\n\n it('should have no accessibility violations in grid mode', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'grid'}\n .model=${{\n title: 'Example Title',\n mediatype: 'texts',\n }}\n >\n </tile-dispatcher>\n `);\n\n await expect(el).to.be.accessible();\n });\n\n it('should have no accessibility violations in list mode', async () => {\n const el = await fixture<TileDispatcher>(html`\n <tile-dispatcher\n .tileDisplayMode=${'list-detail'}\n .model=${{ mediatype: 'texts' }}\n >\n </tile-dispatcher>\n `);\n\n await expect(el).to.be.accessible();\n });\n });\n});\n"]}
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "The Internet Archive Collection Browser.",
4
4
  "license": "AGPL-3.0-only",
5
5
  "author": "Internet Archive",
6
- "version": "4.3.2-rc-webdev-8334.4",
6
+ "version": "4.3.2-rc-webdev-8334.5",
7
7
  "main": "dist/index.js",
8
8
  "module": "dist/index.js",
9
9
  "scripts": {
@@ -176,26 +176,7 @@ export class TileDispatcher
176
176
  // Use the server-specified href if available.
177
177
  // Otherwise, construct a details page URL from the item identifier.
178
178
  if (this.model.href) {
179
- // Backstop for legacy Wayback Machine URLs where the target URL was
180
- // erroneously percent-encoded by encodeURIComponent (the root cause in
181
- // tile-display-value-provider is fixed, but old stored data may still
182
- // carry encoded URLs). Decode only the target-URL segment after the
183
- // /web/{timestamp}/ prefix — decoding the full href risks corrupting the
184
- // Wayback prefix or intentional encoding elsewhere in the path.
185
- // %3A%2F%2F (encoded "://") is an unambiguous indicator the entire URL
186
- // was over-encoded; legitimate paths with %3A never appear next to %2F%2F.
187
- const href = this.model.href.replace(
188
- /(\/web\/\d+\/)(.+)/,
189
- (_, prefix, target) => {
190
- if (!/%3A%2F%2F/i.test(target)) return `${prefix}${target}`;
191
- try {
192
- return `${prefix}${decodeURIComponent(target)}`;
193
- } catch {
194
- return `${prefix}${target}`;
195
- }
196
- },
197
- );
198
- return `${this.baseNavigationUrl}${href}`;
179
+ return `${this.baseNavigationUrl}${this.model.href}`;
199
180
  }
200
181
 
201
182
  return this.displayValueProvider.itemPageUrl(
@@ -110,7 +110,7 @@ describe('Tile Dispatcher', () => {
110
110
  window.open = oldWindowOpen;
111
111
  });
112
112
 
113
- it('should use model href as-is when not percent-encoded', async () => {
113
+ it('should use model href as link href', async () => {
114
114
  const el = await fixture<TileDispatcher>(html`
115
115
  <tile-dispatcher
116
116
  .model=${{
@@ -130,45 +130,6 @@ describe('Tile Dispatcher', () => {
130
130
  );
131
131
  });
132
132
 
133
- it('should decode percent-encoded model href before use', async () => {
134
- const el = await fixture<TileDispatcher>(html`
135
- <tile-dispatcher
136
- .model=${{
137
- identifier: 'foo',
138
- href: 'https://web.archive.org/web/20180613065659/http%3A%2F%2Fwww.sankei.com%2F',
139
- }}
140
- .baseNavigationUrl=${''}
141
- ></tile-dispatcher>
142
- `);
143
-
144
- const tileLink = el.shadowRoot?.querySelector(
145
- 'a[href]',
146
- ) as HTMLAnchorElement;
147
- expect(tileLink).to.exist;
148
- expect(tileLink.getAttribute('href')).to.equal(
149
- 'https://web.archive.org/web/20180613065659/http://www.sankei.com/',
150
- );
151
- });
152
-
153
- it('should not decode %3A in Wayback URL path when not an encoded scheme', async () => {
154
- // %3A in the path (e.g. /path/%3Asomething) is not a sign of over-encoding;
155
- // only %3A%2F%2F (encoded "://") is.
156
- const href =
157
- 'https://web.archive.org/web/20180613065659/https://example.com/path/%3Asomething';
158
- const el = await fixture<TileDispatcher>(html`
159
- <tile-dispatcher
160
- .model=${{ identifier: 'foo', href }}
161
- .baseNavigationUrl=${''}
162
- ></tile-dispatcher>
163
- `);
164
-
165
- const tileLink = el.shadowRoot?.querySelector(
166
- 'a[href]',
167
- ) as HTMLAnchorElement;
168
- expect(tileLink).to.exist;
169
- expect(tileLink.getAttribute('href')).to.equal(href);
170
- });
171
-
172
133
  it('should toggle model checked state when manage check clicked', async () => {
173
134
  const el = await fixture<TileDispatcher>(html`
174
135
  <tile-dispatcher