@internetarchive/elements 0.4.0 → 0.4.2-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/dist/src/elements/ia-audio-element/ia-audio-element.d.ts.map +1 -1
- package/dist/src/elements/ia-audio-element/ia-audio-element.js +2 -1
- package/dist/src/elements/ia-audio-element/ia-audio-element.js.map +1 -1
- package/dist/src/elements/ia-button/ia-button.d.ts.map +1 -1
- package/dist/src/elements/ia-button/ia-button.js +2 -1
- package/dist/src/elements/ia-button/ia-button.js.map +1 -1
- package/dist/src/elements/ia-combo-box/ia-combo-box.d.ts.map +1 -1
- package/dist/src/elements/ia-combo-box/ia-combo-box.js +2 -1
- package/dist/src/elements/ia-combo-box/ia-combo-box.js.map +1 -1
- package/dist/src/elements/ia-dropdown-search-bar/ia-dropdown-search-bar.d.ts.map +1 -1
- package/dist/src/elements/ia-dropdown-search-bar/ia-dropdown-search-bar.js +2 -1
- package/dist/src/elements/ia-dropdown-search-bar/ia-dropdown-search-bar.js.map +1 -1
- package/dist/src/elements/ia-expandable-search-bar/ia-expandable-search-bar.d.ts.map +1 -1
- package/dist/src/elements/ia-expandable-search-bar/ia-expandable-search-bar.js +2 -1
- package/dist/src/elements/ia-expandable-search-bar/ia-expandable-search-bar.js.map +1 -1
- package/dist/src/elements/ia-expandable-search-bar/ia-quick-search.d.ts.map +1 -1
- package/dist/src/elements/ia-expandable-search-bar/ia-quick-search.js +2 -1
- package/dist/src/elements/ia-expandable-search-bar/ia-quick-search.js.map +1 -1
- package/dist/src/elements/ia-image-viewer/ia-image-viewer.d.ts.map +1 -1
- package/dist/src/elements/ia-image-viewer/ia-image-viewer.js +2 -1
- package/dist/src/elements/ia-image-viewer/ia-image-viewer.js.map +1 -1
- package/dist/src/elements/ia-image-viewer/ia-imgview-controls.d.ts.map +1 -1
- package/dist/src/elements/ia-image-viewer/ia-imgview-controls.js +2 -1
- package/dist/src/elements/ia-image-viewer/ia-imgview-controls.js.map +1 -1
- package/dist/src/elements/ia-image-viewer/ia-imgview-slide.d.ts.map +1 -1
- package/dist/src/elements/ia-image-viewer/ia-imgview-slide.js +2 -1
- package/dist/src/elements/ia-image-viewer/ia-imgview-slide.js.map +1 -1
- package/dist/src/elements/ia-item-navigator/ia-item-navigator.d.ts.map +1 -1
- package/dist/src/elements/ia-item-navigator/ia-item-navigator.js +2 -1
- package/dist/src/elements/ia-item-navigator/ia-item-navigator.js.map +1 -1
- package/dist/src/elements/ia-item-navigator/ia-itemnav-menu-button.d.ts.map +1 -1
- package/dist/src/elements/ia-item-navigator/ia-itemnav-menu-button.js +2 -1
- package/dist/src/elements/ia-item-navigator/ia-itemnav-menu-button.js.map +1 -1
- package/dist/src/elements/ia-item-navigator/ia-itemnav-menu-slider.d.ts.map +1 -1
- package/dist/src/elements/ia-item-navigator/ia-itemnav-menu-slider.js +2 -1
- package/dist/src/elements/ia-item-navigator/ia-itemnav-menu-slider.js.map +1 -1
- package/dist/src/elements/ia-item-navigator/ia-itemnav-no-theater-available.d.ts.map +1 -1
- package/dist/src/elements/ia-item-navigator/ia-itemnav-no-theater-available.js +2 -1
- package/dist/src/elements/ia-item-navigator/ia-itemnav-no-theater-available.js.map +1 -1
- package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-share-panel.d.ts.map +1 -1
- package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-share-panel.js +2 -1
- package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-share-panel.js.map +1 -1
- package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-sort-files-button.d.ts.map +1 -1
- package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-sort-files-button.js +2 -1
- package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-sort-files-button.js.map +1 -1
- package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-viewable-files-panel.d.ts.map +1 -1
- package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-viewable-files-panel.js +2 -1
- package/dist/src/elements/ia-item-navigator/menus/ia-itemnav-viewable-files-panel.js.map +1 -1
- package/dist/src/elements/ia-otp-form/ia-otp-form.d.ts.map +1 -1
- package/dist/src/elements/ia-otp-form/ia-otp-form.js +2 -1
- package/dist/src/elements/ia-otp-form/ia-otp-form.js.map +1 -1
- package/dist/src/elements/ia-otp-input/ia-otp-input.d.ts.map +1 -1
- package/dist/src/elements/ia-otp-input/ia-otp-input.js +2 -1
- package/dist/src/elements/ia-otp-input/ia-otp-input.js.map +1 -1
- package/dist/src/elements/ia-playback-controls/ia-playback-controls.d.ts.map +1 -1
- package/dist/src/elements/ia-playback-controls/ia-playback-controls.js +2 -1
- package/dist/src/elements/ia-playback-controls/ia-playback-controls.js.map +1 -1
- 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 +2 -1
- package/dist/src/elements/ia-radio-player/ia-radio-player.js.map +1 -1
- package/dist/src/elements/ia-radio-player/ia-search-results-switcher.d.ts.map +1 -1
- package/dist/src/elements/ia-radio-player/ia-search-results-switcher.js +2 -1
- package/dist/src/elements/ia-radio-player/ia-search-results-switcher.js.map +1 -1
- package/dist/src/elements/ia-reviews/assets/delete-icon.svg +8 -0
- package/dist/src/elements/ia-reviews/assets/star-basic.svg +6 -0
- package/dist/src/elements/ia-reviews/assets/star-selected.svg +8 -0
- package/dist/src/elements/ia-reviews/assets/star-unselected.svg +8 -0
- package/dist/src/elements/ia-reviews/ia-review-form.d.ts +104 -0
- package/dist/src/elements/ia-reviews/ia-review-form.d.ts.map +1 -0
- package/dist/src/elements/ia-reviews/ia-review-form.js +678 -0
- package/dist/src/elements/ia-reviews/ia-review-form.js.map +1 -0
- package/dist/src/elements/ia-reviews/ia-review.d.ts +49 -0
- package/dist/src/elements/ia-reviews/ia-review.d.ts.map +1 -0
- package/dist/src/elements/ia-reviews/ia-review.js +349 -0
- package/dist/src/elements/ia-reviews/ia-review.js.map +1 -0
- package/dist/src/elements/ia-reviews/ia-reviews.d.ts +63 -0
- package/dist/src/elements/ia-reviews/ia-reviews.d.ts.map +1 -0
- package/dist/src/elements/ia-reviews/ia-reviews.js +357 -0
- package/dist/src/elements/ia-reviews/ia-reviews.js.map +1 -0
- package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.d.ts +8 -0
- package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.d.ts.map +1 -0
- package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.js +15 -0
- package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.js.map +1 -0
- package/dist/src/elements/ia-reviews/utils/collapse-space.d.ts +13 -0
- package/dist/src/elements/ia-reviews/utils/collapse-space.d.ts.map +1 -0
- package/dist/src/elements/ia-reviews/utils/collapse-space.js +19 -0
- package/dist/src/elements/ia-reviews/utils/collapse-space.js.map +1 -0
- package/dist/src/elements/ia-reviews/utils/friendly-truncate.d.ts +14 -0
- package/dist/src/elements/ia-reviews/utils/friendly-truncate.d.ts.map +1 -0
- package/dist/src/elements/ia-reviews/utils/friendly-truncate.js +65 -0
- package/dist/src/elements/ia-reviews/utils/friendly-truncate.js.map +1 -0
- package/dist/src/elements/ia-reviews/utils/link-urls-in-text.d.ts +9 -0
- package/dist/src/elements/ia-reviews/utils/link-urls-in-text.d.ts.map +1 -0
- package/dist/src/elements/ia-reviews/utils/link-urls-in-text.js +40 -0
- package/dist/src/elements/ia-reviews/utils/link-urls-in-text.js.map +1 -0
- package/dist/src/elements/ia-reviews/utils/sanitize-review-body.d.ts +9 -0
- package/dist/src/elements/ia-reviews/utils/sanitize-review-body.d.ts.map +1 -0
- package/dist/src/elements/ia-reviews/utils/sanitize-review-body.js +29 -0
- package/dist/src/elements/ia-reviews/utils/sanitize-review-body.js.map +1 -0
- package/dist/src/elements/ia-reviews/utils/truncate-screenname.d.ts +13 -0
- package/dist/src/elements/ia-reviews/utils/truncate-screenname.d.ts.map +1 -0
- package/dist/src/elements/ia-reviews/utils/truncate-screenname.js +19 -0
- package/dist/src/elements/ia-reviews/utils/truncate-screenname.js.map +1 -0
- package/dist/src/elements/ia-scrubber-bar/ia-scrubber-bar.d.ts.map +1 -1
- package/dist/src/elements/ia-scrubber-bar/ia-scrubber-bar.js +2 -1
- package/dist/src/elements/ia-scrubber-bar/ia-scrubber-bar.js.map +1 -1
- package/dist/src/elements/ia-scrubber-bar/ia-section-marker.d.ts.map +1 -1
- package/dist/src/elements/ia-scrubber-bar/ia-section-marker.js +2 -1
- package/dist/src/elements/ia-scrubber-bar/ia-section-marker.js.map +1 -1
- package/dist/src/elements/ia-sr-only-text/ia-sr-only-text.js +1 -1
- package/dist/src/elements/ia-sr-only-text/ia-sr-only-text.js.map +1 -1
- package/dist/src/elements/ia-status-indicator/ia-status-indicator.d.ts.map +1 -1
- package/dist/src/elements/ia-status-indicator/ia-status-indicator.js +2 -1
- package/dist/src/elements/ia-status-indicator/ia-status-indicator.js.map +1 -1
- package/dist/src/elements/ia-transcript-view/ia-transcript-entry.d.ts.map +1 -1
- package/dist/src/elements/ia-transcript-view/ia-transcript-entry.js +2 -1
- package/dist/src/elements/ia-transcript-view/ia-transcript-entry.js.map +1 -1
- package/dist/src/elements/ia-transcript-view/ia-transcript-view.d.ts.map +1 -1
- package/dist/src/elements/ia-transcript-view/ia-transcript-view.js +2 -1
- package/dist/src/elements/ia-transcript-view/ia-transcript-view.js.map +1 -1
- package/dist/src/elements/ia-waveform-progress/ia-waveform-progress.d.ts.map +1 -1
- package/dist/src/elements/ia-waveform-progress/ia-waveform-progress.js +2 -1
- package/dist/src/elements/ia-waveform-progress/ia-waveform-progress.js.map +1 -1
- package/dist/src/elements/index.d.ts +3 -0
- package/dist/src/elements/index.d.ts.map +1 -1
- package/dist/src/elements/index.js +3 -0
- package/dist/src/elements/index.js.map +1 -1
- package/dist/src/labs/ia-snow/ia-snow.js +1 -1
- package/dist/src/labs/ia-snow/ia-snow.js.map +1 -1
- package/dist/src/util/custom-element.d.ts +39 -0
- package/dist/src/util/custom-element.d.ts.map +1 -0
- package/dist/src/util/custom-element.js +50 -0
- package/dist/src/util/custom-element.js.map +1 -0
- package/package.json +17 -1
|
@@ -0,0 +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 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"]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { LitElement, CSSResultGroup } from 'lit';
|
|
2
|
+
import { Review } from '@internetarchive/metadata-service';
|
|
3
|
+
/**
|
|
4
|
+
* Renders a single IA review
|
|
5
|
+
*/
|
|
6
|
+
export declare class IAReview extends LitElement {
|
|
7
|
+
review?: Review;
|
|
8
|
+
identifier?: string;
|
|
9
|
+
maxSubjectLength: number;
|
|
10
|
+
maxBodyLength: number;
|
|
11
|
+
baseHost: string;
|
|
12
|
+
csrfToken: string;
|
|
13
|
+
canDelete: boolean;
|
|
14
|
+
bypassTruncation: boolean;
|
|
15
|
+
private showTruncatedContent;
|
|
16
|
+
private deleteMsg;
|
|
17
|
+
render(): import("lit").TemplateResult<1>;
|
|
18
|
+
private get subjectTemplate();
|
|
19
|
+
private get bodyTemplate();
|
|
20
|
+
private get truncationButtonsTemplate();
|
|
21
|
+
private get moreButtonTemplate();
|
|
22
|
+
private get lessButtonTemplate();
|
|
23
|
+
private get reviewerTemplate();
|
|
24
|
+
private get starsTemplate();
|
|
25
|
+
private get createDateTemplate();
|
|
26
|
+
/**
|
|
27
|
+
* Generates a unique ID for the review, using its createdate.
|
|
28
|
+
*
|
|
29
|
+
* @returns {string} The ID to render
|
|
30
|
+
*/
|
|
31
|
+
private generateDomId;
|
|
32
|
+
/** Truncates the review subject/body if needed */
|
|
33
|
+
private truncateContent;
|
|
34
|
+
/**
|
|
35
|
+
* Uses a set of utils in sequence to prepare a review for render,
|
|
36
|
+
* including transforming inline links into anchor links
|
|
37
|
+
* and collapsing internal spaces.
|
|
38
|
+
*
|
|
39
|
+
* @param {string} review The review to be prepped
|
|
40
|
+
* @returns {string} The review prepped for render
|
|
41
|
+
*/
|
|
42
|
+
private prepReview;
|
|
43
|
+
/**
|
|
44
|
+
* Deletes the review, following an extra confirmation.
|
|
45
|
+
*/
|
|
46
|
+
private deleteReview;
|
|
47
|
+
static get styles(): CSSResultGroup;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=ia-review.d.ts.map
|
|
@@ -0,0 +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;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"}
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import { __decorate } from "tslib";
|
|
2
|
+
import { html, css, LitElement, nothing, } from 'lit';
|
|
3
|
+
import { property, state } from 'lit/decorators.js';
|
|
4
|
+
import { customElement } from '../../util/custom-element.js';
|
|
5
|
+
import { msg } from '@lit/localize';
|
|
6
|
+
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
|
7
|
+
import starBasic from './assets/star-basic.svg';
|
|
8
|
+
import { truncateScreenname } from './utils/truncate-screenname.js';
|
|
9
|
+
import sanitizeReviewBody from './utils/sanitize-review-body.js';
|
|
10
|
+
import friendlyTruncate from './utils/friendly-truncate.js';
|
|
11
|
+
import linkUrlsInText from './utils/link-urls-in-text.js';
|
|
12
|
+
import collapseSpace from './utils/collapse-space.js';
|
|
13
|
+
import deleteIcon from './assets/delete-icon.svg';
|
|
14
|
+
/**
|
|
15
|
+
* Renders a single IA review
|
|
16
|
+
*/
|
|
17
|
+
let IAReview = class IAReview extends LitElement {
|
|
18
|
+
constructor() {
|
|
19
|
+
super(...arguments);
|
|
20
|
+
/* Maximum renderable length for subject */
|
|
21
|
+
this.maxSubjectLength = 100;
|
|
22
|
+
/* Maximum renderable length for body */
|
|
23
|
+
this.maxBodyLength = 150;
|
|
24
|
+
/* Base for URLs */
|
|
25
|
+
this.baseHost = 'https://archive.org';
|
|
26
|
+
/* CSRF token to use for delete request submission */
|
|
27
|
+
this.csrfToken = '';
|
|
28
|
+
/* Whether the person viewing this review has the power to delete it */
|
|
29
|
+
this.canDelete = false;
|
|
30
|
+
/* Whether we should skip the truncation step for the subject/body */
|
|
31
|
+
this.bypassTruncation = false;
|
|
32
|
+
/* Whether to show truncated review title / body */
|
|
33
|
+
this.showTruncatedContent = false;
|
|
34
|
+
/* An optional message created following attempted review deletion */
|
|
35
|
+
this.deleteMsg = '';
|
|
36
|
+
}
|
|
37
|
+
render() {
|
|
38
|
+
return !this.review
|
|
39
|
+
? html `
|
|
40
|
+
<div class="error">
|
|
41
|
+
${msg('This review cannot be displayed at this time.')}
|
|
42
|
+
</div>
|
|
43
|
+
`
|
|
44
|
+
: html `
|
|
45
|
+
<article class="review" id=${this.generateDomId()}>
|
|
46
|
+
${this.canDelete
|
|
47
|
+
? html `
|
|
48
|
+
<button
|
|
49
|
+
class="delete-btn"
|
|
50
|
+
title="Delete this review"
|
|
51
|
+
@click=${this.deleteReview}
|
|
52
|
+
>
|
|
53
|
+
<img
|
|
54
|
+
class="delete-icon"
|
|
55
|
+
src=${deleteIcon}
|
|
56
|
+
alt=""
|
|
57
|
+
aria-hidden="true"
|
|
58
|
+
/>
|
|
59
|
+
</button>
|
|
60
|
+
`
|
|
61
|
+
: nothing}
|
|
62
|
+
<div class="top-line">
|
|
63
|
+
<b>${msg('Reviewer:')}</b> ${this.reviewerTemplate} -
|
|
64
|
+
${this.starsTemplate}${this.createDateTemplate}
|
|
65
|
+
</div>
|
|
66
|
+
<div class="subject">
|
|
67
|
+
<b>${msg('Subject: ')}</b>${this.subjectTemplate}
|
|
68
|
+
</div>
|
|
69
|
+
<div class="body">
|
|
70
|
+
${!this.deleteMsg
|
|
71
|
+
? this.bodyTemplate
|
|
72
|
+
: html `<i>${msg(this.deleteMsg)}</i>`}
|
|
73
|
+
</div>
|
|
74
|
+
${this.truncationButtonsTemplate}
|
|
75
|
+
</article>
|
|
76
|
+
`;
|
|
77
|
+
}
|
|
78
|
+
/* Renders the review subject, truncating if necessary */
|
|
79
|
+
get subjectTemplate() {
|
|
80
|
+
const subject = this.review?.reviewtitle;
|
|
81
|
+
return this.truncateContent(subject ?? '', this.maxSubjectLength);
|
|
82
|
+
}
|
|
83
|
+
/* Renders the review body, truncating if necessary */
|
|
84
|
+
get bodyTemplate() {
|
|
85
|
+
const body = this.review?.reviewbody;
|
|
86
|
+
if (!body)
|
|
87
|
+
return nothing;
|
|
88
|
+
const sanitizedReview = sanitizeReviewBody(body);
|
|
89
|
+
const truncatedReview = this.truncateContent(sanitizedReview, this.maxBodyLength);
|
|
90
|
+
return html `${unsafeHTML(this.prepReview(truncatedReview))}`;
|
|
91
|
+
}
|
|
92
|
+
/* Renders the More/Less button if review is truncated */
|
|
93
|
+
get truncationButtonsTemplate() {
|
|
94
|
+
if (this.bypassTruncation)
|
|
95
|
+
return nothing;
|
|
96
|
+
const noTruncationNeeded = (this.review?.reviewtitle?.length ?? 0) <= this.maxSubjectLength &&
|
|
97
|
+
(this.review?.reviewbody?.length ?? 0) <= this.maxBodyLength;
|
|
98
|
+
if (noTruncationNeeded)
|
|
99
|
+
return nothing;
|
|
100
|
+
return this.showTruncatedContent
|
|
101
|
+
? this.lessButtonTemplate
|
|
102
|
+
: this.moreButtonTemplate;
|
|
103
|
+
}
|
|
104
|
+
/* More button for truncation */
|
|
105
|
+
get moreButtonTemplate() {
|
|
106
|
+
return html `
|
|
107
|
+
<button
|
|
108
|
+
class="simple-link more-btn"
|
|
109
|
+
@click=${() => (this.showTruncatedContent = true)}
|
|
110
|
+
>
|
|
111
|
+
${msg('More...')}
|
|
112
|
+
</button>
|
|
113
|
+
`;
|
|
114
|
+
}
|
|
115
|
+
/* Less button for truncation */
|
|
116
|
+
get lessButtonTemplate() {
|
|
117
|
+
return html `<button
|
|
118
|
+
class="simple-link less-btn"
|
|
119
|
+
@click=${() => (this.showTruncatedContent = false)}
|
|
120
|
+
>
|
|
121
|
+
${msg('...Less')}
|
|
122
|
+
</button>`;
|
|
123
|
+
}
|
|
124
|
+
/* Reviewer name, with hyperlink and truncation if needed */
|
|
125
|
+
get reviewerTemplate() {
|
|
126
|
+
return !this.review
|
|
127
|
+
? nothing
|
|
128
|
+
: this.review.reviewer_itemname
|
|
129
|
+
? html `
|
|
130
|
+
<a
|
|
131
|
+
href="${this.baseHost}/details/${this.review.reviewer_itemname}"
|
|
132
|
+
class="reviewer-link simple-link"
|
|
133
|
+
data-event-click-tracking="ItemReviews|ReviewerLink"
|
|
134
|
+
>
|
|
135
|
+
${truncateScreenname(this.review.reviewer)}
|
|
136
|
+
</a>
|
|
137
|
+
`
|
|
138
|
+
: html `${truncateScreenname(this.review.reviewer)}`;
|
|
139
|
+
}
|
|
140
|
+
/* Number of stars that corresponds to patron's rating */
|
|
141
|
+
get starsTemplate() {
|
|
142
|
+
if (!this.review || !this.review.stars)
|
|
143
|
+
return nothing;
|
|
144
|
+
return html `
|
|
145
|
+
<div
|
|
146
|
+
class="review-stars"
|
|
147
|
+
title="${msg(`${this.review.stars} out of 5 stars`)}"
|
|
148
|
+
>
|
|
149
|
+
${new Array(Number(this.review.stars)).fill(null).map(() => html `<div class="review-star">
|
|
150
|
+
<img
|
|
151
|
+
class="star-basic"
|
|
152
|
+
src=${starBasic}
|
|
153
|
+
alt=""
|
|
154
|
+
aria-hidden="true"
|
|
155
|
+
/>
|
|
156
|
+
</div>`)}
|
|
157
|
+
</div>
|
|
158
|
+
-
|
|
159
|
+
`;
|
|
160
|
+
}
|
|
161
|
+
/* Formats the review's date for render, adding (edited) if needed */
|
|
162
|
+
get createDateTemplate() {
|
|
163
|
+
if (!this.review?.createdate || !this.review?.reviewdate)
|
|
164
|
+
return nothing;
|
|
165
|
+
const reviewDate = new Date(this.review.reviewdate);
|
|
166
|
+
const createDate = new Date(this.review.createdate);
|
|
167
|
+
const prettyDate = createDate.toLocaleString('en-us', {
|
|
168
|
+
month: 'long',
|
|
169
|
+
day: 'numeric',
|
|
170
|
+
year: 'numeric',
|
|
171
|
+
});
|
|
172
|
+
const editedMsg = reviewDate.getTime() !== createDate.getTime() ? '(edited)' : '';
|
|
173
|
+
return msg(`${prettyDate} ${editedMsg}`);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Generates a unique ID for the review, using its createdate.
|
|
177
|
+
*
|
|
178
|
+
* @returns {string} The ID to render
|
|
179
|
+
*/
|
|
180
|
+
generateDomId() {
|
|
181
|
+
if (!this.review?.createdate)
|
|
182
|
+
return '';
|
|
183
|
+
return `review-${Date.parse(this.review.createdate.toString())}`;
|
|
184
|
+
}
|
|
185
|
+
/** Truncates the review subject/body if needed */
|
|
186
|
+
truncateContent(original, maxLength) {
|
|
187
|
+
if (this.showTruncatedContent || this.bypassTruncation)
|
|
188
|
+
return original;
|
|
189
|
+
return friendlyTruncate(original, maxLength);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Uses a set of utils in sequence to prepare a review for render,
|
|
193
|
+
* including transforming inline links into anchor links
|
|
194
|
+
* and collapsing internal spaces.
|
|
195
|
+
*
|
|
196
|
+
* @param {string} review The review to be prepped
|
|
197
|
+
* @returns {string} The review prepped for render
|
|
198
|
+
*/
|
|
199
|
+
prepReview(review) {
|
|
200
|
+
return collapseSpace(linkUrlsInText(review));
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Deletes the review, following an extra confirmation.
|
|
204
|
+
*/
|
|
205
|
+
async deleteReview() {
|
|
206
|
+
if (!this.review || !this.identifier)
|
|
207
|
+
return;
|
|
208
|
+
if (!confirm(msg('Are you sure you want to delete this review?')))
|
|
209
|
+
return;
|
|
210
|
+
// Screennames can contain spaces and ampersands, so the parameters are
|
|
211
|
+
// encoded rather than interpolated straight into the query string.
|
|
212
|
+
const params = new URLSearchParams({
|
|
213
|
+
identifier: this.identifier,
|
|
214
|
+
deleteReviewer: this.review.reviewer ?? '',
|
|
215
|
+
deleteReviewerItemname: this.review.reviewer_itemname ?? '',
|
|
216
|
+
csrf_token: this.csrfToken,
|
|
217
|
+
});
|
|
218
|
+
const deleteUrl = `${this.baseHost}/edit-reviews.php?${params}`;
|
|
219
|
+
try {
|
|
220
|
+
const response = await fetch(deleteUrl, {
|
|
221
|
+
method: 'POST',
|
|
222
|
+
});
|
|
223
|
+
// fetch only rejects on a network error, so a 4xx or 5xx arrives here as
|
|
224
|
+
// a resolved response and has to be checked before reporting success.
|
|
225
|
+
if (!response.ok)
|
|
226
|
+
throw new Error(`Delete failed: ${response.status}`);
|
|
227
|
+
this.deleteMsg = 'This review has been queued for deletion.';
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
this.deleteMsg = 'Sorry, we were unable to delete this review.';
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
static get styles() {
|
|
234
|
+
return css `
|
|
235
|
+
:host {
|
|
236
|
+
font-family: var(
|
|
237
|
+
--ia-font-stack,
|
|
238
|
+
'Helvetica Neue',
|
|
239
|
+
Helvetica,
|
|
240
|
+
Arial,
|
|
241
|
+
sans-serif
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
font-size: inherit;
|
|
245
|
+
--container-bg-color: #fbfbfd;
|
|
246
|
+
--container-border-color: #999999;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.review {
|
|
250
|
+
position: relative;
|
|
251
|
+
padding-right: 30px;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.error {
|
|
255
|
+
color: var(--error-color, #cc0000);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.top-line {
|
|
259
|
+
margin-bottom: 0.5rem;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.top-line > * {
|
|
263
|
+
display: inline-block;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.review-star {
|
|
267
|
+
width: 1rem;
|
|
268
|
+
display: inline-block;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.star-basic {
|
|
272
|
+
display: block;
|
|
273
|
+
width: 100%;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.simple-link,
|
|
277
|
+
.body a {
|
|
278
|
+
color: var(--link-color, #4b64ff);
|
|
279
|
+
text-decoration: none;
|
|
280
|
+
background: transparent;
|
|
281
|
+
border: none;
|
|
282
|
+
padding: 0px;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.simple-link:hover,
|
|
286
|
+
.body a:hover {
|
|
287
|
+
cursor: pointer;
|
|
288
|
+
text-decoration: underline;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.subject {
|
|
292
|
+
margin-bottom: 0.5rem;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.delete-btn {
|
|
296
|
+
position: absolute;
|
|
297
|
+
top: 0;
|
|
298
|
+
right: 0;
|
|
299
|
+
padding: 0;
|
|
300
|
+
background: none;
|
|
301
|
+
border: 0;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.delete-btn:hover {
|
|
305
|
+
cursor: pointer;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.delete-icon {
|
|
309
|
+
width: 20px;
|
|
310
|
+
mix-blend-mode: multiply;
|
|
311
|
+
}
|
|
312
|
+
`;
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
__decorate([
|
|
316
|
+
property({ type: Object })
|
|
317
|
+
], IAReview.prototype, "review", void 0);
|
|
318
|
+
__decorate([
|
|
319
|
+
property({ type: String })
|
|
320
|
+
], IAReview.prototype, "identifier", void 0);
|
|
321
|
+
__decorate([
|
|
322
|
+
property({ type: Number })
|
|
323
|
+
], IAReview.prototype, "maxSubjectLength", void 0);
|
|
324
|
+
__decorate([
|
|
325
|
+
property({ type: Number })
|
|
326
|
+
], IAReview.prototype, "maxBodyLength", void 0);
|
|
327
|
+
__decorate([
|
|
328
|
+
property({ type: String })
|
|
329
|
+
], IAReview.prototype, "baseHost", void 0);
|
|
330
|
+
__decorate([
|
|
331
|
+
property({ type: String })
|
|
332
|
+
], IAReview.prototype, "csrfToken", void 0);
|
|
333
|
+
__decorate([
|
|
334
|
+
property({ type: Boolean })
|
|
335
|
+
], IAReview.prototype, "canDelete", void 0);
|
|
336
|
+
__decorate([
|
|
337
|
+
property({ type: Boolean })
|
|
338
|
+
], IAReview.prototype, "bypassTruncation", void 0);
|
|
339
|
+
__decorate([
|
|
340
|
+
state()
|
|
341
|
+
], IAReview.prototype, "showTruncatedContent", void 0);
|
|
342
|
+
__decorate([
|
|
343
|
+
state()
|
|
344
|
+
], IAReview.prototype, "deleteMsg", void 0);
|
|
345
|
+
IAReview = __decorate([
|
|
346
|
+
customElement('ia-review')
|
|
347
|
+
], IAReview);
|
|
348
|
+
export { IAReview };
|
|
349
|
+
//# sourceMappingURL=ia-review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ia-review.js","sourceRoot":"","sources":["../../../../src/elements/ia-reviews/ia-review.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n html,\n css,\n LitElement,\n nothing,\n HTMLTemplateResult,\n CSSResultGroup,\n} from 'lit';\nimport { property, state } 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 { Review } from '@internetarchive/metadata-service';\n\nimport starBasic from './assets/star-basic.svg';\nimport { truncateScreenname } from './utils/truncate-screenname';\nimport sanitizeReviewBody from './utils/sanitize-review-body';\nimport friendlyTruncate from './utils/friendly-truncate';\nimport linkUrlsInText from './utils/link-urls-in-text';\nimport collapseSpace from './utils/collapse-space';\n\nimport deleteIcon from './assets/delete-icon.svg';\n\n/**\n * Renders a single IA review\n */\n@customElement('ia-review')\nexport class IAReview extends LitElement {\n /* The review to be rendered */\n @property({ type: Object }) review?: Review;\n\n /* The identifier for the item being reviewed */\n @property({ type: String }) identifier?: string;\n\n /* Maximum renderable length for subject */\n @property({ type: Number }) maxSubjectLength = 100;\n\n /* Maximum renderable length for body */\n @property({ type: Number }) maxBodyLength = 150;\n\n /* Base for URLs */\n @property({ type: String }) baseHost = 'https://archive.org';\n\n /* CSRF token to use for delete request submission */\n @property({ type: String }) csrfToken: string = '';\n\n /* Whether the person viewing this review has the power to delete it */\n @property({ type: Boolean }) canDelete = false;\n\n /* Whether we should skip the truncation step for the subject/body */\n @property({ type: Boolean }) bypassTruncation = false;\n\n /* Whether to show truncated review title / body */\n @state()\n private showTruncatedContent: boolean = false;\n\n /* An optional message created following attempted review deletion */\n @state()\n private deleteMsg: string = '';\n\n render() {\n return !this.review\n ? html`\n <div class=\"error\">\n ${msg('This review cannot be displayed at this time.')}\n </div>\n `\n : html`\n <article class=\"review\" id=${this.generateDomId()}>\n ${this.canDelete\n ? html`\n <button\n class=\"delete-btn\"\n title=\"Delete this review\"\n @click=${this.deleteReview}\n >\n <img\n class=\"delete-icon\"\n src=${deleteIcon}\n alt=\"\"\n aria-hidden=\"true\"\n />\n </button>\n `\n : nothing}\n <div class=\"top-line\">\n <b>${msg('Reviewer:')}</b> ${this.reviewerTemplate} -\n ${this.starsTemplate}${this.createDateTemplate}\n </div>\n <div class=\"subject\">\n <b>${msg('Subject: ')}</b>${this.subjectTemplate}\n </div>\n <div class=\"body\">\n ${!this.deleteMsg\n ? this.bodyTemplate\n : html`<i>${msg(this.deleteMsg)}</i>`}\n </div>\n ${this.truncationButtonsTemplate}\n </article>\n `;\n }\n\n /* Renders the review subject, truncating if necessary */\n private get subjectTemplate(): string {\n const subject = this.review?.reviewtitle;\n\n return this.truncateContent(subject ?? '', this.maxSubjectLength);\n }\n\n /* Renders the review body, truncating if necessary */\n private get bodyTemplate(): HTMLTemplateResult | typeof nothing {\n const body = this.review?.reviewbody;\n if (!body) return nothing;\n\n const sanitizedReview = sanitizeReviewBody(body);\n const truncatedReview = this.truncateContent(\n sanitizedReview,\n this.maxBodyLength,\n );\n\n return html`${unsafeHTML(this.prepReview(truncatedReview))}`;\n }\n\n /* Renders the More/Less button if review is truncated */\n private get truncationButtonsTemplate(): HTMLTemplateResult | typeof nothing {\n if (this.bypassTruncation) return nothing;\n\n const noTruncationNeeded =\n (this.review?.reviewtitle?.length ?? 0) <= this.maxSubjectLength &&\n (this.review?.reviewbody?.length ?? 0) <= this.maxBodyLength;\n\n if (noTruncationNeeded) return nothing;\n\n return this.showTruncatedContent\n ? this.lessButtonTemplate\n : this.moreButtonTemplate;\n }\n\n /* More button for truncation */\n private get moreButtonTemplate(): HTMLTemplateResult {\n return html`\n <button\n class=\"simple-link more-btn\"\n @click=${() => (this.showTruncatedContent = true)}\n >\n ${msg('More...')}\n </button>\n `;\n }\n\n /* Less button for truncation */\n private get lessButtonTemplate(): HTMLTemplateResult {\n return html`<button\n class=\"simple-link less-btn\"\n @click=${() => (this.showTruncatedContent = false)}\n >\n ${msg('...Less')}\n </button>`;\n }\n\n /* Reviewer name, with hyperlink and truncation if needed */\n private get reviewerTemplate(): HTMLTemplateResult | typeof nothing {\n return !this.review\n ? nothing\n : this.review.reviewer_itemname\n ? html`\n <a\n href=\"${this.baseHost}/details/${this.review.reviewer_itemname}\"\n class=\"reviewer-link simple-link\"\n data-event-click-tracking=\"ItemReviews|ReviewerLink\"\n >\n ${truncateScreenname(this.review.reviewer)}\n </a>\n `\n : html`${truncateScreenname(this.review.reviewer)}`;\n }\n\n /* Number of stars that corresponds to patron's rating */\n private get starsTemplate(): HTMLTemplateResult | typeof nothing {\n if (!this.review || !this.review.stars) return nothing;\n return html`\n <div\n class=\"review-stars\"\n title=\"${msg(`${this.review.stars} out of 5 stars`)}\"\n >\n ${new Array(Number(this.review.stars)).fill(null).map(\n () =>\n html`<div class=\"review-star\">\n <img\n class=\"star-basic\"\n src=${starBasic}\n alt=\"\"\n aria-hidden=\"true\"\n />\n </div>`,\n )}\n </div>\n -\n `;\n }\n\n /* Formats the review's date for render, adding (edited) if needed */\n private get createDateTemplate(): string | typeof nothing {\n if (!this.review?.createdate || !this.review?.reviewdate) return nothing;\n\n const reviewDate = new Date(this.review.reviewdate);\n const createDate = new Date(this.review.createdate);\n\n const prettyDate = createDate.toLocaleString('en-us', {\n month: 'long',\n day: 'numeric',\n year: 'numeric',\n });\n\n const editedMsg =\n reviewDate.getTime() !== createDate.getTime() ? '(edited)' : '';\n\n return msg(`${prettyDate} ${editedMsg}`);\n }\n\n /**\n * Generates a unique ID for the review, using its createdate.\n *\n * @returns {string} The ID to render\n */\n private generateDomId(): string {\n if (!this.review?.createdate) return '';\n\n return `review-${Date.parse(this.review.createdate.toString())}`;\n }\n\n /** Truncates the review subject/body if needed */\n private truncateContent(original: string, maxLength: number): string {\n if (this.showTruncatedContent || this.bypassTruncation) return original;\n\n return friendlyTruncate(original, maxLength);\n }\n\n /**\n * Uses a set of utils in sequence to prepare a review for render,\n * including transforming inline links into anchor links\n * and collapsing internal spaces.\n *\n * @param {string} review The review to be prepped\n * @returns {string} The review prepped for render\n */\n private prepReview(review: string): string {\n return collapseSpace(linkUrlsInText(review));\n }\n\n /**\n * Deletes the review, following an extra confirmation.\n */\n private async deleteReview(): Promise<void> {\n if (!this.review || !this.identifier) return;\n if (!confirm(msg('Are you sure you want to delete this review?'))) return;\n\n // Screennames can contain spaces and ampersands, so the parameters are\n // encoded rather than interpolated straight into the query string.\n const params = new URLSearchParams({\n identifier: this.identifier,\n deleteReviewer: this.review.reviewer ?? '',\n deleteReviewerItemname: this.review.reviewer_itemname ?? '',\n csrf_token: this.csrfToken,\n });\n const deleteUrl = `${this.baseHost}/edit-reviews.php?${params}`;\n try {\n const response = await fetch(deleteUrl, {\n method: 'POST',\n });\n // fetch only rejects on a network error, so a 4xx or 5xx arrives here as\n // a resolved response and has to be checked before reporting success.\n if (!response.ok) throw new Error(`Delete failed: ${response.status}`);\n\n this.deleteMsg = 'This review has been queued for deletion.';\n } catch {\n this.deleteMsg = 'Sorry, we were unable to delete this review.';\n }\n }\n\n static get styles(): CSSResultGroup {\n return css`\n :host {\n font-family: var(\n --ia-font-stack,\n 'Helvetica Neue',\n Helvetica,\n Arial,\n sans-serif\n );\n\n font-size: inherit;\n --container-bg-color: #fbfbfd;\n --container-border-color: #999999;\n }\n\n .review {\n position: relative;\n padding-right: 30px;\n }\n\n .error {\n color: var(--error-color, #cc0000);\n }\n\n .top-line {\n margin-bottom: 0.5rem;\n }\n\n .top-line > * {\n display: inline-block;\n }\n\n .review-star {\n width: 1rem;\n display: inline-block;\n }\n\n .star-basic {\n display: block;\n width: 100%;\n }\n\n .simple-link,\n .body a {\n color: var(--link-color, #4b64ff);\n text-decoration: none;\n background: transparent;\n border: none;\n padding: 0px;\n }\n\n .simple-link:hover,\n .body a:hover {\n cursor: pointer;\n text-decoration: underline;\n }\n\n .subject {\n margin-bottom: 0.5rem;\n }\n\n .delete-btn {\n position: absolute;\n top: 0;\n right: 0;\n padding: 0;\n background: none;\n border: 0;\n }\n\n .delete-btn:hover {\n cursor: pointer;\n }\n\n .delete-icon {\n width: 20px;\n mix-blend-mode: multiply;\n }\n `;\n }\n}\n"]}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { CSSResultGroup, HTMLTemplateResult, LitElement, PropertyValues } from 'lit';
|
|
2
|
+
import type { Review } from '@internetarchive/metadata-service';
|
|
3
|
+
import type { RecaptchaManagerInterface } from '@internetarchive/recaptcha-manager';
|
|
4
|
+
import { FetchHandlerInterface } from '@internetarchive/fetch-handler';
|
|
5
|
+
import '../../elements/ia-button/ia-button.js';
|
|
6
|
+
import './ia-review.js';
|
|
7
|
+
import './ia-review-form.js';
|
|
8
|
+
/**
|
|
9
|
+
* Renders the full IA reviews piece
|
|
10
|
+
*/
|
|
11
|
+
export declare class IAReviews extends LitElement {
|
|
12
|
+
/** GLOBAL/REVIEW-RENDERING PROPERTIES */
|
|
13
|
+
identifier?: string;
|
|
14
|
+
reviews: Review[];
|
|
15
|
+
reviewsDisabled: boolean;
|
|
16
|
+
reviewsFrozen: boolean;
|
|
17
|
+
canDelete: boolean;
|
|
18
|
+
displayReviewsByDefault: boolean;
|
|
19
|
+
maxSubjectLength?: number;
|
|
20
|
+
maxBodyLength?: number;
|
|
21
|
+
baseHost: string;
|
|
22
|
+
/** REVIEW FORM PROPERTIES */
|
|
23
|
+
token: string;
|
|
24
|
+
endpointPath: string;
|
|
25
|
+
/** Form submitter's screenname, if applicable */
|
|
26
|
+
submitterScreenname: string;
|
|
27
|
+
/** Form submitter's itemname, if applicable */
|
|
28
|
+
submitterItemname?: string;
|
|
29
|
+
recaptchaManager?: RecaptchaManagerInterface;
|
|
30
|
+
bypassRecaptcha: boolean;
|
|
31
|
+
reviewSubmissionError?: string;
|
|
32
|
+
reviewAddEditRequested: boolean;
|
|
33
|
+
fetchHandler: FetchHandlerInterface;
|
|
34
|
+
displayReviewForm: boolean;
|
|
35
|
+
private displayReviews;
|
|
36
|
+
private filteredReviews;
|
|
37
|
+
private currentReview?;
|
|
38
|
+
private reviewsCount;
|
|
39
|
+
private recaptchaActivated;
|
|
40
|
+
render(): HTMLTemplateResult;
|
|
41
|
+
protected willUpdate(changed: PropertyValues): void;
|
|
42
|
+
private get reviewsDisabledTemplate();
|
|
43
|
+
private get noReviewsMsgTemplate();
|
|
44
|
+
private get displayReviewsMsgTemplate();
|
|
45
|
+
/**
|
|
46
|
+
* Renders the review form, passing along all necessary properties; this will also render
|
|
47
|
+
* the patron's own review if applicable and/or following submission.
|
|
48
|
+
*/
|
|
49
|
+
private get editableCurrentReviewTemplate();
|
|
50
|
+
/** Sorts the reviews and splits the patron's own review out of the reviews array */
|
|
51
|
+
private sortFilterReviews;
|
|
52
|
+
/** Sorts reviews by create date for render */
|
|
53
|
+
private sortReviews;
|
|
54
|
+
private renderReview;
|
|
55
|
+
/** Prepare the review form for adding or editing */
|
|
56
|
+
private addEditReview;
|
|
57
|
+
/** Handles successful review submission */
|
|
58
|
+
private handleReviewUpdate;
|
|
59
|
+
/** Closes the review form if requested */
|
|
60
|
+
private handleEditCanceled;
|
|
61
|
+
static get styles(): CSSResultGroup;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=ia-reviews.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ia-reviews.d.ts","sourceRoot":"","sources":["../../../../src/elements/ia-reviews/ia-reviews.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,cAAc,EAEd,kBAAkB,EAClB,UAAU,EAEV,cAAc,EACf,MAAM,KAAK,CAAC;AAKb,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AAChE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AACpF,OAAO,EACL,qBAAqB,EAEtB,MAAM,gCAAgC,CAAC;AAExC,OAAO,mCAAmC,CAAC;AAE3C,OAAO,aAAa,CAAC;AACrB,OAAO,kBAAkB,CAAC;AAE1B;;GAEG;AACH,qBACa,SAAU,SAAQ,UAAU;IACvC,yCAAyC;IAEb,UAAU,CAAC,EAAE,MAAM,CAAC;IAGrB,OAAO,EAAE,MAAM,EAAE,CAAM;IAGrB,eAAe,UAAS;IAGxB,aAAa,UAAS;IAGtB,SAAS,UAAS;IAGlB,uBAAuB,UAAS;IAGjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAG1B,aAAa,CAAC,EAAE,MAAM,CAAC;IAGvB,QAAQ,SAAyB;IAE7D,6BAA6B;IAED,KAAK,EAAE,MAAM,CAAM;IAGnB,YAAY,EAAE,MAAM,CAAuB;IAEvE,iDAAiD;IACrB,mBAAmB,EAAE,MAAM,CAAe;IAEtE,+CAA+C;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAG3B,gBAAgB,CAAC,EAAE,yBAAyB,CAAC;IAG5C,eAAe,EAAE,OAAO,CAAS;IAGlC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAG9B,sBAAsB,EAAE,OAAO,CAAS;IAGzC,YAAY,EAAE,qBAAqB,CACxC;IAIvB,iBAAiB,EAAE,OAAO,CAAS;IAInC,OAAO,CAAC,cAAc,CAAkB;IAIxC,OAAO,CAAC,eAAe,CAAgB;IAIvC,OAAO,CAAC,aAAa,CAAC,CAAS;IAI/B,OAAO,CAAC,YAAY,CAAa;IAIjC,OAAO,CAAC,kBAAkB,CAAkB;IAE5C,MAAM;IAuBN,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAqBnD,OAAO,KAAK,uBAAuB,GAIlC;IAGD,OAAO,KAAK,oBAAoB,GAuB/B;IAGD,OAAO,KAAK,yBAAyB,GAiBpC;IAED;;;OAGG;IACH,OAAO,KAAK,6BAA6B,GA4BxC;IAED,oFAAoF;IACpF,OAAO,CAAC,iBAAiB;IAiBzB,8CAA8C;IAC9C,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,YAAY;IAapB,oDAAoD;IACpD,OAAO,CAAC,aAAa;IAKrB,2CAA2C;IAC3C,OAAO,CAAC,kBAAkB;IAS1B,0CAA0C;IAC1C,OAAO,CAAC,kBAAkB;IAS1B,MAAM,KAAK,MAAM,IAAI,cAAc,CAuDlC;CACF"}
|