@pie-players/pie-assessment-toolkit 0.3.63 → 0.3.65
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 +92 -1
- package/dist/components/ItemToolBar.custom-element.js +1 -1
- package/dist/components/PieAssessmentToolkit.custom-element.js +11 -11
- package/dist/components/SectionToolBar.custom-element.js +1 -1
- package/dist/components/chunks/ItemToolBar-cckwpz6c.js +51 -0
- package/dist/components/chunks/ItemToolBar-pryf0rtz.js +22 -0
- package/dist/index.d.ts +10 -6
- package/dist/index.js +12 -4
- package/dist/policy/core/ToolPolicyEngine.d.ts +21 -0
- package/dist/policy/core/ToolPolicyEngine.js +27 -0
- package/dist/policy/core/feature-decision.d.ts +57 -0
- package/dist/policy/core/feature-decision.js +40 -0
- package/dist/policy/engine.d.ts +1 -0
- package/dist/policy/sources/PnpPolicySource.d.ts +22 -0
- package/dist/policy/sources/PnpPolicySource.js +41 -11
- package/dist/runtime/catalog-registration.d.ts +56 -1
- package/dist/runtime/catalog-registration.js +64 -31
- package/dist/runtime/composition-emit-scheduler.d.ts +78 -0
- package/dist/runtime/composition-emit-scheduler.js +154 -0
- package/dist/runtime/core/engine-resolver.d.ts +1 -1
- package/dist/services/AccessibilityCatalogResolver.d.ts +100 -4
- package/dist/services/AccessibilityCatalogResolver.js +183 -58
- package/dist/services/SSMLExtractor.js +28 -18
- package/dist/services/TTSService.d.ts +25 -0
- package/dist/services/TTSService.js +241 -45
- package/dist/services/ToolRegistry.d.ts +218 -8
- package/dist/services/ToolRegistry.js +124 -8
- package/dist/services/ToolkitCoordinator.d.ts +25 -3
- package/dist/services/ToolkitCoordinator.js +47 -6
- package/dist/services/catalog-media.d.ts +25 -0
- package/dist/services/catalog-media.js +101 -0
- package/dist/services/createDefaultToolRegistry.d.ts +25 -58
- package/dist/services/createDefaultToolRegistry.js +24 -104
- package/dist/services/defaultPersonalNeedsProfile.d.ts +20 -2
- package/dist/services/defaultPersonalNeedsProfile.js +21 -19
- package/dist/services/interfaces.d.ts +29 -2
- package/dist/services/pnp-standard-features.d.ts +1 -1
- package/dist/services/spoken-audio-cards.d.ts +54 -0
- package/dist/services/spoken-audio-cards.js +66 -0
- package/dist/services/tool-config-defaults.d.ts +7 -23
- package/dist/services/tool-config-defaults.js +7 -46
- package/dist/services/tool-config-validation.d.ts +1 -1
- package/dist/services/tool-config-validation.js +44 -4
- package/dist/services/tts/browser-provider.js +2 -1
- package/dist/services/tts/math-aware-text-processing.js +3 -3
- package/dist/services/tts/text-processing.d.ts +51 -0
- package/dist/services/tts/text-processing.js +117 -1
- package/dist/services/tts-runtime-config.js +7 -2
- package/dist/tools/internal.d.ts +34 -0
- package/dist/tools/internal.js +33 -0
- package/dist/tools/tool-tag-map.d.ts +15 -3
- package/dist/tools/tool-tag-map.js +21 -18
- package/package.json +14 -10
- package/dist/components/chunks/ItemToolBar-843902tp.js +0 -51
- package/dist/components/chunks/ItemToolBar-84nv78dy.js +0 -22
- package/dist/tools/registrations/accessibility-tools.d.ts +0 -34
- package/dist/tools/registrations/accessibility-tools.js +0 -217
- package/dist/tools/registrations/calculator.d.ts +0 -20
- package/dist/tools/registrations/calculator.js +0 -228
- package/dist/tools/registrations/interaction-tools.d.ts +0 -27
- package/dist/tools/registrations/interaction-tools.js +0 -143
- package/dist/tools/registrations/measurement-tools.d.ts +0 -24
- package/dist/tools/registrations/measurement-tools.js +0 -130
- package/dist/tools/registrations/subject-specific-tools.d.ts +0 -27
- package/dist/tools/registrations/subject-specific-tools.js +0 -158
- package/dist/tools/registrations/tts.d.ts +0 -21
- package/dist/tools/registrations/tts.js +0 -184
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation primitives shared by every catalog card whose payload references
|
|
3
|
+
* media.
|
|
4
|
+
*
|
|
5
|
+
* Extracted from `sign-language-cards.ts` when `spoken` cards gained a recorded
|
|
6
|
+
* audio form: both card types take authored, wire-facing URLs and hand them to a
|
|
7
|
+
* media element in the learner's browser, so both need the same scheme
|
|
8
|
+
* allow-list and the same "treat as absent, never as partially valid" posture.
|
|
9
|
+
* Two copies of a URL allow-list is one copy that gets a fix and one that does
|
|
10
|
+
* not.
|
|
11
|
+
*
|
|
12
|
+
* Part of PIE Assessment Toolkit.
|
|
13
|
+
*/
|
|
14
|
+
import type { MediaFragmentRange, MediaSource } from "@pie-players/pie-players-shared/types";
|
|
15
|
+
export declare function isSafeMediaSrc(raw: unknown): raw is string;
|
|
16
|
+
export declare function normalizeMediaSources(raw: unknown): MediaSource[];
|
|
17
|
+
export declare function normalizeMediaFragment(raw: unknown): MediaFragmentRange | undefined;
|
|
18
|
+
export declare function trimmedOrUndefined(value: unknown): string | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Apply a fragment range to a source URL as a Media Fragments URI, so one
|
|
21
|
+
* recording can serve several content nodes. Browsers honour the start offset;
|
|
22
|
+
* the end offset is enforced by the caller, because support for the end bound is
|
|
23
|
+
* inconsistent.
|
|
24
|
+
*/
|
|
25
|
+
export declare function applyMediaFragment(src: string, fragment?: MediaFragmentRange): string;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation primitives shared by every catalog card whose payload references
|
|
3
|
+
* media.
|
|
4
|
+
*
|
|
5
|
+
* Extracted from `sign-language-cards.ts` when `spoken` cards gained a recorded
|
|
6
|
+
* audio form: both card types take authored, wire-facing URLs and hand them to a
|
|
7
|
+
* media element in the learner's browser, so both need the same scheme
|
|
8
|
+
* allow-list and the same "treat as absent, never as partially valid" posture.
|
|
9
|
+
* Two copies of a URL allow-list is one copy that gets a fix and one that does
|
|
10
|
+
* not.
|
|
11
|
+
*
|
|
12
|
+
* Part of PIE Assessment Toolkit.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Media source URLs are handed to a media element in the learner's browser. Only
|
|
16
|
+
* schemes such an element can actually fetch are allowed; anything else is
|
|
17
|
+
* dropped so an authored `javascript:` / `file:` URL cannot ride into the DOM.
|
|
18
|
+
* Relative and protocol-relative URLs are allowed — host content is commonly
|
|
19
|
+
* served from the same origin as the player.
|
|
20
|
+
*/
|
|
21
|
+
const DISALLOWED_SRC_SCHEME = /^[a-z][a-z0-9+.-]*:/i;
|
|
22
|
+
const ALLOWED_SRC_SCHEMES = new Set(["http:", "https:", "data:", "blob:"]);
|
|
23
|
+
export function isSafeMediaSrc(raw) {
|
|
24
|
+
if (typeof raw !== "string")
|
|
25
|
+
return false;
|
|
26
|
+
const src = raw.trim();
|
|
27
|
+
if (!src)
|
|
28
|
+
return false;
|
|
29
|
+
// Relative ("/video.mp4", "video.mp4") and protocol-relative ("//cdn/x.mp4")
|
|
30
|
+
// forms carry no scheme to check and inherit the document's.
|
|
31
|
+
if (src.startsWith("//") || !DISALLOWED_SRC_SCHEME.test(src))
|
|
32
|
+
return true;
|
|
33
|
+
const scheme = src.slice(0, src.indexOf(":") + 1).toLowerCase();
|
|
34
|
+
return ALLOWED_SRC_SCHEMES.has(scheme);
|
|
35
|
+
}
|
|
36
|
+
export function normalizeMediaSources(raw) {
|
|
37
|
+
if (!Array.isArray(raw))
|
|
38
|
+
return [];
|
|
39
|
+
const sources = [];
|
|
40
|
+
for (const entry of raw) {
|
|
41
|
+
if (!entry || typeof entry !== "object")
|
|
42
|
+
continue;
|
|
43
|
+
const candidate = entry;
|
|
44
|
+
if (!isSafeMediaSrc(candidate.src))
|
|
45
|
+
continue;
|
|
46
|
+
const source = { src: candidate.src.trim() };
|
|
47
|
+
if (typeof candidate.type === "string" && candidate.type.trim()) {
|
|
48
|
+
source.type = candidate.type.trim();
|
|
49
|
+
}
|
|
50
|
+
if (Number.isFinite(candidate.width))
|
|
51
|
+
source.width = candidate.width;
|
|
52
|
+
if (Number.isFinite(candidate.height))
|
|
53
|
+
source.height = candidate.height;
|
|
54
|
+
// Deduplicated by `src`, because the signing region renders `<source>`
|
|
55
|
+
// elements in an `{#each}` keyed on exactly that: an authored card listing
|
|
56
|
+
// one URL twice — the same file under two MIME types is the plausible way —
|
|
57
|
+
// would otherwise throw Svelte's duplicate-key error and take the whole
|
|
58
|
+
// region down rather than degrade. The first entry wins, so authored order
|
|
59
|
+
// still decides which encoding the browser is offered first.
|
|
60
|
+
if (sources.some((existing) => existing.src === source.src))
|
|
61
|
+
continue;
|
|
62
|
+
sources.push(source);
|
|
63
|
+
}
|
|
64
|
+
return sources;
|
|
65
|
+
}
|
|
66
|
+
export function normalizeMediaFragment(raw) {
|
|
67
|
+
if (!raw || typeof raw !== "object")
|
|
68
|
+
return undefined;
|
|
69
|
+
const candidate = raw;
|
|
70
|
+
const start = Number(candidate.startSeconds);
|
|
71
|
+
if (!Number.isFinite(start) || start < 0)
|
|
72
|
+
return undefined;
|
|
73
|
+
const end = Number(candidate.endSeconds);
|
|
74
|
+
// An end at or before the start would produce a zero/negative slice; treat
|
|
75
|
+
// it as "no end" rather than a range that can never play.
|
|
76
|
+
if (!Number.isFinite(end) || end <= start)
|
|
77
|
+
return { startSeconds: start };
|
|
78
|
+
return { startSeconds: start, endSeconds: end };
|
|
79
|
+
}
|
|
80
|
+
export function trimmedOrUndefined(value) {
|
|
81
|
+
if (typeof value !== "string")
|
|
82
|
+
return undefined;
|
|
83
|
+
const trimmed = value.trim();
|
|
84
|
+
return trimmed || undefined;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Apply a fragment range to a source URL as a Media Fragments URI, so one
|
|
88
|
+
* recording can serve several content nodes. Browsers honour the start offset;
|
|
89
|
+
* the end offset is enforced by the caller, because support for the end bound is
|
|
90
|
+
* inconsistent.
|
|
91
|
+
*/
|
|
92
|
+
export function applyMediaFragment(src, fragment) {
|
|
93
|
+
if (!fragment)
|
|
94
|
+
return src;
|
|
95
|
+
// Never stack a second fragment onto a URL that already carries one — the
|
|
96
|
+
// authored value wins.
|
|
97
|
+
if (src.includes("#"))
|
|
98
|
+
return src;
|
|
99
|
+
const end = fragment.endSeconds !== undefined ? `,${fragment.endSeconds}` : "";
|
|
100
|
+
return `${src}#t=${fragment.startSeconds}${end}`;
|
|
101
|
+
}
|
|
@@ -1,86 +1,53 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Tool Registry Factory
|
|
3
3
|
*
|
|
4
|
-
* Creates
|
|
5
|
-
*
|
|
4
|
+
* Creates an empty `ToolRegistry` and installs whatever component overrides and
|
|
5
|
+
* lazy module loaders the caller supplies.
|
|
6
|
+
*
|
|
7
|
+
* It registers nothing by itself, deliberately. Eleven concrete registrations
|
|
8
|
+
* used to live in this package, which made the policy and registry core know
|
|
9
|
+
* every capability by name and left a host unable to contribute one without a PR
|
|
10
|
+
* against this package. The packaged set now lives in the composition layer:
|
|
11
|
+
* `createPackagedToolRegistry` from `@pie-players/pie-default-tool-loaders`.
|
|
6
12
|
*/
|
|
13
|
+
import type { ToolRegistration, ToolModuleLoader } from "./ToolRegistry.js";
|
|
7
14
|
import { ToolRegistry } from "./ToolRegistry.js";
|
|
8
|
-
import type {
|
|
9
|
-
import
|
|
10
|
-
import { type ToolComponentFactory, type ToolComponentFactoryMap, type ToolTagMap } from "../tools/tool-tag-map.js";
|
|
11
|
-
import { DEFAULT_TOOL_PLACEMENT, PACKAGED_TOOL_PLACEMENT, SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT } from "./tool-config-defaults.js";
|
|
15
|
+
import type { ToolComponentFactory, ToolComponentFactoryMap, ToolTagMap } from "../tools/tool-tag-map.js";
|
|
16
|
+
import { DEFAULT_TOOL_PLACEMENT } from "./tool-config-defaults.js";
|
|
12
17
|
export interface DefaultToolRegistryOptions {
|
|
13
18
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
19
|
+
* Registrations to register, keyed by toolId. Nothing is registered when this
|
|
20
|
+
* is absent.
|
|
16
21
|
*/
|
|
17
|
-
|
|
22
|
+
registrations?: Partial<Record<string, ToolRegistration>>;
|
|
18
23
|
/**
|
|
19
|
-
*
|
|
24
|
+
* Element tag mapping for the registrations being installed. There is no
|
|
25
|
+
* built-in default: a tag map names capabilities, so it belongs to whoever
|
|
26
|
+
* decides which capabilities exist.
|
|
20
27
|
*/
|
|
21
28
|
toolTagMap?: Partial<ToolTagMap>;
|
|
22
29
|
/**
|
|
23
|
-
* Override component
|
|
30
|
+
* Override component creation globally (all tools) or per tool.
|
|
24
31
|
*/
|
|
25
32
|
toolComponentFactory?: ToolComponentFactory;
|
|
26
33
|
toolComponentFactories?: Partial<ToolComponentFactoryMap>;
|
|
27
34
|
/**
|
|
28
35
|
* Optional lazy module loaders keyed by toolId.
|
|
29
|
-
* Hosts can inject default loaders from an external package.
|
|
30
36
|
*/
|
|
31
37
|
toolModuleLoaders?: Partial<Record<string, ToolModuleLoader>>;
|
|
32
|
-
/**
|
|
33
|
-
* Register packaged PIE tools by default.
|
|
34
|
-
*
|
|
35
|
-
* @default false
|
|
36
|
-
*/
|
|
37
|
-
includePackagedTools?: boolean;
|
|
38
|
-
/**
|
|
39
|
-
* Restrict registration to specific packaged tool IDs.
|
|
40
|
-
* Ignored when includePackagedTools is false.
|
|
41
|
-
*/
|
|
42
|
-
toolIds?: string[];
|
|
43
38
|
}
|
|
44
39
|
/**
|
|
45
40
|
* Create a tool registry.
|
|
46
41
|
*
|
|
47
|
-
*
|
|
48
|
-
* For convenience, pass { includePackagedTools: true } to register all packaged tools,
|
|
49
|
-
* or use createPackagedToolRegistry().
|
|
50
|
-
*
|
|
51
|
-
* @returns ToolRegistry with all default tools
|
|
42
|
+
* @returns an empty `ToolRegistry` unless `registrations` is supplied
|
|
52
43
|
*/
|
|
53
44
|
export declare function createDefaultToolRegistry(options?: DefaultToolRegistryOptions): ToolRegistry;
|
|
54
|
-
export interface RegisterPackagedToolsOptions {
|
|
55
|
-
toolIds?: string[];
|
|
56
|
-
applyOverrides?: (registration: ToolRegistration) => ToolRegistration;
|
|
57
|
-
}
|
|
58
45
|
/**
|
|
59
|
-
*
|
|
60
|
-
*/
|
|
61
|
-
export declare function registerPackagedTools(registry: ToolRegistry, options?: RegisterPackagedToolsOptions): void;
|
|
62
|
-
/**
|
|
63
|
-
* Convenience factory that registers all packaged PIE tools.
|
|
64
|
-
*/
|
|
65
|
-
export declare function createPackagedToolRegistry(options?: Omit<DefaultToolRegistryOptions, "includePackagedTools">): ToolRegistry;
|
|
66
|
-
/**
|
|
67
|
-
* Default tool placement configuration
|
|
46
|
+
* Placement configuration with every level empty.
|
|
68
47
|
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* - Global tools: theme (assessment/section level)
|
|
74
|
-
* - Context-smart: calculator, graph, periodicTable (item/element, auto-detect)
|
|
75
|
-
* - Reading aids: textToSpeech, lineReader, annotationToolbar (where text exists)
|
|
76
|
-
* - Interaction-specific: answerEliminator (choice questions), highlighter (text)
|
|
77
|
-
* - Measurement: ruler, protractor (element level, diagram/geometry)
|
|
48
|
+
* The only placement default this package can hold: a populated one would name
|
|
49
|
+
* capabilities. `PACKAGED_TOOL_PLACEMENT` and
|
|
50
|
+
* `SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT` are in
|
|
51
|
+
* `@pie-players/pie-default-tool-loaders`.
|
|
78
52
|
*/
|
|
79
53
|
export { DEFAULT_TOOL_PLACEMENT };
|
|
80
|
-
export { PACKAGED_TOOL_PLACEMENT };
|
|
81
|
-
export { SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT };
|
|
82
|
-
/**
|
|
83
|
-
* Tool priority order for rendering
|
|
84
|
-
* Tools will be rendered in this order when multiple tools are visible
|
|
85
|
-
*/
|
|
86
|
-
export declare const DEFAULT_TOOL_ORDER: readonly ["theme", "calculator", "textToSpeech", "lineReader", "annotationToolbar", "highlighter", "answerEliminator", "ruler", "protractor", "graph", "periodicTable"];
|
|
@@ -1,125 +1,45 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Tool Registry Factory
|
|
3
3
|
*
|
|
4
|
-
* Creates
|
|
5
|
-
*
|
|
4
|
+
* Creates an empty `ToolRegistry` and installs whatever component overrides and
|
|
5
|
+
* lazy module loaders the caller supplies.
|
|
6
|
+
*
|
|
7
|
+
* It registers nothing by itself, deliberately. Eleven concrete registrations
|
|
8
|
+
* used to live in this package, which made the policy and registry core know
|
|
9
|
+
* every capability by name and left a host unable to contribute one without a PR
|
|
10
|
+
* against this package. The packaged set now lives in the composition layer:
|
|
11
|
+
* `createPackagedToolRegistry` from `@pie-players/pie-default-tool-loaders`.
|
|
6
12
|
*/
|
|
7
13
|
import { ToolRegistry } from "./ToolRegistry.js";
|
|
8
|
-
import {
|
|
9
|
-
import { ttsToolRegistration } from "../tools/registrations/tts.js";
|
|
10
|
-
import { rulerToolRegistration, protractorToolRegistration, } from "../tools/registrations/measurement-tools.js";
|
|
11
|
-
import { answerEliminatorToolRegistration, highlighterToolRegistration, } from "../tools/registrations/interaction-tools.js";
|
|
12
|
-
import { lineReaderToolRegistration, themeToolRegistration, annotationToolbarRegistration, } from "../tools/registrations/accessibility-tools.js";
|
|
13
|
-
import { graphToolRegistration, periodicTableToolRegistration, } from "../tools/registrations/subject-specific-tools.js";
|
|
14
|
-
import { DEFAULT_TOOL_TAG_MAP, } from "../tools/tool-tag-map.js";
|
|
15
|
-
import { DEFAULT_TOOL_PLACEMENT, PACKAGED_TOOL_PLACEMENT, SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT, } from "./tool-config-defaults.js";
|
|
16
|
-
const PACKAGED_TOOL_REGISTRATIONS = [
|
|
17
|
-
calculatorToolRegistration,
|
|
18
|
-
ttsToolRegistration,
|
|
19
|
-
rulerToolRegistration,
|
|
20
|
-
protractorToolRegistration,
|
|
21
|
-
answerEliminatorToolRegistration,
|
|
22
|
-
highlighterToolRegistration,
|
|
23
|
-
lineReaderToolRegistration,
|
|
24
|
-
themeToolRegistration,
|
|
25
|
-
annotationToolbarRegistration,
|
|
26
|
-
graphToolRegistration,
|
|
27
|
-
periodicTableToolRegistration,
|
|
28
|
-
];
|
|
14
|
+
import { DEFAULT_TOOL_PLACEMENT } from "./tool-config-defaults.js";
|
|
29
15
|
/**
|
|
30
16
|
* Create a tool registry.
|
|
31
17
|
*
|
|
32
|
-
*
|
|
33
|
-
* For convenience, pass { includePackagedTools: true } to register all packaged tools,
|
|
34
|
-
* or use createPackagedToolRegistry().
|
|
35
|
-
*
|
|
36
|
-
* @returns ToolRegistry with all default tools
|
|
18
|
+
* @returns an empty `ToolRegistry` unless `registrations` is supplied
|
|
37
19
|
*/
|
|
38
20
|
export function createDefaultToolRegistry(options = {}) {
|
|
39
21
|
const registry = new ToolRegistry();
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
...(options.toolTagMap || {}),
|
|
44
|
-
},
|
|
45
|
-
toolComponentFactory: options.toolComponentFactory,
|
|
46
|
-
toolComponentFactories: options.toolComponentFactories,
|
|
47
|
-
};
|
|
48
|
-
const applyOverrides = (registration) => options.overrides?.[registration.toolId] || registration;
|
|
49
|
-
if (options.includePackagedTools) {
|
|
50
|
-
registerPackagedTools(registry, {
|
|
51
|
-
toolIds: options.toolIds,
|
|
52
|
-
applyOverrides,
|
|
53
|
-
});
|
|
22
|
+
for (const registration of Object.values(options.registrations ?? {})) {
|
|
23
|
+
if (registration)
|
|
24
|
+
registry.register(registration);
|
|
54
25
|
}
|
|
55
26
|
if (options.toolModuleLoaders &&
|
|
56
27
|
Object.keys(options.toolModuleLoaders).length > 0) {
|
|
57
28
|
registry.setToolModuleLoaders(options.toolModuleLoaders);
|
|
58
29
|
}
|
|
59
|
-
registry.setComponentOverrides(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
* Register packaged PIE tools onto an existing registry.
|
|
64
|
-
*/
|
|
65
|
-
export function registerPackagedTools(registry, options = {}) {
|
|
66
|
-
const selectedToolIds = options.toolIds && options.toolIds.length > 0
|
|
67
|
-
? new Set(options.toolIds)
|
|
68
|
-
: null;
|
|
69
|
-
const applyOverrides = options.applyOverrides ||
|
|
70
|
-
((registration) => registration);
|
|
71
|
-
for (const registration of PACKAGED_TOOL_REGISTRATIONS) {
|
|
72
|
-
if (selectedToolIds && !selectedToolIds.has(registration.toolId)) {
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
registry.register(applyOverrides(registration));
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Convenience factory that registers all packaged PIE tools.
|
|
80
|
-
*/
|
|
81
|
-
export function createPackagedToolRegistry(options = {}) {
|
|
82
|
-
return createDefaultToolRegistry({
|
|
83
|
-
...options,
|
|
84
|
-
includePackagedTools: true,
|
|
30
|
+
registry.setComponentOverrides({
|
|
31
|
+
toolTagMap: options.toolTagMap,
|
|
32
|
+
toolComponentFactory: options.toolComponentFactory,
|
|
33
|
+
toolComponentFactories: options.toolComponentFactories,
|
|
85
34
|
});
|
|
35
|
+
return registry;
|
|
86
36
|
}
|
|
87
37
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* Defines which tools appear at which levels by default.
|
|
91
|
-
* Integrators can override this configuration.
|
|
38
|
+
* Placement configuration with every level empty.
|
|
92
39
|
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* -
|
|
97
|
-
* - Interaction-specific: answerEliminator (choice questions), highlighter (text)
|
|
98
|
-
* - Measurement: ruler, protractor (element level, diagram/geometry)
|
|
40
|
+
* The only placement default this package can hold: a populated one would name
|
|
41
|
+
* capabilities. `PACKAGED_TOOL_PLACEMENT` and
|
|
42
|
+
* `SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT` are in
|
|
43
|
+
* `@pie-players/pie-default-tool-loaders`.
|
|
99
44
|
*/
|
|
100
45
|
export { DEFAULT_TOOL_PLACEMENT };
|
|
101
|
-
export { PACKAGED_TOOL_PLACEMENT };
|
|
102
|
-
export { SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT };
|
|
103
|
-
/**
|
|
104
|
-
* Tool priority order for rendering
|
|
105
|
-
* Tools will be rendered in this order when multiple tools are visible
|
|
106
|
-
*/
|
|
107
|
-
export const DEFAULT_TOOL_ORDER = [
|
|
108
|
-
// Global accessibility first
|
|
109
|
-
"theme",
|
|
110
|
-
// Common tools
|
|
111
|
-
"calculator",
|
|
112
|
-
"textToSpeech",
|
|
113
|
-
// Reading aids
|
|
114
|
-
"lineReader",
|
|
115
|
-
"annotationToolbar",
|
|
116
|
-
"highlighter",
|
|
117
|
-
// Interaction tools
|
|
118
|
-
"answerEliminator",
|
|
119
|
-
// Measurement tools
|
|
120
|
-
"ruler",
|
|
121
|
-
"protractor",
|
|
122
|
-
// Subject-specific
|
|
123
|
-
"graph",
|
|
124
|
-
"periodicTable",
|
|
125
|
-
];
|
|
@@ -1,3 +1,21 @@
|
|
|
1
1
|
import type { PersonalNeedsProfile } from "@pie-players/pie-players-shared/types";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* An empty personal-needs profile: nothing granted, nothing prohibited, nothing
|
|
4
|
+
* activated at init.
|
|
5
|
+
*
|
|
6
|
+
* The core ships no populated default on purpose. It once derived one from every
|
|
7
|
+
* registered tool's `pnpSupportIds`, which read *registry membership* as
|
|
8
|
+
* *eligibility tier* — registration means "policy-addressable", not "universal,
|
|
9
|
+
* on by default" — so an accommodation-tier capability was granted to every
|
|
10
|
+
* student of every host that supplied no profile. The remedy at the time was a
|
|
11
|
+
* compile-time list of ids to exclude, which a host could not extend for its own
|
|
12
|
+
* accommodation.
|
|
13
|
+
*
|
|
14
|
+
* Which capabilities a deployment grants by default is a property of the
|
|
15
|
+
* program, not of this package: TTS is a universal feature in one program and a
|
|
16
|
+
* documented accommodation in another. That belongs in policy configuration
|
|
17
|
+
* alongside the district and test-administration levels. A named preset of
|
|
18
|
+
* today's universal set ships as data from
|
|
19
|
+
* `@pie-players/pie-default-tool-loaders`, for hosts that want it.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createEmptyPersonalNeedsProfile(): PersonalNeedsProfile;
|
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
/**
|
|
2
|
+
* An empty personal-needs profile: nothing granted, nothing prohibited, nothing
|
|
3
|
+
* activated at init.
|
|
4
|
+
*
|
|
5
|
+
* The core ships no populated default on purpose. It once derived one from every
|
|
6
|
+
* registered tool's `pnpSupportIds`, which read *registry membership* as
|
|
7
|
+
* *eligibility tier* — registration means "policy-addressable", not "universal,
|
|
8
|
+
* on by default" — so an accommodation-tier capability was granted to every
|
|
9
|
+
* student of every host that supplied no profile. The remedy at the time was a
|
|
10
|
+
* compile-time list of ids to exclude, which a host could not extend for its own
|
|
11
|
+
* accommodation.
|
|
12
|
+
*
|
|
13
|
+
* Which capabilities a deployment grants by default is a property of the
|
|
14
|
+
* program, not of this package: TTS is a universal feature in one program and a
|
|
15
|
+
* documented accommodation in another. That belongs in policy configuration
|
|
16
|
+
* alongside the district and test-administration levels. A named preset of
|
|
17
|
+
* today's universal set ships as data from
|
|
18
|
+
* `@pie-players/pie-default-tool-loaders`, for hosts that want it.
|
|
19
|
+
*/
|
|
20
|
+
export function createEmptyPersonalNeedsProfile() {
|
|
19
21
|
return {
|
|
20
|
-
supports: [
|
|
22
|
+
supports: [],
|
|
21
23
|
prohibitedSupports: [],
|
|
22
24
|
activateAtInit: [],
|
|
23
25
|
};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Part of PIE Assessment Toolkit.
|
|
9
9
|
*/
|
|
10
10
|
import type { I18nServiceApi } from "@pie-players/pie-players-shared/i18n";
|
|
11
|
-
import type { AccessibilityCatalogResolver, CatalogLookupContext, CatalogLookupOptions, CatalogOwnerContext, CatalogStatistics, CatalogType, ResolvedCatalog } from "./AccessibilityCatalogResolver.js";
|
|
11
|
+
import type { AccessibilityCatalogResolver, CatalogChangeListener, CatalogLookupContext, CatalogLookupOptions, CatalogOwnerContext, CatalogStatistics, CatalogType, ResolvedCatalog } from "./AccessibilityCatalogResolver.js";
|
|
12
12
|
import type { FrameworkErrorListener } from "./framework-error-bus.js";
|
|
13
13
|
import type { HighlightColor, HighlightType } from "./HighlightCoordinator.js";
|
|
14
14
|
import type { SectionControllerHandle, SectionItemEventSubscriptionArgs, SectionScopedEventSubscriptionArgs, SectionEventSubscriptionArgs, ToolkitCoordinatorHooks, ToolkitInitStatus } from "./ToolkitCoordinator.js";
|
|
@@ -18,7 +18,7 @@ import type { PlaybackState, TTSConfig } from "./TTSService.js";
|
|
|
18
18
|
import type { TTSHighlightTargetResolverProvider } from "./tts/highlight-target-resolver.js";
|
|
19
19
|
import type { ToolPlacementConfig, ToolPlacementLevel, ToolProviderConfig } from "./tools-config-normalizer.js";
|
|
20
20
|
import type { ToolProviderRegistry } from "./tool-providers/ToolProviderRegistry.js";
|
|
21
|
-
import type { PolicySource, PnpEnforcementMode, ResolvedEngineInputs, ToolPolicyChangeListener, ToolPolicyDecision, ToolPolicyDecisionRequest } from "../policy/engine.js";
|
|
21
|
+
import type { FeaturePolicyDecision, PolicySource, PnpEnforcementMode, ResolvedEngineInputs, ToolPolicyChangeListener, ToolPolicyDecision, ToolPolicyDecisionRequest } from "../policy/engine.js";
|
|
22
22
|
import type { AssessmentEntity, AssessmentItemRef } from "@pie-players/pie-players-shared/types";
|
|
23
23
|
import type { ITTSProvider, TTSProviderCapabilities } from "@pie-players/pie-tts";
|
|
24
24
|
import type { ResolvedToolContext, ToolContextResolver, ToolContextResolverContext, ToolContextResolverMap } from "./ToolRegistry.js";
|
|
@@ -593,6 +593,16 @@ export interface ToolkitCoordinatorApi {
|
|
|
593
593
|
* `decision.visibleTools` themselves.
|
|
594
594
|
*/
|
|
595
595
|
decideToolPolicy(request: ToolPolicyDecisionRequest): ToolPolicyDecision;
|
|
596
|
+
/**
|
|
597
|
+
* Resolve eligibility for one PNP/AfA feature id through the six-level
|
|
598
|
+
* precedence, independent of toolbar placement — for capabilities that
|
|
599
|
+
* render as their own surface rather than a toolbar button (a signed
|
|
600
|
+
* alternate's region, for example).
|
|
601
|
+
*
|
|
602
|
+
* Optional so host-supplied coordinator stubs predating this method stay
|
|
603
|
+
* assignable; call sites must feature-detect.
|
|
604
|
+
*/
|
|
605
|
+
decideFeaturePolicy?(featureId: string): FeaturePolicyDecision;
|
|
596
606
|
/**
|
|
597
607
|
* Subscribe to policy-engine change events. Fires whenever the
|
|
598
608
|
* coordinator's bound policy inputs change (`updateToolConfig`,
|
|
@@ -602,6 +612,23 @@ export interface ToolkitCoordinatorApi {
|
|
|
602
612
|
* call `decideToolPolicy(...)` with their level / scope.
|
|
603
613
|
*/
|
|
604
614
|
onPolicyChange(listener: ToolPolicyChangeListener): () => void;
|
|
615
|
+
/**
|
|
616
|
+
* Subscribe to accessibility-catalog registrations and removals.
|
|
617
|
+
*
|
|
618
|
+
* The companion to {@link onPolicyChange} for the other mutable input a
|
|
619
|
+
* capability's visibility depends on. A region that renders a catalog card
|
|
620
|
+
* needs both: policy decides whether the learner may have it, catalogs decide
|
|
621
|
+
* whether the content exists, and catalogs arrive on an item shell's mount
|
|
622
|
+
* event — after a card alongside that item has already computed its first
|
|
623
|
+
* answer. Listeners re-query through
|
|
624
|
+
* {@link accessibilityCatalogResolver}; the event names only what changed.
|
|
625
|
+
*
|
|
626
|
+
* Required, unlike {@link decideFeaturePolicy}: this ships with its only
|
|
627
|
+
* consumer, so there are no pre-existing stubs to stay assignable to, and
|
|
628
|
+
* `AGENTS.md` rules out adding an internal-API compatibility shim without a
|
|
629
|
+
* documented exception.
|
|
630
|
+
*/
|
|
631
|
+
onCatalogsChange(listener: CatalogChangeListener): () => void;
|
|
605
632
|
/**
|
|
606
633
|
* Bind (or clear) the active assessment for PNP/profile policy decisions.
|
|
607
634
|
*
|
|
@@ -167,7 +167,7 @@ export declare const QTI_STANDARD_ACCESS_FEATURES: {
|
|
|
167
167
|
/**
|
|
168
168
|
* Flat list of all standard access features for validation
|
|
169
169
|
*/
|
|
170
|
-
export declare const ALL_STANDARD_ACCESS_FEATURES: ("
|
|
170
|
+
export declare const ALL_STANDARD_ACCESS_FEATURES: ("transcript" | "braille" | "textToSpeech" | "calculator" | "strikethrough" | "answerEliminator" | "magnification" | "screenMagnifier" | "zoomable" | "highContrastDisplay" | "highContrastAudio" | "colorContrast" | "invertColors" | "displayTransformability" | "largePrint" | "fontEnlargement" | "resizeText" | "alternativeText" | "longDescription" | "describedMath" | "tactileGraphic" | "tactileObject" | "audioDescription" | "readAloud" | "humanVoice" | "syntheticVoice" | "speechRate" | "speechVolume" | "voicePitch" | "captions" | "closedCaptions" | "openCaptions" | "signLanguage" | "subtitles" | "audioControl" | "noBackgroundAudio" | "keyboardControl" | "mouseControl" | "touchControl" | "voiceControl" | "switchControl" | "eyeGazeControl" | "singleSwitchAccess" | "stickyKeys" | "keyboardShortcuts" | "timingControl" | "unlimitedTime" | "extendedTime" | "pauseControl" | "simplifiedLanguage" | "reducedComplexity" | "structuralNavigation" | "tableOfContents" | "reducedDistraction" | "noFlashing" | "pauseAnimation" | "annotations" | "bookmarking" | "highlighting" | "guidedNavigation" | "thesaurus" | "spellingAssistance" | "grammarAssistance" | "lineSpacing" | "wordSpacing" | "letterSpacing" | "fontFamily" | "readingMask" | "readingGuide" | "readingRuler" | "wordHighlighting" | "lineHighlighting" | "focusIndicator" | "printableResource" | "nemeth" | "refreshableBraille" | "index" | "pageNavigation" | "skipContent" | "breadcrumbs" | "searchable" | "fullTextSearch" | "multilingualText" | "translatedText" | "glossary" | "signLanguageInterpretation" | "visualLanguage" | "protractor" | "ruler" | "graph" | "graphingCalculator" | "periodicTable" | "formulaSheet" | "answerMasking" | "itemGlossary" | "tutorialAvailable")[];
|
|
171
171
|
/**
|
|
172
172
|
* Example PNP configurations for common accessibility needs
|
|
173
173
|
* These are NOT official profiles but illustrative examples showing
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recorded audio as a `spoken` catalog card.
|
|
3
|
+
*
|
|
4
|
+
* QTI 3 treats a recording and synthesized speech as the *same* support — both
|
|
5
|
+
* are `spoken`, and a card carries recorded audio through `qti-file-href` plus a
|
|
6
|
+
* MIME type — so this is not a new accommodation but the other form the existing
|
|
7
|
+
* one can take. Some programs prefer a human voice to synthesis; PIE's `spoken`
|
|
8
|
+
* card was string-only, so it had no way to say "play this file for this node".
|
|
9
|
+
*
|
|
10
|
+
* A node commonly carries both forms in the same language: the reading script
|
|
11
|
+
* *and* a recording of it. That is APIP's pattern and what QTI's migration
|
|
12
|
+
* guidance preserves, because the script is both the source the audio was
|
|
13
|
+
* generated from and the fallback for when the audio will not play. Resolution
|
|
14
|
+
* chooses between them with `CatalogLookupOptions.form`; playback treats the
|
|
15
|
+
* script as the recording's fallback.
|
|
16
|
+
*
|
|
17
|
+
* Validation posture matches sign-language cards: "treat as absent, never as
|
|
18
|
+
* partially valid". A malformed payload must not produce a silent player that
|
|
19
|
+
* looks like read-aloud is working.
|
|
20
|
+
*
|
|
21
|
+
* Part of PIE Assessment Toolkit.
|
|
22
|
+
*/
|
|
23
|
+
import type { CatalogCardPayload, MediaFragmentRange, MediaSource } from "@pie-players/pie-players-shared/types";
|
|
24
|
+
/** Catalog type token for spoken alternates. Matches QTI 3's `support` value. */
|
|
25
|
+
export declare const SPOKEN_CATALOG_TYPE = "spoken";
|
|
26
|
+
/** A validated recorded spoken alternate, flattened for playback. */
|
|
27
|
+
export interface SpokenAudioMedia {
|
|
28
|
+
/**
|
|
29
|
+
* Authored order preserved. Playback uses the first entry: an `<audio>` element
|
|
30
|
+
* fed alternative `<source>` children reports failure through a path that is
|
|
31
|
+
* awkward to observe reliably, and a dependable fallback to the reading script
|
|
32
|
+
* is worth more than encoding negotiation. Extra entries are kept so a future
|
|
33
|
+
* consumer can negotiate without re-reading the card.
|
|
34
|
+
*/
|
|
35
|
+
sources: MediaSource[];
|
|
36
|
+
fragment?: MediaFragmentRange;
|
|
37
|
+
label?: string;
|
|
38
|
+
}
|
|
39
|
+
type SpokenAudioCardLike = {
|
|
40
|
+
language?: string;
|
|
41
|
+
content?: string;
|
|
42
|
+
payload?: CatalogCardPayload;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Validate a `spoken` card's payload into something playable, or `null`.
|
|
46
|
+
*
|
|
47
|
+
* Silent when the card simply is not a recording — a card carrying `content` is
|
|
48
|
+
* a reading script, which is the overwhelmingly common case and not a fault.
|
|
49
|
+
* Loud when a card looks like it meant to be a recording and cannot be played,
|
|
50
|
+
* because that failure is otherwise invisible to everyone but the learner who
|
|
51
|
+
* needed it.
|
|
52
|
+
*/
|
|
53
|
+
export declare function resolveSpokenAudioMedia(card: SpokenAudioCardLike | null | undefined): SpokenAudioMedia | null;
|
|
54
|
+
export {};
|