@internetarchive/elements 1.1.3-webdev-8840.0 → 1.1.3-webdev-9107.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.
- package/README.md +1 -1
- package/dist/src/elements/ia-radio-player/ia-radio-player.d.ts +2 -0
- package/dist/src/elements/ia-radio-player/ia-radio-player.d.ts.map +1 -1
- package/dist/src/elements/ia-radio-player/ia-radio-player.js +6 -1
- package/dist/src/elements/ia-radio-player/ia-radio-player.js.map +1 -1
- package/dist/src/elements/ia-reviews/ia-review-form.d.ts +7 -2
- package/dist/src/elements/ia-reviews/ia-review-form.d.ts.map +1 -1
- package/dist/src/elements/ia-reviews/ia-review-form.js +43 -11
- package/dist/src/elements/ia-reviews/ia-review-form.js.map +1 -1
- package/dist/src/elements/ia-reviews/ia-review.d.ts +1 -2
- package/dist/src/elements/ia-reviews/ia-review.d.ts.map +1 -1
- package/dist/src/elements/ia-reviews/ia-review.js +25 -13
- package/dist/src/elements/ia-reviews/ia-review.js.map +1 -1
- package/dist/src/elements/ia-reviews/ia-reviews.d.ts +4 -9
- package/dist/src/elements/ia-reviews/ia-reviews.d.ts.map +1 -1
- package/dist/src/elements/ia-reviews/ia-reviews.js +20 -16
- package/dist/src/elements/ia-reviews/ia-reviews.js.map +1 -1
- package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.d.ts +2 -17
- package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.d.ts.map +1 -1
- package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.js +2 -24
- package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.js.map +1 -1
- package/dist/src/elements/index.d.ts +0 -2
- package/dist/src/elements/index.d.ts.map +1 -1
- package/dist/src/elements/index.js +0 -2
- package/dist/src/elements/index.js.map +1 -1
- package/package.json +3 -3
- package/dist/src/elements/ia-reviews/mocks/mock-review-service.d.ts +0 -12
- package/dist/src/elements/ia-reviews/mocks/mock-review-service.d.ts.map +0 -1
- package/dist/src/elements/ia-reviews/mocks/mock-review-service.js +0 -19
- package/dist/src/elements/ia-reviews/mocks/mock-review-service.js.map +0 -1
- package/dist/src/elements/ia-reviews/models.d.ts +0 -38
- package/dist/src/elements/ia-reviews/models.d.ts.map +0 -1
- package/dist/src/elements/ia-reviews/models.js +0 -2
- package/dist/src/elements/ia-reviews/models.js.map +0 -1
- package/dist/src/elements/ia-reviews/review-service.d.ts +0 -53
- package/dist/src/elements/ia-reviews/review-service.d.ts.map +0 -1
- package/dist/src/elements/ia-reviews/review-service.js +0 -97
- package/dist/src/elements/ia-reviews/review-service.js.map +0 -1
package/README.md
CHANGED
|
@@ -87,7 +87,7 @@ Add to Jest config:
|
|
|
87
87
|
|
|
88
88
|
## Development
|
|
89
89
|
|
|
90
|
-
Requires Node 24+ and pnpm
|
|
90
|
+
Requires Node 24+ and pnpm 12+. `engine-strict=true` in `.npmrc` makes an older
|
|
91
91
|
Node fail the install instead of warning, but nothing hard-blocks `npm install`:
|
|
92
92
|
npm ignores `engines.pnpm`, and there's deliberately no preinstall guard since it
|
|
93
93
|
would run for consumers too. Use pnpm. `packageManager` and the committed
|
|
@@ -32,6 +32,8 @@ export declare class IARadioPlayer extends LitElement {
|
|
|
32
32
|
searchTerm: string;
|
|
33
33
|
/** Whether to skip past the music sections rather than play them */
|
|
34
34
|
skipMusicSections: boolean;
|
|
35
|
+
/** Whether to shade the music sections on the waveform */
|
|
36
|
+
showMusicZones: boolean;
|
|
35
37
|
private percentComplete;
|
|
36
38
|
private isPlaying;
|
|
37
39
|
private duration;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ia-radio-player.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-radio-player/ia-radio-player.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EAEV,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,KAAK,CAAC;AAQb,OAAO,KAAK,EACV,gBAAgB,EAEjB,MAAM,yCAAyC,CAAC;AAKjD,OAAO,KAAK,EAAa,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAGtE,OAAO,iDAAiD,CAAC;AACzD,OAAO,iEAAiE,CAAC;AACzE,OAAO,yDAAyD,CAAC;AACjE,OAAO,+CAA+C,CAAC;AACvD,OAAO,uDAAuD,CAAC;AAC/D,OAAO,qDAAqD,CAAC;AAC7D,OAAO,yDAAyD,CAAC;AACjE,OAAO,8BAA8B,CAAC;AAqCtC;;;;;;GAMG;AACH,qBACa,aAAc,SAAQ,UAAU;IAC3C,sDAAsD;IAC1B,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAEvD,mEAAmE;IACvC,aAAa,CAAC,EAAE,sBAAsB,CAAC;IAEnE,uDAAuD;IAC3B,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAEhE,0EAA0E;IAC9C,uBAAuB,CAAC,EAAE,gBAAgB,CAAC;IAEvE,oCAAoC;IACR,WAAW,SAAK;IAE5C,0CAA0C;IACd,UAAU,SAAM;IAE5C,oEAAoE;IACvC,iBAAiB,UAAS;
|
|
1
|
+
{"version":3,"file":"ia-radio-player.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-radio-player/ia-radio-player.ts"],"names":[],"mappings":"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"}
|
|
@@ -59,6 +59,8 @@ let IARadioPlayer = class IARadioPlayer extends LitElement {
|
|
|
59
59
|
this.searchTerm = '';
|
|
60
60
|
/** Whether to skip past the music sections rather than play them */
|
|
61
61
|
this.skipMusicSections = false;
|
|
62
|
+
/** Whether to shade the music sections on the waveform */
|
|
63
|
+
this.showMusicZones = false;
|
|
62
64
|
this.percentComplete = 0;
|
|
63
65
|
this.isPlaying = false;
|
|
64
66
|
this.duration = 0;
|
|
@@ -154,7 +156,7 @@ let IARadioPlayer = class IARadioPlayer extends LitElement {
|
|
|
154
156
|
interactive
|
|
155
157
|
.waveformUrl=${waveformUrl}
|
|
156
158
|
.percentComplete=${this.percentComplete}
|
|
157
|
-
.zonesOfSilence=${this.zonesOfSilence}
|
|
159
|
+
.zonesOfSilence=${this.showMusicZones ? this.zonesOfSilence : []}
|
|
158
160
|
@valuechange=${this.handleScrub}
|
|
159
161
|
></ia-waveform-progress>
|
|
160
162
|
`;
|
|
@@ -715,6 +717,9 @@ __decorate([
|
|
|
715
717
|
__decorate([
|
|
716
718
|
property({ type: Boolean })
|
|
717
719
|
], IARadioPlayer.prototype, "skipMusicSections", void 0);
|
|
720
|
+
__decorate([
|
|
721
|
+
property({ type: Boolean })
|
|
722
|
+
], IARadioPlayer.prototype, "showMusicZones", void 0);
|
|
718
723
|
__decorate([
|
|
719
724
|
state()
|
|
720
725
|
], IARadioPlayer.prototype, "percentComplete", void 0);
|
|
@@ -1 +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 { property, query, state } from 'lit/decorators.js';\nimport { customElement } from '@src/util/custom-element';\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"]}
|
|
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 { property, query, state } from 'lit/decorators.js';\nimport { customElement } from '@src/util/custom-element';\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 /** Whether to shade the music sections on the waveform */\n @property({ type: Boolean }) showMusicZones = 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.showMusicZones ? 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"]}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { LitElement, PropertyValues, CSSResultGroup } from 'lit';
|
|
2
2
|
import type { RecaptchaManagerInterface } from '@internetarchive/recaptcha-manager';
|
|
3
3
|
import '../../elements/ia-button/ia-button.js';
|
|
4
|
+
import type { FetchHandlerInterface } from '@internetarchive/fetch-handler';
|
|
4
5
|
import { Review } from '@internetarchive/metadata-service';
|
|
5
|
-
import type { ReviewServiceInterface } from './models.js';
|
|
6
6
|
import './ia-review.js';
|
|
7
7
|
/**
|
|
8
8
|
* Renders a form to edit a given IA review.
|
|
9
9
|
*/
|
|
10
10
|
export declare class IAReviewForm extends LitElement {
|
|
11
11
|
identifier?: string;
|
|
12
|
+
token: string;
|
|
13
|
+
baseHost: string;
|
|
14
|
+
endpointPath: string;
|
|
12
15
|
/** Form submitter's screenname, if applicable */
|
|
13
16
|
submitterScreenname: string;
|
|
14
17
|
/** Form submitter's itemname, if applicable */
|
|
@@ -17,7 +20,7 @@ export declare class IAReviewForm extends LitElement {
|
|
|
17
20
|
unrecoverableError?: string;
|
|
18
21
|
maxSubjectLength?: number;
|
|
19
22
|
maxBodyLength?: number;
|
|
20
|
-
|
|
23
|
+
fetchHandler?: FetchHandlerInterface;
|
|
21
24
|
recaptchaManager?: RecaptchaManagerInterface;
|
|
22
25
|
bypassRecaptcha: boolean;
|
|
23
26
|
private recaptchaWidget?;
|
|
@@ -43,6 +46,8 @@ export declare class IAReviewForm extends LitElement {
|
|
|
43
46
|
private get subjectInputTemplate();
|
|
44
47
|
/** Body input and character counter */
|
|
45
48
|
private get bodyInputTemplate();
|
|
49
|
+
/** Hidden inputs we use to store other information for form submission */
|
|
50
|
+
private get hiddenInputsTemplate();
|
|
46
51
|
/** Buttons to render at bottom of form */
|
|
47
52
|
private get actionButtonsTemplate();
|
|
48
53
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ia-review-form.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-reviews/ia-review-form.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EAGV,cAAc,EACd,cAAc,EACf,MAAM,KAAK,CAAC;AAQb,OAAO,KAAK,EACV,yBAAyB,EAE1B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,mCAAmC,CAAC;AAC3C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"ia-review-form.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-reviews/ia-review-form.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EAGV,cAAc,EACd,cAAc,EACf,MAAM,KAAK,CAAC;AAQb,OAAO,KAAK,EACV,yBAAyB,EAE1B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AAK3D,OAAO,aAAa,CAAC;AAErB;;GAEG;AACH,qBACa,YAAa,SAAQ,UAAU;IAEd,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB,KAAK,EAAE,MAAM,CAAM;IAGnB,QAAQ,EAAE,MAAM,CAAyB;IAGzC,YAAY,EAAE,MAAM,CAAuB;IAEvE,iDAAiD;IACrB,mBAAmB,EAAE,MAAM,CAAe;IAEtE,+CAA+C;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAG3B,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAG5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAG1B,aAAa,CAAC,EAAE,MAAM,CAAC;IAGvB,YAAY,CAAC,EAAE,qBAAqB,CAAC;IAGrC,gBAAgB,CAAC,EAAE,yBAAyB,CAAC;IAG5C,eAAe,EAAE,OAAO,CAAS;IAG9D,OAAO,CAAC,eAAe,CAAC,CAA2B;IAInD,OAAO,CAAC,YAAY,CAAa;IAIjC,OAAO,CAAC,oBAAoB,CAAa;IAIzC,OAAO,CAAC,iBAAiB,CAAa;IAItC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAI1B,OAAO,CAAC,aAAa,CAAkB;IAIvC,oBAAoB,EAAE,OAAO,CAAS;IAItC,OAAO,CAAC,UAAU,CAAmB;IAGrC,OAAO,CAAC,uBAAuB,CACwB;IAEvD,OAAO,CAAC,qBAAqB,CAC2C;IAExE,MAAM;IAeN,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAiCnD,6CAA6C;IAC7C,OAAO,KAAK,0BAA0B,GAUrC;IAED,4CAA4C;IAC5C,OAAO,KAAK,wBAAwB,GAQnC;IAED,OAAO,KAAK,wBAAwB,GAwBnC;IAED,+BAA+B;IAC/B,OAAO,KAAK,kBAAkB,GAuB7B;IAED,0CAA0C;IAC1C,OAAO,KAAK,oBAAoB,GAqC/B;IAED,uCAAuC;IACvC,OAAO,KAAK,iBAAiB,GAkC5B;IAED,0EAA0E;IAC1E,OAAO,KAAK,oBAAoB,GAW/B;IAED,0CAA0C;IAC1C,OAAO,KAAK,qBAAqB,GAoBhC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,UAAU;IA2BlB;;;;OAIG;YACW,cAAc;IAQ5B;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IAIxB,oEAAoE;YACtD,YAAY;IAmE1B;;;;;OAKG;IACH,OAAO,CAAC,uBAAuB;IAiB/B;;;OAGG;IACH,OAAO,CAAC,YAAY;IAKpB;;;SAGK;YACS,iBAAiB;IAgB/B,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,sBAAsB;IA2B9B,MAAM,KAAK,MAAM,IAAI,cAAc,CAgJlC;CACF"}
|
|
@@ -16,6 +16,12 @@ import './ia-review.js';
|
|
|
16
16
|
let IAReviewForm = class IAReviewForm extends LitElement {
|
|
17
17
|
constructor() {
|
|
18
18
|
super(...arguments);
|
|
19
|
+
/* The token for the review edit */
|
|
20
|
+
this.token = '';
|
|
21
|
+
/* The host for archive endpoints and data */
|
|
22
|
+
this.baseHost = 'https://archive.org';
|
|
23
|
+
/* The path for the endpoint we're submitting to */
|
|
24
|
+
this.endpointPath = '/write-review.php';
|
|
19
25
|
/** Form submitter's screenname, if applicable */
|
|
20
26
|
this.submitterScreenname = 'Anonymous';
|
|
21
27
|
/* Optionally avoid using recaptcha for the form */
|
|
@@ -41,7 +47,7 @@ let IAReviewForm = class IAReviewForm extends LitElement {
|
|
|
41
47
|
: html `
|
|
42
48
|
<span class="inputs">
|
|
43
49
|
${this.starsInputTemplate} ${this.subjectInputTemplate}
|
|
44
|
-
${this.bodyInputTemplate}
|
|
50
|
+
${this.bodyInputTemplate} ${this.hiddenInputsTemplate}
|
|
45
51
|
</span>
|
|
46
52
|
`}
|
|
47
53
|
${this.recaptchaMessageTemplate} ${this.recoverableErrorTemplate}
|
|
@@ -208,6 +214,19 @@ let IAReviewForm = class IAReviewForm extends LitElement {
|
|
|
208
214
|
</span>
|
|
209
215
|
`;
|
|
210
216
|
}
|
|
217
|
+
/** Hidden inputs we use to store other information for form submission */
|
|
218
|
+
get hiddenInputsTemplate() {
|
|
219
|
+
return html `
|
|
220
|
+
<input type="hidden" name="field_reviewtoken" .value=${this.token} />
|
|
221
|
+
${this.identifier
|
|
222
|
+
? html `<input
|
|
223
|
+
type="hidden"
|
|
224
|
+
name="identifier"
|
|
225
|
+
.value=${this.identifier}
|
|
226
|
+
/>`
|
|
227
|
+
: nothing}
|
|
228
|
+
`;
|
|
229
|
+
}
|
|
211
230
|
/** Buttons to render at bottom of form */
|
|
212
231
|
get actionButtonsTemplate() {
|
|
213
232
|
return html `<div class="action-btns">
|
|
@@ -297,23 +316,27 @@ let IAReviewForm = class IAReviewForm extends LitElement {
|
|
|
297
316
|
if (!this.reviewForm.reportValidity()) {
|
|
298
317
|
return this.stopSubmission();
|
|
299
318
|
}
|
|
300
|
-
if (!this.
|
|
319
|
+
if (!this.fetchHandler) {
|
|
301
320
|
this.recoverableError = this.GENERIC_ERROR_MESSAGE;
|
|
302
321
|
return this.stopSubmission();
|
|
303
322
|
}
|
|
304
323
|
try {
|
|
305
|
-
|
|
324
|
+
const formData = new URLSearchParams();
|
|
306
325
|
if (!this.bypassRecaptcha) {
|
|
307
|
-
recaptchaToken = await this.getRecaptchaToken();
|
|
326
|
+
const recaptchaToken = await this.getRecaptchaToken();
|
|
308
327
|
if (!recaptchaToken)
|
|
309
328
|
return this.handleRecaptchaError();
|
|
329
|
+
formData.append('g-recaptcha-response', recaptchaToken ?? '');
|
|
330
|
+
}
|
|
331
|
+
for (const entry of new FormData(this.reviewForm)) {
|
|
332
|
+
formData.append(entry[0], entry[1]);
|
|
310
333
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
334
|
+
// Indicates to the backend that submission is intended
|
|
335
|
+
formData.append('submitter', 'review-form');
|
|
336
|
+
const result = await this.fetchHandler.fetchApiResponse(`${this.baseHost}${this.endpointPath}`, {
|
|
337
|
+
method: 'POST',
|
|
338
|
+
includeCredentials: true,
|
|
339
|
+
body: formData,
|
|
317
340
|
});
|
|
318
341
|
if (result?.success === true) {
|
|
319
342
|
this.submissionInProgress = false;
|
|
@@ -591,6 +614,15 @@ let IAReviewForm = class IAReviewForm extends LitElement {
|
|
|
591
614
|
__decorate([
|
|
592
615
|
property({ type: String })
|
|
593
616
|
], IAReviewForm.prototype, "identifier", void 0);
|
|
617
|
+
__decorate([
|
|
618
|
+
property({ type: String })
|
|
619
|
+
], IAReviewForm.prototype, "token", void 0);
|
|
620
|
+
__decorate([
|
|
621
|
+
property({ type: String })
|
|
622
|
+
], IAReviewForm.prototype, "baseHost", void 0);
|
|
623
|
+
__decorate([
|
|
624
|
+
property({ type: String })
|
|
625
|
+
], IAReviewForm.prototype, "endpointPath", void 0);
|
|
594
626
|
__decorate([
|
|
595
627
|
property({ type: String })
|
|
596
628
|
], IAReviewForm.prototype, "submitterScreenname", void 0);
|
|
@@ -611,7 +643,7 @@ __decorate([
|
|
|
611
643
|
], IAReviewForm.prototype, "maxBodyLength", void 0);
|
|
612
644
|
__decorate([
|
|
613
645
|
property({ type: Object })
|
|
614
|
-
], IAReviewForm.prototype, "
|
|
646
|
+
], IAReviewForm.prototype, "fetchHandler", void 0);
|
|
615
647
|
__decorate([
|
|
616
648
|
property({ type: Object })
|
|
617
649
|
], IAReviewForm.prototype, "recaptchaManager", void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ia-review-form.js","sourceRoot":"","sources":["../../../../src/elements/ia-reviews/ia-review-form.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n html,\n css,\n LitElement,\n nothing,\n HTMLTemplateResult,\n PropertyValues,\n CSSResultGroup,\n} from 'lit';\nimport { property, state, query } from 'lit/decorators.js';\nimport { customElement } from '@src/util/custom-element';\nimport { msg } from '@lit/localize';\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js';\n\nimport DOMPurify from 'dompurify';\n\nimport type {\n RecaptchaManagerInterface,\n RecaptchaWidgetInterface,\n} from '@internetarchive/recaptcha-manager';\nimport '@src/elements/ia-button/ia-button';\nimport { Review } from '@internetarchive/metadata-service';\n\nimport starSelected from './assets/star-selected.svg';\nimport starUnselected from './assets/star-unselected.svg';\n\nimport type { ReviewServiceInterface } from './models';\nimport './ia-review';\n\n/**\n * Renders a form to edit a given IA review.\n */\n@customElement('ia-review-form')\nexport class IAReviewForm extends LitElement {\n /* The IA item being reviewed */\n @property({ type: String }) identifier?: string;\n\n /** Form submitter's screenname, if applicable */\n @property({ type: String }) submitterScreenname: string = 'Anonymous';\n\n /** Form submitter's itemname, if applicable */\n @property({ type: String }) submitterItemname?: string;\n\n /* The previous review to pre-fill, if any */\n @property({ type: Object }) oldReview?: Review;\n\n /* An optional unrecoverable error to pass in instead of rendering the form inputs */\n @property({ type: String }) unrecoverableError?: string;\n\n /* Optional max length for review subject */\n @property({ type: Number }) maxSubjectLength?: number;\n\n /* Optional max length for review body */\n @property({ type: Number }) maxBodyLength?: number;\n\n /* Handles the review submission request */\n @property({ type: Object }) reviewService?: ReviewServiceInterface;\n\n /* Service for activating the recaptcha challenge */\n @property({ type: Object }) recaptchaManager?: RecaptchaManagerInterface;\n\n /* Optionally avoid using recaptcha for the form */\n @property({ type: Boolean }) bypassRecaptcha: boolean = false;\n\n /* Recaptcha widget for the form */\n private recaptchaWidget?: RecaptchaWidgetInterface;\n\n /* Number of stars currently selected */\n @state()\n private currentStars: number = 0;\n\n /* Length of review subject currently filled in */\n @state()\n private currentSubjectLength: number = 0;\n\n /* Length of review body currently filled in */\n @state()\n private currentBodyLength: number = 0;\n\n /* Any recoverable error to display for the form. Will still allow submission. */\n @state()\n recoverableError?: string;\n\n /* Whether to enable the submit button */\n @state()\n private formCanSubmit: boolean = false;\n\n /* Whether to show a loading indicator for the form */\n @state()\n submissionInProgress: boolean = false;\n\n /* The form to be submitted */\n @query('#review-form')\n private reviewForm!: HTMLFormElement;\n\n /* Error to show if recaptcha cannot be loaded */\n private RECAPTCHA_ERROR_MESSAGE =\n 'Could not validate review. Please try again later.';\n\n private GENERIC_ERROR_MESSAGE =\n \"There's been a temporary error. Please wait a moment and try again.\";\n\n render() {\n return html`<form id=\"review-form\" @submit=${this.handleSubmit}>\n ${this.unrecoverableError\n ? this.unrecoverableErrorTemplate\n : html`\n <span class=\"inputs\">\n ${this.starsInputTemplate} ${this.subjectInputTemplate}\n ${this.bodyInputTemplate}\n </span>\n `}\n ${this.recaptchaMessageTemplate} ${this.recoverableErrorTemplate}\n ${this.actionButtonsTemplate}\n </form>`;\n }\n\n protected willUpdate(changed: PropertyValues): void {\n // Fill in previous review, if provided\n if (changed.has('oldReview')) {\n this.currentStars = this.oldReview?.stars ?? 0;\n this.currentSubjectLength = this.oldReview?.reviewtitle?.length ?? 0;\n this.currentBodyLength = this.oldReview?.reviewbody?.length ?? 0;\n }\n\n // Set up ReCaptcha, if possible\n if (\n changed.has('recaptchaManager') &&\n !this.bypassRecaptcha &&\n this.recaptchaManager\n ) {\n this.setupRecaptcha();\n }\n\n // Disable form if unrecoverable error added\n if (changed.has('unrecoverableError')) {\n this.formCanSubmit = this.checkSubmissionAllowed();\n }\n\n // Ensure new subject and body have correct length\n if (\n changed.has('currentSubjectLength') ||\n changed.has('currentBodyLength') ||\n changed.has('maxSubjectLength') ||\n changed.has('maxBodyLength')\n ) {\n this.formCanSubmit = this.checkSubmissionAllowed();\n }\n }\n\n /** Error to render instead of form inputs */\n private get unrecoverableErrorTemplate():\n | HTMLTemplateResult\n | typeof nothing {\n return this.unrecoverableError\n ? html`\n <div class=\"unrecoverable-error\">\n <span class=\"error-msg\">${msg(this.unrecoverableError)}</span>\n </div>\n `\n : nothing;\n }\n\n /** Error to render next to submit button */\n private get recoverableErrorTemplate(): HTMLTemplateResult | typeof nothing {\n return this.recoverableError\n ? html`\n <div class=\"recoverable-error\">\n ${unsafeHTML(this.sanitizeErrorMsg(msg(this.recoverableError)))}\n </div>\n `\n : nothing;\n }\n\n private get recaptchaMessageTemplate(): HTMLTemplateResult | typeof nothing {\n if (this.bypassRecaptcha) return nothing;\n\n return html`\n <span class=\"recaptcha-disclaimer\"\n >${msg(\n html`This site is protected by reCAPTCHA and the Google\n <a\n target=\"_blank\"\n class=\"inline-link\"\n href=\"https://policies.google.com/privacy\"\n >Privacy Policy</a\n >\n and\n <a\n target=\"_blank\"\n class=\"inline-link\"\n href=\"https://policies.google.com/terms\"\n >Terms of Service</a\n >\n apply.`,\n )}</span\n >\n `;\n }\n\n /** Clickable group of stars */\n private get starsInputTemplate(): HTMLTemplateResult {\n return html`\n <div class=\"form-heading rating\">\n <label for=\"stars-field\">${msg('Rating (optional)')}</label>\n </div>\n <input\n type=\"hidden\"\n name=\"field_stars\"\n id=\"stars-input\"\n .value=${this.currentStars.toString()}\n required\n />\n <div class=\"stars\">\n ${[1, 2, 3, 4, 5].map((num) => this.renderStar(num))}\n <button\n type=\"button\"\n class=\"clear-stars-btn\"\n @click=${this.handleClearBtnClicked}\n >\n ${msg('Clear')}\n </button>\n </div>\n `;\n }\n\n /** Subject input and character counter */\n private get subjectInputTemplate(): HTMLTemplateResult {\n return html`\n <span id=\"subject-input\" class=\"input-box ${\n this.maxSubjectLength &&\n this.currentSubjectLength > this.maxSubjectLength\n ? 'error'\n : ''\n }\"\n ><div class=\"form-heading\">\n <label for=\"field_reviewtitle\">${msg('Subject')}</label>\n ${\n this.maxSubjectLength\n ? html`<div class=\"char-count subject\">\n ${this.currentSubjectLength}/${this.maxSubjectLength}\n </div>`\n : nothing\n }\n </div>\n <input\n type=\"text\"\n name=\"field_reviewtitle\"\n id=\"field_reviewtitle\"\n .value=${this.oldReview?.reviewtitle ?? ''}\n @input=${this.handleSubjectChanged}\n required\n />${\n this.maxSubjectLength\n ? html`\n <div class=\"input-error\">\n ${msg(\n `Subject may only have ${this.maxSubjectLength} characters`,\n )}\n </div>\n `\n : nothing\n }</div></span>\n `;\n }\n\n /** Body input and character counter */\n private get bodyInputTemplate(): HTMLTemplateResult {\n return html`\n <span\n id=\"body-input\"\n class=\"input-box ${this.maxBodyLength &&\n this.currentBodyLength > this.maxBodyLength\n ? 'error'\n : ''}\"\n ><div class=\"form-heading\">\n <label for=\"field_reviewbody\">${msg('Review')}</label>\n ${this.maxBodyLength\n ? html`<div class=\"char-count body\">\n ${this.currentBodyLength}/${this.maxBodyLength}\n </div>`\n : nothing}\n </div>\n <textarea\n name=\"field_reviewbody\"\n id=\"field_reviewbody\"\n .value=${this.oldReview?.reviewbody ?? ''}\n rows=\"10\"\n cols=\"50\"\n required\n @input=${this.handleBodyChanged}\n ></textarea>\n ${this.maxBodyLength\n ? html`\n <div class=\"input-error\">\n ${msg(`Review may only have ${this.maxBodyLength} characters`)}\n </div>\n `\n : nothing}\n </span>\n `;\n }\n\n /** Buttons to render at bottom of form */\n private get actionButtonsTemplate(): HTMLTemplateResult {\n return html`<div class=\"action-btns\">\n <ia-button\n mode=\"secondary\"\n class=\"cancel-btn\"\n data-testid=\"cancel-btn\"\n @click=${this.cancelReviewEdit}\n >\n ${msg('Cancel')}\n </ia-button>\n <ia-button\n mode=\"primary\"\n type=\"submit\"\n class=\"submit-btn\"\n .disabled=${!this.formCanSubmit}\n .loading=${this.submissionInProgress}\n >\n ${msg('Submit review')}\n </ia-button>\n </div>`;\n }\n\n /**\n * Renders a star icon, using its number and the current star rating\n * to determine whether it should appear selected or not\n *\n * @param {number} num The number of the current star\n * @returns {HTMLTemplateResult} The correct icon, rendered within a button\n */\n private renderStar(num: number): HTMLTemplateResult {\n const isSelected = num === this.currentStars;\n const ratingLabel = msg(`Rate ${num > 1 ? `${num} stars` : '1 star'}`);\n\n return html`\n <button\n class=\"star star-${num}\"\n title=${isSelected ? msg('Clear rating') : ratingLabel}\n @click=${(e: Event) => this.handleStarClicked(e, num)}\n >\n ${num <= this.currentStars\n ? html`<img\n class=\"star-selected\"\n src=${starSelected}\n alt=\"\"\n aria-hidden=\"true\"\n />`\n : html`<img\n class=\"star-unselected\"\n src=${starUnselected}\n alt=\"\"\n aria-hidden=\"true\"\n />`}\n </button>\n `;\n }\n\n /**\n * Sets up ReCaptcha for the form, if possible.\n *\n * On failure, replaces form inputs with the ReCaptcha error message.\n */\n private async setupRecaptcha(): Promise<void> {\n try {\n this.recaptchaWidget = await this.recaptchaManager?.getRecaptchaWidget();\n } catch {\n this.unrecoverableError = this.RECAPTCHA_ERROR_MESSAGE;\n }\n }\n\n /**\n * Uses DOMpurify to sanitize any error message before render.\n *\n * @param {string} errorMsg The error message to be sanitized\n * @returns {string} The sanitized error message\n */\n private sanitizeErrorMsg(errorMsg: string): string {\n return DOMPurify.sanitize(errorMsg, { ALLOWED_TAGS: ['a', 'b', 'br'] });\n }\n\n /** Handles validation and recaptcha execution on form submission */\n private async handleSubmit(e: Event): Promise<void> {\n e.preventDefault();\n\n // Prevent disallowed or double submission\n if (!this.formCanSubmit || this.submissionInProgress) return;\n\n // Set loading behavior\n this.submissionInProgress = true;\n this.recoverableError = '';\n\n // Check for HTML errors\n if (!this.reviewForm.reportValidity()) {\n return this.stopSubmission();\n }\n\n if (!this.reviewService || !this.identifier) {\n this.recoverableError = this.GENERIC_ERROR_MESSAGE;\n return this.stopSubmission();\n }\n\n try {\n let recaptchaToken: string | undefined;\n if (!this.bypassRecaptcha) {\n recaptchaToken = await this.getRecaptchaToken();\n if (!recaptchaToken) return this.handleRecaptchaError();\n }\n\n const result = await this.reviewService.submitReview({\n identifier: this.identifier,\n title: this.reviewForm.field_reviewtitle.value,\n body: this.reviewForm.field_reviewbody.value,\n stars: this.reviewForm.field_stars.value,\n recaptchaToken,\n });\n\n if (result?.success === true) {\n this.submissionInProgress = false;\n const newReview = this.generateSubmittedReview();\n\n // Emit a reviewUpdated event\n const event = new CustomEvent<Review>('reviewUpdated', {\n detail: newReview,\n });\n this.dispatchEvent(event);\n } else {\n this.recoverableError = result.error ?? this.GENERIC_ERROR_MESSAGE;\n this.stopSubmission();\n }\n } catch (e) {\n console.error(e);\n this.recoverableError = this.GENERIC_ERROR_MESSAGE;\n this.stopSubmission();\n }\n }\n\n /**\n * Generates a review object from the submitted review,\n * for optimistic display on success.\n *\n * @returns {Review} The review to display\n */\n private generateSubmittedReview(): Review {\n const today = new Date().toDateString();\n\n const newReview = new Review({\n reviewtitle: this.reviewForm.field_reviewtitle.value,\n reviewbody: this.reviewForm.field_reviewbody.value,\n stars: this.reviewForm.field_stars.value,\n reviewdate: today,\n reviewer: this.oldReview?.reviewer ?? this.submitterScreenname,\n reviewer_itemname:\n this.oldReview?.reviewer_itemname ?? this.submitterItemname,\n createdate: this.dateToString(this.oldReview?.createdate) ?? today,\n });\n\n return newReview;\n }\n\n /**\n * Converts date to string if it is a Date, otherwise\n * leaves unchanged.\n */\n private dateToString(date: string | Date | undefined) {\n if (date instanceof Date) return date.toDateString();\n return date;\n }\n\n /**\n * Executes the ReCaptcha challenge for the form.\n * Attempts form submission on success.\n * */\n private async getRecaptchaToken(): Promise<string | undefined> {\n if (!this.recaptchaWidget) {\n this.handleRecaptchaError();\n return;\n }\n\n try {\n const recaptchaToken = await this.recaptchaWidget.execute();\n return recaptchaToken;\n } catch {\n this.handleRecaptchaError();\n return;\n }\n }\n\n /* Handles a recaptcha error during submission */\n private handleRecaptchaError(): void {\n this.recoverableError = this.RECAPTCHA_ERROR_MESSAGE;\n this.stopSubmission();\n }\n\n /* Handles canceled form submission */\n private stopSubmission(): void {\n if (this.submissionInProgress) {\n this.submissionInProgress = false;\n }\n }\n\n /* Emits an event to close the form */\n private cancelReviewEdit(): void {\n const event = new CustomEvent('reviewEditCanceled');\n this.dispatchEvent(event);\n }\n\n /* Prevents form submission and sets stars based on number clicked */\n private handleStarClicked(e: Event, num: number): void {\n e.preventDefault();\n this.setStars(num);\n }\n\n /* Clear stars if requested */\n private handleClearBtnClicked(e: Event): void {\n e.preventDefault();\n this.currentStars = 0;\n }\n\n /* Updates star count, resetting to 0 if the currently selected star is clicked */\n private setStars(num: number): void {\n this.currentStars = num === this.currentStars ? 0 : num;\n }\n\n /* Updates subject input length */\n private handleSubjectChanged(e: Event): void {\n const subjectInput = e.target as HTMLInputElement;\n this.currentSubjectLength = subjectInput.value.length;\n }\n\n /* Updates body input length */\n private handleBodyChanged(e: Event): void {\n const bodyInput = e.target as HTMLInputElement;\n this.currentBodyLength = bodyInput.value.length;\n }\n\n /* Checks if submission should be allowed */\n private checkSubmissionAllowed(): boolean {\n // Form must not have an unrecoverable error\n if (this.unrecoverableError) {\n return false;\n }\n\n // Subject and body must not be empty\n if (!this.currentBodyLength || !this.currentSubjectLength) {\n return false;\n }\n\n // Subject must be correct length\n if (\n !!this.maxSubjectLength &&\n this.currentSubjectLength > this.maxSubjectLength\n ) {\n return false;\n }\n\n // Body must be correct length\n if (!!this.maxBodyLength && this.currentBodyLength > this.maxBodyLength) {\n return false;\n }\n\n return true;\n }\n\n static get styles(): CSSResultGroup {\n return [\n css`\n .form-heading {\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n padding-top: 15px;\n }\n\n .form-heading.rating {\n padding-top: 0;\n }\n\n .form-heading label {\n font-size: 1.6rem;\n font-weight: bold;\n }\n\n label {\n display: inline-block;\n margin-bottom: 5px;\n }\n\n textarea,\n input[type='text'],\n .unrecoverable-error {\n padding: 5px;\n width: calc(100% - 10px);\n font-family: inherit;\n border-radius: 5px;\n border: 1px solid var(--container-border-color, #999999);\n }\n\n .input-box.error input,\n .input-box.error textarea {\n border: 2px solid var(--container-error-color, #ea0202);\n }\n\n .input-box.error .char-count,\n .input-error,\n .unrecoverable-error,\n .recoverable-error {\n color: var(--container-error-color, #ea0202);\n }\n\n .input-error {\n display: none;\n }\n\n .input-box.error .input-error {\n display: block;\n text-align: right;\n padding-top: 5px;\n }\n\n .inline-link {\n color: var(--container-link-color, #4f65f5);\n text-decoration: none;\n }\n\n .inline-link:hover {\n text-decoration: underline;\n }\n\n .stars {\n display: flex;\n flex-direction: row;\n gap: 2px;\n align-items: center;\n }\n\n .star {\n all: unset;\n height: 30px;\n width: 30px;\n }\n\n .star-selected,\n .star-unselected {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .star:hover {\n cursor: pointer;\n }\n\n .clear-stars-btn,\n .recoverable-error a {\n padding: 0 5px;\n color: var(--container-link-color, #4f65f5);\n font-family: inherit;\n border: none;\n background: transparent;\n display: inline-block;\n padding-top: 5px;\n }\n\n .clear-stars-btn:hover,\n .recoverable-error a:hover {\n cursor: pointer;\n text-decoration: underline;\n }\n\n .action-btns {\n width: 100%;\n display: flex;\n justify-content: flex-end;\n gap: 10px;\n padding-top: 15px;\n }\n\n .ia-button:disabled {\n opacity: 0.75;\n }\n\n .ia-button:disabled:hover {\n cursor: not-allowed;\n }\n\n .unrecoverable-error {\n min-height: 50px;\n padding: 5px;\n text-align: center;\n display: flex;\n flex-direction: column;\n justify-content: center;\n background-color: var(--container-bg-color, #fbfbfd);\n }\n\n .recaptcha-disclaimer {\n font-size: 1.2rem;\n }\n\n @media only screen and (max-width: 350px) {\n .action-btns {\n flex-direction: column-reverse;\n align-items: center;\n }\n }\n `,\n ];\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ia-review-form.js","sourceRoot":"","sources":["../../../../src/elements/ia-reviews/ia-review-form.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n html,\n css,\n LitElement,\n nothing,\n HTMLTemplateResult,\n PropertyValues,\n CSSResultGroup,\n} from 'lit';\nimport { property, state, query } from 'lit/decorators.js';\nimport { customElement } from '@src/util/custom-element';\nimport { msg } from '@lit/localize';\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js';\n\nimport DOMPurify from 'dompurify';\n\nimport type {\n RecaptchaManagerInterface,\n RecaptchaWidgetInterface,\n} from '@internetarchive/recaptcha-manager';\nimport '@src/elements/ia-button/ia-button';\nimport type { FetchHandlerInterface } from '@internetarchive/fetch-handler';\nimport { Review } from '@internetarchive/metadata-service';\n\nimport starSelected from './assets/star-selected.svg';\nimport starUnselected from './assets/star-unselected.svg';\n\nimport './ia-review';\n\n/**\n * Renders a form to edit a given IA review.\n */\n@customElement('ia-review-form')\nexport class IAReviewForm extends LitElement {\n /* The IA item being reviewed */\n @property({ type: String }) identifier?: string;\n\n /* The token for the review edit */\n @property({ type: String }) token: string = '';\n\n /* The host for archive endpoints and data */\n @property({ type: String }) baseHost: string = 'https://archive.org';\n\n /* The path for the endpoint we're submitting to */\n @property({ type: String }) endpointPath: string = '/write-review.php';\n\n /** Form submitter's screenname, if applicable */\n @property({ type: String }) submitterScreenname: string = 'Anonymous';\n\n /** Form submitter's itemname, if applicable */\n @property({ type: String }) submitterItemname?: string;\n\n /* The previous review to pre-fill, if any */\n @property({ type: Object }) oldReview?: Review;\n\n /* An optional unrecoverable error to pass in instead of rendering the form inputs */\n @property({ type: String }) unrecoverableError?: string;\n\n /* Optional max length for review subject */\n @property({ type: Number }) maxSubjectLength?: number;\n\n /* Optional max length for review body */\n @property({ type: Number }) maxBodyLength?: number;\n\n /* Handler for form submission */\n @property({ type: Object }) fetchHandler?: FetchHandlerInterface;\n\n /* Service for activating the recaptcha challenge */\n @property({ type: Object }) recaptchaManager?: RecaptchaManagerInterface;\n\n /* Optionally avoid using recaptcha for the form */\n @property({ type: Boolean }) bypassRecaptcha: boolean = false;\n\n /* Recaptcha widget for the form */\n private recaptchaWidget?: RecaptchaWidgetInterface;\n\n /* Number of stars currently selected */\n @state()\n private currentStars: number = 0;\n\n /* Length of review subject currently filled in */\n @state()\n private currentSubjectLength: number = 0;\n\n /* Length of review body currently filled in */\n @state()\n private currentBodyLength: number = 0;\n\n /* Any recoverable error to display for the form. Will still allow submission. */\n @state()\n recoverableError?: string;\n\n /* Whether to enable the submit button */\n @state()\n private formCanSubmit: boolean = false;\n\n /* Whether to show a loading indicator for the form */\n @state()\n submissionInProgress: boolean = false;\n\n /* The form to be submitted */\n @query('#review-form')\n private reviewForm!: HTMLFormElement;\n\n /* Error to show if recaptcha cannot be loaded */\n private RECAPTCHA_ERROR_MESSAGE =\n 'Could not validate review. Please try again later.';\n\n private GENERIC_ERROR_MESSAGE =\n \"There's been a temporary error. Please wait a moment and try again.\";\n\n render() {\n return html`<form id=\"review-form\" @submit=${this.handleSubmit}>\n ${this.unrecoverableError\n ? this.unrecoverableErrorTemplate\n : html`\n <span class=\"inputs\">\n ${this.starsInputTemplate} ${this.subjectInputTemplate}\n ${this.bodyInputTemplate} ${this.hiddenInputsTemplate}\n </span>\n `}\n ${this.recaptchaMessageTemplate} ${this.recoverableErrorTemplate}\n ${this.actionButtonsTemplate}\n </form>`;\n }\n\n protected willUpdate(changed: PropertyValues): void {\n // Fill in previous review, if provided\n if (changed.has('oldReview')) {\n this.currentStars = this.oldReview?.stars ?? 0;\n this.currentSubjectLength = this.oldReview?.reviewtitle?.length ?? 0;\n this.currentBodyLength = this.oldReview?.reviewbody?.length ?? 0;\n }\n\n // Set up ReCaptcha, if possible\n if (\n changed.has('recaptchaManager') &&\n !this.bypassRecaptcha &&\n this.recaptchaManager\n ) {\n this.setupRecaptcha();\n }\n\n // Disable form if unrecoverable error added\n if (changed.has('unrecoverableError')) {\n this.formCanSubmit = this.checkSubmissionAllowed();\n }\n\n // Ensure new subject and body have correct length\n if (\n changed.has('currentSubjectLength') ||\n changed.has('currentBodyLength') ||\n changed.has('maxSubjectLength') ||\n changed.has('maxBodyLength')\n ) {\n this.formCanSubmit = this.checkSubmissionAllowed();\n }\n }\n\n /** Error to render instead of form inputs */\n private get unrecoverableErrorTemplate():\n | HTMLTemplateResult\n | typeof nothing {\n return this.unrecoverableError\n ? html`\n <div class=\"unrecoverable-error\">\n <span class=\"error-msg\">${msg(this.unrecoverableError)}</span>\n </div>\n `\n : nothing;\n }\n\n /** Error to render next to submit button */\n private get recoverableErrorTemplate(): HTMLTemplateResult | typeof nothing {\n return this.recoverableError\n ? html`\n <div class=\"recoverable-error\">\n ${unsafeHTML(this.sanitizeErrorMsg(msg(this.recoverableError)))}\n </div>\n `\n : nothing;\n }\n\n private get recaptchaMessageTemplate(): HTMLTemplateResult | typeof nothing {\n if (this.bypassRecaptcha) return nothing;\n\n return html`\n <span class=\"recaptcha-disclaimer\"\n >${msg(\n html`This site is protected by reCAPTCHA and the Google\n <a\n target=\"_blank\"\n class=\"inline-link\"\n href=\"https://policies.google.com/privacy\"\n >Privacy Policy</a\n >\n and\n <a\n target=\"_blank\"\n class=\"inline-link\"\n href=\"https://policies.google.com/terms\"\n >Terms of Service</a\n >\n apply.`,\n )}</span\n >\n `;\n }\n\n /** Clickable group of stars */\n private get starsInputTemplate(): HTMLTemplateResult {\n return html`\n <div class=\"form-heading rating\">\n <label for=\"stars-field\">${msg('Rating (optional)')}</label>\n </div>\n <input\n type=\"hidden\"\n name=\"field_stars\"\n id=\"stars-input\"\n .value=${this.currentStars.toString()}\n required\n />\n <div class=\"stars\">\n ${[1, 2, 3, 4, 5].map((num) => this.renderStar(num))}\n <button\n type=\"button\"\n class=\"clear-stars-btn\"\n @click=${this.handleClearBtnClicked}\n >\n ${msg('Clear')}\n </button>\n </div>\n `;\n }\n\n /** Subject input and character counter */\n private get subjectInputTemplate(): HTMLTemplateResult {\n return html`\n <span id=\"subject-input\" class=\"input-box ${\n this.maxSubjectLength &&\n this.currentSubjectLength > this.maxSubjectLength\n ? 'error'\n : ''\n }\"\n ><div class=\"form-heading\">\n <label for=\"field_reviewtitle\">${msg('Subject')}</label>\n ${\n this.maxSubjectLength\n ? html`<div class=\"char-count subject\">\n ${this.currentSubjectLength}/${this.maxSubjectLength}\n </div>`\n : nothing\n }\n </div>\n <input\n type=\"text\"\n name=\"field_reviewtitle\"\n id=\"field_reviewtitle\"\n .value=${this.oldReview?.reviewtitle ?? ''}\n @input=${this.handleSubjectChanged}\n required\n />${\n this.maxSubjectLength\n ? html`\n <div class=\"input-error\">\n ${msg(\n `Subject may only have ${this.maxSubjectLength} characters`,\n )}\n </div>\n `\n : nothing\n }</div></span>\n `;\n }\n\n /** Body input and character counter */\n private get bodyInputTemplate(): HTMLTemplateResult {\n return html`\n <span\n id=\"body-input\"\n class=\"input-box ${this.maxBodyLength &&\n this.currentBodyLength > this.maxBodyLength\n ? 'error'\n : ''}\"\n ><div class=\"form-heading\">\n <label for=\"field_reviewbody\">${msg('Review')}</label>\n ${this.maxBodyLength\n ? html`<div class=\"char-count body\">\n ${this.currentBodyLength}/${this.maxBodyLength}\n </div>`\n : nothing}\n </div>\n <textarea\n name=\"field_reviewbody\"\n id=\"field_reviewbody\"\n .value=${this.oldReview?.reviewbody ?? ''}\n rows=\"10\"\n cols=\"50\"\n required\n @input=${this.handleBodyChanged}\n ></textarea>\n ${this.maxBodyLength\n ? html`\n <div class=\"input-error\">\n ${msg(`Review may only have ${this.maxBodyLength} characters`)}\n </div>\n `\n : nothing}\n </span>\n `;\n }\n\n /** Hidden inputs we use to store other information for form submission */\n private get hiddenInputsTemplate(): HTMLTemplateResult {\n return html`\n <input type=\"hidden\" name=\"field_reviewtoken\" .value=${this.token} />\n ${this.identifier\n ? html`<input\n type=\"hidden\"\n name=\"identifier\"\n .value=${this.identifier}\n />`\n : nothing}\n `;\n }\n\n /** Buttons to render at bottom of form */\n private get actionButtonsTemplate(): HTMLTemplateResult {\n return html`<div class=\"action-btns\">\n <ia-button\n mode=\"secondary\"\n class=\"cancel-btn\"\n data-testid=\"cancel-btn\"\n @click=${this.cancelReviewEdit}\n >\n ${msg('Cancel')}\n </ia-button>\n <ia-button\n mode=\"primary\"\n type=\"submit\"\n class=\"submit-btn\"\n .disabled=${!this.formCanSubmit}\n .loading=${this.submissionInProgress}\n >\n ${msg('Submit review')}\n </ia-button>\n </div>`;\n }\n\n /**\n * Renders a star icon, using its number and the current star rating\n * to determine whether it should appear selected or not\n *\n * @param {number} num The number of the current star\n * @returns {HTMLTemplateResult} The correct icon, rendered within a button\n */\n private renderStar(num: number): HTMLTemplateResult {\n const isSelected = num === this.currentStars;\n const ratingLabel = msg(`Rate ${num > 1 ? `${num} stars` : '1 star'}`);\n\n return html`\n <button\n class=\"star star-${num}\"\n title=${isSelected ? msg('Clear rating') : ratingLabel}\n @click=${(e: Event) => this.handleStarClicked(e, num)}\n >\n ${num <= this.currentStars\n ? html`<img\n class=\"star-selected\"\n src=${starSelected}\n alt=\"\"\n aria-hidden=\"true\"\n />`\n : html`<img\n class=\"star-unselected\"\n src=${starUnselected}\n alt=\"\"\n aria-hidden=\"true\"\n />`}\n </button>\n `;\n }\n\n /**\n * Sets up ReCaptcha for the form, if possible.\n *\n * On failure, replaces form inputs with the ReCaptcha error message.\n */\n private async setupRecaptcha(): Promise<void> {\n try {\n this.recaptchaWidget = await this.recaptchaManager?.getRecaptchaWidget();\n } catch {\n this.unrecoverableError = this.RECAPTCHA_ERROR_MESSAGE;\n }\n }\n\n /**\n * Uses DOMpurify to sanitize any error message before render.\n *\n * @param {string} errorMsg The error message to be sanitized\n * @returns {string} The sanitized error message\n */\n private sanitizeErrorMsg(errorMsg: string): string {\n return DOMPurify.sanitize(errorMsg, { ALLOWED_TAGS: ['a', 'b', 'br'] });\n }\n\n /** Handles validation and recaptcha execution on form submission */\n private async handleSubmit(e: Event): Promise<void> {\n e.preventDefault();\n\n // Prevent disallowed or double submission\n if (!this.formCanSubmit || this.submissionInProgress) return;\n\n // Set loading behavior\n this.submissionInProgress = true;\n this.recoverableError = '';\n\n // Check for HTML errors\n if (!this.reviewForm.reportValidity()) {\n return this.stopSubmission();\n }\n\n if (!this.fetchHandler) {\n this.recoverableError = this.GENERIC_ERROR_MESSAGE;\n return this.stopSubmission();\n }\n\n try {\n const formData = new URLSearchParams();\n\n if (!this.bypassRecaptcha) {\n const recaptchaToken = await this.getRecaptchaToken();\n if (!recaptchaToken) return this.handleRecaptchaError();\n\n formData.append('g-recaptcha-response', recaptchaToken ?? '');\n }\n\n for (const entry of new FormData(this.reviewForm)) {\n formData.append(entry[0], entry[1] as string);\n }\n\n // Indicates to the backend that submission is intended\n formData.append('submitter', 'review-form');\n\n const result: { success: boolean; error?: string } =\n await this.fetchHandler.fetchApiResponse(\n `${this.baseHost}${this.endpointPath}`,\n {\n method: 'POST',\n includeCredentials: true,\n body: formData,\n },\n );\n\n if (result?.success === true) {\n this.submissionInProgress = false;\n const newReview = this.generateSubmittedReview();\n\n // Emit a reviewUpdated event\n const event = new CustomEvent<Review>('reviewUpdated', {\n detail: newReview,\n });\n this.dispatchEvent(event);\n } else {\n this.recoverableError = result.error ?? this.GENERIC_ERROR_MESSAGE;\n this.stopSubmission();\n }\n } catch (e) {\n console.error(e);\n this.recoverableError = this.GENERIC_ERROR_MESSAGE;\n this.stopSubmission();\n }\n }\n\n /**\n * Generates a review object from the submitted review,\n * for optimistic display on success.\n *\n * @returns {Review} The review to display\n */\n private generateSubmittedReview(): Review {\n const today = new Date().toDateString();\n\n const newReview = new Review({\n reviewtitle: this.reviewForm.field_reviewtitle.value,\n reviewbody: this.reviewForm.field_reviewbody.value,\n stars: this.reviewForm.field_stars.value,\n reviewdate: today,\n reviewer: this.oldReview?.reviewer ?? this.submitterScreenname,\n reviewer_itemname:\n this.oldReview?.reviewer_itemname ?? this.submitterItemname,\n createdate: this.dateToString(this.oldReview?.createdate) ?? today,\n });\n\n return newReview;\n }\n\n /**\n * Converts date to string if it is a Date, otherwise\n * leaves unchanged.\n */\n private dateToString(date: string | Date | undefined) {\n if (date instanceof Date) return date.toDateString();\n return date;\n }\n\n /**\n * Executes the ReCaptcha challenge for the form.\n * Attempts form submission on success.\n * */\n private async getRecaptchaToken(): Promise<string | undefined> {\n if (!this.recaptchaWidget) {\n this.handleRecaptchaError();\n return;\n }\n\n try {\n const recaptchaToken = await this.recaptchaWidget.execute();\n return recaptchaToken;\n } catch {\n this.handleRecaptchaError();\n return;\n }\n }\n\n /* Handles a recaptcha error during submission */\n private handleRecaptchaError(): void {\n this.recoverableError = this.RECAPTCHA_ERROR_MESSAGE;\n this.stopSubmission();\n }\n\n /* Handles canceled form submission */\n private stopSubmission(): void {\n if (this.submissionInProgress) {\n this.submissionInProgress = false;\n }\n }\n\n /* Emits an event to close the form */\n private cancelReviewEdit(): void {\n const event = new CustomEvent('reviewEditCanceled');\n this.dispatchEvent(event);\n }\n\n /* Prevents form submission and sets stars based on number clicked */\n private handleStarClicked(e: Event, num: number): void {\n e.preventDefault();\n this.setStars(num);\n }\n\n /* Clear stars if requested */\n private handleClearBtnClicked(e: Event): void {\n e.preventDefault();\n this.currentStars = 0;\n }\n\n /* Updates star count, resetting to 0 if the currently selected star is clicked */\n private setStars(num: number): void {\n this.currentStars = num === this.currentStars ? 0 : num;\n }\n\n /* Updates subject input length */\n private handleSubjectChanged(e: Event): void {\n const subjectInput = e.target as HTMLInputElement;\n this.currentSubjectLength = subjectInput.value.length;\n }\n\n /* Updates body input length */\n private handleBodyChanged(e: Event): void {\n const bodyInput = e.target as HTMLInputElement;\n this.currentBodyLength = bodyInput.value.length;\n }\n\n /* Checks if submission should be allowed */\n private checkSubmissionAllowed(): boolean {\n // Form must not have an unrecoverable error\n if (this.unrecoverableError) {\n return false;\n }\n\n // Subject and body must not be empty\n if (!this.currentBodyLength || !this.currentSubjectLength) {\n return false;\n }\n\n // Subject must be correct length\n if (\n !!this.maxSubjectLength &&\n this.currentSubjectLength > this.maxSubjectLength\n ) {\n return false;\n }\n\n // Body must be correct length\n if (!!this.maxBodyLength && this.currentBodyLength > this.maxBodyLength) {\n return false;\n }\n\n return true;\n }\n\n static get styles(): CSSResultGroup {\n return [\n css`\n .form-heading {\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n padding-top: 15px;\n }\n\n .form-heading.rating {\n padding-top: 0;\n }\n\n .form-heading label {\n font-size: 1.6rem;\n font-weight: bold;\n }\n\n label {\n display: inline-block;\n margin-bottom: 5px;\n }\n\n textarea,\n input[type='text'],\n .unrecoverable-error {\n padding: 5px;\n width: calc(100% - 10px);\n font-family: inherit;\n border-radius: 5px;\n border: 1px solid var(--container-border-color, #999999);\n }\n\n .input-box.error input,\n .input-box.error textarea {\n border: 2px solid var(--container-error-color, #ea0202);\n }\n\n .input-box.error .char-count,\n .input-error,\n .unrecoverable-error,\n .recoverable-error {\n color: var(--container-error-color, #ea0202);\n }\n\n .input-error {\n display: none;\n }\n\n .input-box.error .input-error {\n display: block;\n text-align: right;\n padding-top: 5px;\n }\n\n .inline-link {\n color: var(--container-link-color, #4f65f5);\n text-decoration: none;\n }\n\n .inline-link:hover {\n text-decoration: underline;\n }\n\n .stars {\n display: flex;\n flex-direction: row;\n gap: 2px;\n align-items: center;\n }\n\n .star {\n all: unset;\n height: 30px;\n width: 30px;\n }\n\n .star-selected,\n .star-unselected {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .star:hover {\n cursor: pointer;\n }\n\n .clear-stars-btn,\n .recoverable-error a {\n padding: 0 5px;\n color: var(--container-link-color, #4f65f5);\n font-family: inherit;\n border: none;\n background: transparent;\n display: inline-block;\n padding-top: 5px;\n }\n\n .clear-stars-btn:hover,\n .recoverable-error a:hover {\n cursor: pointer;\n text-decoration: underline;\n }\n\n .action-btns {\n width: 100%;\n display: flex;\n justify-content: flex-end;\n gap: 10px;\n padding-top: 15px;\n }\n\n .ia-button:disabled {\n opacity: 0.75;\n }\n\n .ia-button:disabled:hover {\n cursor: not-allowed;\n }\n\n .unrecoverable-error {\n min-height: 50px;\n padding: 5px;\n text-align: center;\n display: flex;\n flex-direction: column;\n justify-content: center;\n background-color: var(--container-bg-color, #fbfbfd);\n }\n\n .recaptcha-disclaimer {\n font-size: 1.2rem;\n }\n\n @media only screen and (max-width: 350px) {\n .action-btns {\n flex-direction: column-reverse;\n align-items: center;\n }\n }\n `,\n ];\n }\n}\n"]}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { LitElement, CSSResultGroup } from 'lit';
|
|
2
2
|
import { Review } from '@internetarchive/metadata-service';
|
|
3
|
-
import type { ReviewServiceInterface } from './models.js';
|
|
4
3
|
/**
|
|
5
4
|
* Renders a single IA review
|
|
6
5
|
*/
|
|
@@ -10,7 +9,7 @@ export declare class IAReview extends LitElement {
|
|
|
10
9
|
maxSubjectLength: number;
|
|
11
10
|
maxBodyLength: number;
|
|
12
11
|
baseHost: string;
|
|
13
|
-
|
|
12
|
+
csrfToken: string;
|
|
14
13
|
canDelete: boolean;
|
|
15
14
|
bypassTruncation: boolean;
|
|
16
15
|
private showTruncatedContent;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ia-review.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-reviews/ia-review.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EAGV,cAAc,EACf,MAAM,KAAK,CAAC;AAMb,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"ia-review.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-reviews/ia-review.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,UAAU,EAGV,cAAc,EACf,MAAM,KAAK,CAAC;AAMb,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AAW3D;;GAEG;AACH,qBACa,QAAS,SAAQ,UAAU;IAEV,MAAM,CAAC,EAAE,MAAM,CAAC;IAGhB,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB,gBAAgB,SAAO;IAGvB,aAAa,SAAO;IAGpB,QAAQ,SAAyB;IAGjC,SAAS,EAAE,MAAM,CAAM;IAGtB,SAAS,UAAS;IAGlB,gBAAgB,UAAS;IAItD,OAAO,CAAC,oBAAoB,CAAkB;IAI9C,OAAO,CAAC,SAAS,CAAc;IAE/B,MAAM;IA2CN,OAAO,KAAK,eAAe,GAI1B;IAGD,OAAO,KAAK,YAAY,GAWvB;IAGD,OAAO,KAAK,yBAAyB,GAYpC;IAGD,OAAO,KAAK,kBAAkB,GAS7B;IAGD,OAAO,KAAK,kBAAkB,GAO7B;IAGD,OAAO,KAAK,gBAAgB,GAc3B;IAGD,OAAO,KAAK,aAAa,GAqBxB;IAGD,OAAO,KAAK,kBAAkB,GAgB7B;IAED;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAMrB,kDAAkD;IAClD,OAAO,CAAC,eAAe;IAMvB;;;;;;;OAOG;IACH,OAAO,CAAC,UAAU;IAIlB;;OAEG;YACW,YAAY;IA2B1B,MAAM,KAAK,MAAM,IAAI,cAAc,CAgFlC;CACF"}
|