@internetarchive/elements 1.1.3-webdev-9240.0 → 1.1.3
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-status-indicator/ia-status-indicator.d.ts +16 -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 +136 -8
- package/dist/src/elements/ia-status-indicator/ia-status-indicator.js.map +1 -1
- package/package.json +1 -9
- package/dist/src/elements/ia-reviews/assets/delete-icon.svg +0 -8
- package/dist/src/elements/ia-reviews/assets/star-basic.svg +0 -6
- package/dist/src/elements/ia-reviews/assets/star-selected.svg +0 -8
- package/dist/src/elements/ia-reviews/assets/star-unselected.svg +0 -8
- package/dist/src/elements/ia-reviews/ia-review-form.d.ts +0 -103
- package/dist/src/elements/ia-reviews/ia-review-form.d.ts.map +0 -1
- package/dist/src/elements/ia-reviews/ia-review-form.js +0 -685
- package/dist/src/elements/ia-reviews/ia-review-form.js.map +0 -1
- package/dist/src/elements/ia-reviews/ia-review.d.ts +0 -51
- package/dist/src/elements/ia-reviews/ia-review.d.ts.map +0 -1
- package/dist/src/elements/ia-reviews/ia-review.js +0 -344
- package/dist/src/elements/ia-reviews/ia-review.js.map +0 -1
- package/dist/src/elements/ia-reviews/ia-reviews.d.ts +0 -68
- package/dist/src/elements/ia-reviews/ia-reviews.d.ts.map +0 -1
- package/dist/src/elements/ia-reviews/ia-reviews.js +0 -354
- package/dist/src/elements/ia-reviews/ia-reviews.js.map +0 -1
- package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.d.ts +0 -23
- package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.d.ts.map +0 -1
- package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.js +0 -37
- package/dist/src/elements/ia-reviews/mocks/mock-fetch-handler.js.map +0 -1
- 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/dist/src/elements/ia-reviews/utils/collapse-space.d.ts +0 -13
- package/dist/src/elements/ia-reviews/utils/collapse-space.d.ts.map +0 -1
- package/dist/src/elements/ia-reviews/utils/collapse-space.js +0 -19
- package/dist/src/elements/ia-reviews/utils/collapse-space.js.map +0 -1
- package/dist/src/elements/ia-reviews/utils/friendly-truncate.d.ts +0 -14
- package/dist/src/elements/ia-reviews/utils/friendly-truncate.d.ts.map +0 -1
- package/dist/src/elements/ia-reviews/utils/friendly-truncate.js +0 -65
- package/dist/src/elements/ia-reviews/utils/friendly-truncate.js.map +0 -1
- package/dist/src/elements/ia-reviews/utils/link-urls-in-text.d.ts +0 -9
- package/dist/src/elements/ia-reviews/utils/link-urls-in-text.d.ts.map +0 -1
- package/dist/src/elements/ia-reviews/utils/link-urls-in-text.js +0 -40
- package/dist/src/elements/ia-reviews/utils/link-urls-in-text.js.map +0 -1
- package/dist/src/elements/ia-reviews/utils/sanitize-review-body.d.ts +0 -9
- package/dist/src/elements/ia-reviews/utils/sanitize-review-body.d.ts.map +0 -1
- package/dist/src/elements/ia-reviews/utils/sanitize-review-body.js +0 -29
- package/dist/src/elements/ia-reviews/utils/sanitize-review-body.js.map +0 -1
- package/dist/src/elements/ia-reviews/utils/truncate-screenname.d.ts +0 -13
- package/dist/src/elements/ia-reviews/utils/truncate-screenname.d.ts.map +0 -1
- package/dist/src/elements/ia-reviews/utils/truncate-screenname.js +0 -19
- package/dist/src/elements/ia-reviews/utils/truncate-screenname.js.map +0 -1
- package/dist/src/elements/index.d.ts +0 -43
- package/dist/src/elements/index.d.ts.map +0 -1
- package/dist/src/elements/index.js +0 -43
- package/dist/src/elements/index.js.map +0 -1
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { msg } from '@lit/localize';
|
|
2
|
-
import { IaFetchHandler } from '@internetarchive/fetch-handler';
|
|
3
|
-
/** The endpoints the legacy details page serves */
|
|
4
|
-
const LEGACY_SUBMIT_PATH = '/write-review.php';
|
|
5
|
-
const LEGACY_DELETE_PATH = '/edit-reviews.php';
|
|
6
|
-
/**
|
|
7
|
-
* Talks to the archive.org review endpoints.
|
|
8
|
-
*
|
|
9
|
-
* The CSRF token is left to the fetch handler: both operations opt into its automatic
|
|
10
|
-
* `X-CSRF-Token` header, which resolves the token per request.
|
|
11
|
-
*/
|
|
12
|
-
export class ReviewService {
|
|
13
|
-
constructor(options) {
|
|
14
|
-
this.fetchHandler = options?.fetchHandler ?? new IaFetchHandler();
|
|
15
|
-
this.baseHost = options?.baseHost ?? 'https://archive.org';
|
|
16
|
-
this.submitPath = options?.submitPath ?? LEGACY_SUBMIT_PATH;
|
|
17
|
-
this.deletePath = options?.deletePath ?? LEGACY_DELETE_PATH;
|
|
18
|
-
this.deleteMethod = options?.deleteMethod ?? 'POST';
|
|
19
|
-
}
|
|
20
|
-
/** @inheritdoc */
|
|
21
|
-
async submitReview(submission) {
|
|
22
|
-
const body = new URLSearchParams();
|
|
23
|
-
body.append('identifier', submission.identifier);
|
|
24
|
-
body.append('field_reviewtitle', submission.title);
|
|
25
|
-
body.append('field_reviewbody', submission.body);
|
|
26
|
-
body.append('field_stars', submission.stars ?? '0');
|
|
27
|
-
if (submission.recaptchaToken) {
|
|
28
|
-
body.append('g-recaptcha-response', submission.recaptchaToken);
|
|
29
|
-
}
|
|
30
|
-
// tells write-review.php the post came from the form rather than a direct visit
|
|
31
|
-
body.append('submitter', 'review-form');
|
|
32
|
-
return this.request(`${this.baseHost}${this.submitPath}`, {
|
|
33
|
-
method: 'POST',
|
|
34
|
-
body,
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
/** @inheritdoc */
|
|
38
|
-
async deleteReview(deletion) {
|
|
39
|
-
// Screennames can contain spaces and ampersands, so the parameters are
|
|
40
|
-
// encoded rather than interpolated straight into the query string.
|
|
41
|
-
const params = new URLSearchParams();
|
|
42
|
-
params.append('identifier', deletion.identifier);
|
|
43
|
-
params.append('deleteReviewer', deletion.reviewer);
|
|
44
|
-
if (deletion.reviewerItemname) {
|
|
45
|
-
params.append('deleteReviewerItemname', deletion.reviewerItemname);
|
|
46
|
-
}
|
|
47
|
-
const url = `${this.baseHost}${this.deletePath}?${params.toString()}`;
|
|
48
|
-
return this.request(url, { method: this.deleteMethod });
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Sends a credentialed request and reads the `{ success, error }` result out of it.
|
|
52
|
-
*/
|
|
53
|
-
async request(url, init) {
|
|
54
|
-
try {
|
|
55
|
-
const response = await this.fetchHandler.fetch(url, {
|
|
56
|
-
requestInit: {
|
|
57
|
-
method: init.method,
|
|
58
|
-
body: init.body,
|
|
59
|
-
credentials: 'include',
|
|
60
|
-
},
|
|
61
|
-
includeCsrfToken: true,
|
|
62
|
-
});
|
|
63
|
-
return await this.parseResult(response);
|
|
64
|
-
}
|
|
65
|
-
catch (e) {
|
|
66
|
-
console.error('Review request failed', e);
|
|
67
|
-
return { success: false, error: this.genericError };
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Reads a result out of a response.
|
|
72
|
-
*
|
|
73
|
-
* The status decides the outcome, so a rejected request can't read as a success. fetch
|
|
74
|
-
* resolves on a 4xx or 5xx, so that check can't be left to the catch. A JSON body supplies
|
|
75
|
-
* the patron-facing message; the legacy delete endpoint answers with an HTML page instead,
|
|
76
|
-
* and there the status is all there is to go on.
|
|
77
|
-
*/
|
|
78
|
-
async parseResult(response) {
|
|
79
|
-
let payload;
|
|
80
|
-
try {
|
|
81
|
-
payload = (await response.json());
|
|
82
|
-
}
|
|
83
|
-
catch {
|
|
84
|
-
payload = undefined;
|
|
85
|
-
}
|
|
86
|
-
if (!response.ok) {
|
|
87
|
-
return { success: false, error: payload?.error ?? this.genericError };
|
|
88
|
-
}
|
|
89
|
-
if (!payload || payload.success)
|
|
90
|
-
return { success: true };
|
|
91
|
-
return { success: false, error: payload.error ?? this.genericError };
|
|
92
|
-
}
|
|
93
|
-
get genericError() {
|
|
94
|
-
return msg('Sorry, something went wrong. Please try again later.');
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
//# sourceMappingURL=review-service.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"review-service.js","sourceRoot":"","sources":["../../../../src/elements/ia-reviews/review-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { msg } from '@lit/localize';\nimport { IaFetchHandler } from '@internetarchive/fetch-handler';\nimport type { FetchHandlerInterface } from '@internetarchive/fetch-handler';\n\nimport type {\n ReviewDeletion,\n ReviewServiceInterface,\n ReviewServiceResult,\n ReviewSubmission,\n} from './models';\n\nexport type ReviewServiceOptions = {\n /**\n * Handles retries and the CSRF token.\n *\n * Writing and deleting need a handler built with a `getCsrfToken` source, since that is what\n * supplies the `X-CSRF-Token` header these endpoints require. The token resolves per request,\n * so it doesn't have to be known when the service is constructed.\n */\n fetchHandler?: FetchHandlerInterface;\n\n /** Origin for the endpoints. Empty string keeps requests same-origin. */\n baseHost?: string;\n\n /** Path a review submission POSTs to */\n submitPath?: string;\n\n /** Path a review deletion goes to */\n deletePath?: string;\n\n /** Verb the delete endpoint expects */\n deleteMethod?: 'POST' | 'DELETE';\n};\n\n/** The endpoints the legacy details page serves */\nconst LEGACY_SUBMIT_PATH = '/write-review.php';\nconst LEGACY_DELETE_PATH = '/edit-reviews.php';\n\n/**\n * Talks to the archive.org review endpoints.\n *\n * The CSRF token is left to the fetch handler: both operations opt into its automatic\n * `X-CSRF-Token` header, which resolves the token per request.\n */\nexport class ReviewService implements ReviewServiceInterface {\n private fetchHandler: FetchHandlerInterface;\n\n private baseHost: string;\n\n private submitPath: string;\n\n private deletePath: string;\n\n private deleteMethod: 'POST' | 'DELETE';\n\n constructor(options?: ReviewServiceOptions) {\n this.fetchHandler = options?.fetchHandler ?? new IaFetchHandler();\n this.baseHost = options?.baseHost ?? 'https://archive.org';\n this.submitPath = options?.submitPath ?? LEGACY_SUBMIT_PATH;\n this.deletePath = options?.deletePath ?? LEGACY_DELETE_PATH;\n this.deleteMethod = options?.deleteMethod ?? 'POST';\n }\n\n /** @inheritdoc */\n async submitReview(\n submission: ReviewSubmission,\n ): Promise<ReviewServiceResult> {\n const body = new URLSearchParams();\n body.append('identifier', submission.identifier);\n body.append('field_reviewtitle', submission.title);\n body.append('field_reviewbody', submission.body);\n body.append('field_stars', submission.stars ?? '0');\n\n if (submission.recaptchaToken) {\n body.append('g-recaptcha-response', submission.recaptchaToken);\n }\n\n // tells write-review.php the post came from the form rather than a direct visit\n body.append('submitter', 'review-form');\n\n return this.request(`${this.baseHost}${this.submitPath}`, {\n method: 'POST',\n body,\n });\n }\n\n /** @inheritdoc */\n async deleteReview(deletion: ReviewDeletion): Promise<ReviewServiceResult> {\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 params.append('identifier', deletion.identifier);\n params.append('deleteReviewer', deletion.reviewer);\n if (deletion.reviewerItemname) {\n params.append('deleteReviewerItemname', deletion.reviewerItemname);\n }\n\n const url = `${this.baseHost}${this.deletePath}?${params.toString()}`;\n\n return this.request(url, { method: this.deleteMethod });\n }\n\n /**\n * Sends a credentialed request and reads the `{ success, error }` result out of it.\n */\n private async request(\n url: string,\n init: { method: string; body?: BodyInit },\n ): Promise<ReviewServiceResult> {\n try {\n const response = await this.fetchHandler.fetch(url, {\n requestInit: {\n method: init.method,\n body: init.body,\n credentials: 'include',\n },\n includeCsrfToken: true,\n });\n\n return await this.parseResult(response);\n } catch (e) {\n console.error('Review request failed', e);\n return { success: false, error: this.genericError };\n }\n }\n\n /**\n * Reads a result out of a response.\n *\n * The status decides the outcome, so a rejected request can't read as a success. fetch\n * resolves on a 4xx or 5xx, so that check can't be left to the catch. A JSON body supplies\n * the patron-facing message; the legacy delete endpoint answers with an HTML page instead,\n * and there the status is all there is to go on.\n */\n private async parseResult(response: Response): Promise<ReviewServiceResult> {\n let payload: ReviewServiceResult | undefined;\n try {\n payload = (await response.json()) as ReviewServiceResult;\n } catch {\n payload = undefined;\n }\n\n if (!response.ok) {\n return { success: false, error: payload?.error ?? this.genericError };\n }\n\n if (!payload || payload.success) return { success: true };\n\n return { success: false, error: payload.error ?? this.genericError };\n }\n\n private get genericError(): string {\n return msg('Sorry, something went wrong. Please try again later.');\n }\n}\n"]}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Trims the string, collapses runs of spaces and tabs down to one space, and
|
|
3
|
-
* turns runs of newlines and existing `<br>` tags into a single `<br />`.
|
|
4
|
-
*
|
|
5
|
-
* The whitespace patterns list only real whitespace. A pipe written into a
|
|
6
|
-
* character class here would be treated as whitespace too, and quietly
|
|
7
|
-
* disappear from any review body containing one.
|
|
8
|
-
*
|
|
9
|
-
* @param {string} str The string to transform
|
|
10
|
-
* @returns {string} The string with space collapsed
|
|
11
|
-
*/
|
|
12
|
-
export default function collapseSpace(str: string): string;
|
|
13
|
-
//# sourceMappingURL=collapse-space.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"collapse-space.d.ts","sourceRoot":"","sources":["../../../../../src/elements/ia-reviews/utils/collapse-space.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMzD"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Trims the string, collapses runs of spaces and tabs down to one space, and
|
|
3
|
-
* turns runs of newlines and existing `<br>` tags into a single `<br />`.
|
|
4
|
-
*
|
|
5
|
-
* The whitespace patterns list only real whitespace. A pipe written into a
|
|
6
|
-
* character class here would be treated as whitespace too, and quietly
|
|
7
|
-
* disappear from any review body containing one.
|
|
8
|
-
*
|
|
9
|
-
* @param {string} str The string to transform
|
|
10
|
-
* @returns {string} The string with space collapsed
|
|
11
|
-
*/
|
|
12
|
-
export default function collapseSpace(str) {
|
|
13
|
-
return str
|
|
14
|
-
.trim()
|
|
15
|
-
.replace(/[ \t]+/g, ' ')
|
|
16
|
-
.replace(/(?:\r?\n)+/g, '<br />')
|
|
17
|
-
.replace(/(<br[^>]*>(<\/br>)?)+/g, '<br />');
|
|
18
|
-
}
|
|
19
|
-
//# sourceMappingURL=collapse-space.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"collapse-space.js","sourceRoot":"","sources":["../../../../../src/elements/ia-reviews/utils/collapse-space.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,GAAW;IAC/C,OAAO,GAAG;SACP,IAAI,EAAE;SACN,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,OAAO,CAAC,aAAa,EAAE,QAAQ,CAAC;SAChC,OAAO,CAAC,wBAAwB,EAAE,QAAQ,CAAC,CAAC;AACjD,CAAC","sourcesContent":["/**\n * Trims the string, collapses runs of spaces and tabs down to one space, and\n * turns runs of newlines and existing `<br>` tags into a single `<br />`.\n *\n * The whitespace patterns list only real whitespace. A pipe written into a\n * character class here would be treated as whitespace too, and quietly\n * disappear from any review body containing one.\n *\n * @param {string} str The string to transform\n * @returns {string} The string with space collapsed\n */\nexport default function collapseSpace(str: string): string {\n return str\n .trim()\n .replace(/[ \\t]+/g, ' ')\n .replace(/(?:\\r?\\n)+/g, '<br />')\n .replace(/(<br[^>]*>(<\\/br>)?)+/g, '<br />');\n}\n"]}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Truncates a string, given the original string and a max length.
|
|
3
|
-
* Continues up to 20 chars after the limit to find the last space,
|
|
4
|
-
* if possible.
|
|
5
|
-
*
|
|
6
|
-
* Avoids breaking up anchor tags.
|
|
7
|
-
*
|
|
8
|
-
* @param {string} str The original string
|
|
9
|
-
* @param {number} maxLength The max length to truncate to
|
|
10
|
-
* @param {boolean} useSpaceTruncation Whether to truncate at the last space
|
|
11
|
-
* @returns {string} The truncated field
|
|
12
|
-
*/
|
|
13
|
-
export default function friendlyTruncate(str: string, maxLength?: number, useSpaceTruncation?: boolean): string;
|
|
14
|
-
//# sourceMappingURL=friendly-truncate.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"friendly-truncate.d.ts","sourceRoot":"","sources":["../../../../../src/elements/ia-reviews/utils/friendly-truncate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CACtC,GAAG,EAAE,MAAM,EACX,SAAS,GAAE,MAAY,EACvB,kBAAkB,GAAE,OAAc,GACjC,MAAM,CAoBR"}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Truncates a string, given the original string and a max length.
|
|
3
|
-
* Continues up to 20 chars after the limit to find the last space,
|
|
4
|
-
* if possible.
|
|
5
|
-
*
|
|
6
|
-
* Avoids breaking up anchor tags.
|
|
7
|
-
*
|
|
8
|
-
* @param {string} str The original string
|
|
9
|
-
* @param {number} maxLength The max length to truncate to
|
|
10
|
-
* @param {boolean} useSpaceTruncation Whether to truncate at the last space
|
|
11
|
-
* @returns {string} The truncated field
|
|
12
|
-
*/
|
|
13
|
-
export default function friendlyTruncate(str, maxLength = 100, useSpaceTruncation = true) {
|
|
14
|
-
if (str.length < maxLength)
|
|
15
|
-
return str;
|
|
16
|
-
let cutoffPoint = maxLength;
|
|
17
|
-
if (useSpaceTruncation) {
|
|
18
|
-
const lastSpace = str.indexOf(' ', maxLength);
|
|
19
|
-
const safeDistanceFromMax = lastSpace - maxLength <= 20;
|
|
20
|
-
// No need to truncate if the safe last space is at the end of the string
|
|
21
|
-
if (safeDistanceFromMax && lastSpace === str.length - 1) {
|
|
22
|
-
return str;
|
|
23
|
-
}
|
|
24
|
-
if (lastSpace !== -1 && safeDistanceFromMax) {
|
|
25
|
-
cutoffPoint = lastSpace;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return truncateTagSafe(str, cutoffPoint, maxLength);
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Utility function to prevent truncation in the middle of
|
|
32
|
-
* an anchor tag.
|
|
33
|
-
*
|
|
34
|
-
* @param {string} str The string to truncate
|
|
35
|
-
* @param {number} cutoffPoint The index currently selsected for truncation
|
|
36
|
-
* @param {number} maxLength The max length for the string
|
|
37
|
-
* @returns {string} The string, truncated either earlier or later to preserve anchor tags
|
|
38
|
-
*/
|
|
39
|
-
function truncateTagSafe(str, cutoffPoint, maxLength) {
|
|
40
|
-
let truncatedString = str.slice(0, cutoffPoint);
|
|
41
|
-
const openingAnchorTags = truncatedString.match(/<a/gi);
|
|
42
|
-
if (openingAnchorTags) {
|
|
43
|
-
const closingAnchorTags = truncatedString.match(/<\/a/gi);
|
|
44
|
-
if (!closingAnchorTags ||
|
|
45
|
-
closingAnchorTags.length < openingAnchorTags.length) {
|
|
46
|
-
const firstClosingTag = str.indexOf('</a>', cutoffPoint);
|
|
47
|
-
const safeDistanceFromMax = firstClosingTag - maxLength <= 20;
|
|
48
|
-
// No need to truncate if closing tag is at the end of the string
|
|
49
|
-
if (safeDistanceFromMax && str.length === firstClosingTag + 4) {
|
|
50
|
-
return str;
|
|
51
|
-
}
|
|
52
|
-
// Truncate at end of first closing tag if possible
|
|
53
|
-
if (firstClosingTag !== -1 && safeDistanceFromMax) {
|
|
54
|
-
truncatedString = str.slice(0, firstClosingTag + 4);
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
// Otherwise, truncate before last opening tag
|
|
58
|
-
const lastOpeningTag = truncatedString.lastIndexOf('<a');
|
|
59
|
-
truncatedString = str.slice(0, lastOpeningTag);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
return truncatedString.concat('...');
|
|
64
|
-
}
|
|
65
|
-
//# sourceMappingURL=friendly-truncate.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"friendly-truncate.js","sourceRoot":"","sources":["../../../../../src/elements/ia-reviews/utils/friendly-truncate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CACtC,GAAW,EACX,YAAoB,GAAG,EACvB,qBAA8B,IAAI;IAElC,IAAI,GAAG,CAAC,MAAM,GAAG,SAAS;QAAE,OAAO,GAAG,CAAC;IAEvC,IAAI,WAAW,GAAG,SAAS,CAAC;IAE5B,IAAI,kBAAkB,EAAE,CAAC;QACvB,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC9C,MAAM,mBAAmB,GAAG,SAAS,GAAG,SAAS,IAAI,EAAE,CAAC;QAExD,yEAAyE;QACzE,IAAI,mBAAmB,IAAI,SAAS,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxD,OAAO,GAAG,CAAC;QACb,CAAC;QAED,IAAI,SAAS,KAAK,CAAC,CAAC,IAAI,mBAAmB,EAAE,CAAC;YAC5C,WAAW,GAAG,SAAS,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,OAAO,eAAe,CAAC,GAAG,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,eAAe,CACtB,GAAW,EACX,WAAmB,EACnB,SAAiB;IAEjB,IAAI,eAAe,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IAEhD,MAAM,iBAAiB,GAAG,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACxD,IAAI,iBAAiB,EAAE,CAAC;QACtB,MAAM,iBAAiB,GAAG,eAAe,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAE1D,IACE,CAAC,iBAAiB;YAClB,iBAAiB,CAAC,MAAM,GAAG,iBAAiB,CAAC,MAAM,EACnD,CAAC;YACD,MAAM,eAAe,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;YACzD,MAAM,mBAAmB,GAAG,eAAe,GAAG,SAAS,IAAI,EAAE,CAAC;YAE9D,iEAAiE;YACjE,IAAI,mBAAmB,IAAI,GAAG,CAAC,MAAM,KAAK,eAAe,GAAG,CAAC,EAAE,CAAC;gBAC9D,OAAO,GAAG,CAAC;YACb,CAAC;YAED,mDAAmD;YACnD,IAAI,eAAe,KAAK,CAAC,CAAC,IAAI,mBAAmB,EAAE,CAAC;gBAClD,eAAe,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,GAAG,CAAC,CAAC,CAAC;YACtD,CAAC;iBAAM,CAAC;gBACN,8CAA8C;gBAC9C,MAAM,cAAc,GAAG,eAAe,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;gBACzD,eAAe,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACvC,CAAC","sourcesContent":["/**\n * Truncates a string, given the original string and a max length.\n * Continues up to 20 chars after the limit to find the last space,\n * if possible.\n *\n * Avoids breaking up anchor tags.\n *\n * @param {string} str The original string\n * @param {number} maxLength The max length to truncate to\n * @param {boolean} useSpaceTruncation Whether to truncate at the last space\n * @returns {string} The truncated field\n */\nexport default function friendlyTruncate(\n str: string,\n maxLength: number = 100,\n useSpaceTruncation: boolean = true,\n): string {\n if (str.length < maxLength) return str;\n\n let cutoffPoint = maxLength;\n\n if (useSpaceTruncation) {\n const lastSpace = str.indexOf(' ', maxLength);\n const safeDistanceFromMax = lastSpace - maxLength <= 20;\n\n // No need to truncate if the safe last space is at the end of the string\n if (safeDistanceFromMax && lastSpace === str.length - 1) {\n return str;\n }\n\n if (lastSpace !== -1 && safeDistanceFromMax) {\n cutoffPoint = lastSpace;\n }\n }\n\n return truncateTagSafe(str, cutoffPoint, maxLength);\n}\n\n/**\n * Utility function to prevent truncation in the middle of\n * an anchor tag.\n *\n * @param {string} str The string to truncate\n * @param {number} cutoffPoint The index currently selsected for truncation\n * @param {number} maxLength The max length for the string\n * @returns {string} The string, truncated either earlier or later to preserve anchor tags\n */\nfunction truncateTagSafe(\n str: string,\n cutoffPoint: number,\n maxLength: number,\n): string {\n let truncatedString = str.slice(0, cutoffPoint);\n\n const openingAnchorTags = truncatedString.match(/<a/gi);\n if (openingAnchorTags) {\n const closingAnchorTags = truncatedString.match(/<\\/a/gi);\n\n if (\n !closingAnchorTags ||\n closingAnchorTags.length < openingAnchorTags.length\n ) {\n const firstClosingTag = str.indexOf('</a>', cutoffPoint);\n const safeDistanceFromMax = firstClosingTag - maxLength <= 20;\n\n // No need to truncate if closing tag is at the end of the string\n if (safeDistanceFromMax && str.length === firstClosingTag + 4) {\n return str;\n }\n\n // Truncate at end of first closing tag if possible\n if (firstClosingTag !== -1 && safeDistanceFromMax) {\n truncatedString = str.slice(0, firstClosingTag + 4);\n } else {\n // Otherwise, truncate before last opening tag\n const lastOpeningTag = truncatedString.lastIndexOf('<a');\n truncatedString = str.slice(0, lastOpeningTag);\n }\n }\n }\n\n return truncatedString.concat('...');\n}\n"]}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Transforms any links in text into live clickable anchor tags.
|
|
3
|
-
* Adds rel="ugc nofollow" to each for spam mitigation.
|
|
4
|
-
*
|
|
5
|
-
* @param {string} text The text to be linked
|
|
6
|
-
* @returns {string} The text with live links added
|
|
7
|
-
*/
|
|
8
|
-
export default function linkUrlsInText(text: string): string;
|
|
9
|
-
//# sourceMappingURL=link-urls-in-text.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"link-urls-in-text.d.ts","sourceRoot":"","sources":["../../../../../src/elements/ia-reviews/utils/link-urls-in-text.ts"],"names":[],"mappings":"AAkBA;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuB3D"}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This is not designed to capture all valid URLs but simply the most common ones.
|
|
3
|
-
* Highlights:
|
|
4
|
-
* - Optional "http://" or "https://"
|
|
5
|
-
* - Capital letter only captured if at beginning of hostname, to avoid false positives when
|
|
6
|
-
* people omit spaces e.g. "It's great.Right?"
|
|
7
|
-
* - Unlimited hostname parts, separated by periods
|
|
8
|
-
* - Any number of subdirectories/paths
|
|
9
|
-
* - Optional querystring parameters
|
|
10
|
-
* - Optional anchor
|
|
11
|
-
*
|
|
12
|
-
* Quotes and angle brackets terminate a match. The match is interpolated into
|
|
13
|
-
* an anchor tag that gets rendered as raw HTML, so a quote inside one would
|
|
14
|
-
* close the href and let the rest of the text become attributes.
|
|
15
|
-
*/
|
|
16
|
-
const URL_REGEXP = /(http(s)?)?(:\/\/)?([a-zA-Z][-a-z0-9]*(\.[-a-z0-9]+)+(\/[^\s?#<>"']*)*(\?[^\s#<>"']*)?(#[^\s<>"']*)?)/;
|
|
17
|
-
/**
|
|
18
|
-
* Transforms any links in text into live clickable anchor tags.
|
|
19
|
-
* Adds rel="ugc nofollow" to each for spam mitigation.
|
|
20
|
-
*
|
|
21
|
-
* @param {string} text The text to be linked
|
|
22
|
-
* @returns {string} The text with live links added
|
|
23
|
-
*/
|
|
24
|
-
export default function linkUrlsInText(text) {
|
|
25
|
-
// Protect existing links by ignoring them in search. Keep this pattern free of
|
|
26
|
-
// lookbehind assertions: Safari below 16.4 treats one as a syntax error and
|
|
27
|
-
// fails to load the module at all.
|
|
28
|
-
const textWithExistingLinksPreserved = text.replace(/href="([^"]+)"/, (_match, url) => `href="${url.replace('.', '__DOT__')}"`);
|
|
29
|
-
// Add live links
|
|
30
|
-
const textWithLiveLinks = textWithExistingLinksPreserved.replace(URL_REGEXP, (match) => {
|
|
31
|
-
const url = match.match(/^(https|http)/) ? match : `https://${match}`;
|
|
32
|
-
// The attribute value is escaped as well as the pattern being quote-free,
|
|
33
|
-
// so the href stays a single attribute whatever the match contains.
|
|
34
|
-
const href = url.replace(/"/g, '"');
|
|
35
|
-
return `<a href="${href}" rel="ugc nofollow" target="_blank">${match}</a>`;
|
|
36
|
-
});
|
|
37
|
-
// Restore existing links
|
|
38
|
-
return textWithLiveLinks.replace('__DOT__', '.');
|
|
39
|
-
}
|
|
40
|
-
//# sourceMappingURL=link-urls-in-text.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"link-urls-in-text.js","sourceRoot":"","sources":["../../../../../src/elements/ia-reviews/utils/link-urls-in-text.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,GACd,uGAAuG,CAAC;AAE1G;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,IAAY;IACjD,+EAA+E;IAC/E,4EAA4E;IAC5E,mCAAmC;IACnC,MAAM,8BAA8B,GAAG,IAAI,CAAC,OAAO,CACjD,gBAAgB,EAChB,CAAC,MAAM,EAAE,GAAW,EAAE,EAAE,CAAC,SAAS,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,GAAG,CACjE,CAAC;IAEF,iBAAiB;IACjB,MAAM,iBAAiB,GAAG,8BAA8B,CAAC,OAAO,CAC9D,UAAU,EACV,CAAC,KAAK,EAAE,EAAE;QACR,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,KAAK,EAAE,CAAC;QACtE,0EAA0E;QAC1E,oEAAoE;QACpE,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACzC,OAAO,YAAY,IAAI,wCAAwC,KAAK,MAAM,CAAC;IAC7E,CAAC,CACF,CAAC;IAEF,yBAAyB;IACzB,OAAO,iBAAiB,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;AACnD,CAAC","sourcesContent":["/**\n * This is not designed to capture all valid URLs but simply the most common ones.\n * Highlights:\n * - Optional \"http://\" or \"https://\"\n * - Capital letter only captured if at beginning of hostname, to avoid false positives when\n * people omit spaces e.g. \"It's great.Right?\"\n * - Unlimited hostname parts, separated by periods\n * - Any number of subdirectories/paths\n * - Optional querystring parameters\n * - Optional anchor\n *\n * Quotes and angle brackets terminate a match. The match is interpolated into\n * an anchor tag that gets rendered as raw HTML, so a quote inside one would\n * close the href and let the rest of the text become attributes.\n */\nconst URL_REGEXP =\n /(http(s)?)?(:\\/\\/)?([a-zA-Z][-a-z0-9]*(\\.[-a-z0-9]+)+(\\/[^\\s?#<>\"']*)*(\\?[^\\s#<>\"']*)?(#[^\\s<>\"']*)?)/;\n\n/**\n * Transforms any links in text into live clickable anchor tags.\n * Adds rel=\"ugc nofollow\" to each for spam mitigation.\n *\n * @param {string} text The text to be linked\n * @returns {string} The text with live links added\n */\nexport default function linkUrlsInText(text: string): string {\n // Protect existing links by ignoring them in search. Keep this pattern free of\n // lookbehind assertions: Safari below 16.4 treats one as a syntax error and\n // fails to load the module at all.\n const textWithExistingLinksPreserved = text.replace(\n /href=\"([^\"]+)\"/,\n (_match, url: string) => `href=\"${url.replace('.', '__DOT__')}\"`,\n );\n\n // Add live links\n const textWithLiveLinks = textWithExistingLinksPreserved.replace(\n URL_REGEXP,\n (match) => {\n const url = match.match(/^(https|http)/) ? match : `https://${match}`;\n // The attribute value is escaped as well as the pattern being quote-free,\n // so the href stays a single attribute whatever the match contains.\n const href = url.replace(/\"/g, '"');\n return `<a href=\"${href}\" rel=\"ugc nofollow\" target=\"_blank\">${match}</a>`;\n },\n );\n\n // Restore existing links\n return textWithLiveLinks.replace('__DOT__', '.');\n}\n"]}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Uses DOMpurify to sanitize a given review body.
|
|
3
|
-
* Currently only allows a tags.
|
|
4
|
-
*
|
|
5
|
-
* @param {string} reviewBody The review to be sanitized
|
|
6
|
-
* @returns {string} The sanitized review
|
|
7
|
-
*/
|
|
8
|
-
export default function sanitizeReviewBody(reviewBody: string): string;
|
|
9
|
-
//# sourceMappingURL=sanitize-review-body.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize-review-body.d.ts","sourceRoot":"","sources":["../../../../../src/elements/ia-reviews/utils/sanitize-review-body.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAUrE"}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import DOMPurify from 'dompurify';
|
|
2
|
-
const ALLOWED_TAGS = ['a'];
|
|
3
|
-
/**
|
|
4
|
-
* Uses DOMpurify to sanitize a given review body.
|
|
5
|
-
* Currently only allows a tags.
|
|
6
|
-
*
|
|
7
|
-
* @param {string} reviewBody The review to be sanitized
|
|
8
|
-
* @returns {string} The sanitized review
|
|
9
|
-
*/
|
|
10
|
-
export default function sanitizeReviewBody(reviewBody) {
|
|
11
|
-
// DOMPurify is a shared singleton, so the hook is added around this one call
|
|
12
|
-
// and taken off again. Leaving it registered would stack up another copy per
|
|
13
|
-
// review and force these attributes onto every other caller's anchors too.
|
|
14
|
-
DOMPurify.addHook('afterSanitizeAttributes', forceExternalLinkAttributes);
|
|
15
|
-
try {
|
|
16
|
-
return DOMPurify.sanitize(reviewBody, { ALLOWED_TAGS: ALLOWED_TAGS });
|
|
17
|
-
}
|
|
18
|
-
finally {
|
|
19
|
-
DOMPurify.removeHook('afterSanitizeAttributes');
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
/** Marks links as untrusted user content and opens them away from the page. */
|
|
23
|
-
function forceExternalLinkAttributes(node) {
|
|
24
|
-
if (node.nodeName.toLowerCase() !== 'a')
|
|
25
|
-
return;
|
|
26
|
-
node.setAttribute('rel', 'ugc nofollow');
|
|
27
|
-
node.setAttribute('target', '_blank');
|
|
28
|
-
}
|
|
29
|
-
//# sourceMappingURL=sanitize-review-body.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize-review-body.js","sourceRoot":"","sources":["../../../../../src/elements/ia-reviews/utils/sanitize-review-body.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,WAAW,CAAC;AAElC,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,CAAC;AAE3B;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,UAAkB;IAC3D,6EAA6E;IAC7E,6EAA6E;IAC7E,2EAA2E;IAC3E,SAAS,CAAC,OAAO,CAAC,yBAAyB,EAAE,2BAA2B,CAAC,CAAC;IAC1E,IAAI,CAAC;QACH,OAAO,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC,CAAC;IACxE,CAAC;YAAS,CAAC;QACT,SAAS,CAAC,UAAU,CAAC,yBAAyB,CAAC,CAAC;IAClD,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,SAAS,2BAA2B,CAAC,IAAU;IAC7C,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,GAAG;QAAE,OAAO;IAC/C,IAAgB,CAAC,YAAY,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;IACrD,IAAgB,CAAC,YAAY,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AACrD,CAAC","sourcesContent":["import DOMPurify from 'dompurify';\n\nconst ALLOWED_TAGS = ['a'];\n\n/**\n * Uses DOMpurify to sanitize a given review body.\n * Currently only allows a tags.\n *\n * @param {string} reviewBody The review to be sanitized\n * @returns {string} The sanitized review\n */\nexport default function sanitizeReviewBody(reviewBody: string): string {\n // DOMPurify is a shared singleton, so the hook is added around this one call\n // and taken off again. Leaving it registered would stack up another copy per\n // review and force these attributes onto every other caller's anchors too.\n DOMPurify.addHook('afterSanitizeAttributes', forceExternalLinkAttributes);\n try {\n return DOMPurify.sanitize(reviewBody, { ALLOWED_TAGS: ALLOWED_TAGS });\n } finally {\n DOMPurify.removeHook('afterSanitizeAttributes');\n }\n}\n\n/** Marks links as untrusted user content and opens them away from the page. */\nfunction forceExternalLinkAttributes(node: Node): void {\n if (node.nodeName.toLowerCase() !== 'a') return;\n (node as Element).setAttribute('rel', 'ugc nofollow');\n (node as Element).setAttribute('target', '_blank');\n}\n"]}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { HTMLTemplateResult } from 'lit';
|
|
2
|
-
/**
|
|
3
|
-
* Truncates screenname as needed to ensure we only display the correct
|
|
4
|
-
* number of chars throughout site. Must be kept in sync with screenname
|
|
5
|
-
* limit in Account.inc.
|
|
6
|
-
*
|
|
7
|
-
* Adds a title tooltip with full screenname if truncated.
|
|
8
|
-
*
|
|
9
|
-
* @param {string} screenname Screenname to be truncated
|
|
10
|
-
* @returns {HTMLTemplateResult} String or HTML to be displayed
|
|
11
|
-
*/
|
|
12
|
-
export declare function truncateScreenname(screenname?: string): HTMLTemplateResult | string;
|
|
13
|
-
//# sourceMappingURL=truncate-screenname.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"truncate-screenname.d.ts","sourceRoot":"","sources":["../../../../../src/elements/ia-reviews/utils/truncate-screenname.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,kBAAkB,EAAE,MAAM,KAAK,CAAC;AAE/C;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,GAAE,MAAW,GACtB,kBAAkB,GAAG,MAAM,CAQ7B"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { html } from 'lit';
|
|
2
|
-
/**
|
|
3
|
-
* Truncates screenname as needed to ensure we only display the correct
|
|
4
|
-
* number of chars throughout site. Must be kept in sync with screenname
|
|
5
|
-
* limit in Account.inc.
|
|
6
|
-
*
|
|
7
|
-
* Adds a title tooltip with full screenname if truncated.
|
|
8
|
-
*
|
|
9
|
-
* @param {string} screenname Screenname to be truncated
|
|
10
|
-
* @returns {HTMLTemplateResult} String or HTML to be displayed
|
|
11
|
-
*/
|
|
12
|
-
export function truncateScreenname(screenname = '') {
|
|
13
|
-
const SCREENNAME_MAX_LENGTH = 40;
|
|
14
|
-
if (screenname.length <= SCREENNAME_MAX_LENGTH)
|
|
15
|
-
return screenname;
|
|
16
|
-
const truncatedScreenname = screenname.substring(0, SCREENNAME_MAX_LENGTH) + '...';
|
|
17
|
-
return html `<span title="${screenname}">${truncatedScreenname}</span>`;
|
|
18
|
-
}
|
|
19
|
-
//# sourceMappingURL=truncate-screenname.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"truncate-screenname.js","sourceRoot":"","sources":["../../../../../src/elements/ia-reviews/utils/truncate-screenname.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAsB,MAAM,KAAK,CAAC;AAE/C;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAChC,aAAqB,EAAE;IAEvB,MAAM,qBAAqB,GAAG,EAAE,CAAC;IAEjC,IAAI,UAAU,CAAC,MAAM,IAAI,qBAAqB;QAAE,OAAO,UAAU,CAAC;IAElE,MAAM,mBAAmB,GACvB,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,qBAAqB,CAAC,GAAG,KAAK,CAAC;IACzD,OAAO,IAAI,CAAA,gBAAgB,UAAU,KAAK,mBAAmB,SAAS,CAAC;AACzE,CAAC","sourcesContent":["import { html, HTMLTemplateResult } from 'lit';\n\n/**\n * Truncates screenname as needed to ensure we only display the correct\n * number of chars throughout site. Must be kept in sync with screenname\n * limit in Account.inc.\n *\n * Adds a title tooltip with full screenname if truncated.\n *\n * @param {string} screenname Screenname to be truncated\n * @returns {HTMLTemplateResult} String or HTML to be displayed\n */\nexport function truncateScreenname(\n screenname: string = '',\n): HTMLTemplateResult | string {\n const SCREENNAME_MAX_LENGTH = 40;\n\n if (screenname.length <= SCREENNAME_MAX_LENGTH) return screenname;\n\n const truncatedScreenname =\n screenname.substring(0, SCREENNAME_MAX_LENGTH) + '...';\n return html`<span title=\"${screenname}\">${truncatedScreenname}</span>`;\n}\n"]}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
export * from './ia-audio-element/ia-audio-element.js';
|
|
2
|
-
export * from './ia-audio-element/models.js';
|
|
3
|
-
export * from './ia-button/ia-button.js';
|
|
4
|
-
export * from './ia-combo-box/ia-combo-box.js';
|
|
5
|
-
export * from './ia-dropdown-search-bar/ia-dropdown-search-bar.js';
|
|
6
|
-
export * from './ia-expandable-search-bar/ia-expandable-search-bar.js';
|
|
7
|
-
export * from './ia-expandable-search-bar/ia-quick-search.js';
|
|
8
|
-
export * from './ia-expandable-search-bar/models.js';
|
|
9
|
-
export * from './ia-histogram-date-range/ia-histogram-date-range.js';
|
|
10
|
-
export * from './ia-histogram-date-range/models.js';
|
|
11
|
-
export * from './ia-image-viewer/ia-image-viewer.js';
|
|
12
|
-
export * from './ia-item-navigator/ia-item-navigator.js';
|
|
13
|
-
export * from './ia-item-navigator/menus/ia-itemnav-viewable-files-panel.js';
|
|
14
|
-
export * from './ia-item-navigator/menus/ia-itemnav-sort-files-button.js';
|
|
15
|
-
export * from './ia-item-navigator/menus/ia-itemnav-share-panel.js';
|
|
16
|
-
export * from './ia-playback-controls/ia-playback-controls.js';
|
|
17
|
-
export * from './ia-playback-controls/models.js';
|
|
18
|
-
export * from './ia-radio-player/ia-radio-player.js';
|
|
19
|
-
export * from './ia-radio-player/ia-search-results-switcher.js';
|
|
20
|
-
export * from './ia-radio-player/models.js';
|
|
21
|
-
export * from './ia-radio-player/search/backends/full-text-search-backend.js';
|
|
22
|
-
export * from './ia-radio-player/search/backends/full-text-search-response.js';
|
|
23
|
-
export * from './ia-radio-player/search/backends/local-search-backend.js';
|
|
24
|
-
export * from './ia-radio-player/search/backends/search-backend.js';
|
|
25
|
-
export * from './ia-radio-player/search/models.js';
|
|
26
|
-
export * from './ia-radio-player/search/search-handler.js';
|
|
27
|
-
export * from './ia-radio-player/search/search-helper.js';
|
|
28
|
-
export * from './ia-radio-player/search/transcript-index.js';
|
|
29
|
-
export * from './ia-reviews/ia-review.js';
|
|
30
|
-
export * from './ia-reviews/ia-review-form.js';
|
|
31
|
-
export * from './ia-reviews/ia-reviews.js';
|
|
32
|
-
export * from './ia-reviews/models.js';
|
|
33
|
-
export * from './ia-reviews/review-service.js';
|
|
34
|
-
export * from './ia-scrubber-bar/ia-scrubber-bar.js';
|
|
35
|
-
export * from './ia-scrubber-bar/ia-section-marker.js';
|
|
36
|
-
export * from './ia-scrubber-bar/models.js';
|
|
37
|
-
export * from './ia-transcript-view/duration-formatter.js';
|
|
38
|
-
export * from './ia-transcript-view/ia-transcript-entry.js';
|
|
39
|
-
export * from './ia-transcript-view/ia-transcript-view.js';
|
|
40
|
-
export * from './ia-transcript-view/models.js';
|
|
41
|
-
export * from './ia-waveform-progress/ia-waveform-progress.js';
|
|
42
|
-
export * from './ia-waveform-progress/models.js';
|
|
43
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/elements/index.ts"],"names":[],"mappings":"AAAA,cAAc,qCAAqC,CAAC;AACpD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iDAAiD,CAAC;AAChE,cAAc,qDAAqD,CAAC;AACpE,cAAc,4CAA4C,CAAC;AAC3D,cAAc,mCAAmC,CAAC;AAClD,cAAc,mDAAmD,CAAC;AAClE,cAAc,kCAAkC,CAAC;AACjD,cAAc,mCAAmC,CAAC;AAClD,cAAc,uCAAuC,CAAC;AACtD,cAAc,2DAA2D,CAAC;AAC1E,cAAc,wDAAwD,CAAC;AACvE,cAAc,kDAAkD,CAAC;AACjE,cAAc,6CAA6C,CAAC;AAC5D,cAAc,+BAA+B,CAAC;AAC9C,cAAc,mCAAmC,CAAC;AAClD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,0BAA0B,CAAC;AACzC,cAAc,4DAA4D,CAAC;AAC3E,cAAc,6DAA6D,CAAC;AAC5E,cAAc,wDAAwD,CAAC;AACvE,cAAc,kDAAkD,CAAC;AACjE,cAAc,iCAAiC,CAAC;AAChD,cAAc,yCAAyC,CAAC;AACxD,cAAc,wCAAwC,CAAC;AACvD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,0BAA0B,CAAC;AACzC,cAAc,yCAAyC,CAAC;AACxD,cAAc,0CAA0C,CAAC;AACzD,cAAc,yCAAyC,CAAC;AACxD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6CAA6C,CAAC;AAC5D,cAAc,+BAA+B,CAAC"}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
export * from './ia-audio-element/ia-audio-element.js';
|
|
2
|
-
export * from './ia-audio-element/models.js';
|
|
3
|
-
export * from './ia-button/ia-button.js';
|
|
4
|
-
export * from './ia-combo-box/ia-combo-box.js';
|
|
5
|
-
export * from './ia-dropdown-search-bar/ia-dropdown-search-bar.js';
|
|
6
|
-
export * from './ia-expandable-search-bar/ia-expandable-search-bar.js';
|
|
7
|
-
export * from './ia-expandable-search-bar/ia-quick-search.js';
|
|
8
|
-
export * from './ia-expandable-search-bar/models.js';
|
|
9
|
-
export * from './ia-histogram-date-range/ia-histogram-date-range.js';
|
|
10
|
-
export * from './ia-histogram-date-range/models.js';
|
|
11
|
-
export * from './ia-image-viewer/ia-image-viewer.js';
|
|
12
|
-
export * from './ia-item-navigator/ia-item-navigator.js';
|
|
13
|
-
export * from './ia-item-navigator/menus/ia-itemnav-viewable-files-panel.js';
|
|
14
|
-
export * from './ia-item-navigator/menus/ia-itemnav-sort-files-button.js';
|
|
15
|
-
export * from './ia-item-navigator/menus/ia-itemnav-share-panel.js';
|
|
16
|
-
export * from './ia-playback-controls/ia-playback-controls.js';
|
|
17
|
-
export * from './ia-playback-controls/models.js';
|
|
18
|
-
export * from './ia-radio-player/ia-radio-player.js';
|
|
19
|
-
export * from './ia-radio-player/ia-search-results-switcher.js';
|
|
20
|
-
export * from './ia-radio-player/models.js';
|
|
21
|
-
export * from './ia-radio-player/search/backends/full-text-search-backend.js';
|
|
22
|
-
export * from './ia-radio-player/search/backends/full-text-search-response.js';
|
|
23
|
-
export * from './ia-radio-player/search/backends/local-search-backend.js';
|
|
24
|
-
export * from './ia-radio-player/search/backends/search-backend.js';
|
|
25
|
-
export * from './ia-radio-player/search/models.js';
|
|
26
|
-
export * from './ia-radio-player/search/search-handler.js';
|
|
27
|
-
export * from './ia-radio-player/search/search-helper.js';
|
|
28
|
-
export * from './ia-radio-player/search/transcript-index.js';
|
|
29
|
-
export * from './ia-reviews/ia-review.js';
|
|
30
|
-
export * from './ia-reviews/ia-review-form.js';
|
|
31
|
-
export * from './ia-reviews/ia-reviews.js';
|
|
32
|
-
export * from './ia-reviews/models.js';
|
|
33
|
-
export * from './ia-reviews/review-service.js';
|
|
34
|
-
export * from './ia-scrubber-bar/ia-scrubber-bar.js';
|
|
35
|
-
export * from './ia-scrubber-bar/ia-section-marker.js';
|
|
36
|
-
export * from './ia-scrubber-bar/models.js';
|
|
37
|
-
export * from './ia-transcript-view/duration-formatter.js';
|
|
38
|
-
export * from './ia-transcript-view/ia-transcript-entry.js';
|
|
39
|
-
export * from './ia-transcript-view/ia-transcript-view.js';
|
|
40
|
-
export * from './ia-transcript-view/models.js';
|
|
41
|
-
export * from './ia-waveform-progress/ia-waveform-progress.js';
|
|
42
|
-
export * from './ia-waveform-progress/models.js';
|
|
43
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/elements/index.ts"],"names":[],"mappings":"AAAA,cAAc,qCAAqC,CAAC;AACpD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,iDAAiD,CAAC;AAChE,cAAc,qDAAqD,CAAC;AACpE,cAAc,4CAA4C,CAAC;AAC3D,cAAc,mCAAmC,CAAC;AAClD,cAAc,mDAAmD,CAAC;AAClE,cAAc,kCAAkC,CAAC;AACjD,cAAc,mCAAmC,CAAC;AAClD,cAAc,uCAAuC,CAAC;AACtD,cAAc,2DAA2D,CAAC;AAC1E,cAAc,wDAAwD,CAAC;AACvE,cAAc,kDAAkD,CAAC;AACjE,cAAc,6CAA6C,CAAC;AAC5D,cAAc,+BAA+B,CAAC;AAC9C,cAAc,mCAAmC,CAAC;AAClD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,0BAA0B,CAAC;AACzC,cAAc,4DAA4D,CAAC;AAC3E,cAAc,6DAA6D,CAAC;AAC5E,cAAc,wDAAwD,CAAC;AACvE,cAAc,kDAAkD,CAAC;AACjE,cAAc,iCAAiC,CAAC;AAChD,cAAc,yCAAyC,CAAC;AACxD,cAAc,wCAAwC,CAAC;AACvD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mCAAmC,CAAC;AAClD,cAAc,qCAAqC,CAAC;AACpD,cAAc,0BAA0B,CAAC;AACzC,cAAc,yCAAyC,CAAC;AACxD,cAAc,0CAA0C,CAAC;AACzD,cAAc,yCAAyC,CAAC;AACxD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6CAA6C,CAAC;AAC5D,cAAc,+BAA+B,CAAC","sourcesContent":["export * from './ia-audio-element/ia-audio-element';\nexport * from './ia-audio-element/models';\nexport * from './ia-button/ia-button';\nexport * from './ia-combo-box/ia-combo-box';\nexport * from './ia-dropdown-search-bar/ia-dropdown-search-bar';\nexport * from './ia-expandable-search-bar/ia-expandable-search-bar';\nexport * from './ia-expandable-search-bar/ia-quick-search';\nexport * from './ia-expandable-search-bar/models';\nexport * from './ia-histogram-date-range/ia-histogram-date-range';\nexport * from './ia-histogram-date-range/models';\nexport * from './ia-image-viewer/ia-image-viewer';\nexport * from './ia-item-navigator/ia-item-navigator';\nexport * from './ia-item-navigator/menus/ia-itemnav-viewable-files-panel';\nexport * from './ia-item-navigator/menus/ia-itemnav-sort-files-button';\nexport * from './ia-item-navigator/menus/ia-itemnav-share-panel';\nexport * from './ia-playback-controls/ia-playback-controls';\nexport * from './ia-playback-controls/models';\nexport * from './ia-radio-player/ia-radio-player';\nexport * from './ia-radio-player/ia-search-results-switcher';\nexport * from './ia-radio-player/models';\nexport * from './ia-radio-player/search/backends/full-text-search-backend';\nexport * from './ia-radio-player/search/backends/full-text-search-response';\nexport * from './ia-radio-player/search/backends/local-search-backend';\nexport * from './ia-radio-player/search/backends/search-backend';\nexport * from './ia-radio-player/search/models';\nexport * from './ia-radio-player/search/search-handler';\nexport * from './ia-radio-player/search/search-helper';\nexport * from './ia-radio-player/search/transcript-index';\nexport * from './ia-reviews/ia-review';\nexport * from './ia-reviews/ia-review-form';\nexport * from './ia-reviews/ia-reviews';\nexport * from './ia-reviews/models';\nexport * from './ia-reviews/review-service';\nexport * from './ia-scrubber-bar/ia-scrubber-bar';\nexport * from './ia-scrubber-bar/ia-section-marker';\nexport * from './ia-scrubber-bar/models';\nexport * from './ia-transcript-view/duration-formatter';\nexport * from './ia-transcript-view/ia-transcript-entry';\nexport * from './ia-transcript-view/ia-transcript-view';\nexport * from './ia-transcript-view/models';\nexport * from './ia-waveform-progress/ia-waveform-progress';\nexport * from './ia-waveform-progress/models';\n"]}
|