@internetarchive/elements 0.2.14-webdev-9022.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/dist/src/elements/ia-audio-element/ia-audio-element.d.ts +72 -0
  2. package/dist/src/elements/ia-audio-element/ia-audio-element.d.ts.map +1 -0
  3. package/dist/src/elements/ia-audio-element/ia-audio-element.js +173 -0
  4. package/dist/src/elements/ia-audio-element/ia-audio-element.js.map +1 -0
  5. package/dist/src/elements/ia-audio-element/models.d.ts +13 -0
  6. package/dist/src/elements/ia-audio-element/models.d.ts.map +1 -0
  7. package/dist/src/elements/ia-audio-element/models.js +2 -0
  8. package/dist/src/elements/ia-audio-element/models.js.map +1 -0
  9. package/dist/src/elements/ia-expandable-search-bar/assets/clear-results.d.ts +3 -0
  10. package/dist/src/elements/ia-expandable-search-bar/assets/clear-results.d.ts.map +1 -0
  11. package/dist/src/elements/ia-expandable-search-bar/assets/clear-results.js +28 -0
  12. package/dist/src/elements/ia-expandable-search-bar/assets/clear-results.js.map +1 -0
  13. package/dist/src/elements/ia-expandable-search-bar/assets/disclosure.d.ts +3 -0
  14. package/dist/src/elements/ia-expandable-search-bar/assets/disclosure.d.ts.map +1 -0
  15. package/dist/src/elements/ia-expandable-search-bar/assets/disclosure.js +26 -0
  16. package/dist/src/elements/ia-expandable-search-bar/assets/disclosure.js.map +1 -0
  17. package/dist/src/elements/ia-expandable-search-bar/assets/magnifying-glass.d.ts +3 -0
  18. package/dist/src/elements/ia-expandable-search-bar/assets/magnifying-glass.d.ts.map +1 -0
  19. package/dist/src/elements/ia-expandable-search-bar/assets/magnifying-glass.js +22 -0
  20. package/dist/src/elements/ia-expandable-search-bar/assets/magnifying-glass.js.map +1 -0
  21. package/dist/src/elements/ia-expandable-search-bar/ia-expandable-search-bar.d.ts +53 -0
  22. package/dist/src/elements/ia-expandable-search-bar/ia-expandable-search-bar.d.ts.map +1 -0
  23. package/dist/src/elements/ia-expandable-search-bar/ia-expandable-search-bar.js +352 -0
  24. package/dist/src/elements/ia-expandable-search-bar/ia-expandable-search-bar.js.map +1 -0
  25. package/dist/src/elements/ia-expandable-search-bar/ia-quick-search.d.ts +19 -0
  26. package/dist/src/elements/ia-expandable-search-bar/ia-quick-search.d.ts.map +1 -0
  27. package/dist/src/elements/ia-expandable-search-bar/ia-quick-search.js +115 -0
  28. package/dist/src/elements/ia-expandable-search-bar/ia-quick-search.js.map +1 -0
  29. package/dist/src/elements/ia-expandable-search-bar/models.d.ts +13 -0
  30. package/dist/src/elements/ia-expandable-search-bar/models.d.ts.map +1 -0
  31. package/dist/src/elements/ia-expandable-search-bar/models.js +2 -0
  32. package/dist/src/elements/ia-expandable-search-bar/models.js.map +1 -0
  33. package/dist/src/elements/ia-playback-controls/assets/next-section.d.ts +3 -0
  34. package/dist/src/elements/ia-playback-controls/assets/next-section.d.ts.map +1 -0
  35. package/dist/src/elements/ia-playback-controls/assets/next-section.js +16 -0
  36. package/dist/src/elements/ia-playback-controls/assets/next-section.js.map +1 -0
  37. package/dist/src/elements/ia-playback-controls/assets/pause.d.ts +3 -0
  38. package/dist/src/elements/ia-playback-controls/assets/pause.d.ts.map +1 -0
  39. package/dist/src/elements/ia-playback-controls/assets/pause.js +17 -0
  40. package/dist/src/elements/ia-playback-controls/assets/pause.js.map +1 -0
  41. package/dist/src/elements/ia-playback-controls/assets/play.d.ts +3 -0
  42. package/dist/src/elements/ia-playback-controls/assets/play.d.ts.map +1 -0
  43. package/dist/src/elements/ia-playback-controls/assets/play.js +18 -0
  44. package/dist/src/elements/ia-playback-controls/assets/play.js.map +1 -0
  45. package/dist/src/elements/ia-playback-controls/assets/playback-speed.d.ts +3 -0
  46. package/dist/src/elements/ia-playback-controls/assets/playback-speed.d.ts.map +1 -0
  47. package/dist/src/elements/ia-playback-controls/assets/playback-speed.js +28 -0
  48. package/dist/src/elements/ia-playback-controls/assets/playback-speed.js.map +1 -0
  49. package/dist/src/elements/ia-playback-controls/assets/previous-section.d.ts +3 -0
  50. package/dist/src/elements/ia-playback-controls/assets/previous-section.d.ts.map +1 -0
  51. package/dist/src/elements/ia-playback-controls/assets/previous-section.js +16 -0
  52. package/dist/src/elements/ia-playback-controls/assets/previous-section.js.map +1 -0
  53. package/dist/src/elements/ia-playback-controls/assets/replay.d.ts +3 -0
  54. package/dist/src/elements/ia-playback-controls/assets/replay.d.ts.map +1 -0
  55. package/dist/src/elements/ia-playback-controls/assets/replay.js +28 -0
  56. package/dist/src/elements/ia-playback-controls/assets/replay.js.map +1 -0
  57. package/dist/src/elements/ia-playback-controls/assets/skip-ahead.d.ts +3 -0
  58. package/dist/src/elements/ia-playback-controls/assets/skip-ahead.d.ts.map +1 -0
  59. package/dist/src/elements/ia-playback-controls/assets/skip-ahead.js +29 -0
  60. package/dist/src/elements/ia-playback-controls/assets/skip-ahead.js.map +1 -0
  61. package/dist/src/elements/ia-playback-controls/assets/volume-full.d.ts +3 -0
  62. package/dist/src/elements/ia-playback-controls/assets/volume-full.d.ts.map +1 -0
  63. package/dist/src/elements/ia-playback-controls/assets/volume-full.js +19 -0
  64. package/dist/src/elements/ia-playback-controls/assets/volume-full.js.map +1 -0
  65. package/dist/src/elements/ia-playback-controls/assets/volume-medium.d.ts +3 -0
  66. package/dist/src/elements/ia-playback-controls/assets/volume-medium.d.ts.map +1 -0
  67. package/dist/src/elements/ia-playback-controls/assets/volume-medium.js +24 -0
  68. package/dist/src/elements/ia-playback-controls/assets/volume-medium.js.map +1 -0
  69. package/dist/src/elements/ia-playback-controls/assets/volume-mute.d.ts +3 -0
  70. package/dist/src/elements/ia-playback-controls/assets/volume-mute.d.ts.map +1 -0
  71. package/dist/src/elements/ia-playback-controls/assets/volume-mute.js +35 -0
  72. package/dist/src/elements/ia-playback-controls/assets/volume-mute.js.map +1 -0
  73. package/dist/src/elements/ia-playback-controls/ia-playback-controls.d.ts +66 -0
  74. package/dist/src/elements/ia-playback-controls/ia-playback-controls.d.ts.map +1 -0
  75. package/dist/src/elements/ia-playback-controls/ia-playback-controls.js +337 -0
  76. package/dist/src/elements/ia-playback-controls/ia-playback-controls.js.map +1 -0
  77. package/dist/src/elements/ia-playback-controls/models.d.ts +13 -0
  78. package/dist/src/elements/ia-playback-controls/models.d.ts.map +1 -0
  79. package/dist/src/elements/ia-playback-controls/models.js +12 -0
  80. package/dist/src/elements/ia-playback-controls/models.js.map +1 -0
  81. package/dist/src/elements/ia-radio-player/assets/next-result.d.ts +3 -0
  82. package/dist/src/elements/ia-radio-player/assets/next-result.d.ts.map +1 -0
  83. package/dist/src/elements/ia-radio-player/assets/next-result.js +27 -0
  84. package/dist/src/elements/ia-radio-player/assets/next-result.js.map +1 -0
  85. package/dist/src/elements/ia-radio-player/assets/previous-result.d.ts +3 -0
  86. package/dist/src/elements/ia-radio-player/assets/previous-result.d.ts.map +1 -0
  87. package/dist/src/elements/ia-radio-player/assets/previous-result.js +27 -0
  88. package/dist/src/elements/ia-radio-player/assets/previous-result.js.map +1 -0
  89. package/dist/src/elements/ia-radio-player/ia-radio-player.d.ts +130 -0
  90. package/dist/src/elements/ia-radio-player/ia-radio-player.d.ts.map +1 -0
  91. package/dist/src/elements/ia-radio-player/ia-radio-player.js +748 -0
  92. package/dist/src/elements/ia-radio-player/ia-radio-player.js.map +1 -0
  93. package/dist/src/elements/ia-radio-player/ia-search-results-switcher.d.ts +22 -0
  94. package/dist/src/elements/ia-radio-player/ia-search-results-switcher.d.ts.map +1 -0
  95. package/dist/src/elements/ia-radio-player/ia-search-results-switcher.js +137 -0
  96. package/dist/src/elements/ia-radio-player/ia-search-results-switcher.js.map +1 -0
  97. package/dist/src/elements/ia-radio-player/models.d.ts +29 -0
  98. package/dist/src/elements/ia-radio-player/models.d.ts.map +1 -0
  99. package/dist/src/elements/ia-radio-player/models.js +2 -0
  100. package/dist/src/elements/ia-radio-player/models.js.map +1 -0
  101. package/dist/src/elements/ia-radio-player/search/backends/full-text-search-backend.d.ts +38 -0
  102. package/dist/src/elements/ia-radio-player/search/backends/full-text-search-backend.d.ts.map +1 -0
  103. package/dist/src/elements/ia-radio-player/search/backends/full-text-search-backend.js +64 -0
  104. package/dist/src/elements/ia-radio-player/search/backends/full-text-search-backend.js.map +1 -0
  105. package/dist/src/elements/ia-radio-player/search/backends/full-text-search-response.d.ts +94 -0
  106. package/dist/src/elements/ia-radio-player/search/backends/full-text-search-response.d.ts.map +1 -0
  107. package/dist/src/elements/ia-radio-player/search/backends/full-text-search-response.js +56 -0
  108. package/dist/src/elements/ia-radio-player/search/backends/full-text-search-response.js.map +1 -0
  109. package/dist/src/elements/ia-radio-player/search/backends/local-search-backend.d.ts +15 -0
  110. package/dist/src/elements/ia-radio-player/search/backends/local-search-backend.d.ts.map +1 -0
  111. package/dist/src/elements/ia-radio-player/search/backends/local-search-backend.js +26 -0
  112. package/dist/src/elements/ia-radio-player/search/backends/local-search-backend.js.map +1 -0
  113. package/dist/src/elements/ia-radio-player/search/backends/search-backend.d.ts +12 -0
  114. package/dist/src/elements/ia-radio-player/search/backends/search-backend.d.ts.map +1 -0
  115. package/dist/src/elements/ia-radio-player/search/backends/search-backend.js +2 -0
  116. package/dist/src/elements/ia-radio-player/search/backends/search-backend.js.map +1 -0
  117. package/dist/src/elements/ia-radio-player/search/models.d.ts +38 -0
  118. package/dist/src/elements/ia-radio-player/search/models.d.ts.map +1 -0
  119. package/dist/src/elements/ia-radio-player/search/models.js +17 -0
  120. package/dist/src/elements/ia-radio-player/search/models.js.map +1 -0
  121. package/dist/src/elements/ia-radio-player/search/search-handler.d.ts +49 -0
  122. package/dist/src/elements/ia-radio-player/search/search-handler.d.ts.map +1 -0
  123. package/dist/src/elements/ia-radio-player/search/search-handler.js +128 -0
  124. package/dist/src/elements/ia-radio-player/search/search-handler.js.map +1 -0
  125. package/dist/src/elements/ia-radio-player/search/search-helper.d.ts +9 -0
  126. package/dist/src/elements/ia-radio-player/search/search-helper.d.ts.map +1 -0
  127. package/dist/src/elements/ia-radio-player/search/search-helper.js +15 -0
  128. package/dist/src/elements/ia-radio-player/search/search-helper.js.map +1 -0
  129. package/dist/src/elements/ia-radio-player/search/transcript-index.d.ts +45 -0
  130. package/dist/src/elements/ia-radio-player/search/transcript-index.d.ts.map +1 -0
  131. package/dist/src/elements/ia-radio-player/search/transcript-index.js +48 -0
  132. package/dist/src/elements/ia-radio-player/search/transcript-index.js.map +1 -0
  133. package/dist/src/elements/ia-scrubber-bar/assets/next-section-marker.d.ts +3 -0
  134. package/dist/src/elements/ia-scrubber-bar/assets/next-section-marker.d.ts.map +1 -0
  135. package/dist/src/elements/ia-scrubber-bar/assets/next-section-marker.js +18 -0
  136. package/dist/src/elements/ia-scrubber-bar/assets/next-section-marker.js.map +1 -0
  137. package/dist/src/elements/ia-scrubber-bar/assets/previous-section-marker.d.ts +3 -0
  138. package/dist/src/elements/ia-scrubber-bar/assets/previous-section-marker.d.ts.map +1 -0
  139. package/dist/src/elements/ia-scrubber-bar/assets/previous-section-marker.js +18 -0
  140. package/dist/src/elements/ia-scrubber-bar/assets/previous-section-marker.js.map +1 -0
  141. package/dist/src/elements/ia-scrubber-bar/ia-scrubber-bar.d.ts +82 -0
  142. package/dist/src/elements/ia-scrubber-bar/ia-scrubber-bar.d.ts.map +1 -0
  143. package/dist/src/elements/ia-scrubber-bar/ia-scrubber-bar.js +387 -0
  144. package/dist/src/elements/ia-scrubber-bar/ia-scrubber-bar.js.map +1 -0
  145. package/dist/src/elements/ia-scrubber-bar/ia-section-marker.d.ts +16 -0
  146. package/dist/src/elements/ia-scrubber-bar/ia-section-marker.d.ts.map +1 -0
  147. package/dist/src/elements/ia-scrubber-bar/ia-section-marker.js +109 -0
  148. package/dist/src/elements/ia-scrubber-bar/ia-section-marker.js.map +1 -0
  149. package/dist/src/elements/ia-scrubber-bar/models.d.ts +21 -0
  150. package/dist/src/elements/ia-scrubber-bar/models.d.ts.map +1 -0
  151. package/dist/src/elements/ia-scrubber-bar/models.js +20 -0
  152. package/dist/src/elements/ia-scrubber-bar/models.js.map +1 -0
  153. package/dist/src/elements/ia-transcript-view/duration-formatter.d.ts +13 -0
  154. package/dist/src/elements/ia-transcript-view/duration-formatter.d.ts.map +1 -0
  155. package/dist/src/elements/ia-transcript-view/duration-formatter.js +25 -0
  156. package/dist/src/elements/ia-transcript-view/duration-formatter.js.map +1 -0
  157. package/dist/src/elements/ia-transcript-view/ia-transcript-entry.d.ts +25 -0
  158. package/dist/src/elements/ia-transcript-view/ia-transcript-entry.d.ts.map +1 -0
  159. package/dist/src/elements/ia-transcript-view/ia-transcript-entry.js +51 -0
  160. package/dist/src/elements/ia-transcript-view/ia-transcript-entry.js.map +1 -0
  161. package/dist/src/elements/ia-transcript-view/ia-transcript-view.d.ts +87 -0
  162. package/dist/src/elements/ia-transcript-view/ia-transcript-view.d.ts.map +1 -0
  163. package/dist/src/elements/ia-transcript-view/ia-transcript-view.js +565 -0
  164. package/dist/src/elements/ia-transcript-view/ia-transcript-view.js.map +1 -0
  165. package/dist/src/elements/ia-transcript-view/models.d.ts +34 -0
  166. package/dist/src/elements/ia-transcript-view/models.d.ts.map +1 -0
  167. package/dist/src/elements/ia-transcript-view/models.js +38 -0
  168. package/dist/src/elements/ia-transcript-view/models.js.map +1 -0
  169. package/dist/src/elements/ia-waveform-progress/ia-waveform-progress.d.ts +62 -0
  170. package/dist/src/elements/ia-waveform-progress/ia-waveform-progress.d.ts.map +1 -0
  171. package/dist/src/elements/ia-waveform-progress/ia-waveform-progress.js +217 -0
  172. package/dist/src/elements/ia-waveform-progress/ia-waveform-progress.js.map +1 -0
  173. package/dist/src/elements/ia-waveform-progress/models.d.ts +13 -0
  174. package/dist/src/elements/ia-waveform-progress/models.d.ts.map +1 -0
  175. package/dist/src/elements/ia-waveform-progress/models.js +2 -0
  176. package/dist/src/elements/ia-waveform-progress/models.js.map +1 -0
  177. package/dist/src/elements/index.d.ts +27 -0
  178. package/dist/src/elements/index.d.ts.map +1 -1
  179. package/dist/src/elements/index.js +27 -0
  180. package/dist/src/elements/index.js.map +1 -1
  181. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ia-radio-player.js","sourceRoot":"","sources":["../../../../src/elements/ia-radio-player/ia-radio-player.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n css,\n html,\n LitElement,\n nothing,\n type CSSResultGroup,\n type PropertyValues,\n type TemplateResult,\n} from 'lit';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { msg, str } from '@lit/localize';\n\nimport type { AudioSource } from '@src/elements/ia-audio-element/models';\nimport type { QuickSearchEntry } from '@src/elements/ia-expandable-search-bar/models';\nimport { PlaybackMode } from '@src/elements/ia-playback-controls/models';\nimport type {\n TranscriptConfig,\n TranscriptEntryConfig,\n} from '@src/elements/ia-transcript-view/models';\nimport type { IAAudioElement } from '@src/elements/ia-audio-element/ia-audio-element';\nimport type { IATranscriptView } from '@src/elements/ia-transcript-view/ia-transcript-view';\nimport type { ZoneOfSilence } from '@src/elements/ia-waveform-progress/models';\n\nimport type { MusicZone, RadioPlayerConfig } from './models';\nimport type { SearchHandlerInterface } from './search/search-handler';\nimport type { IASearchResultsSwitcher } from './ia-search-results-switcher';\n\nimport '@src/elements/ia-audio-element/ia-audio-element';\nimport '@src/elements/ia-expandable-search-bar/ia-expandable-search-bar';\nimport '@src/elements/ia-playback-controls/ia-playback-controls';\nimport '@src/elements/ia-scrubber-bar/ia-scrubber-bar';\nimport '@src/elements/ia-status-indicator/ia-status-indicator';\nimport '@src/elements/ia-transcript-view/ia-transcript-view';\nimport '@src/elements/ia-waveform-progress/ia-waveform-progress';\nimport './ia-search-results-switcher';\n\n/**\n * Event names emitted by this component\n */\nconst Events = {\n CanPlay: 'canplay',\n CurrentTimeChanged: 'currentTimeChanged',\n HighlightedSearchResultChanged: 'highlightedSearchResultChanged',\n JumpBackButtonPressed: 'jumpBackButtonPressed',\n JumpForwardButtonPressed: 'jumpForwardButtonPressed',\n NextSectionButtonPressed: 'nextSectionButtonPressed',\n PlaybackPaused: 'playbackPaused',\n PlaybackRateChanged: 'playbackRateChanged',\n PlaybackStarted: 'playbackStarted',\n PlayPauseButtonPressed: 'playPauseButtonPressed',\n PrevSectionButtonPressed: 'prevSectionButtonPressed',\n SearchCleared: 'searchCleared',\n SearchExecuted: 'searchExecuted',\n SearchFailed: 'searchFailed',\n SearchTermChanged: 'searchTermChanged',\n TimeChangedFromScrub: 'timeChangedFromScrub',\n TranscriptEntrySelected: 'transcriptEntrySelected',\n};\n\n/** How far the skip buttons move, in seconds */\nconst SKIP_SECONDS = 10;\n\n/** Shortest term worth searching for */\nconst MIN_SEARCH_LENGTH = 2;\n\n/**\n * Nudge past a section boundary when jumping to it, so playback lands inside\n * the next section rather than exactly on its edge.\n */\nconst SECTION_SEEK_NUDGE = 0.1;\n\n/**\n * A player for transcribed radio broadcasts.\n *\n * It owns no playback or search logic of its own. It wires the audio element,\n * transport controls, waveform, scrubber, search bar and transcript together,\n * and hands searching off to whatever `searchHandler` it is given.\n */\n@customElement('ia-radio-player')\nexport class IARadioPlayer extends LitElement {\n /** What is being played, and what to show about it */\n @property({ type: Object }) config?: RadioPlayerConfig;\n\n /** Where searches go. Without one, the search bar does nothing. */\n @property({ type: Object }) searchHandler?: SearchHandlerInterface;\n\n /** The transcript to show when no search is running */\n @property({ type: Object }) transcriptConfig?: TranscriptConfig;\n\n /** The transcript marked up with search results, shown while searching */\n @property({ type: Object }) searchResultsTranscript?: TranscriptConfig;\n\n /** Playback position, in seconds */\n @property({ type: Number }) currentTime = 0;\n\n /** What is currently in the search bar */\n @property({ type: String }) searchTerm = '';\n\n /** Whether to skip past the music sections rather than play them */\n @property({ type: Boolean }) skipMusicSections = false;\n\n @state() private percentComplete = 0;\n\n @state() private isPlaying = false;\n\n @state() private duration = 0;\n\n @state() private playbackRate = 1;\n\n @state() private volume = 1;\n\n @state() private isSearching = false;\n\n /** Numbers each search so a stale one can be told from the current one. */\n private latestSearchId = 0;\n\n @query('ia-audio-element') private audioElement?: IAAudioElement | null;\n\n @query('ia-transcript-view') private transcriptView?: IATranscriptView | null;\n\n @query('ia-search-results-switcher')\n private searchResultsSwitcher?: IASearchResultsSwitcher | null;\n\n render(): TemplateResult {\n return html`\n ${this.audioElementTemplate}\n <section role=\"main\">\n ${this.titleDateTemplate} ${this.collectionLogoTemplate}\n ${this.playbackControlsTemplate}\n <div class=\"waveform-scrubber-container\">\n ${this.waveformProgressTemplate} ${this.scrubberBarTemplate}\n </div>\n ${this.searchSectionTemplate} ${this.transcriptViewTemplate}\n </section>\n `;\n }\n\n /** Starts playback */\n play(): void {\n this.audioElement?.play();\n }\n\n /** Pauses playback */\n pause(): void {\n this.audioElement?.pause();\n }\n\n /** Jumps to a position in the track, in seconds */\n seekTo(seconds: number): void {\n this.audioElement?.seekTo(seconds);\n }\n\n private get audioElementTemplate(): TemplateResult {\n return html`\n <ia-audio-element\n .sources=${this.audioSources}\n .playbackRate=${this.playbackRate}\n .volume=${this.volume}\n @timeupdate=${this.handleTimeChange}\n @durationchange=${this.handleDurationChange}\n @playbackStarted=${this.playbackStarted}\n @playbackPaused=${this.playbackPaused}\n @canplay=${this.canPlay}\n ></ia-audio-element>\n `;\n }\n\n private get titleDateTemplate(): TemplateResult {\n return html`\n <div class=\"title-date\">\n <div class=\"title\">${this.config?.title ?? ''}</div>\n <div class=\"date\">${this.config?.date ?? ''}</div>\n </div>\n `;\n }\n\n private get collectionLogoTemplate(): TemplateResult | typeof nothing {\n const logoUrl = this.config?.logoUrl;\n if (!logoUrl) return nothing;\n\n return html`\n <img\n class=\"collection-logo\"\n src=${logoUrl}\n alt=${msg('Collection logo')}\n />\n `;\n }\n\n private get playbackControlsTemplate(): TemplateResult {\n return html`\n <ia-playback-controls\n .playbackMode=${this.isPlaying\n ? PlaybackMode.playing\n : PlaybackMode.paused}\n .playbackRate=${this.playbackRate}\n .volume=${this.volume}\n @back-button-pressed=${this.handleBackButton}\n @play-pause-button-pressed=${this.handlePlayPauseButton}\n @forward-button-pressed=${this.handleForwardButton}\n @volumeChange=${this.handleVolumeChange}\n @playbackRateChange=${this.handlePlaybackRateChange}\n @next-section-button-pressed=${this.handleNextSectionButton}\n @prev-section-button-pressed=${this.handlePrevSectionButton}\n ></ia-playback-controls>\n `;\n }\n\n private get waveformProgressTemplate(): TemplateResult | typeof nothing {\n const waveformUrl = this.config?.waveformUrl;\n if (!waveformUrl) return nothing;\n\n return html`\n <ia-waveform-progress\n interactive\n .waveformUrl=${waveformUrl}\n .percentComplete=${this.percentComplete}\n .zonesOfSilence=${this.zonesOfSilence}\n @valuechange=${this.handleScrub}\n ></ia-waveform-progress>\n `;\n }\n\n private get scrubberBarTemplate(): TemplateResult {\n return html`\n <ia-scrubber-bar\n .sectionMarkerPercentages=${this.sectionMarkerPercentages}\n .value=${this.percentComplete}\n @valuechange=${this.handleScrub}\n ></ia-scrubber-bar>\n `;\n }\n\n private get transcriptViewTemplate(): TemplateResult {\n return html`\n <div class=\"transcript-container\">\n <ia-transcript-view\n .config=${this.currentTranscript}\n .currentTime=${this.currentTime}\n @transcriptEntrySelected=${this.handleTranscriptEntrySelected}\n ></ia-transcript-view>\n </div>\n `;\n }\n\n private get searchSectionTemplate(): TemplateResult {\n return html`\n <div class=\"search-section\">\n <ia-expandable-search-bar\n .searchTerm=${this.searchTerm}\n .quickSearches=${this.quickSearches}\n ?showsDisclosure=${this.quickSearches.length > 0}\n @inputchange=${this.handleSearchInput}\n @enterKeyPressed=${this.handleSearchSubmitted}\n @quickSearchSelected=${this.handleQuickSearchSelected}\n @searchCleared=${this.handleSearchCleared}\n ></ia-expandable-search-bar>\n\n <div class=\"search-results-info\">\n <!--\n Always rendered, so a screen reader is already watching it by the\n time the text changes. A live region added to the page with its\n text already in place is not announced.\n -->\n <div class=\"sr-only\" role=\"status\">${this.searchStatusMessage}</div>\n\n ${this.isSearching\n ? html`<ia-status-indicator\n mode=\"loading\"\n loadingTitle=${msg('Searching the transcript')}\n ></ia-status-indicator>`\n : this.searchOutcomeTemplate}\n </div>\n </div>\n `;\n }\n\n /** What to show once a search has come back: a counter, or nothing found. */\n private get searchOutcomeTemplate(): TemplateResult | typeof nothing {\n if (this.searchTerm.length === 0 || !this.searchResultsTranscript) {\n return nothing;\n }\n\n const resultCount = this.searchResults.length;\n if (resultCount === 0) {\n return html`\n <div class=\"no-search-results-message\" aria-hidden=\"true\">\n ${msg('No search results.')}\n </div>\n `;\n }\n\n return html`\n <ia-search-results-switcher\n .numberOfResults=${resultCount}\n @searchResultIndexChanged=${this.handleSearchResultIndexChanged}\n ></ia-search-results-switcher>\n `;\n }\n\n /** What the live region announces as a search runs and comes back. */\n private get searchStatusMessage(): string {\n if (this.isSearching) return msg('Searching the transcript');\n if (this.searchTerm.length === 0 || !this.searchResultsTranscript)\n return '';\n\n const count = this.searchResults.length;\n if (count === 0) return msg('No search results.');\n\n return msg(str`${count} search results`);\n }\n\n private get currentTranscript(): TranscriptConfig | undefined {\n return this.searchResultsTranscript ?? this.transcriptConfig;\n }\n\n private get transcriptEntries(): TranscriptEntryConfig[] {\n return this.currentTranscript?.entries ?? [];\n }\n\n private get searchResults(): TranscriptEntryConfig[] {\n return this.searchResultsTranscript?.searchResults ?? [];\n }\n\n private get audioSources(): AudioSource[] {\n return this.config?.audioSources ?? [];\n }\n\n private get quickSearches(): QuickSearchEntry[] {\n return (this.config?.quickSearches ?? []).map((displayText) => ({\n displayText,\n }));\n }\n\n private get musicEntries(): TranscriptEntryConfig[] {\n return this.transcriptEntries.filter((entry) => entry.isMusic);\n }\n\n /** The music stretches, as percentages, for marking on the waveform. */\n private get zonesOfSilence(): ZoneOfSilence[] {\n if (this.duration === 0) return [];\n\n return this.musicEntries.map((entry) => ({\n startPercent: (entry.start / this.duration) * 100,\n endPercent: (entry.end / this.duration) * 100,\n }));\n }\n\n /** The music stretches in seconds, for skipping past them. */\n private get musicZones(): MusicZone[] {\n return this.musicEntries.map((entry) => ({\n start: entry.start,\n end: entry.end,\n }));\n }\n\n /**\n * Every section boundary as a percentage, including the two ends.\n *\n * The section skip buttons step between these, and the scrubber draws a\n * marker at each.\n */\n private get sectionMarkerPercentages(): number[] {\n const percentages = [0];\n\n this.zonesOfSilence.forEach((zone) => {\n percentages.push(zone.startPercent, zone.endPercent);\n });\n percentages.push(100);\n\n return percentages;\n }\n\n updated(changedProperties: PropertyValues): void {\n if (changedProperties.has('searchResultsTranscript')) {\n this.resetSearchResultPosition();\n }\n\n if (changedProperties.has('searchHandler') && this.searchTerm) {\n this.executeSearch(this.searchTerm);\n }\n\n if (changedProperties.has('currentTime')) {\n this.dispatchEvent(\n new CustomEvent<{ currentTime: number }>(Events.CurrentTimeChanged, {\n detail: { currentTime: this.currentTime },\n }),\n );\n\n if (this.skipMusicSections) this.skipMusicZone();\n }\n }\n\n private handleTimeChange(e: CustomEvent<{ currentTime: number }>): void {\n const { currentTime } = e.detail;\n if (currentTime === undefined) return;\n\n this.currentTime = currentTime;\n // A duration of 0 means nothing has loaded yet, and dividing by it would\n // put NaN into the scrubber and the waveform.\n this.percentComplete =\n this.duration > 0 ? (currentTime / this.duration) * 100 : 0;\n }\n\n private handleDurationChange(e: CustomEvent<{ duration: number }>): void {\n const { duration } = e.detail;\n // A stream reports Infinity, and metadata that hasn't loaded reports NaN.\n if (!Number.isFinite(duration)) return;\n\n this.duration = duration;\n }\n\n private handlePlaybackRateChange(\n e: CustomEvent<{ playbackRate: number }>,\n ): void {\n const { playbackRate } = e.detail;\n if (playbackRate === undefined) return;\n\n this.playbackRate = playbackRate;\n this.dispatchEvent(\n new CustomEvent<{ playbackRate: number }>(Events.PlaybackRateChanged, {\n detail: { playbackRate },\n }),\n );\n }\n\n private handleVolumeChange(e: CustomEvent<{ volume: number }>): void {\n const { volume } = e.detail;\n if (volume === undefined) return;\n\n this.volume = volume;\n this.dispatchEvent(\n new CustomEvent<{ volume: number }>('volumeChanged', {\n detail: { volume },\n }),\n );\n }\n\n private handleBackButton(): void {\n this.audioElement?.seekBy(-SKIP_SECONDS);\n this.dispatchEvent(new Event(Events.JumpBackButtonPressed));\n }\n\n private handleForwardButton(): void {\n this.audioElement?.seekBy(SKIP_SECONDS);\n this.dispatchEvent(new Event(Events.JumpForwardButtonPressed));\n }\n\n private handlePlayPauseButton(): void {\n this.isPlaying = !this.isPlaying;\n\n if (this.isPlaying) this.audioElement?.play();\n else this.audioElement?.pause();\n\n this.dispatchEvent(\n new CustomEvent<{ isPlaying: boolean }>(Events.PlayPauseButtonPressed, {\n detail: { isPlaying: this.isPlaying },\n }),\n );\n }\n\n private handleNextSectionButton(): void {\n const ahead = this.sectionMarkerPercentages.filter(\n (percent) => percent > this.percentComplete + SECTION_SEEK_NUDGE,\n );\n this.seekToSectionBoundary(ahead, Math.min, SECTION_SEEK_NUDGE);\n\n this.dispatchEvent(new Event(Events.NextSectionButtonPressed));\n }\n\n private handlePrevSectionButton(): void {\n const behind = this.sectionMarkerPercentages.filter(\n (percent) => percent < this.percentComplete - SECTION_SEEK_NUDGE,\n );\n this.seekToSectionBoundary(behind, Math.max, -SECTION_SEEK_NUDGE);\n\n this.dispatchEvent(new Event(Events.PrevSectionButtonPressed));\n }\n\n /**\n * Seeks to the nearest of a set of boundaries.\n *\n * Does nothing when the set is empty, since `Math.min` of nothing is\n * `Infinity` and `Math.max` of nothing is `-Infinity`, either of which would\n * be handed straight to the audio element as a position.\n */\n private seekToSectionBoundary(\n percentages: number[],\n pick: (...values: number[]) => number,\n nudge: number,\n ): void {\n if (percentages.length === 0) return;\n\n const boundary = pick(...percentages);\n this.audioElement?.seekTo(this.duration * (boundary / 100) + nudge);\n }\n\n private handleScrub(e: CustomEvent<{ value: number }>): void {\n const percentage = e.detail.value;\n if (percentage === undefined) return;\n\n const newTime = this.duration * (percentage / 100);\n this.currentTime = newTime;\n this.percentComplete = percentage;\n this.audioElement?.seekTo(newTime);\n\n this.dispatchEvent(\n new CustomEvent<{ newTime: number }>(Events.TimeChangedFromScrub, {\n detail: { newTime },\n }),\n );\n }\n\n private handleTranscriptEntrySelected(\n e: CustomEvent<{ entry: TranscriptEntryConfig }>,\n ): void {\n const { entry } = e.detail;\n if (!entry) return;\n\n this.currentTime = entry.start;\n this.audioElement?.seekTo(entry.start);\n this.audioElement?.play();\n\n this.dispatchEvent(\n new CustomEvent<{ newTime: number }>(Events.TranscriptEntrySelected, {\n detail: { newTime: entry.start },\n }),\n );\n }\n\n private handleSearchInput(e: CustomEvent<{ value: string }>): void {\n const { value } = e.detail;\n if (value === undefined) return;\n\n this.searchTerm = value;\n\n // An empty box has nothing to show results for. The counter already hides\n // itself on an empty term, so without dropping the results too the\n // transcript keeps its outlines and offers no way to step between them.\n if (value.length === 0) {\n this.searchResultsTranscript = undefined;\n // Abandons whatever is in flight, so its results can't land afterwards.\n this.latestSearchId += 1;\n this.isSearching = false;\n this.resetSearchResultPosition();\n }\n\n this.emitSearchTermChanged(value);\n }\n\n private handleSearchSubmitted(e: CustomEvent<{ value: string }>): void {\n const { value } = e.detail;\n if (!value) return;\n\n this.executeSearch(value);\n }\n\n private handleQuickSearchSelected(\n e: CustomEvent<{ quickSearchEntry: QuickSearchEntry }>,\n ): void {\n const term = e.detail.quickSearchEntry?.displayText;\n if (!term) return;\n\n this.emitSearchTermChanged(term);\n this.executeSearch(term);\n }\n\n private handleSearchCleared(): void {\n this.searchTerm = '';\n this.searchResultsTranscript = undefined;\n // Abandons whatever is in flight, so its results can't arrive after this.\n this.latestSearchId += 1;\n this.isSearching = false;\n\n this.dispatchEvent(new Event(Events.SearchCleared));\n this.emitSearchTermChanged('');\n this.resetSearchResultPosition();\n }\n\n /**\n * Runs a search and shows its results.\n *\n * Each run is numbered, and only the newest one is allowed to report back.\n * Searches go over the network, so a slow one started earlier can land after\n * a fast one started later, and without this the older results would end up\n * on screen under the newer term.\n *\n * A failed search has to put the spinner away as surely as a successful one,\n * hence the `finally`. Leaving it up would hide the search UI for as long as\n * the page lives.\n */\n private async executeSearch(term: string): Promise<void> {\n if (!this.searchHandler || term.length < MIN_SEARCH_LENGTH) {\n this.searchResultsTranscript = undefined;\n return;\n }\n\n this.searchTerm = term;\n this.isSearching = true;\n this.dispatchEvent(new Event(Events.SearchExecuted));\n\n this.latestSearchId += 1;\n const searchId = this.latestSearchId;\n\n try {\n const results = await this.searchHandler.search(term);\n if (searchId !== this.latestSearchId) return;\n\n this.searchResultsTranscript = results;\n } catch {\n if (searchId !== this.latestSearchId) return;\n\n this.searchResultsTranscript = undefined;\n this.dispatchEvent(new Event(Events.SearchFailed));\n } finally {\n if (searchId === this.latestSearchId) this.isSearching = false;\n }\n }\n\n private handleSearchResultIndexChanged(\n e: CustomEvent<{ searchResultIndex: number }>,\n ): void {\n const { searchResultIndex } = e.detail;\n if (searchResultIndex === undefined || !this.transcriptView) return;\n\n this.transcriptView.selectedSearchResultIndex = searchResultIndex;\n this.transcriptView.scrollToSelectedSearchResult();\n\n this.dispatchEvent(\n new CustomEvent<{ searchResultIndex: number }>(\n Events.HighlightedSearchResultChanged,\n { detail: { searchResultIndex } },\n ),\n );\n }\n\n /** Puts both the transcript and the switcher back to the first result. */\n private resetSearchResultPosition(): void {\n if (this.transcriptView) this.transcriptView.selectedSearchResultIndex = 0;\n if (this.searchResultsSwitcher) {\n this.searchResultsSwitcher.currentResultIndex = 0;\n }\n }\n\n private emitSearchTermChanged(searchTerm: string): void {\n this.dispatchEvent(\n new CustomEvent<{ searchTerm: string }>(Events.SearchTermChanged, {\n detail: { searchTerm },\n }),\n );\n }\n\n private playbackPaused(): void {\n this.isPlaying = false;\n this.dispatchEvent(new Event(Events.PlaybackPaused));\n }\n\n private playbackStarted(): void {\n this.isPlaying = true;\n this.dispatchEvent(new Event(Events.PlaybackStarted));\n }\n\n private canPlay(): void {\n this.dispatchEvent(new Event(Events.CanPlay));\n }\n\n /** Jumps past a music stretch if playback has wandered into one. */\n private skipMusicZone(): void {\n const activeZone = this.musicZones.find(\n (zone) => this.currentTime > zone.start && this.currentTime < zone.end,\n );\n if (!activeZone) return;\n\n this.audioElement?.seekTo(activeZone.end + SECTION_SEEK_NUDGE);\n }\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n --radio-player-title-color--: var(\n --ia-theme-radio-player-title-color,\n #fff\n );\n --radio-player-title-font--: var(\n --ia-theme-radio-player-title-font,\n 1.5em sans-serif\n );\n --radio-player-date-color--: var(\n --ia-theme-radio-player-date-color,\n #fff\n );\n --radio-player-date-font--: var(\n --ia-theme-radio-player-date-font,\n 1em sans-serif\n );\n --radio-player-logo-max-height--: var(\n --ia-theme-radio-player-logo-max-height,\n 8rem\n );\n --radio-player-waveform-height--: var(\n --ia-theme-radio-player-waveform-height,\n 5rem\n );\n }\n\n section[role='main'] {\n display: grid;\n grid-gap: 0.5rem;\n }\n\n ia-status-indicator {\n --ia-theme-icon-width: 1.5em;\n --ia-theme-primary-text-color: #999;\n\n display: block;\n margin: auto;\n }\n\n /* mobile view */\n @media (max-width: 770px) {\n section[role='main'] {\n grid-template-columns: 25% 1fr;\n grid-template-areas:\n 'collection-logo title-date'\n 'waveform-scrubber waveform-scrubber'\n 'playback-controls playback-controls'\n 'search-section search-section'\n 'transcript-container transcript-container';\n }\n\n .date {\n text-align: left;\n }\n\n ia-transcript-view {\n --ia-theme-transcript-time-display: none;\n }\n\n ia-playback-controls {\n width: 75%;\n margin: auto;\n }\n\n .search-section {\n width: 75%;\n margin: auto;\n }\n }\n\n /* wide view */\n @media (min-width: 770px) {\n section[role='main'] {\n grid-template-columns: 192px 0 250px 1fr;\n grid-template-areas:\n 'title-date title-date title-date title-date'\n 'collection-logo . playback-controls waveform-scrubber'\n 'search-section transcript-container transcript-container transcript-container';\n }\n\n .title-date {\n display: flex;\n justify-content: space-between;\n align-items: baseline;\n }\n\n ia-transcript-view {\n --ia-theme-transcript-time-display: block;\n }\n }\n\n .title-date {\n grid-area: title-date;\n }\n\n .title {\n color: var(--radio-player-title-color--);\n font: var(--radio-player-title-font--);\n }\n\n .date {\n color: var(--radio-player-date-color--);\n font: var(--radio-player-date-font--);\n }\n\n ia-waveform-progress {\n width: 100%;\n height: var(--radio-player-waveform-height--);\n }\n\n ia-playback-controls {\n grid-area: playback-controls;\n }\n\n .transcript-container {\n grid-area: transcript-container;\n }\n\n ia-transcript-view {\n max-width: 600px;\n display: block;\n }\n\n .collection-logo {\n width: 100%;\n max-height: var(--radio-player-logo-max-height--);\n object-fit: contain;\n grid-area: collection-logo;\n align-self: center;\n }\n\n .waveform-scrubber-container {\n width: 100%;\n height: 100%;\n grid-area: waveform-scrubber;\n }\n\n .search-section {\n grid-area: search-section;\n }\n\n .search-results-info {\n margin-top: 0.5em;\n }\n\n ia-expandable-search-bar {\n display: block;\n margin: auto;\n }\n\n .no-search-results-message {\n text-align: center;\n }\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n `;\n }\n}\n"]}
@@ -0,0 +1,22 @@
1
+ import { LitElement, type CSSResultGroup, type PropertyValues, type TemplateResult } from 'lit';
2
+ /**
3
+ * Steps through search results, reading `‹ 3 / 7 ›`.
4
+ *
5
+ * Both ends wrap around, so there is always somewhere to go.
6
+ */
7
+ export declare class IASearchResultsSwitcher extends LitElement {
8
+ /** How many results there are to step through */
9
+ numberOfResults: number;
10
+ /** Which result is being looked at, counting from zero */
11
+ currentResultIndex: number;
12
+ render(): TemplateResult;
13
+ updated(changedProperties: PropertyValues): void;
14
+ /** Steps back one result, wrapping round to the last. */
15
+ goToPreviousResult(): void;
16
+ /** Steps on one result, wrapping round to the first. */
17
+ goToNextResult(): void;
18
+ private get positionLabel();
19
+ private emitSearchResultIndexChanged;
20
+ static get styles(): CSSResultGroup;
21
+ }
22
+ //# sourceMappingURL=ia-search-results-switcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ia-search-results-switcher.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-radio-player/ia-search-results-switcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EACV,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAcb;;;;GAIG;AACH,qBACa,uBAAwB,SAAQ,UAAU;IACrD,iDAAiD;IACrB,eAAe,SAAK;IAEhD,0DAA0D;IAC9B,kBAAkB,SAAK;IAEnD,MAAM,IAAI,cAAc;IAoCxB,OAAO,CAAC,iBAAiB,EAAE,cAAc,GAAG,IAAI;IAKhD,yDAAyD;IACzD,kBAAkB,IAAI,IAAI;IAS1B,wDAAwD;IACxD,cAAc,IAAI,IAAI;IAStB,OAAO,KAAK,aAAa,GAKxB;IAED,OAAO,CAAC,4BAA4B;IASpC,MAAM,KAAK,MAAM,IAAI,cAAc,CAmClC;CACF"}
@@ -0,0 +1,137 @@
1
+ import { __decorate } from "tslib";
2
+ import { css, html, LitElement, } from 'lit';
3
+ import { customElement, property } from 'lit/decorators.js';
4
+ import { msg, str } from '@lit/localize';
5
+ import nextResultIcon from './assets/next-result.js';
6
+ import previousResultIcon from './assets/previous-result.js';
7
+ /**
8
+ * Event names emitted by this component
9
+ */
10
+ const Events = {
11
+ SearchResultIndexChanged: 'searchResultIndexChanged',
12
+ };
13
+ /**
14
+ * Steps through search results, reading `‹ 3 / 7 ›`.
15
+ *
16
+ * Both ends wrap around, so there is always somewhere to go.
17
+ */
18
+ let IASearchResultsSwitcher = class IASearchResultsSwitcher extends LitElement {
19
+ constructor() {
20
+ super(...arguments);
21
+ /** How many results there are to step through */
22
+ this.numberOfResults = 0;
23
+ /** Which result is being looked at, counting from zero */
24
+ this.currentResultIndex = 0;
25
+ }
26
+ render() {
27
+ return html `
28
+ <div class="container">
29
+ <button
30
+ id="previous-button"
31
+ type="button"
32
+ aria-label=${msg('Previous search result')}
33
+ @click=${this.goToPreviousResult}
34
+ >
35
+ ${previousResultIcon}
36
+ </button>
37
+
38
+ <span class="results-range">
39
+ <span id="current-result">${this.currentResultIndex + 1}</span> /
40
+ <span id="number-of-results">${this.numberOfResults}</span>
41
+ </span>
42
+
43
+ <button
44
+ id="next-button"
45
+ type="button"
46
+ aria-label=${msg('Next search result')}
47
+ @click=${this.goToNextResult}
48
+ >
49
+ ${nextResultIcon}
50
+ </button>
51
+ </div>
52
+
53
+ <!--
54
+ The counter above is two bare numbers, which say nothing on their own.
55
+ This says what they mean, and being a live region it is announced each
56
+ time the reader moves between results.
57
+ -->
58
+ <div class="sr-only" role="status">${this.positionLabel}</div>
59
+ `;
60
+ }
61
+ updated(changedProperties) {
62
+ // A new set of results starts at the first one.
63
+ if (changedProperties.has('numberOfResults'))
64
+ this.currentResultIndex = 0;
65
+ }
66
+ /** Steps back one result, wrapping round to the last. */
67
+ goToPreviousResult() {
68
+ this.currentResultIndex =
69
+ this.currentResultIndex < 1
70
+ ? this.numberOfResults - 1
71
+ : this.currentResultIndex - 1;
72
+ this.emitSearchResultIndexChanged();
73
+ }
74
+ /** Steps on one result, wrapping round to the first. */
75
+ goToNextResult() {
76
+ this.currentResultIndex =
77
+ this.currentResultIndex === this.numberOfResults - 1
78
+ ? 0
79
+ : this.currentResultIndex + 1;
80
+ this.emitSearchResultIndexChanged();
81
+ }
82
+ get positionLabel() {
83
+ const position = this.currentResultIndex + 1;
84
+ const total = this.numberOfResults;
85
+ return msg(str `Search result ${position} of ${total}`);
86
+ }
87
+ emitSearchResultIndexChanged() {
88
+ this.dispatchEvent(new CustomEvent(Events.SearchResultIndexChanged, { detail: { searchResultIndex: this.currentResultIndex } }));
89
+ }
90
+ static get styles() {
91
+ return css `
92
+ :host {
93
+ --search-switcher-color--: var(--ia-theme-search-switcher-color, #fff);
94
+
95
+ color: var(--search-switcher-color--);
96
+ }
97
+
98
+ .container {
99
+ display: flex;
100
+ align-items: center;
101
+ justify-content: center;
102
+ gap: 0.5em;
103
+ }
104
+
105
+ button {
106
+ background: none;
107
+ border: 0;
108
+ padding: 0;
109
+ color: inherit;
110
+ cursor: pointer;
111
+ }
112
+
113
+ .sr-only {
114
+ position: absolute;
115
+ width: 1px;
116
+ height: 1px;
117
+ padding: 0;
118
+ margin: -1px;
119
+ overflow: hidden;
120
+ clip: rect(0, 0, 0, 0);
121
+ white-space: nowrap;
122
+ border: 0;
123
+ }
124
+ `;
125
+ }
126
+ };
127
+ __decorate([
128
+ property({ type: Number })
129
+ ], IASearchResultsSwitcher.prototype, "numberOfResults", void 0);
130
+ __decorate([
131
+ property({ type: Number })
132
+ ], IASearchResultsSwitcher.prototype, "currentResultIndex", void 0);
133
+ IASearchResultsSwitcher = __decorate([
134
+ customElement('ia-search-results-switcher')
135
+ ], IASearchResultsSwitcher);
136
+ export { IASearchResultsSwitcher };
137
+ //# sourceMappingURL=ia-search-results-switcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ia-search-results-switcher.js","sourceRoot":"","sources":["../../../../src/elements/ia-radio-player/ia-search-results-switcher.ts"],"names":[],"mappings":";AAAA,OAAO,EACL,GAAG,EACH,IAAI,EACJ,UAAU,GAIX,MAAM,KAAK,CAAC;AACb,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,cAAc,MAAM,sBAAsB,CAAC;AAClD,OAAO,kBAAkB,MAAM,0BAA0B,CAAC;AAE1D;;GAEG;AACH,MAAM,MAAM,GAAG;IACb,wBAAwB,EAAE,0BAA0B;CACrD,CAAC;AAEF;;;;GAIG;AAEI,IAAM,uBAAuB,GAA7B,MAAM,uBAAwB,SAAQ,UAAU;IAAhD;;QACL,iDAAiD;QACrB,oBAAe,GAAG,CAAC,CAAC;QAEhD,0DAA0D;QAC9B,uBAAkB,GAAG,CAAC,CAAC;IAmHrD,CAAC;IAjHC,MAAM;QACJ,OAAO,IAAI,CAAA;;;;;uBAKQ,GAAG,CAAC,wBAAwB,CAAC;mBACjC,IAAI,CAAC,kBAAkB;;YAE9B,kBAAkB;;;;sCAIQ,IAAI,CAAC,kBAAkB,GAAG,CAAC;yCACxB,IAAI,CAAC,eAAe;;;;;;uBAMtC,GAAG,CAAC,oBAAoB,CAAC;mBAC7B,IAAI,CAAC,cAAc;;YAE1B,cAAc;;;;;;;;;2CASiB,IAAI,CAAC,aAAa;KACxD,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,iBAAiC;QACvC,gDAAgD;QAChD,IAAI,iBAAiB,CAAC,GAAG,CAAC,iBAAiB,CAAC;YAAE,IAAI,CAAC,kBAAkB,GAAG,CAAC,CAAC;IAC5E,CAAC;IAED,yDAAyD;IACzD,kBAAkB;QAChB,IAAI,CAAC,kBAAkB;YACrB,IAAI,CAAC,kBAAkB,GAAG,CAAC;gBACzB,CAAC,CAAC,IAAI,CAAC,eAAe,GAAG,CAAC;gBAC1B,CAAC,CAAC,IAAI,CAAC,kBAAkB,GAAG,CAAC,CAAC;QAElC,IAAI,CAAC,4BAA4B,EAAE,CAAC;IACtC,CAAC;IAED,wDAAwD;IACxD,cAAc;QACZ,IAAI,CAAC,kBAAkB;YACrB,IAAI,CAAC,kBAAkB,KAAK,IAAI,CAAC,eAAe,GAAG,CAAC;gBAClD,CAAC,CAAC,CAAC;gBACH,CAAC,CAAC,IAAI,CAAC,kBAAkB,GAAG,CAAC,CAAC;QAElC,IAAI,CAAC,4BAA4B,EAAE,CAAC;IACtC,CAAC;IAED,IAAY,aAAa;QACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,kBAAkB,GAAG,CAAC,CAAC;QAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC;QAEnC,OAAO,GAAG,CAAC,GAAG,CAAA,iBAAiB,QAAQ,OAAO,KAAK,EAAE,CAAC,CAAC;IACzD,CAAC;IAEO,4BAA4B;QAClC,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CACb,MAAM,CAAC,wBAAwB,EAC/B,EAAE,MAAM,EAAE,EAAE,iBAAiB,EAAE,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAC3D,CACF,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,MAAM;QACf,OAAO,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAiCT,CAAC;IACJ,CAAC;CACF,CAAA;AAtH6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;gEAAqB;AAGpB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;mEAAwB;AALxC,uBAAuB;IADnC,aAAa,CAAC,4BAA4B,CAAC;GAC/B,uBAAuB,CAwHnC","sourcesContent":["import {\n css,\n html,\n LitElement,\n type CSSResultGroup,\n type PropertyValues,\n type TemplateResult,\n} from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { msg, str } from '@lit/localize';\n\nimport nextResultIcon from './assets/next-result';\nimport previousResultIcon from './assets/previous-result';\n\n/**\n * Event names emitted by this component\n */\nconst Events = {\n SearchResultIndexChanged: 'searchResultIndexChanged',\n};\n\n/**\n * Steps through search results, reading `‹ 3 / 7 ›`.\n *\n * Both ends wrap around, so there is always somewhere to go.\n */\n@customElement('ia-search-results-switcher')\nexport class IASearchResultsSwitcher extends LitElement {\n /** How many results there are to step through */\n @property({ type: Number }) numberOfResults = 0;\n\n /** Which result is being looked at, counting from zero */\n @property({ type: Number }) currentResultIndex = 0;\n\n render(): TemplateResult {\n return html`\n <div class=\"container\">\n <button\n id=\"previous-button\"\n type=\"button\"\n aria-label=${msg('Previous search result')}\n @click=${this.goToPreviousResult}\n >\n ${previousResultIcon}\n </button>\n\n <span class=\"results-range\">\n <span id=\"current-result\">${this.currentResultIndex + 1}</span> /\n <span id=\"number-of-results\">${this.numberOfResults}</span>\n </span>\n\n <button\n id=\"next-button\"\n type=\"button\"\n aria-label=${msg('Next search result')}\n @click=${this.goToNextResult}\n >\n ${nextResultIcon}\n </button>\n </div>\n\n <!--\n The counter above is two bare numbers, which say nothing on their own.\n This says what they mean, and being a live region it is announced each\n time the reader moves between results.\n -->\n <div class=\"sr-only\" role=\"status\">${this.positionLabel}</div>\n `;\n }\n\n updated(changedProperties: PropertyValues): void {\n // A new set of results starts at the first one.\n if (changedProperties.has('numberOfResults')) this.currentResultIndex = 0;\n }\n\n /** Steps back one result, wrapping round to the last. */\n goToPreviousResult(): void {\n this.currentResultIndex =\n this.currentResultIndex < 1\n ? this.numberOfResults - 1\n : this.currentResultIndex - 1;\n\n this.emitSearchResultIndexChanged();\n }\n\n /** Steps on one result, wrapping round to the first. */\n goToNextResult(): void {\n this.currentResultIndex =\n this.currentResultIndex === this.numberOfResults - 1\n ? 0\n : this.currentResultIndex + 1;\n\n this.emitSearchResultIndexChanged();\n }\n\n private get positionLabel(): string {\n const position = this.currentResultIndex + 1;\n const total = this.numberOfResults;\n\n return msg(str`Search result ${position} of ${total}`);\n }\n\n private emitSearchResultIndexChanged(): void {\n this.dispatchEvent(\n new CustomEvent<{ searchResultIndex: number }>(\n Events.SearchResultIndexChanged,\n { detail: { searchResultIndex: this.currentResultIndex } },\n ),\n );\n }\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n --search-switcher-color--: var(--ia-theme-search-switcher-color, #fff);\n\n color: var(--search-switcher-color--);\n }\n\n .container {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.5em;\n }\n\n button {\n background: none;\n border: 0;\n padding: 0;\n color: inherit;\n cursor: pointer;\n }\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n `;\n }\n}\n"]}
@@ -0,0 +1,29 @@
1
+ import type { AudioSource } from '../../elements/ia-audio-element/models.js';
2
+ /**
3
+ * A stretch of the broadcast that is music rather than speech.
4
+ *
5
+ * Both bounds are seconds into the track. Used to mark the waveform and,
6
+ * optionally, to skip past them.
7
+ */
8
+ export interface MusicZone {
9
+ start: number;
10
+ end: number;
11
+ }
12
+ /**
13
+ * Everything the player needs to know about the broadcast it is playing.
14
+ */
15
+ export interface RadioPlayerConfig {
16
+ /** The title shown above the player. */
17
+ title: string;
18
+ /** The broadcast date, shown beside the title. */
19
+ date: string;
20
+ /** The collection logo shown alongside the player. */
21
+ logoUrl: string;
22
+ /** The waveform image drawn behind the progress bar, if there is one. */
23
+ waveformUrl?: string;
24
+ /** The audio to play, in order of preference. */
25
+ audioSources: AudioSource[];
26
+ /** Suggested searches offered under the search bar. */
27
+ quickSearches?: string[];
28
+ }
29
+ //# sourceMappingURL=models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-radio-player/models.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAC;AAEzE;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;IAEd,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IAEb,sDAAsD;IACtD,OAAO,EAAE,MAAM,CAAC;IAEhB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,iDAAiD;IACjD,YAAY,EAAE,WAAW,EAAE,CAAC;IAE5B,uDAAuD;IACvD,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../../../../src/elements/ia-radio-player/models.ts"],"names":[],"mappings":"","sourcesContent":["import type { AudioSource } from '@src/elements/ia-audio-element/models';\n\n/**\n * A stretch of the broadcast that is music rather than speech.\n *\n * Both bounds are seconds into the track. Used to mark the waveform and,\n * optionally, to skip past them.\n */\nexport interface MusicZone {\n start: number;\n end: number;\n}\n\n/**\n * Everything the player needs to know about the broadcast it is playing.\n */\nexport interface RadioPlayerConfig {\n /** The title shown above the player. */\n title: string;\n\n /** The broadcast date, shown beside the title. */\n date: string;\n\n /** The collection logo shown alongside the player. */\n logoUrl: string;\n\n /** The waveform image drawn behind the progress bar, if there is one. */\n waveformUrl?: string;\n\n /** The audio to play, in order of preference. */\n audioSources: AudioSource[];\n\n /** Suggested searches offered under the search bar. */\n quickSearches?: string[];\n}\n"]}
@@ -0,0 +1,38 @@
1
+ import { TextRange } from '../models.js';
2
+ import type { SearchBackendInterface } from './search-backend.js';
3
+ import type { FullTextSearchServiceInterface } from './full-text-search-response.js';
4
+ /**
5
+ * Turns archive.org full text search hits into spans of the transcript.
6
+ *
7
+ * The search service returns matched snippets with the matches wrapped in
8
+ * tags. This finds where each snippet sits in the full transcript, then works
9
+ * out the span of each match inside it, so the handler can rebuild the
10
+ * transcript with its results in the right places.
11
+ */
12
+ export declare class FullTextSearchBackend implements SearchBackendInterface {
13
+ private service;
14
+ /** The tag opening a match, e.g. `{{{` or `<em>` */
15
+ private startTag;
16
+ /** The tag closing a match, e.g. `}}}` or `</em>` */
17
+ private endTag;
18
+ constructor(service: FullTextSearchServiceInterface, startTag?: string, endTag?: string);
19
+ getSearchRanges(query: string): Promise<TextRange[]>;
20
+ /**
21
+ * The spans of each tagged match within the full transcript.
22
+ *
23
+ * With `highlight` of `bar {{{baz}}} snip` and a transcript of
24
+ * `beep boop foo bar baz snip`, the match sits at 18 to 21, so that is the
25
+ * span returned. Each match found shifts the ones after it back by the
26
+ * length of the tags already stepped over, since those tags are not in the
27
+ * transcript itself.
28
+ */
29
+ private rangesOfResultInTranscript;
30
+ /**
31
+ * Where a highlighted snippet begins in the full transcript.
32
+ *
33
+ * The tags are stripped first, since the transcript has none in it. Returns
34
+ * -1 when the snippet isn't found.
35
+ */
36
+ private startIndexOfHighlight;
37
+ }
38
+ //# sourceMappingURL=full-text-search-backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"full-text-search-backend.d.ts","sourceRoot":"","sources":["../../../../../../src/elements/ia-radio-player/search/backends/full-text-search-backend.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,KAAK,EAEV,8BAA8B,EAC/B,MAAM,6BAA6B,CAAC;AAOrC;;;;;;;GAOG;AACH,qBAAa,qBAAsB,YAAW,sBAAsB;IAClE,OAAO,CAAC,OAAO,CAAiC;IAEhD,oDAAoD;IACpD,OAAO,CAAC,QAAQ,CAAS;IAEzB,qDAAqD;IACrD,OAAO,CAAC,MAAM,CAAS;gBAGrB,OAAO,EAAE,8BAA8B,EACvC,QAAQ,SAAQ,EAChB,MAAM,SAAQ;IAOV,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAU1D;;;;;;;;OAQG;IACH,OAAO,CAAC,0BAA0B;IA8BlC;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;CAO9B"}
@@ -0,0 +1,64 @@
1
+ import { TextRange } from '../models.js';
2
+ /** Makes a string safe to drop into a regular expression as a literal. */
3
+ function escapeForRegExp(literal) {
4
+ return literal.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
5
+ }
6
+ /**
7
+ * Turns archive.org full text search hits into spans of the transcript.
8
+ *
9
+ * The search service returns matched snippets with the matches wrapped in
10
+ * tags. This finds where each snippet sits in the full transcript, then works
11
+ * out the span of each match inside it, so the handler can rebuild the
12
+ * transcript with its results in the right places.
13
+ */
14
+ export class FullTextSearchBackend {
15
+ constructor(service, startTag = '{{{', endTag = '}}}') {
16
+ this.service = service;
17
+ this.startTag = startTag;
18
+ this.endTag = endTag;
19
+ }
20
+ async getSearchRanges(query) {
21
+ const results = await this.service.searchRequested(query);
22
+ return results.value.docs.flatMap((doc) => doc.highlight.cc.flatMap((highlight) => this.rangesOfResultInTranscript(highlight, doc.text)));
23
+ }
24
+ /**
25
+ * The spans of each tagged match within the full transcript.
26
+ *
27
+ * With `highlight` of `bar {{{baz}}} snip` and a transcript of
28
+ * `beep boop foo bar baz snip`, the match sits at 18 to 21, so that is the
29
+ * span returned. Each match found shifts the ones after it back by the
30
+ * length of the tags already stepped over, since those tags are not in the
31
+ * transcript itself.
32
+ */
33
+ rangesOfResultInTranscript(highlight, transcript) {
34
+ const regex = new RegExp(`${escapeForRegExp(this.startTag)}(.*?)${escapeForRegExp(this.endTag)}`, 'gm');
35
+ const highlightStart = this.startIndexOfHighlight(highlight, transcript);
36
+ if (highlightStart === -1)
37
+ return [];
38
+ const totalTagLength = this.startTag.length + this.endTag.length;
39
+ const ranges = [];
40
+ let matchIndex = 0;
41
+ let match = regex.exec(highlight);
42
+ while (match !== null) {
43
+ const adjustedStart = match.index - matchIndex * totalTagLength;
44
+ const start = highlightStart + adjustedStart;
45
+ ranges.push(new TextRange(start, start + match[1].length));
46
+ matchIndex += 1;
47
+ match = regex.exec(highlight);
48
+ }
49
+ return ranges;
50
+ }
51
+ /**
52
+ * Where a highlighted snippet begins in the full transcript.
53
+ *
54
+ * The tags are stripped first, since the transcript has none in it. Returns
55
+ * -1 when the snippet isn't found.
56
+ */
57
+ startIndexOfHighlight(highlight, transcript) {
58
+ const untagged = highlight
59
+ .replaceAll(this.startTag, '')
60
+ .replaceAll(this.endTag, '');
61
+ return transcript.indexOf(untagged);
62
+ }
63
+ }
64
+ //# sourceMappingURL=full-text-search-backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"full-text-search-backend.js","sourceRoot":"","sources":["../../../../../../src/elements/ia-radio-player/search/backends/full-text-search-backend.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAOtC,0EAA0E;AAC1E,SAAS,eAAe,CAAC,OAAe;IACtC,OAAO,OAAO,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AACxD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,qBAAqB;IAShC,YACE,OAAuC,EACvC,QAAQ,GAAG,KAAK,EAChB,MAAM,GAAG,KAAK;QAEd,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,KAAa;QACjC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAE1D,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAA8B,EAAE,EAAE,CACnE,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE,CACrC,IAAI,CAAC,0BAA0B,CAAC,SAAS,EAAE,GAAG,CAAC,IAAI,CAAC,CACrD,CACF,CAAC;IACJ,CAAC;IAED;;;;;;;;OAQG;IACK,0BAA0B,CAChC,SAAiB,EACjB,UAAkB;QAElB,MAAM,KAAK,GAAG,IAAI,MAAM,CACtB,GAAG,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,EACvE,IAAI,CACL,CAAC;QAEF,MAAM,cAAc,GAAG,IAAI,CAAC,qBAAqB,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QACzE,IAAI,cAAc,KAAK,CAAC,CAAC;YAAE,OAAO,EAAE,CAAC;QAErC,MAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QACjE,MAAM,MAAM,GAAgB,EAAE,CAAC;QAE/B,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAClC,OAAO,KAAK,KAAK,IAAI,EAAE,CAAC;YACtB,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,GAAG,UAAU,GAAG,cAAc,CAAC;YAChE,MAAM,KAAK,GAAG,cAAc,GAAG,aAAa,CAAC;YAE7C,MAAM,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;YAE3D,UAAU,IAAI,CAAC,CAAC;YAChB,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAChC,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;;;;OAKG;IACK,qBAAqB,CAAC,SAAiB,EAAE,UAAkB;QACjE,MAAM,QAAQ,GAAG,SAAS;aACvB,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;aAC7B,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAE/B,OAAO,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACtC,CAAC;CACF","sourcesContent":["import { TextRange } from '../models';\nimport type { SearchBackendInterface } from './search-backend';\nimport type {\n FullTextSearchResponseDoc,\n FullTextSearchServiceInterface,\n} from './full-text-search-response';\n\n/** Makes a string safe to drop into a regular expression as a literal. */\nfunction escapeForRegExp(literal: string): string {\n return literal.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Turns archive.org full text search hits into spans of the transcript.\n *\n * The search service returns matched snippets with the matches wrapped in\n * tags. This finds where each snippet sits in the full transcript, then works\n * out the span of each match inside it, so the handler can rebuild the\n * transcript with its results in the right places.\n */\nexport class FullTextSearchBackend implements SearchBackendInterface {\n private service: FullTextSearchServiceInterface;\n\n /** The tag opening a match, e.g. `{{{` or `<em>` */\n private startTag: string;\n\n /** The tag closing a match, e.g. `}}}` or `</em>` */\n private endTag: string;\n\n constructor(\n service: FullTextSearchServiceInterface,\n startTag = '{{{',\n endTag = '}}}',\n ) {\n this.service = service;\n this.startTag = startTag;\n this.endTag = endTag;\n }\n\n async getSearchRanges(query: string): Promise<TextRange[]> {\n const results = await this.service.searchRequested(query);\n\n return results.value.docs.flatMap((doc: FullTextSearchResponseDoc) =>\n doc.highlight.cc.flatMap((highlight) =>\n this.rangesOfResultInTranscript(highlight, doc.text),\n ),\n );\n }\n\n /**\n * The spans of each tagged match within the full transcript.\n *\n * With `highlight` of `bar {{{baz}}} snip` and a transcript of\n * `beep boop foo bar baz snip`, the match sits at 18 to 21, so that is the\n * span returned. Each match found shifts the ones after it back by the\n * length of the tags already stepped over, since those tags are not in the\n * transcript itself.\n */\n private rangesOfResultInTranscript(\n highlight: string,\n transcript: string,\n ): TextRange[] {\n const regex = new RegExp(\n `${escapeForRegExp(this.startTag)}(.*?)${escapeForRegExp(this.endTag)}`,\n 'gm',\n );\n\n const highlightStart = this.startIndexOfHighlight(highlight, transcript);\n if (highlightStart === -1) return [];\n\n const totalTagLength = this.startTag.length + this.endTag.length;\n const ranges: TextRange[] = [];\n\n let matchIndex = 0;\n let match = regex.exec(highlight);\n while (match !== null) {\n const adjustedStart = match.index - matchIndex * totalTagLength;\n const start = highlightStart + adjustedStart;\n\n ranges.push(new TextRange(start, start + match[1].length));\n\n matchIndex += 1;\n match = regex.exec(highlight);\n }\n\n return ranges;\n }\n\n /**\n * Where a highlighted snippet begins in the full transcript.\n *\n * The tags are stripped first, since the transcript has none in it. Returns\n * -1 when the snippet isn't found.\n */\n private startIndexOfHighlight(highlight: string, transcript: string): number {\n const untagged = highlight\n .replaceAll(this.startTag, '')\n .replaceAll(this.endTag, '');\n\n return transcript.indexOf(untagged);\n }\n}\n"]}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * @file Response models for the archive.org full text search backend.
3
+ *
4
+ * The raw JSON is deserialized into these on arrival, so the rest of the
5
+ * search code works against named fields rather than untyped payloads.
6
+ */
7
+ /** The shape of the raw JSON, as far as these models read it. */
8
+ interface RawHighlighting {
9
+ text: string[];
10
+ }
11
+ interface RawFacetCounts {
12
+ facet_dates: object;
13
+ facet_fields: object;
14
+ }
15
+ interface RawDocHighlight {
16
+ cc: string[];
17
+ }
18
+ interface RawDoc {
19
+ identifier: string;
20
+ title: string;
21
+ text: string;
22
+ times: string;
23
+ downloads: number;
24
+ collection: string;
25
+ highlight: RawDocHighlight;
26
+ description: string;
27
+ mediatype: string;
28
+ __href__: string;
29
+ 'SE-BYPASS': number;
30
+ }
31
+ interface RawValue {
32
+ numFound: number;
33
+ start: number;
34
+ docs: RawDoc[];
35
+ highlighting: Record<string, RawHighlighting>;
36
+ facet_counts: RawFacetCounts;
37
+ }
38
+ interface RawResponse {
39
+ success: boolean;
40
+ value: RawValue;
41
+ }
42
+ export declare class FullTextSearchResponseValueHighlighting {
43
+ text: string[];
44
+ constructor(payload: RawHighlighting);
45
+ }
46
+ export declare class FullTextSearchResponseValueFacetCounts {
47
+ facetFields: object;
48
+ facetDates: object;
49
+ constructor(payload: RawFacetCounts);
50
+ }
51
+ export declare class FullTextSearchResponseDocHighlight {
52
+ /** The matched closed-caption snippets, with the match tags still in them. */
53
+ cc: string[];
54
+ constructor(payload: RawDocHighlight);
55
+ }
56
+ export declare class FullTextSearchResponseDoc {
57
+ identifier: string;
58
+ title: string;
59
+ /** The full transcript the highlights are positions within. */
60
+ text: string;
61
+ times: string;
62
+ downloads: number;
63
+ collection: string;
64
+ highlight: FullTextSearchResponseDocHighlight;
65
+ description: string;
66
+ mediatype: string;
67
+ __href__: string;
68
+ 'SE-BYPASS': number;
69
+ constructor(payload: RawDoc);
70
+ }
71
+ export declare class FullTextSearchResponseValue {
72
+ numFound: number;
73
+ start: number;
74
+ docs: FullTextSearchResponseDoc[];
75
+ highlighting: Record<string, FullTextSearchResponseValueHighlighting>;
76
+ facetCounts: FullTextSearchResponseValueFacetCounts;
77
+ constructor(payload: RawValue);
78
+ }
79
+ export declare class FullTextSearchResponse {
80
+ success: boolean;
81
+ value: FullTextSearchResponseValue;
82
+ constructor(payload: RawResponse);
83
+ }
84
+ /**
85
+ * Where the full text search request actually goes.
86
+ *
87
+ * The backend hands the request off through this, so a consumer can fetch
88
+ * however it needs to rather than being tied to one HTTP client.
89
+ */
90
+ export interface FullTextSearchServiceInterface {
91
+ searchRequested(query: string): Promise<FullTextSearchResponse>;
92
+ }
93
+ export {};
94
+ //# sourceMappingURL=full-text-search-response.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"full-text-search-response.d.ts","sourceRoot":"","sources":["../../../../../../src/elements/ia-radio-player/search/backends/full-text-search-response.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,iEAAiE;AACjE,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,UAAU,cAAc;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,UAAU,eAAe;IACvB,EAAE,EAAE,MAAM,EAAE,CAAC;CACd;AAED,UAAU,MAAM;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,eAAe,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,QAAQ;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC9C,YAAY,EAAE,cAAc,CAAC;CAC9B;AAED,UAAU,WAAW;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,QAAQ,CAAC;CACjB;AAED,qBAAa,uCAAuC;IAClD,IAAI,EAAE,MAAM,EAAE,CAAC;gBAEH,OAAO,EAAE,eAAe;CAGrC;AAED,qBAAa,sCAAsC;IACjD,WAAW,EAAE,MAAM,CAAC;IAEpB,UAAU,EAAE,MAAM,CAAC;gBAEP,OAAO,EAAE,cAAc;CAIpC;AAED,qBAAa,kCAAkC;IAC7C,8EAA8E;IAC9E,EAAE,EAAE,MAAM,EAAE,CAAC;gBAED,OAAO,EAAE,eAAe;CAGrC;AAED,qBAAa,yBAAyB;IACpC,UAAU,EAAE,MAAM,CAAC;IAEnB,KAAK,EAAE,MAAM,CAAC;IAEd,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IAEb,KAAK,EAAE,MAAM,CAAC;IAEd,SAAS,EAAE,MAAM,CAAC;IAElB,UAAU,EAAE,MAAM,CAAC;IAEnB,SAAS,EAAE,kCAAkC,CAAC;IAE9C,WAAW,EAAE,MAAM,CAAC;IAEpB,SAAS,EAAE,MAAM,CAAC;IAElB,QAAQ,EAAE,MAAM,CAAC;IAEjB,WAAW,EAAE,MAAM,CAAC;gBAER,OAAO,EAAE,MAAM;CAa5B;AAED,qBAAa,2BAA2B;IACtC,QAAQ,EAAE,MAAM,CAAC;IAEjB,KAAK,EAAE,MAAM,CAAC;IAEd,IAAI,EAAE,yBAAyB,EAAE,CAAC;IAElC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,uCAAuC,CAAC,CAAM;IAE3E,WAAW,EAAE,sCAAsC,CAAC;gBAExC,OAAO,EAAE,QAAQ;CAe9B;AAED,qBAAa,sBAAsB;IACjC,OAAO,EAAE,OAAO,CAAC;IAEjB,KAAK,EAAE,2BAA2B,CAAC;gBAEvB,OAAO,EAAE,WAAW;CAIjC;AAED;;;;;GAKG;AACH,MAAM,WAAW,8BAA8B;IAC7C,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;CACjE"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @file Response models for the archive.org full text search backend.
3
+ *
4
+ * The raw JSON is deserialized into these on arrival, so the rest of the
5
+ * search code works against named fields rather than untyped payloads.
6
+ */
7
+ export class FullTextSearchResponseValueHighlighting {
8
+ constructor(payload) {
9
+ this.text = payload.text;
10
+ }
11
+ }
12
+ export class FullTextSearchResponseValueFacetCounts {
13
+ constructor(payload) {
14
+ this.facetDates = payload.facet_dates;
15
+ this.facetFields = payload.facet_fields;
16
+ }
17
+ }
18
+ export class FullTextSearchResponseDocHighlight {
19
+ constructor(payload) {
20
+ this.cc = payload.cc;
21
+ }
22
+ }
23
+ export class FullTextSearchResponseDoc {
24
+ constructor(payload) {
25
+ this.identifier = payload.identifier;
26
+ this.title = payload.title;
27
+ this.text = payload.text;
28
+ this.times = payload.times;
29
+ this.downloads = payload.downloads;
30
+ this.collection = payload.collection;
31
+ this.highlight = new FullTextSearchResponseDocHighlight(payload.highlight);
32
+ this.description = payload.description;
33
+ this.mediatype = payload.mediatype;
34
+ this.__href__ = payload.__href__;
35
+ this['SE-BYPASS'] = payload['SE-BYPASS'];
36
+ }
37
+ }
38
+ export class FullTextSearchResponseValue {
39
+ constructor(payload) {
40
+ this.highlighting = {};
41
+ this.numFound = payload.numFound;
42
+ this.start = payload.start;
43
+ this.docs = payload.docs.map((doc) => new FullTextSearchResponseDoc(doc));
44
+ Object.entries(payload.highlighting ?? {}).forEach(([key, value]) => {
45
+ this.highlighting[key] = new FullTextSearchResponseValueHighlighting(value);
46
+ });
47
+ this.facetCounts = new FullTextSearchResponseValueFacetCounts(payload.facet_counts);
48
+ }
49
+ }
50
+ export class FullTextSearchResponse {
51
+ constructor(payload) {
52
+ this.success = payload.success;
53
+ this.value = new FullTextSearchResponseValue(payload.value);
54
+ }
55
+ }
56
+ //# sourceMappingURL=full-text-search-response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"full-text-search-response.js","sourceRoot":"","sources":["../../../../../../src/elements/ia-radio-player/search/backends/full-text-search-response.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2CH,MAAM,OAAO,uCAAuC;IAGlD,YAAY,OAAwB;QAClC,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;CACF;AAED,MAAM,OAAO,sCAAsC;IAKjD,YAAY,OAAuB;QACjC,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC;QACtC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAC1C,CAAC;CACF;AAED,MAAM,OAAO,kCAAkC;IAI7C,YAAY,OAAwB;QAClC,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC;IACvB,CAAC;CACF;AAED,MAAM,OAAO,yBAAyB;IAwBpC,YAAY,OAAe;QACzB,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QACrC,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QACrC,IAAI,CAAC,SAAS,GAAG,IAAI,kCAAkC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC3E,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;QACvC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC3C,CAAC;CACF;AAED,MAAM,OAAO,2BAA2B;IAWtC,YAAY,OAAiB;QAJ7B,iBAAY,GAA4D,EAAE,CAAC;QAKzE,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,yBAAyB,CAAC,GAAG,CAAC,CAAC,CAAC;QAE1E,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;YAClE,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,IAAI,uCAAuC,CAClE,KAAK,CACN,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,WAAW,GAAG,IAAI,sCAAsC,CAC3D,OAAO,CAAC,YAAY,CACrB,CAAC;IACJ,CAAC;CACF;AAED,MAAM,OAAO,sBAAsB;IAKjC,YAAY,OAAoB;QAC9B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,KAAK,GAAG,IAAI,2BAA2B,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC9D,CAAC;CACF","sourcesContent":["/**\n * @file Response models for the archive.org full text search backend.\n *\n * The raw JSON is deserialized into these on arrival, so the rest of the\n * search code works against named fields rather than untyped payloads.\n */\n\n/** The shape of the raw JSON, as far as these models read it. */\ninterface RawHighlighting {\n text: string[];\n}\n\ninterface RawFacetCounts {\n facet_dates: object;\n facet_fields: object;\n}\n\ninterface RawDocHighlight {\n cc: string[];\n}\n\ninterface RawDoc {\n identifier: string;\n title: string;\n text: string;\n times: string;\n downloads: number;\n collection: string;\n highlight: RawDocHighlight;\n description: string;\n mediatype: string;\n __href__: string;\n 'SE-BYPASS': number;\n}\n\ninterface RawValue {\n numFound: number;\n start: number;\n docs: RawDoc[];\n highlighting: Record<string, RawHighlighting>;\n facet_counts: RawFacetCounts;\n}\n\ninterface RawResponse {\n success: boolean;\n value: RawValue;\n}\n\nexport class FullTextSearchResponseValueHighlighting {\n text: string[];\n\n constructor(payload: RawHighlighting) {\n this.text = payload.text;\n }\n}\n\nexport class FullTextSearchResponseValueFacetCounts {\n facetFields: object;\n\n facetDates: object;\n\n constructor(payload: RawFacetCounts) {\n this.facetDates = payload.facet_dates;\n this.facetFields = payload.facet_fields;\n }\n}\n\nexport class FullTextSearchResponseDocHighlight {\n /** The matched closed-caption snippets, with the match tags still in them. */\n cc: string[];\n\n constructor(payload: RawDocHighlight) {\n this.cc = payload.cc;\n }\n}\n\nexport class FullTextSearchResponseDoc {\n identifier: string;\n\n title: string;\n\n /** The full transcript the highlights are positions within. */\n text: string;\n\n times: string;\n\n downloads: number;\n\n collection: string;\n\n highlight: FullTextSearchResponseDocHighlight;\n\n description: string;\n\n mediatype: string;\n\n __href__: string;\n\n 'SE-BYPASS': number;\n\n constructor(payload: RawDoc) {\n this.identifier = payload.identifier;\n this.title = payload.title;\n this.text = payload.text;\n this.times = payload.times;\n this.downloads = payload.downloads;\n this.collection = payload.collection;\n this.highlight = new FullTextSearchResponseDocHighlight(payload.highlight);\n this.description = payload.description;\n this.mediatype = payload.mediatype;\n this.__href__ = payload.__href__;\n this['SE-BYPASS'] = payload['SE-BYPASS'];\n }\n}\n\nexport class FullTextSearchResponseValue {\n numFound: number;\n\n start: number;\n\n docs: FullTextSearchResponseDoc[];\n\n highlighting: Record<string, FullTextSearchResponseValueHighlighting> = {};\n\n facetCounts: FullTextSearchResponseValueFacetCounts;\n\n constructor(payload: RawValue) {\n this.numFound = payload.numFound;\n this.start = payload.start;\n this.docs = payload.docs.map((doc) => new FullTextSearchResponseDoc(doc));\n\n Object.entries(payload.highlighting ?? {}).forEach(([key, value]) => {\n this.highlighting[key] = new FullTextSearchResponseValueHighlighting(\n value,\n );\n });\n\n this.facetCounts = new FullTextSearchResponseValueFacetCounts(\n payload.facet_counts,\n );\n }\n}\n\nexport class FullTextSearchResponse {\n success: boolean;\n\n value: FullTextSearchResponseValue;\n\n constructor(payload: RawResponse) {\n this.success = payload.success;\n this.value = new FullTextSearchResponseValue(payload.value);\n }\n}\n\n/**\n * Where the full text search request actually goes.\n *\n * The backend hands the request off through this, so a consumer can fetch\n * however it needs to rather than being tied to one HTTP client.\n */\nexport interface FullTextSearchServiceInterface {\n searchRequested(query: string): Promise<FullTextSearchResponse>;\n}\n"]}
@@ -0,0 +1,15 @@
1
+ import { TextRange } from '../models.js';
2
+ import type { TranscriptIndexInterface } from '../transcript-index.js';
3
+ import type { SearchBackendInterface } from './search-backend.js';
4
+ /**
5
+ * Searches the transcript in the browser, with no network involved.
6
+ *
7
+ * A plain case-insensitive substring scan, which is enough for a transcript
8
+ * already loaded on the page.
9
+ */
10
+ export declare class LocalSearchBackend implements SearchBackendInterface {
11
+ private transcriptIndex;
12
+ constructor(transcriptIndex: TranscriptIndexInterface);
13
+ getSearchRanges(query: string): Promise<TextRange[]>;
14
+ }
15
+ //# sourceMappingURL=local-search-backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-search-backend.d.ts","sourceRoot":"","sources":["../../../../../../src/elements/ia-radio-player/search/backends/local-search-backend.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE/D;;;;;GAKG;AACH,qBAAa,kBAAmB,YAAW,sBAAsB;IAC/D,OAAO,CAAC,eAAe,CAA2B;gBAEtC,eAAe,EAAE,wBAAwB;IAI/C,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;CAe3D"}