@pie-players/pie-default-tool-loaders 0.3.74 → 1.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +116 -107
- package/dist/calculator-providers/CortexToolProvider.d.ts +0 -3
- package/dist/calculator-providers/CortexToolProvider.js +0 -14
- package/dist/calculator-providers/DesmosToolProvider.d.ts +0 -3
- package/dist/calculator-providers/DesmosToolProvider.js +0 -14
- package/dist/calculator-providers/GeoGebraToolProvider.d.ts +0 -3
- package/dist/calculator-providers/GeoGebraToolProvider.js +0 -14
- package/dist/calculator-providers/LazyCalculatorToolProvider.d.ts +3 -5
- package/dist/calculator-providers/LazyCalculatorToolProvider.js +1 -1
- package/dist/content-alternates.d.ts +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/packaged-capability-composition.d.ts +22 -50
- package/dist/packaged-capability-composition.js +61 -266
- package/dist/registrations/accessibility-tools.d.ts +1 -5
- package/dist/registrations/accessibility-tools.js +11 -49
- package/dist/registrations/audio-transcript.d.ts +8 -7
- package/dist/registrations/audio-transcript.js +12 -8
- package/dist/registrations/calculator.d.ts +2 -6
- package/dist/registrations/calculator.js +17 -39
- package/dist/registrations/dictionary-tools.d.ts +6 -5
- package/dist/registrations/dictionary-tools.js +21 -26
- package/dist/registrations/interaction-tools.d.ts +1 -7
- package/dist/registrations/interaction-tools.js +22 -30
- package/dist/registrations/measurement-tools.d.ts +1 -5
- package/dist/registrations/measurement-tools.js +1 -17
- package/dist/registrations/overlay-element-cache.d.ts +3 -1
- package/dist/registrations/overlay-element-cache.js +2 -1
- package/dist/registrations/overlay-toolbar-render.d.ts +9 -19
- package/dist/registrations/overlay-toolbar-render.js +9 -16
- package/dist/registrations/selection-actions.d.ts +1 -1
- package/dist/registrations/selection-actions.js +1 -1
- package/dist/registrations/subject-specific-tools.d.ts +1 -5
- package/dist/registrations/subject-specific-tools.js +1 -15
- package/dist/registrations/tts.d.ts +2 -8
- package/dist/registrations/tts.js +28 -99
- package/package.json +22 -23
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
* Two kinds of content wear the same shape, and the card says which:
|
|
6
6
|
*
|
|
7
7
|
* - `visibility: "always"` is authored presentation. The item family was
|
|
8
|
-
* designed to be delivered with its transcript on screen —
|
|
9
|
-
*
|
|
10
|
-
* revokes it.
|
|
8
|
+
* designed to be delivered with its transcript on screen — sentence items in
|
|
9
|
+
* an early-literacy assessment, for instance — so no profile grants it and
|
|
10
|
+
* none revokes it.
|
|
11
11
|
* - anything else, `"onGrant"` included, is the accommodation. Policy decides
|
|
12
|
-
* against the `transcript` support id, and silence means no. For
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* against the `transcript` support id, and silence means no. For item
|
|
13
|
+
* families where a visible transcript turns the item into a reading task,
|
|
14
|
+
* that gate is the whole point.
|
|
15
15
|
*
|
|
16
16
|
* The toolkit renders the text, not the element. Before this, the transcript rode
|
|
17
17
|
* on `model.audioTranscript` and `mc-populated-blank` revealed its own copy when
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
* absent from the universal preset — a content-dependent support never belongs in
|
|
36
36
|
* a wholesale grant.
|
|
37
37
|
*/
|
|
38
|
-
import type { ToolContentDependencyContext, ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/
|
|
38
|
+
import type { ToolContentDependencyContext, ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
39
39
|
/** QTI 3.0 / AfA support id gating an audio transcript. */
|
|
40
40
|
export declare const AUDIO_TRANSCRIPT_FEATURE_ID = "transcript";
|
|
41
41
|
/** Catalog type carrying the transcript text. */
|
|
@@ -47,6 +47,7 @@ export declare const AUDIO_TRANSCRIPT_REGION_CLASS = "pie-tool-audio-transcript"
|
|
|
47
47
|
export interface ResolvedAudioTranscript {
|
|
48
48
|
catalogId: string;
|
|
49
49
|
text: string;
|
|
50
|
+
/** BCP 47, as the region's `lang` takes it, whatever syntax the card used. */
|
|
50
51
|
language?: string;
|
|
51
52
|
/** True when the card declares itself authored presentation. */
|
|
52
53
|
always: boolean;
|
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
* Two kinds of content wear the same shape, and the card says which:
|
|
6
6
|
*
|
|
7
7
|
* - `visibility: "always"` is authored presentation. The item family was
|
|
8
|
-
* designed to be delivered with its transcript on screen —
|
|
9
|
-
*
|
|
10
|
-
* revokes it.
|
|
8
|
+
* designed to be delivered with its transcript on screen — sentence items in
|
|
9
|
+
* an early-literacy assessment, for instance — so no profile grants it and
|
|
10
|
+
* none revokes it.
|
|
11
11
|
* - anything else, `"onGrant"` included, is the accommodation. Policy decides
|
|
12
|
-
* against the `transcript` support id, and silence means no. For
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* against the `transcript` support id, and silence means no. For item
|
|
13
|
+
* families where a visible transcript turns the item into a reading task,
|
|
14
|
+
* that gate is the whole point.
|
|
15
15
|
*
|
|
16
16
|
* The toolkit renders the text, not the element. Before this, the transcript rode
|
|
17
17
|
* on `model.audioTranscript` and `mc-populated-blank` revealed its own copy when
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
* absent from the universal preset — a content-dependent support never belongs in
|
|
36
36
|
* a wholesale grant.
|
|
37
37
|
*/
|
|
38
|
+
import { toLanguageTag } from "@pie-players/pie-players-shared/i18n/language-tags";
|
|
38
39
|
/** QTI 3.0 / AfA support id gating an audio transcript. */
|
|
39
40
|
export const AUDIO_TRANSCRIPT_FEATURE_ID = "transcript";
|
|
40
41
|
/** Catalog type carrying the transcript text. */
|
|
@@ -55,6 +56,10 @@ const isTranscriptCard = (card) => !!card && card.catalog === AUDIO_TRANSCRIPT_C
|
|
|
55
56
|
const isAlwaysVisible = (card) => typeof card.visibility === "string" &&
|
|
56
57
|
card.visibility.trim().toLowerCase() === ALWAYS_VISIBLE;
|
|
57
58
|
const cardText = (card) => typeof card.content === "string" ? card.content.trim() : "";
|
|
59
|
+
// The Learnosity transform emits POSIX `es_ES`, which `lang` does not accept.
|
|
60
|
+
const cardLanguage = (card) => typeof card.language === "string"
|
|
61
|
+
? toLanguageTag(card.language) || undefined
|
|
62
|
+
: undefined;
|
|
58
63
|
/**
|
|
59
64
|
* The transcript an entity carries, or `null`.
|
|
60
65
|
*
|
|
@@ -83,7 +88,7 @@ export function resolveAudioTranscript(context) {
|
|
|
83
88
|
const resolved = {
|
|
84
89
|
catalogId,
|
|
85
90
|
text,
|
|
86
|
-
language:
|
|
91
|
+
language: cardLanguage(card),
|
|
87
92
|
always: isAlwaysVisible(card),
|
|
88
93
|
};
|
|
89
94
|
// An `always` card answers whether or not policy granted anything, so it
|
|
@@ -147,7 +152,6 @@ export const audioTranscriptRegistration = {
|
|
|
147
152
|
nameKey: "tools.audioTranscript.name",
|
|
148
153
|
descriptionKey: "tools.audioTranscript.description",
|
|
149
154
|
supportedLevels: ["item", "passage"],
|
|
150
|
-
pnpSupportIds: [AUDIO_TRANSCRIPT_FEATURE_ID],
|
|
151
155
|
// No button to press: a transcript is either authored-visible, or granted and
|
|
152
156
|
// present, or absent. `region` is the activation for a capability with no
|
|
153
157
|
// toolbar presence, and tools-config validation reports a `tools.placement`
|
|
@@ -3,13 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Registers the calculator tool with support for multiple calculator types
|
|
5
5
|
* (basic, scientific, graphing) through a host-selected provider.
|
|
6
|
-
*
|
|
7
|
-
* Maps to QTI 3.0 standard access features:
|
|
8
|
-
* - calculator (cognitive support)
|
|
9
|
-
* - graphingCalculator (assessment tool)
|
|
10
6
|
*/
|
|
11
|
-
import type { ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/
|
|
12
|
-
import type { ToolProviderConfig } from "@pie-players/pie-assessment-toolkit/tools/
|
|
7
|
+
import type { ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
8
|
+
import type { ToolProviderConfig } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
13
9
|
export type CalculatorProviderId = "calculator-desmos" | "calculator-geogebra" | "calculator-cortex";
|
|
14
10
|
export declare const DEFAULT_CALCULATOR_PROVIDER_ID: CalculatorProviderId;
|
|
15
11
|
export declare function resolveCalculatorProviderId(config: ToolProviderConfig | undefined): CalculatorProviderId;
|
|
@@ -3,14 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Registers the calculator tool with support for multiple calculator types
|
|
5
5
|
* (basic, scientific, graphing) through a host-selected provider.
|
|
6
|
-
*
|
|
7
|
-
* Maps to QTI 3.0 standard access features:
|
|
8
|
-
* - calculator (cognitive support)
|
|
9
|
-
* - graphingCalculator (assessment tool)
|
|
10
6
|
*/
|
|
11
|
-
import { hasMathContent } from "@pie-players/pie-assessment-toolkit/tools/
|
|
12
|
-
import { createScopedToolId } from "@pie-players/pie-assessment-toolkit/tools/
|
|
13
|
-
import { createToolElement } from "@pie-players/pie-assessment-toolkit/tools/
|
|
7
|
+
import { hasMathContent } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
8
|
+
import { createScopedToolId } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
9
|
+
import { createToolElement } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
14
10
|
import { CortexToolProvider } from "../calculator-providers/CortexToolProvider.js";
|
|
15
11
|
import { DesmosToolProvider } from "../calculator-providers/DesmosToolProvider.js";
|
|
16
12
|
import { GeoGebraToolProvider } from "../calculator-providers/GeoGebraToolProvider.js";
|
|
@@ -58,7 +54,10 @@ function normalizeCalculatorType(value) {
|
|
|
58
54
|
}
|
|
59
55
|
function getCalculatorRenderParams(toolbarContext) {
|
|
60
56
|
const params = toolbarContext.getToolRenderParams?.("calculator") ?? {};
|
|
61
|
-
|
|
57
|
+
// A host resolver or a request names the type; the policy parameters'
|
|
58
|
+
// `type` is the default beneath both.
|
|
59
|
+
const calculatorType = normalizeCalculatorType(params.calculatorType) ??
|
|
60
|
+
normalizeCalculatorType(toolbarContext.getToolParameters?.("calculator")?.type);
|
|
62
61
|
const availableTypesRaw = params.availableTypes;
|
|
63
62
|
const availableTypes = Array.isArray(availableTypesRaw)
|
|
64
63
|
? availableTypesRaw
|
|
@@ -86,11 +85,9 @@ const CALCULATOR_NAME_KEYS = {
|
|
|
86
85
|
graphing: "tools.calculator.nameGraphing",
|
|
87
86
|
untyped: "tools.calculator.name",
|
|
88
87
|
};
|
|
89
|
-
function applyCalculatorParamsToElement(element, calculatorType, availableTypes,
|
|
88
|
+
function applyCalculatorParamsToElement(element, calculatorType, availableTypes, calculatorConfig) {
|
|
90
89
|
const calculatorElement = element;
|
|
91
|
-
calculatorElement.providerId = providerId;
|
|
92
90
|
calculatorElement.calculatorConfig = calculatorConfig;
|
|
93
|
-
element.setAttribute("provider-id", providerId);
|
|
94
91
|
if (calculatorType) {
|
|
95
92
|
calculatorElement.calculatorType = calculatorType;
|
|
96
93
|
element.setAttribute("calculator-type", calculatorType);
|
|
@@ -122,7 +119,6 @@ export const calculatorToolRegistration = {
|
|
|
122
119
|
descriptionKey: "tools.calculator.description",
|
|
123
120
|
icon: "calculator",
|
|
124
121
|
provider: {
|
|
125
|
-
getProviderId: resolveCalculatorProviderId,
|
|
126
122
|
createProvider: createCalculatorToolProvider,
|
|
127
123
|
getInitConfig: (config) => config?.provider?.init ?? {},
|
|
128
124
|
getAuthFetcher: (config) => {
|
|
@@ -135,16 +131,6 @@ export const calculatorToolRegistration = {
|
|
|
135
131
|
},
|
|
136
132
|
// Calculator is item-level in this player architecture.
|
|
137
133
|
supportedLevels: ["item"],
|
|
138
|
-
// PNP support IDs that enable this tool
|
|
139
|
-
// Maps to QTI 3.0 standard features: calculator, graphingCalculator
|
|
140
|
-
// A type is not a feature id: `calculatorType` arrives through the host's
|
|
141
|
-
// render params, so `basicCalculator` / `scientificCalculator` granted the
|
|
142
|
-
// same untyped calculator these two do and only looked like they selected a
|
|
143
|
-
// variant.
|
|
144
|
-
pnpSupportIds: [
|
|
145
|
-
"calculator", // QTI 3.0 standard (cognitive.calculator)
|
|
146
|
-
"graphingCalculator", // QTI 3.0 standard (assessment.graphingCalculator)
|
|
147
|
-
],
|
|
148
134
|
/**
|
|
149
135
|
* Pass 2: Determine if calculator is relevant in this context
|
|
150
136
|
*
|
|
@@ -152,14 +138,12 @@ export const calculatorToolRegistration = {
|
|
|
152
138
|
* (MathML, LaTeX, arithmetic markers).
|
|
153
139
|
*/
|
|
154
140
|
isVisibleInContext(context) {
|
|
155
|
-
// Show only when math is present in item content.
|
|
156
141
|
return hasMathContent(context);
|
|
157
142
|
},
|
|
158
143
|
renderToolbar(context, toolbarContext) {
|
|
159
144
|
const { calculatorType, availableTypes, displayName } = getCalculatorRenderParams(toolbarContext);
|
|
160
145
|
const calculatorToolConfig = toolbarContext.toolkitCoordinator?.getToolConfig(this.toolId) ||
|
|
161
146
|
undefined;
|
|
162
|
-
const providerId = resolveCalculatorProviderId(calculatorToolConfig);
|
|
163
147
|
const calculatorConfig = getCalculatorInstanceConfig(calculatorToolConfig);
|
|
164
148
|
const fullToolId = createScopedToolId(this.toolId, toolbarContext.scope.level, toolbarContext.scope.scopeId);
|
|
165
149
|
const componentOverrides = toolbarContext.componentOverrides;
|
|
@@ -167,16 +151,14 @@ export const calculatorToolRegistration = {
|
|
|
167
151
|
// and container mount on every re-render.
|
|
168
152
|
const overlay = resolveOverlayElement(toolbarContext, fullToolId, () => createToolElement(this.toolId, context, toolbarContext, componentOverrides));
|
|
169
153
|
overlay.setAttribute("tool-id", fullToolId);
|
|
170
|
-
overlay
|
|
171
|
-
applyCalculatorParamsToElement(overlay, calculatorType, availableTypes, providerId, calculatorConfig);
|
|
154
|
+
applyCalculatorParamsToElement(overlay, calculatorType, availableTypes, calculatorConfig);
|
|
172
155
|
const button = {
|
|
173
156
|
toolId: this.toolId,
|
|
174
157
|
label: displayName,
|
|
175
158
|
icon: typeof this.icon === "function" ? this.icon(context) : this.icon,
|
|
176
159
|
// Routes this button through <nds-icon-button> where the host enables NDS
|
|
177
160
|
// icons. Declared here because which capabilities render in the host's
|
|
178
|
-
// design system is a composition decision
|
|
179
|
-
// the `calculator` toolId, which put a capability name in the generic core.
|
|
161
|
+
// design system is a composition decision.
|
|
180
162
|
faIconName: "calculator",
|
|
181
163
|
disabled: false,
|
|
182
164
|
// The name stays put across open and closed. The toolbar mirrors
|
|
@@ -185,7 +167,7 @@ export const calculatorToolRegistration = {
|
|
|
185
167
|
ariaLabel: displayName,
|
|
186
168
|
tooltip: displayName,
|
|
187
169
|
onClick: () => toolbarContext.toggleTool(this.toolId),
|
|
188
|
-
active: toolbarContext.isToolVisible(
|
|
170
|
+
active: toolbarContext.isToolVisible(this.toolId),
|
|
189
171
|
};
|
|
190
172
|
let lastVisibleState = button.active;
|
|
191
173
|
if (overlay.visible !== button.active) {
|
|
@@ -264,29 +246,25 @@ export const calculatorToolRegistration = {
|
|
|
264
246
|
],
|
|
265
247
|
button,
|
|
266
248
|
sync: () => {
|
|
267
|
-
const active = toolbarContext.isToolVisible(
|
|
249
|
+
const active = toolbarContext.isToolVisible(this.toolId);
|
|
268
250
|
button.active = active;
|
|
269
251
|
button.label = displayName;
|
|
270
|
-
// Static across the toggle
|
|
271
|
-
//
|
|
272
|
-
//
|
|
273
|
-
// `aria-pressed` already carries.
|
|
252
|
+
// Static across the toggle: `aria-pressed` carries the state, and a
|
|
253
|
+
// "Close …" template built from a localized noun mixes languages
|
|
254
|
+
// ("Close rekenmachine" under nl-NL).
|
|
274
255
|
button.ariaLabel = displayName;
|
|
275
256
|
button.tooltip = displayName;
|
|
276
257
|
if (lastVisibleState !== active) {
|
|
277
258
|
overlay.visible = active;
|
|
278
259
|
lastVisibleState = active;
|
|
279
260
|
}
|
|
280
|
-
|
|
281
|
-
overlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;
|
|
282
|
-
}
|
|
283
|
-
applyCalculatorParamsToElement(overlay, calculatorType, availableTypes, providerId, calculatorConfig);
|
|
261
|
+
applyCalculatorParamsToElement(overlay, calculatorType, availableTypes, calculatorConfig);
|
|
284
262
|
},
|
|
285
263
|
subscribeActive: (callback) => {
|
|
286
264
|
if (!toolbarContext.subscribeVisibility)
|
|
287
265
|
return () => { };
|
|
288
266
|
return toolbarContext.subscribeVisibility(() => {
|
|
289
|
-
callback(toolbarContext.isToolVisible(
|
|
267
|
+
callback(toolbarContext.isToolVisible(this.toolId));
|
|
290
268
|
});
|
|
291
269
|
},
|
|
292
270
|
};
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* there without caret browsing, an OS toggle absent on mobile — so a selection-only
|
|
16
16
|
* dictionary is unreachable for them. The panel's own field is the keyboard route.
|
|
17
17
|
*/
|
|
18
|
-
import type { ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/
|
|
18
|
+
import type { ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
19
19
|
/**
|
|
20
20
|
* What distinguishes one dictionary capability from another.
|
|
21
21
|
*
|
|
@@ -32,14 +32,15 @@ import type { ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools
|
|
|
32
32
|
* so a host catalog that lacks one is a plain label rather than a broken button.
|
|
33
33
|
*/
|
|
34
34
|
export interface DictionaryVariantOptions {
|
|
35
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* Capability id, unique per language, and the PNP support id that grants it.
|
|
37
|
+
* Defaults to the base tool's id.
|
|
38
|
+
*/
|
|
36
39
|
toolId?: string;
|
|
37
40
|
name?: string;
|
|
38
41
|
description?: string;
|
|
39
42
|
/** Catalog prefix for this variant's strings. Defaults to `tools.<toolId>`. */
|
|
40
43
|
messageKeyPrefix?: string;
|
|
41
|
-
/** PNP ids that grant this variant. A language variant needs its own. */
|
|
42
|
-
pnpSupportIds?: string[];
|
|
43
44
|
/**
|
|
44
45
|
* The corpus language this capability looks words up in, as a BCP-47 tag.
|
|
45
46
|
*
|
|
@@ -53,7 +54,7 @@ export interface DictionaryVariantOptions {
|
|
|
53
54
|
* Dictionary tool registration
|
|
54
55
|
*
|
|
55
56
|
* Word lookup from a host-supplied service, in one language. Call this again with another
|
|
56
|
-
* `toolId
|
|
57
|
+
* `toolId` and `lookupLanguage` to offer a second language beside it.
|
|
57
58
|
*/
|
|
58
59
|
export declare function createDictionaryToolRegistration(options?: DictionaryVariantOptions): ToolRegistration;
|
|
59
60
|
/** The content-following dictionary every deployment gets. */
|
|
@@ -15,8 +15,14 @@
|
|
|
15
15
|
* there without caret browsing, an OS toggle absent on mobile — so a selection-only
|
|
16
16
|
* dictionary is unreachable for them. The panel's own field is the keyboard route.
|
|
17
17
|
*/
|
|
18
|
-
import { createScopedVisibilityBinding, createToolElement, hasReadableText, syncButtonAndOverlayVisibility, } from "@pie-players/pie-assessment-toolkit/tools/
|
|
18
|
+
import { createScopedVisibilityBinding, createToolElement, hasReadableText, syncButtonAndOverlayVisibility, } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
19
19
|
import { resolveOverlayElement } from "./overlay-element-cache.js";
|
|
20
|
+
/**
|
|
21
|
+
* The lookup fields each panel last took from render params. The panel outlives
|
|
22
|
+
* renders, so a field the host stops supplying is cleared here; a field it never
|
|
23
|
+
* supplied, such as one a component factory set, is left alone.
|
|
24
|
+
*/
|
|
25
|
+
const appliedLookupFields = new WeakMap();
|
|
20
26
|
/**
|
|
21
27
|
* Apply the host's per-tool render params to the panel.
|
|
22
28
|
*
|
|
@@ -34,14 +40,23 @@ function applyLookupParams(element, toolId, toolbarContext,
|
|
|
34
40
|
/** A language variant's own corpus language; see {@link DictionaryVariantOptions}. */
|
|
35
41
|
lookupLanguage) {
|
|
36
42
|
const params = toolbarContext.getToolRenderParams?.(toolId) ?? {};
|
|
43
|
+
const supplied = {};
|
|
37
44
|
if (typeof params.endpoint === "string")
|
|
38
|
-
|
|
45
|
+
supplied.endpoint = params.endpoint;
|
|
39
46
|
if (typeof params.lookup === "function")
|
|
40
|
-
|
|
47
|
+
supplied.lookup = params.lookup;
|
|
41
48
|
if (typeof params.headers === "function")
|
|
42
|
-
|
|
49
|
+
supplied.headers = params.headers;
|
|
43
50
|
if (typeof params.credentials === "string")
|
|
44
|
-
|
|
51
|
+
supplied.credentials = params.credentials;
|
|
52
|
+
// A dropped `lookup` left in place would keep outranking the endpoint that
|
|
53
|
+
// replaced it.
|
|
54
|
+
for (const field of appliedLookupFields.get(element) ?? []) {
|
|
55
|
+
if (!(field in supplied))
|
|
56
|
+
element[field] = undefined;
|
|
57
|
+
}
|
|
58
|
+
Object.assign(element, supplied);
|
|
59
|
+
appliedLookupFields.set(element, new Set(Object.keys(supplied)));
|
|
45
60
|
// The selection door: a gateway acting on the learner's selection requests this
|
|
46
61
|
// tool with the words in `term`, and the toolbar layers that over the host's own
|
|
47
62
|
// params. The toolbar stamps every request with a neutral `toolRequestId` — core
|
|
@@ -122,7 +137,7 @@ function renderDictionaryPanel(args) {
|
|
|
122
137
|
* Dictionary tool registration
|
|
123
138
|
*
|
|
124
139
|
* Word lookup from a host-supplied service, in one language. Call this again with another
|
|
125
|
-
* `toolId
|
|
140
|
+
* `toolId` and `lookupLanguage` to offer a second language beside it.
|
|
126
141
|
*/
|
|
127
142
|
export function createDictionaryToolRegistration(options = {}) {
|
|
128
143
|
const toolId = options.toolId ?? "dictionary";
|
|
@@ -136,15 +151,6 @@ export function createDictionaryToolRegistration(options = {}) {
|
|
|
136
151
|
icon: "book-open",
|
|
137
152
|
// Text can appear at any of these; the panel itself floats at section scope.
|
|
138
153
|
supportedLevels: ["section", "item", "passage", "rubric"],
|
|
139
|
-
// PNP support IDs
|
|
140
|
-
// Maps to AfA PNP 3.0 / QTI 3.0 dictionary support, plus the common variants a
|
|
141
|
-
// host profile is likely to carry.
|
|
142
|
-
pnpSupportIds: options.pnpSupportIds ?? [
|
|
143
|
-
"dictionary", // Canonical id
|
|
144
|
-
"englishDictionary", // Common variant
|
|
145
|
-
"glossary", // Common variant
|
|
146
|
-
"definitions", // Common variant
|
|
147
|
-
],
|
|
148
154
|
/** Pass 2: a dictionary is relevant wherever there is text to look words up from. */
|
|
149
155
|
isVisibleInContext(context) {
|
|
150
156
|
return hasReadableText(context);
|
|
@@ -185,15 +191,6 @@ export function createPictureDictionaryToolRegistration(options = {}) {
|
|
|
185
191
|
descriptionKey: `${prefix}.description`,
|
|
186
192
|
icon: "photo",
|
|
187
193
|
supportedLevels: ["section", "item", "passage", "rubric"],
|
|
188
|
-
// PNP support IDs
|
|
189
|
-
// AfA PNP 3.0 names an illustrated equivalent of a glossary; the variants cover
|
|
190
|
-
// what host profiles call it in practice.
|
|
191
|
-
pnpSupportIds: options.pnpSupportIds ?? [
|
|
192
|
-
"pictureDictionary", // Canonical id
|
|
193
|
-
"illustratedGlossary", // Common variant
|
|
194
|
-
"symbolDictionary", // Common variant
|
|
195
|
-
"pictureSupport", // Common variant
|
|
196
|
-
],
|
|
197
194
|
isVisibleInContext(context) {
|
|
198
195
|
return hasReadableText(context);
|
|
199
196
|
},
|
|
@@ -224,13 +221,11 @@ export const spanishDictionaryToolRegistration = createDictionaryToolRegistratio
|
|
|
224
221
|
toolId: "dictionarySpanish",
|
|
225
222
|
name: "Spanish Dictionary",
|
|
226
223
|
description: "Look up word definitions in Spanish",
|
|
227
|
-
pnpSupportIds: ["spanishDictionary"],
|
|
228
224
|
lookupLanguage: "es",
|
|
229
225
|
});
|
|
230
226
|
export const spanishPictureDictionaryToolRegistration = createPictureDictionaryToolRegistration({
|
|
231
227
|
toolId: "pictureDictionarySpanish",
|
|
232
228
|
name: "Spanish Picture Dictionary",
|
|
233
229
|
description: "Look up pictures for words in Spanish",
|
|
234
|
-
pnpSupportIds: ["spanishPictureDictionary"],
|
|
235
230
|
lookupLanguage: "es",
|
|
236
231
|
});
|
|
@@ -3,14 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Registers tools for interacting with question content:
|
|
5
5
|
* - Answer Eliminator (strike through answer choices)
|
|
6
|
-
* - Highlighter (highlight text passages)
|
|
7
|
-
*
|
|
8
|
-
* Maps to QTI 3.0 standard access features:
|
|
9
|
-
* - answerMasking (assessment tool)
|
|
10
|
-
* - strikethrough (visual transformation)
|
|
11
|
-
* - highlighting (cognitive/reading support)
|
|
12
6
|
*/
|
|
13
|
-
import type { ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/
|
|
7
|
+
import type { ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
14
8
|
/**
|
|
15
9
|
* Answer Eliminator tool registration
|
|
16
10
|
*
|
|
@@ -3,17 +3,28 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Registers tools for interacting with question content:
|
|
5
5
|
* - Answer Eliminator (strike through answer choices)
|
|
6
|
-
* - Highlighter (highlight text passages)
|
|
7
|
-
*
|
|
8
|
-
* Maps to QTI 3.0 standard access features:
|
|
9
|
-
* - answerMasking (assessment tool)
|
|
10
|
-
* - strikethrough (visual transformation)
|
|
11
|
-
* - highlighting (cognitive/reading support)
|
|
12
6
|
*/
|
|
13
|
-
import { hasChoiceInteraction } from "@pie-players/pie-assessment-toolkit/tools/
|
|
14
|
-
import { createToolElement, } from "@pie-players/pie-assessment-toolkit/tools/
|
|
15
|
-
import { createScopedVisibilityBinding, syncButtonAndOverlayVisibility, } from "@pie-players/pie-assessment-toolkit/tools/
|
|
7
|
+
import { hasChoiceInteraction } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
8
|
+
import { createToolElement, } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
9
|
+
import { createScopedVisibilityBinding, syncButtonAndOverlayVisibility, } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
16
10
|
import { resolveOverlayElement } from "./overlay-element-cache.js";
|
|
11
|
+
/** The policy parameters' `strategy`, defaulting to strikethrough. */
|
|
12
|
+
const normalizeEliminationStrategy = (value) => value === "mask" ? "mask" : "strikethrough";
|
|
13
|
+
/** The state-store key of each PIE element in the item, by model id. */
|
|
14
|
+
function resolveElementStateKeys(context, toolbarContext) {
|
|
15
|
+
const keys = {};
|
|
16
|
+
if (!("item" in context) || !toolbarContext.getGlobalElementId)
|
|
17
|
+
return keys;
|
|
18
|
+
for (const model of context.item?.config?.models ?? []) {
|
|
19
|
+
const elementId = model?.id;
|
|
20
|
+
if (typeof elementId !== "string" || !elementId)
|
|
21
|
+
continue;
|
|
22
|
+
const key = toolbarContext.getGlobalElementId(elementId);
|
|
23
|
+
if (key)
|
|
24
|
+
keys[elementId] = key;
|
|
25
|
+
}
|
|
26
|
+
return keys;
|
|
27
|
+
}
|
|
17
28
|
/**
|
|
18
29
|
* Answer Eliminator tool registration
|
|
19
30
|
*
|
|
@@ -27,15 +38,7 @@ export const answerEliminatorToolRegistration = {
|
|
|
27
38
|
nameKey: "tools.answerEliminator.name",
|
|
28
39
|
descriptionKey: "tools.answerEliminator.description",
|
|
29
40
|
icon: "strikethrough",
|
|
30
|
-
// Answer eliminator appears at item level only
|
|
31
41
|
supportedLevels: ["item"],
|
|
32
|
-
// PNP support IDs
|
|
33
|
-
// Maps to QTI 3.0 standard feature: answerMasking
|
|
34
|
-
pnpSupportIds: [
|
|
35
|
-
"answerMasking", // QTI 3.0 standard (assessment.answerMasking)
|
|
36
|
-
"answerEliminator", // QTI 3.0 standard (assessment.answerEliminator)
|
|
37
|
-
"strikethrough", // QTI 3.0 standard (assessment.strikethrough)
|
|
38
|
-
],
|
|
39
42
|
/**
|
|
40
43
|
* Pass 2: Answer eliminator is relevant only for choice-based questions
|
|
41
44
|
*/
|
|
@@ -57,9 +60,8 @@ export const answerEliminatorToolRegistration = {
|
|
|
57
60
|
const visibility = createScopedVisibilityBinding(this.toolId, toolbarContext);
|
|
58
61
|
const componentOverrides = toolbarContext.componentOverrides ?? {};
|
|
59
62
|
const overlay = resolveOverlayElement(toolbarContext, visibility.fullToolId, () => createToolElement(this.toolId, context, toolbarContext, componentOverrides));
|
|
60
|
-
overlay.setAttribute("tool-id", visibility.fullToolId);
|
|
61
|
-
overlay.setAttribute("strategy", "strikethrough");
|
|
62
63
|
overlay.setAttribute("button-alignment", "inline");
|
|
64
|
+
overlay.setAttribute("strategy", normalizeEliminationStrategy(toolbarContext.getToolParameters?.("answerEliminator")?.strategy));
|
|
63
65
|
const button = {
|
|
64
66
|
toolId: this.toolId,
|
|
65
67
|
label: this.name,
|
|
@@ -80,17 +82,7 @@ export const answerEliminatorToolRegistration = {
|
|
|
80
82
|
overlay,
|
|
81
83
|
isActive: visibility.isActive,
|
|
82
84
|
});
|
|
83
|
-
|
|
84
|
-
overlay.coordinator = toolbarContext.toolCoordinator;
|
|
85
|
-
}
|
|
86
|
-
overlay.scopeElement = toolbarContext.getScopeElement?.() || null;
|
|
87
|
-
if (toolbarContext.elementToolStateStore) {
|
|
88
|
-
overlay.elementToolStateStore = toolbarContext.elementToolStateStore;
|
|
89
|
-
}
|
|
90
|
-
const globalElementId = toolbarContext.getGlobalElementId?.();
|
|
91
|
-
if (globalElementId) {
|
|
92
|
-
overlay.globalElementId = globalElementId;
|
|
93
|
-
}
|
|
85
|
+
overlay.elementStateKeys = resolveElementStateKeys(context, toolbarContext);
|
|
94
86
|
},
|
|
95
87
|
subscribeActive: visibility.subscribeActive,
|
|
96
88
|
};
|
|
@@ -2,12 +2,8 @@
|
|
|
2
2
|
* Measurement Tools Registrations
|
|
3
3
|
*
|
|
4
4
|
* Registers ruler and protractor tools for on-screen measurements.
|
|
5
|
-
*
|
|
6
|
-
* Maps to QTI 3.0 standard access features:
|
|
7
|
-
* - ruler (assessment tool)
|
|
8
|
-
* - protractor (assessment tool)
|
|
9
5
|
*/
|
|
10
|
-
import type { ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/
|
|
6
|
+
import type { ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
11
7
|
/**
|
|
12
8
|
* Ruler tool registration
|
|
13
9
|
*
|
|
@@ -2,12 +2,8 @@
|
|
|
2
2
|
* Measurement Tools Registrations
|
|
3
3
|
*
|
|
4
4
|
* Registers ruler and protractor tools for on-screen measurements.
|
|
5
|
-
*
|
|
6
|
-
* Maps to QTI 3.0 standard access features:
|
|
7
|
-
* - ruler (assessment tool)
|
|
8
|
-
* - protractor (assessment tool)
|
|
9
5
|
*/
|
|
10
|
-
import { hasMathContent } from "@pie-players/pie-assessment-toolkit/tools/
|
|
6
|
+
import { hasMathContent } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
11
7
|
import { renderOverlayToolbar } from "./overlay-toolbar-render.js";
|
|
12
8
|
/**
|
|
13
9
|
* Ruler tool registration
|
|
@@ -24,11 +20,6 @@ export const rulerToolRegistration = {
|
|
|
24
20
|
icon: "ruler",
|
|
25
21
|
// Ruler typically appears at section/item/element level
|
|
26
22
|
supportedLevels: ["section", "item", "element"],
|
|
27
|
-
// PNP support IDs
|
|
28
|
-
// Maps to QTI 3.0 standard feature: ruler
|
|
29
|
-
pnpSupportIds: [
|
|
30
|
-
"ruler", // QTI 3.0 standard (assessment.ruler)
|
|
31
|
-
],
|
|
32
23
|
/**
|
|
33
24
|
* Pass 2: Ruler is relevant when math content is present
|
|
34
25
|
*/
|
|
@@ -38,7 +29,6 @@ export const rulerToolRegistration = {
|
|
|
38
29
|
renderToolbar(context, toolbarContext) {
|
|
39
30
|
return renderOverlayToolbar(this, context, toolbarContext, {
|
|
40
31
|
surface: "frameless",
|
|
41
|
-
handsOverCoordinator: true,
|
|
42
32
|
});
|
|
43
33
|
},
|
|
44
34
|
};
|
|
@@ -57,11 +47,6 @@ export const protractorToolRegistration = {
|
|
|
57
47
|
icon: "protractor",
|
|
58
48
|
// Protractor typically appears at section/item/element level
|
|
59
49
|
supportedLevels: ["section", "item", "element"],
|
|
60
|
-
// PNP support IDs
|
|
61
|
-
// Maps to QTI 3.0 standard feature: protractor
|
|
62
|
-
pnpSupportIds: [
|
|
63
|
-
"protractor", // QTI 3.0 standard (assessment.protractor)
|
|
64
|
-
],
|
|
65
50
|
/**
|
|
66
51
|
* Pass 2: Protractor is relevant when math content is present
|
|
67
52
|
*/
|
|
@@ -71,7 +56,6 @@ export const protractorToolRegistration = {
|
|
|
71
56
|
renderToolbar(context, toolbarContext) {
|
|
72
57
|
return renderOverlayToolbar(this, context, toolbarContext, {
|
|
73
58
|
surface: "frameless",
|
|
74
|
-
handsOverCoordinator: true,
|
|
75
59
|
});
|
|
76
60
|
},
|
|
77
61
|
};
|
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
* A Svelte custom element tears its component down once it leaves the document,
|
|
13
13
|
* so a cached element found disconnected is dropped and recreated.
|
|
14
14
|
*/
|
|
15
|
-
import type { ToolbarContext } from "@pie-players/pie-assessment-toolkit/tools/
|
|
15
|
+
import type { ToolbarContext } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
16
|
+
/** The property the toolbar calls as it unmounts a tool element. */
|
|
17
|
+
export declare const TOOL_ELEMENT_UNMOUNT_CALLBACK_PROP = "__pieToolElementUnmount";
|
|
16
18
|
/**
|
|
17
19
|
* The element cached for `fullToolId` under this toolbar's coordinator, or the
|
|
18
20
|
* one `create` returns, which is then cached. Without a coordinator there is no
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
* A Svelte custom element tears its component down once it leaves the document,
|
|
13
13
|
* so a cached element found disconnected is dropped and recreated.
|
|
14
14
|
*/
|
|
15
|
-
|
|
15
|
+
/** The property the toolbar calls as it unmounts a tool element. */
|
|
16
|
+
export const TOOL_ELEMENT_UNMOUNT_CALLBACK_PROP = "__pieToolElementUnmount";
|
|
16
17
|
const overlayElements = new WeakMap();
|
|
17
18
|
/**
|
|
18
19
|
* The element cached for `fullToolId` under this toolbar's coordinator, or the
|
|
@@ -2,21 +2,17 @@
|
|
|
2
2
|
* The `renderToolbar` shape shared by every packaged capability that puts one
|
|
3
3
|
* overlay behind one toolbar button.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* the
|
|
9
|
-
* binding, the button, the component-override lookup, the `tool-id` attribute, the
|
|
10
|
-
* sync — was identical, which is why one rule landing in three spellings was
|
|
11
|
-
* possible: the shell title was `resolveToolRegistrationName` in two files,
|
|
12
|
-
* `displayName` in a third and a raw `t(key)` in a fourth.
|
|
5
|
+
* What varies between capabilities is the two options below: whether the overlay
|
|
6
|
+
* paints its own chrome or takes a draggable window, and that window's size. The
|
|
7
|
+
* visibility binding, the button, the component-override lookup, the `tool-id`
|
|
8
|
+
* attribute and the sync are shared, so the shell title has one spelling.
|
|
13
9
|
*
|
|
14
|
-
* Catalog keys are derived from `toolId
|
|
15
|
-
* `tools.<toolId>.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
10
|
+
* Catalog keys are derived from `toolId`: `tools.<toolId>.buttonA11y` and
|
|
11
|
+
* `tools.<toolId>.tooltip`. A capability needing a different prefix — the
|
|
12
|
+
* dictionary variants, which compose several capabilities off one element —
|
|
13
|
+
* keeps its own renderer.
|
|
18
14
|
*/
|
|
19
|
-
import { type ToolContext, type ToolRegistration, type ToolToolbarRenderResult, type ToolbarContext } from "@pie-players/pie-assessment-toolkit/tools/
|
|
15
|
+
import { type ToolContext, type ToolRegistration, type ToolToolbarRenderResult, type ToolbarContext } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
20
16
|
/** A window's geometry. Absent for overlays that paint their own chrome. */
|
|
21
17
|
export interface OverlayToolShell {
|
|
22
18
|
resizable: boolean;
|
|
@@ -33,11 +29,5 @@ export interface RenderOverlayToolbarOptions {
|
|
|
33
29
|
surface?: "frameless";
|
|
34
30
|
/** Present when the capability opens in a draggable, closeable window. */
|
|
35
31
|
shell?: OverlayToolShell;
|
|
36
|
-
/**
|
|
37
|
-
* Re-hand the toolkit coordinator on every sync. Overlays that take part in
|
|
38
|
-
* stacking or visibility restore need it; the two that only render their own
|
|
39
|
-
* model do not, and giving them a property they ignore is not free to assume.
|
|
40
|
-
*/
|
|
41
|
-
handsOverCoordinator?: boolean;
|
|
42
32
|
}
|
|
43
33
|
export declare function renderOverlayToolbar(registration: ToolRegistration, context: ToolContext, toolbarContext: ToolbarContext, options?: RenderOverlayToolbarOptions): ToolToolbarRenderResult;
|