@pie-players/pie-players-shared 0.3.73 → 0.3.75
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 +30 -2
- package/dist/components/vendor/nds/README.md +7 -5
- package/dist/config/profile.d.ts +0 -2
- package/dist/config/profile.js +2 -8
- package/dist/i18n/index.d.ts +2 -3
- package/dist/i18n/index.js +2 -3
- package/dist/i18n/messages/en-US.d.ts +11 -24
- package/dist/i18n/messages/en-US.js +13 -26
- package/dist/i18n/messages/nl-NL.d.ts +7 -24
- package/dist/i18n/messages/nl-NL.js +9 -26
- package/dist/i18n/provider.d.ts +4 -5
- package/dist/i18n/provider.js +4 -5
- package/dist/i18n/types.d.ts +4 -5
- package/dist/index.d.ts +4 -2
- package/dist/index.js +3 -1
- package/dist/instrumentation/index.d.ts +5 -4
- package/dist/instrumentation/index.js +5 -4
- package/dist/instrumentation/new-relic-agent.d.ts +20 -0
- package/dist/instrumentation/new-relic-agent.js +24 -0
- package/dist/instrumentation/providers/BaseInstrumentationProvider.d.ts +5 -4
- package/dist/instrumentation/providers/NewRelicInstrumentationProvider.d.ts +7 -7
- package/dist/instrumentation/providers/NewRelicInstrumentationProvider.js +21 -32
- package/dist/instrumentation/types.d.ts +7 -3
- package/dist/loader-config.d.ts +16 -6
- package/dist/loaders/controller-loading.d.ts +14 -0
- package/dist/loaders/controller-loading.js +12 -0
- package/dist/loaders/defaults.d.ts +10 -0
- package/dist/loaders/defaults.js +10 -0
- package/dist/loaders/element-loader.d.ts +20 -8
- package/dist/loaders/element-loader.js +102 -36
- package/dist/loaders/element-package-policy.d.ts +2 -0
- package/dist/loaders/element-package-policy.js +2 -1
- package/dist/loaders/esm-adapter.d.ts +29 -0
- package/dist/loaders/esm-adapter.js +635 -102
- package/dist/loaders/iife-adapter.d.ts +0 -5
- package/dist/loaders/iife-adapter.js +3 -9
- package/dist/loaders/index.d.ts +12 -3
- package/dist/loaders/index.js +9 -3
- package/dist/loaders/mathjax-events.d.ts +22 -0
- package/dist/loaders/mathjax-events.js +65 -0
- package/dist/loaders/module-shim.d.ts +12 -0
- package/dist/loaders/module-shim.js +12 -0
- package/dist/loaders/preloaded-alignment.d.ts +24 -0
- package/dist/loaders/preloaded-alignment.js +57 -0
- package/dist/loaders/preloaded-authored-tags.d.ts +26 -0
- package/dist/loaders/preloaded-authored-tags.js +69 -0
- package/dist/loaders/preloaded-registration.d.ts +72 -0
- package/dist/loaders/preloaded-registration.js +141 -0
- package/dist/media/index.d.ts +69 -0
- package/dist/media/index.js +194 -0
- package/dist/pie/authoring.d.ts +1 -1
- package/dist/pie/authoring.js +25 -18
- package/dist/pie/element-announcements.d.ts +39 -0
- package/dist/pie/element-announcements.js +67 -0
- package/dist/pie/element-observer.d.ts +3 -1
- package/dist/pie/element-observer.js +1 -0
- package/dist/pie/elements-rendered.d.ts +25 -0
- package/dist/pie/elements-rendered.js +96 -0
- package/dist/pie/index.d.ts +8 -10
- package/dist/pie/index.js +9 -10
- package/dist/pie/initialization.js +13 -22
- package/dist/pie/initialize-element.d.ts +3 -0
- package/dist/pie/initialize-element.js +3 -4
- package/dist/pie/instrumentation-event-bridge.js +23 -1
- package/dist/pie/instrumentation-event-map.js +11 -25
- package/dist/pie/instrumentation-provider-resolution.d.ts +2 -1
- package/dist/pie/instrumentation-provider-resolution.js +0 -1
- package/dist/pie/item-controller.js +4 -0
- package/dist/pie/item-session-contract.d.ts +8 -0
- package/dist/pie/item-session-contract.js +30 -9
- package/dist/pie/logger.d.ts +6 -0
- package/dist/pie/logger.js +10 -0
- package/dist/pie/markup-math.d.ts +20 -0
- package/dist/pie/markup-math.js +118 -0
- package/dist/pie/math-assets.d.ts +48 -0
- package/dist/pie/math-assets.js +81 -0
- package/dist/pie/math-rendering.d.ts +10 -21
- package/dist/pie/math-rendering.js +50 -35
- package/dist/pie/registry.d.ts +13 -1
- package/dist/pie/registry.js +39 -1
- package/dist/pie/resource-monitor.d.ts +6 -33
- package/dist/pie/resource-monitor.js +14 -213
- package/dist/pie/scoring.d.ts +12 -8
- package/dist/pie/scoring.js +21 -24
- package/dist/pie/session-commit.d.ts +16 -0
- package/dist/pie/session-commit.js +34 -6
- package/dist/pie/session-snapshot.d.ts +80 -0
- package/dist/pie/session-snapshot.js +166 -0
- package/dist/pie/stages.d.ts +10 -47
- package/dist/pie/stages.js +10 -47
- package/dist/pie/tag-names.d.ts +1 -0
- package/dist/pie/tag-names.js +1 -0
- package/dist/pie/types.d.ts +4 -5
- package/dist/pie/types.js +1 -0
- package/dist/pie/updates.d.ts +2 -2
- package/dist/pie/updates.js +33 -15
- package/dist/pie/versioned-tag.d.ts +4 -0
- package/dist/pie/versioned-tag.js +4 -0
- package/dist/security/index.d.ts +2 -3
- package/dist/security/index.js +2 -3
- package/dist/security/sanitize-item-markup.d.ts +4 -2
- package/dist/security/sanitize-item-markup.js +48 -6
- package/dist/security/sanitize-svg-icon.d.ts +0 -2
- package/dist/security/sanitize-svg-icon.js +0 -5
- package/dist/security/wrap-overwide-images.js +19 -0
- package/dist/security/wrap-overwide.d.ts +13 -0
- package/dist/security/wrap-overwide.js +63 -3
- package/dist/timed-media/policy.js +5 -16
- package/dist/types/index.d.ts +67 -423
- package/dist/types/index.js +0 -68
- package/dist/ui/attribute-coercion.d.ts +12 -0
- package/dist/ui/attribute-coercion.js +33 -0
- package/dist/ui/content-styles.d.ts +18 -16
- package/dist/ui/content-styles.js +67 -36
- package/dist/ui/overlay-containment.d.ts +31 -0
- package/dist/ui/overlay-containment.js +63 -0
- package/dist/ui/overlay-placement.d.ts +110 -0
- package/dist/ui/overlay-placement.js +222 -0
- package/dist/ui/pointer-gesture.d.ts +32 -0
- package/dist/ui/pointer-gesture.js +56 -0
- package/dist/ui/pointer-rotate.d.ts +29 -0
- package/dist/ui/pointer-rotate.js +39 -0
- package/package.json +23 -18
- package/dist/pie/component-context.d.ts +0 -21
- package/dist/pie/component-context.js +0 -29
- package/dist/pie/player-initializer.d.ts +0 -54
- package/dist/pie/player-initializer.js +0 -122
- package/dist/pie/stage-tracker.d.ts +0 -50
- package/dist/pie/stage-tracker.js +0 -105
- package/dist/security/wrap-model-rich-content.d.ts +0 -1
- package/dist/security/wrap-model-rich-content.js +0 -40
- package/dist/server/npm-auth-env.d.ts +0 -13
- package/dist/server/npm-auth-env.js +0 -64
- package/dist/server/npm-registry.d.ts +0 -7
- package/dist/server/npm-registry.js +0 -59
- package/dist/ui/debug-panel-persistence.d.ts +0 -17
- package/dist/ui/debug-panel-persistence.js +0 -37
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* or supply their own sanitizer function if they need a stricter / looser
|
|
8
8
|
* allow-list.
|
|
9
9
|
*/
|
|
10
|
+
import { markAuthoredColors } from "@pie-element/shared-utils";
|
|
10
11
|
import DOMPurify from "dompurify";
|
|
11
12
|
import { SANITIZER_FORBIDDEN_ATTRS, SANITIZER_FORBIDDEN_TAGS, } from "./sanitize-forbidden-lists.js";
|
|
12
13
|
import { installStyleAttributeHook } from "./sanitize-style-attribute.js";
|
|
@@ -29,6 +30,40 @@ const BASE_ALLOWED_ATTRS = [
|
|
|
29
30
|
"lang",
|
|
30
31
|
"dir",
|
|
31
32
|
];
|
|
33
|
+
// MathML authored content uses that DOMPurify drops: elementary math, which
|
|
34
|
+
// `@pie-element/shared-math-rendering-mathjax` rewrites as a table before
|
|
35
|
+
// MathJax reads it, and `semantics`, `annotation`, `mprescripts` and `none`.
|
|
36
|
+
// `annotation-xml` stays out because it is an HTML integration point.
|
|
37
|
+
const MATHML_TAGS = new Set([
|
|
38
|
+
"mstack",
|
|
39
|
+
"mlongdiv",
|
|
40
|
+
"msgroup",
|
|
41
|
+
"msrow",
|
|
42
|
+
"msline",
|
|
43
|
+
"mscarries",
|
|
44
|
+
"mscarry",
|
|
45
|
+
"semantics",
|
|
46
|
+
"annotation",
|
|
47
|
+
"mprescripts",
|
|
48
|
+
"none",
|
|
49
|
+
]);
|
|
50
|
+
const MATHML_ATTRS = [
|
|
51
|
+
"stackalign",
|
|
52
|
+
"charalign",
|
|
53
|
+
"charspacing",
|
|
54
|
+
"longdivstyle",
|
|
55
|
+
"position",
|
|
56
|
+
"shift",
|
|
57
|
+
"location",
|
|
58
|
+
"crossout",
|
|
59
|
+
"leftoverhang",
|
|
60
|
+
"rightoverhang",
|
|
61
|
+
"mslinethickness",
|
|
62
|
+
"linebreak",
|
|
63
|
+
];
|
|
64
|
+
// Prefixed MathML such as `<m:math>`, which the HTML parser reads as unknown
|
|
65
|
+
// HTML elements and the math adapter re-creates as MathML.
|
|
66
|
+
const PREFIXED_TAG = /^[a-z_][\w.-]*:[a-z][\w.-]*$/;
|
|
32
67
|
const BASE_URI_SAFE_ATTRS = ["pie-id"];
|
|
33
68
|
const FORBIDDEN_TAGS = SANITIZER_FORBIDDEN_TAGS;
|
|
34
69
|
const FORBIDDEN_ATTRS = SANITIZER_FORBIDDEN_ATTRS;
|
|
@@ -57,6 +92,10 @@ function resolvePurifier() {
|
|
|
57
92
|
// `style` is URI-safe to DOMPurify, so nothing inside it is inspected
|
|
58
93
|
// without this. See sanitize-style-attribute.ts.
|
|
59
94
|
installStyleAttributeHook(purifierInstance);
|
|
95
|
+
// After the style filter, so only declarations that survive it are marked.
|
|
96
|
+
// The markers are the contract a color scheme's CSS overrides authored
|
|
97
|
+
// colors through, shared with element model HTML. (PIE-1119)
|
|
98
|
+
purifierInstance.addHook?.("afterSanitizeAttributes", (node) => markAuthoredColors(node));
|
|
60
99
|
return purifierInstance;
|
|
61
100
|
}
|
|
62
101
|
/**
|
|
@@ -67,6 +106,10 @@ function resolvePurifier() {
|
|
|
67
106
|
* `form`, `meta`, `link`).
|
|
68
107
|
* - Preserves PIE custom elements (`pie-*`) and any extra tags listed in
|
|
69
108
|
* `allowedCustomElements`.
|
|
109
|
+
* - Marks elements that carry an authored color, as `markAuthoredColors`
|
|
110
|
+
* in `@pie-element/shared-utils` describes, so a color scheme can override
|
|
111
|
+
* it. A host that opts out with `trust-markup` or supplies its own
|
|
112
|
+
* sanitizer gets no markers.
|
|
70
113
|
* - During SSR (no `window`) returns an empty string so untrusted markup
|
|
71
114
|
* never reaches the prerender output; the live renderer will re-run the
|
|
72
115
|
* sanitizer on hydrate.
|
|
@@ -80,8 +123,11 @@ export function sanitizeItemMarkup(markup, options = {}) {
|
|
|
80
123
|
const allowedCustomElements = (options.allowedCustomElements ?? []).map((name) => name.toLowerCase());
|
|
81
124
|
const explicitCustomElementSet = new Set(allowedCustomElements);
|
|
82
125
|
const result = purifier.sanitize(markup, {
|
|
83
|
-
|
|
84
|
-
|
|
126
|
+
// DOMPurify still removes a tag in FORBID_TAGS that this accepts.
|
|
127
|
+
ADD_TAGS: (tagName) => explicitCustomElementSet.has(tagName) ||
|
|
128
|
+
MATHML_TAGS.has(tagName) ||
|
|
129
|
+
PREFIXED_TAG.test(tagName),
|
|
130
|
+
ADD_ATTR: [...BASE_ALLOWED_ATTRS, ...MATHML_ATTRS],
|
|
85
131
|
ADD_URI_SAFE_ATTR: BASE_URI_SAFE_ATTRS,
|
|
86
132
|
FORBID_TAGS: FORBIDDEN_TAGS,
|
|
87
133
|
FORBID_ATTR: FORBIDDEN_ATTRS,
|
|
@@ -144,7 +190,3 @@ export function buildAuthoringAllowList(elementTagNames) {
|
|
|
144
190
|
}
|
|
145
191
|
return [...out];
|
|
146
192
|
}
|
|
147
|
-
/** Reset the memoised DOMPurify instance. Only intended for tests. */
|
|
148
|
-
export function resetPurifierForTesting() {
|
|
149
|
-
purifierInstance = null;
|
|
150
|
-
}
|
|
@@ -32,12 +32,31 @@ function buildAriaLabel(image) {
|
|
|
32
32
|
const trimmed = alt ? alt.trim() : "";
|
|
33
33
|
return trimmed ? `Scrollable image: ${trimmed}` : "Scrollable image";
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* A block-level image — an element's own `display: block`, a flex item — gets a
|
|
37
|
+
* block wrapper, so wrapping it adds no line box below it — a host reset of
|
|
38
|
+
* `img { display: block }` included. The live pass reads the computed display;
|
|
39
|
+
* markup parsed off-document has only the inline style, so the live pass reads
|
|
40
|
+
* a wrapper built there again.
|
|
41
|
+
*/
|
|
42
|
+
function imageLayoutClass(image) {
|
|
43
|
+
const view = image.ownerDocument?.defaultView;
|
|
44
|
+
const display = view
|
|
45
|
+
? view.getComputedStyle(image).display
|
|
46
|
+
: image.style?.display;
|
|
47
|
+
const blockLevel = !!display &&
|
|
48
|
+
!display.startsWith("inline") &&
|
|
49
|
+
display !== "none" &&
|
|
50
|
+
display !== "contents";
|
|
51
|
+
return blockLevel ? "pie-image-scroll-block" : null;
|
|
52
|
+
}
|
|
35
53
|
const IMAGE_SPEC = {
|
|
36
54
|
selector: "img",
|
|
37
55
|
wrapperTag: "span",
|
|
38
56
|
wrapperClass: "pie-image-scroll",
|
|
39
57
|
markupProbe: /<img\b/i,
|
|
40
58
|
buildAriaLabel,
|
|
59
|
+
layoutClass: imageLayoutClass,
|
|
41
60
|
};
|
|
42
61
|
/**
|
|
43
62
|
* Wrap every unwrapped `<img>` descendant of `root` with the shared
|
|
@@ -14,6 +14,11 @@
|
|
|
14
14
|
* the real divergence — an image has `alt`, a table has `<caption>`,
|
|
15
15
|
* `aria-label` and `aria-labelledby` — which is why it is a function rather than
|
|
16
16
|
* a template.
|
|
17
|
+
*
|
|
18
|
+
* Content inside an editing host is never wrapped, on either pass. The editor
|
|
19
|
+
* owns that DOM: ProseMirror reads the wrapper as a foreign mutation and redraws
|
|
20
|
+
* the node without it, so an observer-driven wrap and the editor undo each other
|
|
21
|
+
* for as long as the editor holds an image.
|
|
17
22
|
*/
|
|
18
23
|
/** What one content kind needs in order to be wrapped. */
|
|
19
24
|
export interface OverwideWrapSpec {
|
|
@@ -27,6 +32,11 @@ export interface OverwideWrapSpec {
|
|
|
27
32
|
markupProbe: RegExp;
|
|
28
33
|
/** The wrapper's accessible name for one node. */
|
|
29
34
|
buildAriaLabel: (node: Element) => string;
|
|
35
|
+
/**
|
|
36
|
+
* An extra wrapper class carrying the node's own layout, or `null` for none.
|
|
37
|
+
* Absent when every wrapper lays out alike.
|
|
38
|
+
*/
|
|
39
|
+
layoutClass?: (node: Element) => string | null;
|
|
30
40
|
}
|
|
31
41
|
export interface WrapOverwideOptions {
|
|
32
42
|
/**
|
|
@@ -40,6 +50,9 @@ export interface WrapOverwideOptions {
|
|
|
40
50
|
/**
|
|
41
51
|
* Wrap every unwrapped match under `root`. Returns the number newly wrapped so
|
|
42
52
|
* callers can short-circuit when nothing changed. Idempotent.
|
|
53
|
+
*
|
|
54
|
+
* Under a connected `root`, a wrapper whose layout was never read live gains
|
|
55
|
+
* the layout class this pass would have given it.
|
|
43
56
|
*/
|
|
44
57
|
export declare function wrapOverwideInElement(root: Element, spec: OverwideWrapSpec, options?: WrapOverwideOptions): number;
|
|
45
58
|
/**
|
|
@@ -14,8 +14,22 @@
|
|
|
14
14
|
* the real divergence — an image has `alt`, a table has `<caption>`,
|
|
15
15
|
* `aria-label` and `aria-labelledby` — which is why it is a function rather than
|
|
16
16
|
* a template.
|
|
17
|
+
*
|
|
18
|
+
* Content inside an editing host is never wrapped, on either pass. The editor
|
|
19
|
+
* owns that DOM: ProseMirror reads the wrapper as a foreign mutation and redraws
|
|
20
|
+
* the node without it, so an observer-driven wrap and the editor undo each other
|
|
21
|
+
* for as long as the editor holds an image.
|
|
17
22
|
*/
|
|
18
23
|
const PIE_CUSTOM_ELEMENT_TAG_REGEX = /^pie-/i;
|
|
24
|
+
/**
|
|
25
|
+
* An editing host: `contenteditable` in any state but `false`. A
|
|
26
|
+
* `contenteditable="false"` island inside a host still belongs to the host's
|
|
27
|
+
* editor — ProseMirror marks every leaf node that way, images included — so the
|
|
28
|
+
* test looks past such islands to the nearest host. A read-only editor root
|
|
29
|
+
* (`contenteditable="false"`) is no host; ProseMirror registers no DOM mutations
|
|
30
|
+
* while its view is not editable.
|
|
31
|
+
*/
|
|
32
|
+
const EDITING_HOST_SELECTOR = '[contenteditable]:not([contenteditable="false" i])';
|
|
19
33
|
function isInsidePieCustomElement(node, root) {
|
|
20
34
|
let ancestor = node.parentElement;
|
|
21
35
|
while (ancestor && ancestor !== root) {
|
|
@@ -26,9 +40,18 @@ function isInsidePieCustomElement(node, root) {
|
|
|
26
40
|
}
|
|
27
41
|
return false;
|
|
28
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Wrappers whose layout class was read from the live cascade. A wrapper built
|
|
45
|
+
* off-document saw only its node's inline style, so the first live pass to meet
|
|
46
|
+
* it reads the layout again; this set keeps that to once per wrapper.
|
|
47
|
+
*/
|
|
48
|
+
const liveLayoutRead = new WeakSet();
|
|
29
49
|
/**
|
|
30
50
|
* Wrap every unwrapped match under `root`. Returns the number newly wrapped so
|
|
31
51
|
* callers can short-circuit when nothing changed. Idempotent.
|
|
52
|
+
*
|
|
53
|
+
* Under a connected `root`, a wrapper whose layout was never read live gains
|
|
54
|
+
* the layout class this pass would have given it.
|
|
32
55
|
*/
|
|
33
56
|
export function wrapOverwideInElement(root, spec, options = {}) {
|
|
34
57
|
const { skipPieDescendants = false } = options;
|
|
@@ -38,22 +61,59 @@ export function wrapOverwideInElement(root, spec, options = {}) {
|
|
|
38
61
|
const ownerDocument = root.ownerDocument;
|
|
39
62
|
if (!ownerDocument)
|
|
40
63
|
return 0;
|
|
41
|
-
|
|
64
|
+
const readsLiveLayout = !!spec.layoutClass && !!ownerDocument.defaultView && root.isConnected;
|
|
65
|
+
const targets = [];
|
|
66
|
+
const unread = [];
|
|
42
67
|
for (const node of nodes) {
|
|
43
68
|
const parent = node.parentElement;
|
|
44
69
|
if (!parent)
|
|
45
70
|
continue;
|
|
46
71
|
// Idempotency — already wrapped.
|
|
47
|
-
|
|
72
|
+
const wrapped = parent.classList?.contains(spec.wrapperClass);
|
|
73
|
+
if (wrapped && (!readsLiveLayout || liveLayoutRead.has(parent)))
|
|
48
74
|
continue;
|
|
49
75
|
// Authored-markup pass: leave PIE custom-element internals alone.
|
|
50
76
|
if (skipPieDescendants && isInsidePieCustomElement(node, root))
|
|
51
77
|
continue;
|
|
78
|
+
if (node.closest(EDITING_HOST_SELECTOR))
|
|
79
|
+
continue;
|
|
80
|
+
if (!wrapped)
|
|
81
|
+
targets.push(node);
|
|
82
|
+
else if (!unread.some((other) => other.parentElement === parent))
|
|
83
|
+
unread.push(node);
|
|
84
|
+
}
|
|
85
|
+
// Layout is read for every node before the first insertion: a read after a
|
|
86
|
+
// wrap forces a fresh style resolution, one per node. A wrapper's own styles
|
|
87
|
+
// override its node's layout — the theme makes every wrapped image a block —
|
|
88
|
+
// so an existing wrapper is read with its classes lifted.
|
|
89
|
+
const unreadWrappers = unread.map((node) => node.parentElement);
|
|
90
|
+
const liftedClasses = unreadWrappers.map((wrapper) => wrapper.className);
|
|
91
|
+
for (const wrapper of unreadWrappers)
|
|
92
|
+
wrapper.className = "";
|
|
93
|
+
const layoutClasses = targets.map((node) => spec.layoutClass?.(node) ?? null);
|
|
94
|
+
const unreadLayoutClasses = unread.map((node) => spec.layoutClass?.(node) ?? null);
|
|
95
|
+
for (const [index, wrapper] of unreadWrappers.entries()) {
|
|
96
|
+
wrapper.className = liftedClasses[index];
|
|
97
|
+
const layoutClass = unreadLayoutClasses[index];
|
|
98
|
+
if (layoutClass)
|
|
99
|
+
wrapper.classList.add(layoutClass);
|
|
100
|
+
liveLayoutRead.add(wrapper);
|
|
101
|
+
}
|
|
102
|
+
let wrapped = 0;
|
|
103
|
+
for (const [index, node] of targets.entries()) {
|
|
104
|
+
const parent = node.parentElement;
|
|
105
|
+
if (!parent)
|
|
106
|
+
continue;
|
|
52
107
|
const wrapper = ownerDocument.createElement(spec.wrapperTag);
|
|
53
|
-
|
|
108
|
+
const layoutClass = layoutClasses[index];
|
|
109
|
+
wrapper.className = layoutClass
|
|
110
|
+
? `${spec.wrapperClass} ${layoutClass}`
|
|
111
|
+
: spec.wrapperClass;
|
|
54
112
|
wrapper.setAttribute("tabindex", "0");
|
|
55
113
|
wrapper.setAttribute("role", "region");
|
|
56
114
|
wrapper.setAttribute("aria-label", spec.buildAriaLabel(node));
|
|
115
|
+
if (readsLiveLayout)
|
|
116
|
+
liveLayoutRead.add(wrapper);
|
|
57
117
|
parent.insertBefore(wrapper, node);
|
|
58
118
|
wrapper.appendChild(node);
|
|
59
119
|
wrapped += 1;
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* reports them as a framework error and delivers as an ordinary section, which is
|
|
7
7
|
* loud without costing the learner the content.
|
|
8
8
|
*/
|
|
9
|
+
import { normalizeMediaFragment } from "../media/index.js";
|
|
9
10
|
/**
|
|
10
11
|
* Applied when `playbackPolicy` is absent entirely. The restrictive values are
|
|
11
12
|
* the defaults because a timed-media section is authored to sequence: a section
|
|
@@ -43,21 +44,6 @@ function isCorrectnessCondition(condition) {
|
|
|
43
44
|
function trimmed(value) {
|
|
44
45
|
return typeof value === "string" ? value.trim() : "";
|
|
45
46
|
}
|
|
46
|
-
function normalizeRange(value) {
|
|
47
|
-
if (!value || typeof value !== "object")
|
|
48
|
-
return null;
|
|
49
|
-
const raw = value;
|
|
50
|
-
const start = Number(raw.startSeconds);
|
|
51
|
-
if (!Number.isFinite(start) || start < 0)
|
|
52
|
-
return null;
|
|
53
|
-
const end = Number(raw.endSeconds);
|
|
54
|
-
// An end at or before the start is a window that can never contain a
|
|
55
|
-
// position, so it is treated as no end — the same rule
|
|
56
|
-
// `normalizeMediaFragment` applies in the toolkit, kept identical on purpose.
|
|
57
|
-
if (!Number.isFinite(end) || end <= start)
|
|
58
|
-
return { startSeconds: start };
|
|
59
|
-
return { startSeconds: start, endSeconds: end };
|
|
60
|
-
}
|
|
61
47
|
function normalizePlaybackPolicy(value) {
|
|
62
48
|
if (value === undefined || value === null) {
|
|
63
49
|
return { policy: { ...TIMED_MEDIA_PLAYBACK_POLICY_DEFAULTS }, error: null };
|
|
@@ -179,7 +165,10 @@ export function normalizeTimedMediaSectionData(args) {
|
|
|
179
165
|
continue;
|
|
180
166
|
}
|
|
181
167
|
seenIdentifiers.add(identifier);
|
|
182
|
-
|
|
168
|
+
// The same rule as every other authored media range: an end at or before
|
|
169
|
+
// the start is a window that can never contain a position, so it is
|
|
170
|
+
// treated as no end.
|
|
171
|
+
const range = normalizeMediaFragment(cue.range);
|
|
183
172
|
if (!range) {
|
|
184
173
|
errors.push({
|
|
185
174
|
code: "invalid-cue-range",
|