@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
|
@@ -2,49 +2,26 @@
|
|
|
2
2
|
* The one authored description of PIE's packaged capability composition.
|
|
3
3
|
*
|
|
4
4
|
* Registrations describe what a capability can do. This module owns the
|
|
5
|
-
* deployment decisions around them: element tags, lazy module
|
|
6
|
-
* placement
|
|
5
|
+
* deployment decisions around them: element tags, lazy module loaders, the
|
|
6
|
+
* section-player placement preset and the explicit universal-support policy.
|
|
7
7
|
* Public constants are projections of this composition so adding a capability
|
|
8
8
|
* cannot leave a second hand-maintained catalogue silently behind.
|
|
9
9
|
*/
|
|
10
|
-
import { ToolRegistry, } from "@pie-players/pie-assessment-toolkit/tools/
|
|
10
|
+
import { ToolRegistry, } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
11
11
|
import { annotationToolbarRegistration, lineReaderToolRegistration, themeToolRegistration, } from "./registrations/accessibility-tools.js";
|
|
12
12
|
import { audioTranscriptRegistration } from "./registrations/audio-transcript.js";
|
|
13
|
-
import { calculatorToolRegistration
|
|
13
|
+
import { calculatorToolRegistration } from "./registrations/calculator.js";
|
|
14
14
|
import { dictionaryToolRegistration, pictureDictionaryToolRegistration, spanishDictionaryToolRegistration, spanishPictureDictionaryToolRegistration, } from "./registrations/dictionary-tools.js";
|
|
15
15
|
import { answerEliminatorToolRegistration } from "./registrations/interaction-tools.js";
|
|
16
16
|
import { protractorToolRegistration, rulerToolRegistration, } from "./registrations/measurement-tools.js";
|
|
17
17
|
import { graphToolRegistration, periodicTableToolRegistration, } from "./registrations/subject-specific-tools.js";
|
|
18
18
|
import { ttsToolRegistration } from "./registrations/tts.js";
|
|
19
19
|
const loadSideEffectModule = (load) => load().then(() => undefined);
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
return loadSideEffectModule(load);
|
|
27
|
-
}
|
|
28
|
-
const loadDesmosCalculatorModule = () => loadCalculatorElement("pie-tool-calculator", () => import("@pie-players/pie-tool-calculator-shared/calculator-element"));
|
|
29
|
-
const loadGeoGebraCalculatorModule = () => loadCalculatorElement("pie-tool-calculator-geogebra", () => import("@pie-players/pie-tool-calculator-geogebra"));
|
|
30
|
-
const loadCortexCalculatorModule = () => loadCalculatorElement("pie-tool-calculator-cortex", () => import("@pie-players/pie-tool-calculator-cortex"));
|
|
31
|
-
const CALCULATOR_DELIVERY = {
|
|
32
|
-
"calculator-desmos": {
|
|
33
|
-
tagName: "pie-tool-calculator",
|
|
34
|
-
loadModule: loadDesmosCalculatorModule,
|
|
35
|
-
},
|
|
36
|
-
"calculator-geogebra": {
|
|
37
|
-
tagName: "pie-tool-calculator-geogebra",
|
|
38
|
-
loadModule: loadGeoGebraCalculatorModule,
|
|
39
|
-
},
|
|
40
|
-
"calculator-cortex": {
|
|
41
|
-
tagName: "pie-tool-calculator-cortex",
|
|
42
|
-
loadModule: loadCortexCalculatorModule,
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
function resolveCalculatorDelivery(config) {
|
|
46
|
-
return CALCULATOR_DELIVERY[resolveCalculatorProviderId(config)];
|
|
47
|
-
}
|
|
20
|
+
// One element serves every calculator provider; the toolkit picks the provider
|
|
21
|
+
// from `tools.providers.calculator` when the element mounts.
|
|
22
|
+
const loadCalculatorModule = () => globalThis.customElements?.get("pie-tool-calculator")
|
|
23
|
+
? Promise.resolve()
|
|
24
|
+
: loadSideEffectModule(() => import("@pie-players/pie-tool-calculator-shared/calculator-element"));
|
|
48
25
|
const loadTtsModule = () => loadSideEffectModule(() => import("@pie-players/pie-tool-tts-inline"));
|
|
49
26
|
const loadRulerModule = () => loadSideEffectModule(() => import("@pie-players/pie-tool-ruler"));
|
|
50
27
|
const loadProtractorModule = () => loadSideEffectModule(() => import("@pie-players/pie-tool-protractor"));
|
|
@@ -59,133 +36,89 @@ const loadPictureDictionaryModule = () => loadSideEffectModule(() => import("@pi
|
|
|
59
36
|
const PACKAGED_CAPABILITY_DEFINITIONS = [
|
|
60
37
|
{
|
|
61
38
|
registration: calculatorToolRegistration,
|
|
62
|
-
tagName:
|
|
63
|
-
loadModule:
|
|
64
|
-
loaderTargets: ["item", "section"],
|
|
65
|
-
placementOrder: { element: 10 },
|
|
39
|
+
tagName: "pie-tool-calculator",
|
|
40
|
+
loadModule: loadCalculatorModule,
|
|
66
41
|
preferredPlacementOrder: { item: 10 },
|
|
67
|
-
|
|
68
|
-
universalSupportIds: ["calculator", "graphingCalculator"],
|
|
42
|
+
universal: true,
|
|
69
43
|
},
|
|
70
44
|
{
|
|
71
45
|
registration: ttsToolRegistration,
|
|
72
46
|
tagName: "pie-tool-tts-inline",
|
|
73
47
|
loadModule: loadTtsModule,
|
|
74
|
-
loaderTargets: ["item"],
|
|
75
|
-
placementOrder: { item: 10, passage: 10, rubric: 10, element: 30 },
|
|
76
48
|
preferredPlacementOrder: { item: 20, passage: 10 },
|
|
77
|
-
|
|
78
|
-
universalSupportIds: ["textToSpeech", "readAloud"],
|
|
49
|
+
universal: true,
|
|
79
50
|
},
|
|
80
51
|
{
|
|
81
52
|
registration: rulerToolRegistration,
|
|
82
53
|
tagName: "pie-tool-ruler",
|
|
83
54
|
loadModule: loadRulerModule,
|
|
84
|
-
loaderTargets: ["section"],
|
|
85
|
-
placementOrder: { element: 40 },
|
|
86
55
|
preferredPlacementOrder: { section: 50 },
|
|
87
|
-
|
|
88
|
-
universalSupportIds: ["ruler"],
|
|
56
|
+
universal: true,
|
|
89
57
|
},
|
|
90
58
|
{
|
|
91
59
|
registration: protractorToolRegistration,
|
|
92
60
|
tagName: "pie-tool-protractor",
|
|
93
61
|
loadModule: loadProtractorModule,
|
|
94
|
-
loaderTargets: ["section"],
|
|
95
|
-
placementOrder: { element: 50 },
|
|
96
62
|
preferredPlacementOrder: { section: 60 },
|
|
97
|
-
|
|
98
|
-
universalSupportIds: ["protractor"],
|
|
63
|
+
universal: true,
|
|
99
64
|
},
|
|
100
65
|
{
|
|
101
66
|
registration: answerEliminatorToolRegistration,
|
|
102
67
|
tagName: "pie-tool-answer-eliminator",
|
|
103
68
|
loadModule: loadAnswerEliminatorModule,
|
|
104
|
-
loaderTargets: ["item"],
|
|
105
|
-
placementOrder: { element: 20 },
|
|
106
69
|
preferredPlacementOrder: { item: 30 },
|
|
107
|
-
|
|
108
|
-
universalSupportIds: ["answerMasking", "answerEliminator", "strikethrough"],
|
|
70
|
+
universal: true,
|
|
109
71
|
},
|
|
110
72
|
{
|
|
111
73
|
registration: lineReaderToolRegistration,
|
|
112
74
|
tagName: "pie-tool-line-reader",
|
|
113
75
|
loadModule: loadLineReaderModule,
|
|
114
|
-
loaderTargets: ["section"],
|
|
115
|
-
placementOrder: { passage: 40, rubric: 40 },
|
|
116
76
|
preferredPlacementOrder: { section: 40 },
|
|
117
|
-
|
|
118
|
-
universalSupportIds: ["readingMask", "readingGuide", "readingRuler"],
|
|
77
|
+
universal: true,
|
|
119
78
|
},
|
|
120
79
|
{
|
|
121
80
|
registration: themeToolRegistration,
|
|
122
81
|
tagName: "pie-tool-theme",
|
|
123
82
|
loadModule: loadThemeModule,
|
|
124
|
-
loaderTargets: ["item"],
|
|
125
|
-
placementOrder: { assessment: 10, section: 10 },
|
|
126
83
|
preferredPlacementOrder: { section: 10 },
|
|
127
|
-
|
|
128
|
-
universalSupportIds: [
|
|
129
|
-
"highContrastDisplay",
|
|
130
|
-
"colorContrast",
|
|
131
|
-
"invertColors",
|
|
132
|
-
"theme",
|
|
133
|
-
],
|
|
84
|
+
universal: true,
|
|
134
85
|
},
|
|
135
86
|
{
|
|
136
87
|
registration: annotationToolbarRegistration,
|
|
137
88
|
tagName: "pie-tool-annotation-toolbar",
|
|
138
89
|
loadModule: loadAnnotationToolbarModule,
|
|
139
|
-
loaderTargets: ["item"],
|
|
140
|
-
placementOrder: { item: 30, passage: 30, rubric: 30, element: 70 },
|
|
141
90
|
preferredPlacementOrder: { item: 40, passage: 20 },
|
|
142
|
-
|
|
143
|
-
// The last three came from the `highlighter` capability, which mounted this
|
|
144
|
-
// same element behind a second identically-labelled button. Kept here so a
|
|
145
|
-
// profile granted one of the older ids still gets highlighting.
|
|
146
|
-
universalSupportIds: ["highlighting", "annotations"],
|
|
91
|
+
universal: true,
|
|
147
92
|
},
|
|
148
93
|
{
|
|
149
94
|
registration: graphToolRegistration,
|
|
150
95
|
tagName: "pie-tool-graph",
|
|
151
96
|
loadModule: loadGraphModule,
|
|
152
|
-
loaderTargets: ["section"],
|
|
153
|
-
placementOrder: { item: 40, element: 80 },
|
|
154
97
|
preferredPlacementOrder: { section: 20 },
|
|
155
|
-
|
|
156
|
-
universalSupportIds: ["graph"],
|
|
98
|
+
universal: true,
|
|
157
99
|
},
|
|
158
100
|
{
|
|
159
101
|
registration: periodicTableToolRegistration,
|
|
160
102
|
tagName: "pie-tool-periodic-table",
|
|
161
103
|
loadModule: loadPeriodicTableModule,
|
|
162
|
-
loaderTargets: ["section"],
|
|
163
|
-
placementOrder: { item: 50, element: 90 },
|
|
164
104
|
preferredPlacementOrder: { section: 30 },
|
|
165
|
-
|
|
166
|
-
universalSupportIds: ["periodicTable"],
|
|
105
|
+
universal: true,
|
|
167
106
|
},
|
|
168
107
|
{
|
|
169
108
|
registration: dictionaryToolRegistration,
|
|
170
109
|
tagName: "pie-tool-dictionary",
|
|
171
110
|
loadModule: loadDictionaryModule,
|
|
172
|
-
loaderTargets: ["section"],
|
|
173
|
-
placementOrder: { item: 60, element: 100 },
|
|
174
111
|
preferredPlacementOrder: { section: 70 },
|
|
175
|
-
|
|
176
|
-
//
|
|
177
|
-
|
|
178
|
-
universalSupportIds: [],
|
|
112
|
+
// A dictionary is a granted accommodation, and on a vocabulary item it is
|
|
113
|
+
// construct-relevant, so it is never universal.
|
|
114
|
+
universal: false,
|
|
179
115
|
},
|
|
180
116
|
{
|
|
181
117
|
registration: pictureDictionaryToolRegistration,
|
|
182
118
|
tagName: "pie-tool-picture-dictionary",
|
|
183
119
|
loadModule: loadPictureDictionaryModule,
|
|
184
|
-
loaderTargets: ["section"],
|
|
185
|
-
placementOrder: { item: 70, element: 110 },
|
|
186
120
|
preferredPlacementOrder: { section: 80 },
|
|
187
|
-
|
|
188
|
-
universalSupportIds: [],
|
|
121
|
+
universal: false,
|
|
189
122
|
},
|
|
190
123
|
// The Spanish variants render the same elements under their own capability ids, so a
|
|
191
124
|
// programme can grant a Spanish gloss beside the content-following dictionary or
|
|
@@ -194,35 +127,21 @@ const PACKAGED_CAPABILITY_DEFINITIONS = [
|
|
|
194
127
|
registration: spanishDictionaryToolRegistration,
|
|
195
128
|
tagName: "pie-tool-dictionary",
|
|
196
129
|
loadModule: loadDictionaryModule,
|
|
197
|
-
loaderTargets: ["section"],
|
|
198
|
-
placementOrder: { item: 80, element: 120 },
|
|
199
130
|
preferredPlacementOrder: { section: 90 },
|
|
200
|
-
|
|
201
|
-
universalSupportIds: [],
|
|
131
|
+
universal: false,
|
|
202
132
|
},
|
|
203
133
|
{
|
|
204
134
|
registration: spanishPictureDictionaryToolRegistration,
|
|
205
135
|
tagName: "pie-tool-picture-dictionary",
|
|
206
136
|
loadModule: loadPictureDictionaryModule,
|
|
207
|
-
loaderTargets: ["section"],
|
|
208
|
-
placementOrder: { item: 90, element: 130 },
|
|
209
137
|
preferredPlacementOrder: { section: 100 },
|
|
210
|
-
|
|
211
|
-
universalSupportIds: [],
|
|
138
|
+
universal: false,
|
|
212
139
|
},
|
|
213
140
|
{
|
|
214
141
|
registration: audioTranscriptRegistration,
|
|
215
|
-
|
|
142
|
+
universal: false,
|
|
216
143
|
},
|
|
217
144
|
];
|
|
218
|
-
const PACKAGED_PLACEMENT_LEVELS = [
|
|
219
|
-
"assessment",
|
|
220
|
-
"section",
|
|
221
|
-
"item",
|
|
222
|
-
"passage",
|
|
223
|
-
"rubric",
|
|
224
|
-
"element",
|
|
225
|
-
];
|
|
226
145
|
const PREFERRED_PLACEMENT_LEVELS = ["section", "item", "passage"];
|
|
227
146
|
function assertUniqueWeights(definitions, levels, read, field) {
|
|
228
147
|
for (const level of levels) {
|
|
@@ -243,8 +162,6 @@ function assertUniqueWeights(definitions, levels, read, field) {
|
|
|
243
162
|
}
|
|
244
163
|
function assertComposition(definitions) {
|
|
245
164
|
const toolIds = new Set();
|
|
246
|
-
const universalSupportIds = new Set();
|
|
247
|
-
const toolbarOrders = new Set();
|
|
248
165
|
for (const definition of definitions) {
|
|
249
166
|
const { registration } = definition;
|
|
250
167
|
if (!registration.toolId.trim()) {
|
|
@@ -258,9 +175,6 @@ function assertComposition(definitions) {
|
|
|
258
175
|
if (isRegion) {
|
|
259
176
|
if (definition.tagName !== undefined ||
|
|
260
177
|
definition.loadModule !== undefined ||
|
|
261
|
-
definition.loaderTargets !== undefined ||
|
|
262
|
-
definition.toolbarOrder !== undefined ||
|
|
263
|
-
Object.keys(definition.placementOrder ?? {}).length > 0 ||
|
|
264
178
|
Object.keys(definition.preferredPlacementOrder ?? {}).length > 0) {
|
|
265
179
|
throw new Error(`Invalid packaged capability "${registration.toolId}": a region capability is surface-hosted and cannot declare element delivery or toolbar placement.`);
|
|
266
180
|
}
|
|
@@ -269,44 +183,12 @@ function assertComposition(definitions) {
|
|
|
269
183
|
if (!definition.tagName?.includes("-")) {
|
|
270
184
|
throw new Error(`Invalid packaged capability "${registration.toolId}": element-backed capabilities need a custom-element tag.`);
|
|
271
185
|
}
|
|
272
|
-
if (typeof definition.loadModule !== "function"
|
|
273
|
-
|
|
274
|
-
throw new Error(`Invalid packaged capability "${registration.toolId}": element-backed capabilities need a lazy loader and at least one bootstrap target.`);
|
|
275
|
-
}
|
|
276
|
-
if (new Set(definition.loaderTargets).size !==
|
|
277
|
-
definition.loaderTargets.length) {
|
|
278
|
-
throw new Error(`Invalid packaged capability "${registration.toolId}": loader bootstrap targets must be unique.`);
|
|
186
|
+
if (typeof definition.loadModule !== "function") {
|
|
187
|
+
throw new Error(`Invalid packaged capability "${registration.toolId}": element-backed capabilities need a lazy loader.`);
|
|
279
188
|
}
|
|
280
|
-
if (definition.toolbarOrder === undefined) {
|
|
281
|
-
throw new Error(`Invalid packaged capability "${registration.toolId}": toolbar capabilities need an order.`);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
if (definition.toolbarOrder !== undefined) {
|
|
285
|
-
if (!Number.isSafeInteger(definition.toolbarOrder) ||
|
|
286
|
-
definition.toolbarOrder < 0) {
|
|
287
|
-
throw new Error(`Invalid packaged capability "${registration.toolId}": toolbar order must be a non-negative integer.`);
|
|
288
|
-
}
|
|
289
|
-
if (toolbarOrders.has(definition.toolbarOrder)) {
|
|
290
|
-
throw new Error(`Invalid packaged capability composition: duplicate toolbar order ${definition.toolbarOrder}.`);
|
|
291
|
-
}
|
|
292
|
-
toolbarOrders.add(definition.toolbarOrder);
|
|
293
189
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
definition.universalSupportIds.length > 0) {
|
|
297
|
-
throw new Error(`Invalid packaged capability "${registration.toolId}": content-dependent support ids cannot be universally granted.`);
|
|
298
|
-
}
|
|
299
|
-
for (const supportId of definition.universalSupportIds) {
|
|
300
|
-
if (!supportId.trim()) {
|
|
301
|
-
throw new Error(`Invalid packaged capability "${registration.toolId}": universal support ids must be non-empty.`);
|
|
302
|
-
}
|
|
303
|
-
if (!registrationSupportIds.has(supportId)) {
|
|
304
|
-
throw new Error(`Invalid packaged capability "${registration.toolId}": universal support id "${supportId}" is not declared by its registration.`);
|
|
305
|
-
}
|
|
306
|
-
if (universalSupportIds.has(supportId)) {
|
|
307
|
-
throw new Error(`Invalid packaged capability composition: universal support id "${supportId}" has more than one owner.`);
|
|
308
|
-
}
|
|
309
|
-
universalSupportIds.add(supportId);
|
|
190
|
+
if (registration.requiresAuthoredContent && definition.universal) {
|
|
191
|
+
throw new Error(`Invalid packaged capability "${registration.toolId}": a content-dependent capability cannot be universally granted.`);
|
|
310
192
|
}
|
|
311
193
|
for (const level of PREFERRED_PLACEMENT_LEVELS) {
|
|
312
194
|
if (definition.preferredPlacementOrder?.[level] !== undefined &&
|
|
@@ -315,7 +197,6 @@ function assertComposition(definitions) {
|
|
|
315
197
|
}
|
|
316
198
|
}
|
|
317
199
|
}
|
|
318
|
-
assertUniqueWeights(definitions, PACKAGED_PLACEMENT_LEVELS, (definition) => definition.placementOrder, "placementOrder");
|
|
319
200
|
assertUniqueWeights(definitions, PREFERRED_PLACEMENT_LEVELS, (definition) => definition.preferredPlacementOrder, "preferredPlacementOrder");
|
|
320
201
|
}
|
|
321
202
|
function orderedToolIds(definitions, level, read) {
|
|
@@ -331,12 +212,8 @@ class PackagedCapabilityComposition {
|
|
|
331
212
|
definitions;
|
|
332
213
|
registrations;
|
|
333
214
|
toolTagMap;
|
|
334
|
-
|
|
335
|
-
sectionModuleLoaders;
|
|
336
|
-
defaultModuleLoaders;
|
|
337
|
-
placement;
|
|
215
|
+
moduleLoaders;
|
|
338
216
|
preferredPlacement;
|
|
339
|
-
toolbarOrder;
|
|
340
217
|
universalSupportIds;
|
|
341
218
|
constructor(definitions) {
|
|
342
219
|
this.definitions = definitions;
|
|
@@ -344,34 +221,20 @@ class PackagedCapabilityComposition {
|
|
|
344
221
|
this.toolTagMap = Object.freeze(Object.fromEntries(definitions.flatMap((definition) => definition.tagName
|
|
345
222
|
? [[definition.registration.toolId, definition.tagName]]
|
|
346
223
|
: [])));
|
|
347
|
-
this.
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
224
|
+
this.moduleLoaders = Object.freeze(Object.fromEntries(definitions.flatMap((definition) => definition.loadModule
|
|
225
|
+
? [[definition.registration.toolId, definition.loadModule]]
|
|
226
|
+
: [])));
|
|
227
|
+
const preferredIds = (level) => Object.freeze(orderedToolIds(definitions, level, ({ preferredPlacementOrder }) => preferredPlacementOrder));
|
|
228
|
+
this.preferredPlacement = Object.freeze({
|
|
229
|
+
section: preferredIds("section"),
|
|
230
|
+
item: preferredIds("item"),
|
|
231
|
+
passage: preferredIds("passage"),
|
|
352
232
|
});
|
|
353
|
-
this.placement = Object.freeze(Object.fromEntries(PACKAGED_PLACEMENT_LEVELS.map((level) => [
|
|
354
|
-
level,
|
|
355
|
-
Object.freeze(orderedToolIds(definitions, level, (definition) => definition.placementOrder)),
|
|
356
|
-
])));
|
|
357
|
-
this.preferredPlacement = Object.freeze(Object.fromEntries(PREFERRED_PLACEMENT_LEVELS.map((level) => [
|
|
358
|
-
level,
|
|
359
|
-
Object.freeze(orderedToolIds(definitions, level, (definition) => definition.preferredPlacementOrder)),
|
|
360
|
-
])));
|
|
361
|
-
this.toolbarOrder = Object.freeze(definitions
|
|
362
|
-
.filter((definition) => definition.toolbarOrder !== undefined)
|
|
363
|
-
.slice()
|
|
364
|
-
.sort((left, right) => left.toolbarOrder - right.toolbarOrder)
|
|
365
|
-
.map(({ registration }) => registration.toolId));
|
|
366
233
|
this.universalSupportIds = Object.freeze(definitions
|
|
367
|
-
.
|
|
234
|
+
.filter((definition) => definition.universal)
|
|
235
|
+
.map(({ registration }) => registration.toolId)
|
|
368
236
|
.sort());
|
|
369
237
|
}
|
|
370
|
-
projectModuleLoaders(target) {
|
|
371
|
-
return Object.freeze(Object.fromEntries(this.definitions.flatMap((definition) => definition.loadModule && definition.loaderTargets?.includes(target)
|
|
372
|
-
? [[definition.registration.toolId, definition.loadModule]]
|
|
373
|
-
: [])));
|
|
374
|
-
}
|
|
375
238
|
selectRegistrations(toolIds) {
|
|
376
239
|
// Preserve the established fail-soft host behavior: no selection means all,
|
|
377
240
|
// and unknown ids are ignored rather than preventing known tools from loading.
|
|
@@ -380,46 +243,19 @@ class PackagedCapabilityComposition {
|
|
|
380
243
|
const selected = new Set(toolIds);
|
|
381
244
|
return this.registrations.filter(({ toolId }) => selected.has(toolId));
|
|
382
245
|
}
|
|
383
|
-
registerTools(registry, options = {}) {
|
|
384
|
-
const applyOverrides = options.applyOverrides ??
|
|
385
|
-
((registration) => registration);
|
|
386
|
-
for (const registration of this.selectRegistrations(options.toolIds)) {
|
|
387
|
-
registry.register(applyOverrides(registration));
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
246
|
createRegistry(options = {}) {
|
|
391
247
|
const registry = new ToolRegistry();
|
|
392
|
-
this.
|
|
393
|
-
|
|
394
|
-
applyOverrides: (registration) => options.overrides?.[registration.toolId] ?? registration,
|
|
395
|
-
});
|
|
396
|
-
// Loader installation remains opt-in. Some hosts preload tool elements or
|
|
397
|
-
// provide their own tags; silently adding package loads here would change
|
|
398
|
-
// their bundle/runtime behavior.
|
|
399
|
-
if (options.toolModuleLoaders &&
|
|
400
|
-
Object.keys(options.toolModuleLoaders).length > 0) {
|
|
401
|
-
const toolModuleLoaders = { ...options.toolModuleLoaders };
|
|
402
|
-
const calculatorDelivery = resolveCalculatorDelivery(options.calculatorProviderConfig);
|
|
403
|
-
// A host using the packaged default map gets a coherent provider-specific
|
|
404
|
-
// loader. A genuinely custom calculator loader remains the host's override.
|
|
405
|
-
if (options.calculatorProviderConfig &&
|
|
406
|
-
toolModuleLoaders.calculator === this.defaultModuleLoaders.calculator) {
|
|
407
|
-
toolModuleLoaders.calculator = calculatorDelivery.loadModule;
|
|
408
|
-
}
|
|
409
|
-
registry.setToolModuleLoaders(toolModuleLoaders);
|
|
248
|
+
for (const registration of this.selectRegistrations(options.toolIds)) {
|
|
249
|
+
registry.register(options.overrides?.[registration.toolId] ?? registration);
|
|
410
250
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
}
|
|
415
|
-
: {};
|
|
251
|
+
registry.setToolModuleLoaders({
|
|
252
|
+
...(options.toolModuleLoaders ?? this.moduleLoaders),
|
|
253
|
+
});
|
|
416
254
|
registry.setComponentOverrides({
|
|
417
255
|
toolTagMap: {
|
|
418
256
|
...this.toolTagMap,
|
|
419
|
-
...calculatorTagMap,
|
|
420
257
|
...(options.toolTagMap ?? {}),
|
|
421
258
|
},
|
|
422
|
-
toolComponentFactory: options.toolComponentFactory,
|
|
423
259
|
toolComponentFactories: options.toolComponentFactories,
|
|
424
260
|
});
|
|
425
261
|
return registry;
|
|
@@ -428,7 +264,6 @@ class PackagedCapabilityComposition {
|
|
|
428
264
|
return {
|
|
429
265
|
supports: [...this.universalSupportIds],
|
|
430
266
|
prohibitedSupports: [],
|
|
431
|
-
activateAtInit: [],
|
|
432
267
|
};
|
|
433
268
|
}
|
|
434
269
|
}
|
|
@@ -450,71 +285,31 @@ export const PACKAGED_TOOL_REGISTRATIONS = [
|
|
|
450
285
|
export const PACKAGED_TOOL_TAG_MAP = {
|
|
451
286
|
...packagedCapabilityComposition.toolTagMap,
|
|
452
287
|
};
|
|
453
|
-
export const ITEM_TOOL_MODULE_LOADERS = {
|
|
454
|
-
...packagedCapabilityComposition.itemModuleLoaders,
|
|
455
|
-
};
|
|
456
|
-
export const SECTION_TOOL_MODULE_LOADERS = {
|
|
457
|
-
...packagedCapabilityComposition.sectionModuleLoaders,
|
|
458
|
-
};
|
|
459
288
|
export const DEFAULT_TOOL_MODULE_LOADERS = {
|
|
460
|
-
...packagedCapabilityComposition.
|
|
461
|
-
};
|
|
462
|
-
/** Build the packaged loader map for a selected calculator provider. */
|
|
463
|
-
export function createDefaultToolModuleLoaders(options = {}) {
|
|
464
|
-
return {
|
|
465
|
-
...DEFAULT_TOOL_MODULE_LOADERS,
|
|
466
|
-
calculator: resolveCalculatorDelivery(options.calculatorProviderConfig)
|
|
467
|
-
.loadModule,
|
|
468
|
-
};
|
|
469
|
-
}
|
|
470
|
-
/** Build the section-bootstrap loader subset for a selected calculator provider. */
|
|
471
|
-
export function createSectionToolModuleLoaders(options = {}) {
|
|
472
|
-
return {
|
|
473
|
-
...SECTION_TOOL_MODULE_LOADERS,
|
|
474
|
-
calculator: resolveCalculatorDelivery(options.calculatorProviderConfig)
|
|
475
|
-
.loadModule,
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
export const PACKAGED_TOOL_PLACEMENT = {
|
|
479
|
-
assessment: [...packagedCapabilityComposition.placement.assessment],
|
|
480
|
-
section: [...packagedCapabilityComposition.placement.section],
|
|
481
|
-
item: [...packagedCapabilityComposition.placement.item],
|
|
482
|
-
passage: [...packagedCapabilityComposition.placement.passage],
|
|
483
|
-
rubric: [...packagedCapabilityComposition.placement.rubric],
|
|
484
|
-
element: [...packagedCapabilityComposition.placement.element],
|
|
289
|
+
...packagedCapabilityComposition.moduleLoaders,
|
|
485
290
|
};
|
|
486
291
|
export const SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT = {
|
|
487
292
|
section: [...packagedCapabilityComposition.preferredPlacement.section],
|
|
488
293
|
item: [...packagedCapabilityComposition.preferredPlacement.item],
|
|
489
294
|
passage: [...packagedCapabilityComposition.preferredPlacement.passage],
|
|
490
295
|
};
|
|
491
|
-
export const PACKAGED_TOOL_ORDER = [
|
|
492
|
-
...packagedCapabilityComposition.toolbarOrder,
|
|
493
|
-
];
|
|
494
|
-
export const UNIVERSAL_SUPPORTS_PRESET = packagedCapabilityComposition.universalSupportIds;
|
|
495
|
-
/** Register packaged PIE capabilities onto an existing registry. */
|
|
496
|
-
export function registerPackagedTools(registry, options = {}) {
|
|
497
|
-
packagedCapabilityComposition.registerTools(registry, options);
|
|
498
|
-
}
|
|
499
296
|
/** Create a registry holding the packaged PIE capabilities. */
|
|
500
297
|
export function createPackagedToolRegistry(options = {}) {
|
|
501
298
|
return packagedCapabilityComposition.createRegistry(options);
|
|
502
299
|
}
|
|
503
|
-
/**
|
|
300
|
+
/**
|
|
301
|
+
* A fresh profile granting the packaged set's universal capabilities, sorted by
|
|
302
|
+
* tool id. Which capabilities are universal is program policy declared on each
|
|
303
|
+
* definition; registry membership never implies it.
|
|
304
|
+
*/
|
|
504
305
|
export function createUniversalPersonalNeedsProfile() {
|
|
505
306
|
return packagedCapabilityComposition.createUniversalPersonalNeedsProfile();
|
|
506
307
|
}
|
|
507
|
-
/**
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
}
|
|
514
|
-
/** Register only the section-bootstrap loader subset, then host overrides. */
|
|
515
|
-
export function registerSectionToolModuleLoaders(registry, options = {}) {
|
|
516
|
-
registry.setToolModuleLoaders({
|
|
517
|
-
...createSectionToolModuleLoaders(options),
|
|
518
|
-
...(options.loaders ?? {}),
|
|
519
|
-
});
|
|
308
|
+
/**
|
|
309
|
+
* A fresh profile granting and prohibiting nothing. The toolkit ships no
|
|
310
|
+
* populated default: a deployment's universal set is program policy, which
|
|
311
|
+
* `createUniversalPersonalNeedsProfile` carries as data for hosts that adopt it.
|
|
312
|
+
*/
|
|
313
|
+
export function createEmptyPersonalNeedsProfile() {
|
|
314
|
+
return { supports: [], prohibitedSupports: [] };
|
|
520
315
|
}
|
|
@@ -5,12 +5,8 @@
|
|
|
5
5
|
* - Line Reader (reading guide)
|
|
6
6
|
* - Color Scheme (theme/contrast)
|
|
7
7
|
* - Annotation Toolbar (text highlighting)
|
|
8
|
-
*
|
|
9
|
-
* Maps to QTI 3.0 standard access features from:
|
|
10
|
-
* - visual category: highContrastDisplay, colorContrast
|
|
11
|
-
* - reading category: readingMask, readingGuide, highlighting
|
|
12
8
|
*/
|
|
13
|
-
import type { ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/
|
|
9
|
+
import type { ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
14
10
|
/**
|
|
15
11
|
* Line Reader tool registration
|
|
16
12
|
*
|
|
@@ -5,13 +5,9 @@
|
|
|
5
5
|
* - Line Reader (reading guide)
|
|
6
6
|
* - Color Scheme (theme/contrast)
|
|
7
7
|
* - Annotation Toolbar (text highlighting)
|
|
8
|
-
*
|
|
9
|
-
* Maps to QTI 3.0 standard access features from:
|
|
10
|
-
* - visual category: highContrastDisplay, colorContrast
|
|
11
|
-
* - reading category: readingMask, readingGuide, highlighting
|
|
12
8
|
*/
|
|
13
|
-
import { hasReadableText } from "@pie-players/pie-assessment-toolkit/tools/
|
|
14
|
-
import { resolveToolTag, } from "@pie-players/pie-assessment-toolkit/tools/
|
|
9
|
+
import { hasReadableText } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
10
|
+
import { resolveToolTag, } from "@pie-players/pie-assessment-toolkit/tools/registration";
|
|
15
11
|
import { buildSelectionActions } from "./selection-actions.js";
|
|
16
12
|
import { renderOverlayToolbar } from "./overlay-toolbar-render.js";
|
|
17
13
|
/**
|
|
@@ -27,15 +23,7 @@ export const lineReaderToolRegistration = {
|
|
|
27
23
|
nameKey: "tools.lineReader.name",
|
|
28
24
|
descriptionKey: "tools.lineReader.description",
|
|
29
25
|
icon: "bars-3",
|
|
30
|
-
// Line reader appears where there's text to read
|
|
31
26
|
supportedLevels: ["section", "passage", "rubric", "item"],
|
|
32
|
-
// PNP support IDs
|
|
33
|
-
// Maps to QTI 3.0 standard features: readingMask, readingGuide, readingRuler
|
|
34
|
-
pnpSupportIds: [
|
|
35
|
-
"readingMask", // QTI 3.0 standard (reading.readingMask)
|
|
36
|
-
"readingGuide", // QTI 3.0 standard (reading.readingGuide)
|
|
37
|
-
"readingRuler", // QTI 3.0 standard (reading.readingRuler)
|
|
38
|
-
],
|
|
39
27
|
/**
|
|
40
28
|
* Pass 2: Line reader is relevant when readable text is present
|
|
41
29
|
*/
|
|
@@ -45,7 +33,6 @@ export const lineReaderToolRegistration = {
|
|
|
45
33
|
renderToolbar(context, toolbarContext) {
|
|
46
34
|
return renderOverlayToolbar(this, context, toolbarContext, {
|
|
47
35
|
surface: "frameless",
|
|
48
|
-
handsOverCoordinator: true,
|
|
49
36
|
});
|
|
50
37
|
},
|
|
51
38
|
};
|
|
@@ -64,19 +51,11 @@ export const themeToolRegistration = {
|
|
|
64
51
|
icon: "swatch",
|
|
65
52
|
// Color scheme is assessment-wide
|
|
66
53
|
supportedLevels: ["assessment", "section"],
|
|
67
|
-
// PNP support IDs
|
|
68
|
-
// Maps to QTI 3.0 standard features: highContrastDisplay, colorContrast, invertColors
|
|
69
|
-
pnpSupportIds: [
|
|
70
|
-
"highContrastDisplay", // QTI 3.0 standard (visual.highContrastDisplay)
|
|
71
|
-
"colorContrast", // QTI 3.0 standard (visual.colorContrast)
|
|
72
|
-
"invertColors", // QTI 3.0 standard (visual.invertColors)
|
|
73
|
-
"theme", // Canonical id, and this registration's toolId
|
|
74
|
-
],
|
|
75
54
|
/**
|
|
76
55
|
* Pass 2: Color scheme is always relevant when allowed
|
|
77
56
|
*/
|
|
78
57
|
isVisibleInContext(context) {
|
|
79
|
-
return true;
|
|
58
|
+
return true;
|
|
80
59
|
},
|
|
81
60
|
renderToolbar(context, toolbarContext) {
|
|
82
61
|
return renderOverlayToolbar(this, context, toolbarContext, {
|
|
@@ -87,7 +66,6 @@ export const themeToolRegistration = {
|
|
|
87
66
|
minWidth: 420,
|
|
88
67
|
minHeight: 300,
|
|
89
68
|
},
|
|
90
|
-
handsOverCoordinator: true,
|
|
91
69
|
});
|
|
92
70
|
},
|
|
93
71
|
};
|
|
@@ -107,22 +85,13 @@ export const annotationToolbarRegistration = {
|
|
|
107
85
|
activation: "selection-gateway",
|
|
108
86
|
singletonScope: "section",
|
|
109
87
|
/**
|
|
110
|
-
* Section-scoped singleton surface. The
|
|
111
|
-
* `
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* moves that wiring into this registration, and the renderer discovers it
|
|
115
|
-
* through `ToolRegistry.getToolsBySurface("section-overlay")`.
|
|
88
|
+
* Section-scoped singleton surface. The renderer discovers it through
|
|
89
|
+
* `ToolRegistry.getToolsBySurface("section-overlay")`, so the section player
|
|
90
|
+
* names no tool id and a host can contribute another section-scoped
|
|
91
|
+
* capability.
|
|
116
92
|
*/
|
|
117
93
|
surfaces: ["section-overlay"],
|
|
118
|
-
// Annotation appears where there's text content
|
|
119
94
|
supportedLevels: ["passage", "rubric", "item", "element"],
|
|
120
|
-
// PNP support IDs
|
|
121
|
-
// Maps to QTI 3.0 standard features: highlighting, annotations
|
|
122
|
-
pnpSupportIds: [
|
|
123
|
-
"highlighting", // QTI 3.0 standard (cognitive.highlighting / reading.wordHighlighting)
|
|
124
|
-
"annotations", // QTI 3.0 standard (cognitive.annotations)
|
|
125
|
-
],
|
|
126
95
|
/**
|
|
127
96
|
* Pass 2: Annotation is relevant when readable text is present
|
|
128
97
|
*/
|
|
@@ -145,16 +114,11 @@ export const annotationToolbarRegistration = {
|
|
|
145
114
|
return null;
|
|
146
115
|
}
|
|
147
116
|
const element = document.createElement(tagName);
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
// `updateAssessment(...)`
|
|
151
|
-
// remounting — closing over the render-time services would leave the gateway
|
|
152
|
-
// highlighting into the previous session's coordinator.
|
|
117
|
+
// The gateway reads its services from the toolkit runtime context. What it
|
|
118
|
+
// takes from here is the action list, rebuilt from the current services on
|
|
119
|
+
// every sync so a mid-session `updateAssessment(...)` reaches it.
|
|
153
120
|
const applyServices = (current) => {
|
|
154
121
|
element.enabled = true;
|
|
155
|
-
element.ttsService = current.services.ttsService;
|
|
156
|
-
element.highlightCoordinator =
|
|
157
|
-
current.services.toolkitCoordinator?.highlightCoordinator ?? null;
|
|
158
122
|
// The second door onto the dictionaries. The gateway renders these and
|
|
159
123
|
// knows nothing of what they open; the pairing is composition's, which is
|
|
160
124
|
// why the list is built in `selection-actions.ts` and not here.
|
|
@@ -164,8 +128,6 @@ export const annotationToolbarRegistration = {
|
|
|
164
128
|
return { element, sync: applyServices };
|
|
165
129
|
},
|
|
166
130
|
renderToolbar(context, toolbarContext) {
|
|
167
|
-
return renderOverlayToolbar(this, context, toolbarContext
|
|
168
|
-
handsOverCoordinator: true,
|
|
169
|
-
});
|
|
131
|
+
return renderOverlayToolbar(this, context, toolbarContext);
|
|
170
132
|
},
|
|
171
133
|
};
|