@pie-players/pie-assessment-player 0.3.73 → 0.3.75
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -15
- package/dist/components/AssessmentPlayerDefaultElement.d.ts +18 -1
- package/dist/components/assessment-section-player-runtime.d.ts +1 -0
- package/dist/contracts/public-events.d.ts +0 -1
- package/dist/controller/AssessmentController.d.ts +19 -5
- package/dist/{nl-NL-FLtEAIq9.js → nl-NL-CfezB59b.js} +9 -26
- package/dist/pie-assessment-player.js +319 -417
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -8,6 +8,9 @@ Primary entrypoint:
|
|
|
8
8
|
|
|
9
9
|
- `@pie-players/pie-assessment-player`
|
|
10
10
|
|
|
11
|
+
The entry is bundler-only: it imports the toolkit, players-shared and the
|
|
12
|
+
section player by bare specifier.
|
|
13
|
+
|
|
11
14
|
## AssessmentController
|
|
12
15
|
|
|
13
16
|
`AssessmentController` is the domain authority for an assessment attempt. It
|
|
@@ -40,10 +43,10 @@ pending or failed, and after disconnect. A waiter resolves to `null` when its
|
|
|
40
43
|
active attempt fails or is retired, or its own timeout expires. A waiter's
|
|
41
44
|
timeout does not cancel a still-active initialization.
|
|
42
45
|
|
|
43
|
-
Connect the element and assign `assessmentId`, `attemptId`, `assessment`,
|
|
44
|
-
`hooks` in the same turn, or assign them before connecting. These
|
|
45
|
-
are batched; changing assessment, attempt, or
|
|
46
|
-
controller and starts a new one. Replace object properties to update them;
|
|
46
|
+
Connect the element and assign `assessmentId`, `attemptId`, `assessment`,
|
|
47
|
+
`hooks` and `session` in the same turn, or assign them before connecting. These
|
|
48
|
+
assignments are batched; changing assessment, attempt, hooks or session later
|
|
49
|
+
retires the previous controller and starts a new one. Replace object properties to update them;
|
|
47
50
|
mutating a previously assigned object in place is not an update signal. Runtime
|
|
48
51
|
props, locale, and navigation visibility do not reload the assessment.
|
|
49
52
|
|
|
@@ -68,7 +71,8 @@ controller.navigateTo("section-2");
|
|
|
68
71
|
controller.navigateNext();
|
|
69
72
|
controller.navigatePrevious();
|
|
70
73
|
|
|
71
|
-
// persist on whatever cadence the host wants;
|
|
74
|
+
// persist on whatever cadence the host wants; saves run in call order.
|
|
75
|
+
// submit() saves first and rejects, unsubmitted, if that save fails.
|
|
72
76
|
await controller.persist();
|
|
73
77
|
await controller.submit();
|
|
74
78
|
unsubscribe();
|
|
@@ -79,10 +83,20 @@ shape the persistence strategy load/save methods exchange and the same
|
|
|
79
83
|
shape per-section bridges roll up into via `updateSectionSession(sectionId,
|
|
80
84
|
snapshot)`.
|
|
81
85
|
|
|
86
|
+
The element's `session` property takes that shape too. The controller's first
|
|
87
|
+
hydrate applies an assigned session in place of the strategy's `loadSession`;
|
|
88
|
+
the strategy still receives every `persist()`. The value is consumed once: a
|
|
89
|
+
rebuild for another reason, such as an `assessment` change, hydrates from the
|
|
90
|
+
strategy. Assigning a session equal to the controller's, as writing
|
|
91
|
+
`assessment-session-changed` back into the property does, is a no-op, and so is
|
|
92
|
+
`null` once the controller is ready. Reading `session` returns the assigned value
|
|
93
|
+
until the controller is ready and a copy of the controller's session after.
|
|
94
|
+
|
|
82
95
|
The default element captures the outgoing section before navigation replaces it,
|
|
83
|
-
including navigation through the controller. A returning section
|
|
84
|
-
|
|
85
|
-
|
|
96
|
+
including navigation through the controller. A returning section receives its
|
|
97
|
+
saved section snapshot as the section player's `session` property, which its
|
|
98
|
+
controller applies before the canonical `engine-ready` stage; the section accepts
|
|
99
|
+
input and session updates from `engine-ready` on. The section region stays `aria-busy` during
|
|
86
100
|
this handoff. Failed restoration leaves the saved snapshot intact, reports
|
|
87
101
|
`assessment-error` and `onError` with phase `navigation`, and offers Retry.
|
|
88
102
|
Navigating away or disconnecting retires that handoff. This in-memory restoration
|
|
@@ -98,9 +112,11 @@ change only — section-level events flow through the embedded
|
|
|
98
112
|
|
|
99
113
|
- `assessment-route-changed` — section-level navigation moved (index / id,
|
|
100
114
|
`previousSectionId`, `canNext` / `canPrevious`).
|
|
101
|
-
- `assessment-session-applied` — `hydrate()`
|
|
115
|
+
- `assessment-session-applied` — `hydrate()` applied a session, persisted or
|
|
116
|
+
assigned as `session`.
|
|
102
117
|
- `assessment-session-changed` — assessment session mutated (navigation,
|
|
103
|
-
per-section snapshot upsert).
|
|
118
|
+
per-section snapshot upsert). The active section's snapshot is upserted once
|
|
119
|
+
for each `session-changed` it emits.
|
|
104
120
|
- `assessment-progress-changed` — visited-section count flipped.
|
|
105
121
|
- `assessment-submission-state-changed` — `submit()` recorded the final
|
|
106
122
|
state.
|
|
@@ -189,16 +205,75 @@ Toolkit tool/backend operational stream (when toolkit is mounted):
|
|
|
189
205
|
- `pie-tool-backend-call-start|success|error`
|
|
190
206
|
- `pie-tool-library-load-start|success|error`
|
|
191
207
|
|
|
208
|
+
## Preloaded elements
|
|
209
|
+
|
|
210
|
+
With `player-type="preloaded"` (or `playerType = "preloaded"`) the section
|
|
211
|
+
players load no element code, and their pre-warm asserts that every tag the
|
|
212
|
+
content names is registered. The host registers the elements with
|
|
213
|
+
`registerPreloadedElements` from `@pie-players/pie-item-player/preloaded`
|
|
214
|
+
before the assessment player mounts:
|
|
215
|
+
|
|
216
|
+
```ts
|
|
217
|
+
import { registerPreloadedElements } from "@pie-players/pie-item-player/preloaded";
|
|
218
|
+
import * as delivery from "@pie-element/multiple-choice/browser/delivery";
|
|
219
|
+
import * as controller from "@pie-element/multiple-choice/browser/controller";
|
|
220
|
+
import manifest from "../package.json"; // pins "@pie-element/multiple-choice" exactly
|
|
221
|
+
|
|
222
|
+
registerPreloadedElements(
|
|
223
|
+
[
|
|
224
|
+
{
|
|
225
|
+
tag: "pie-element-multiple-choice",
|
|
226
|
+
package: "@pie-element/multiple-choice",
|
|
227
|
+
version: manifest.dependencies["@pie-element/multiple-choice"],
|
|
228
|
+
element: delivery,
|
|
229
|
+
controller,
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
{ math: { assetRoot: "https://assets.example.com/npm" } },
|
|
233
|
+
);
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
- A tag missing at pre-warm leaves the section's items unmounted and raises a
|
|
237
|
+
non-recoverable `element-preload` framework error.
|
|
238
|
+
- Install element packages with `npm install --save-exact`. npm otherwise saves
|
|
239
|
+
a caret range, which registration rejects as a `version`, and which a fresh
|
|
240
|
+
install can resolve to another release line: `^13.4.0-next.15` resolves to
|
|
241
|
+
the legacy `13.4.4`, which has no `./browser/*` modules.
|
|
242
|
+
- Install every pie-elements-ng package from one release, in one install from
|
|
243
|
+
the same dist-tag, and upgrade them together. Elements whose `./browser/*`
|
|
244
|
+
builds typeset on `window.MathJax` share the MathJax the first of them loads,
|
|
245
|
+
in the build and configuration of that element's release, so in a mixed set
|
|
246
|
+
an element can typeset with a MathJax it was not built for. Elements that
|
|
247
|
+
bundle their own MathJax share none
|
|
248
|
+
([One MathJax version per page](../../docs/item-player/loading-strategies.md#one-mathjax-version-per-page)).
|
|
249
|
+
- Pass `math.assetRoot`, an npm root serving the fonts and speech the elements'
|
|
250
|
+
bundled MathJax loads, or `math.assetUrls`, each file's URL; without either,
|
|
251
|
+
elements on adapter 0.1.3 or later render without web fonts and speech
|
|
252
|
+
([MathJax assets](../../docs/item-player/loading-strategies.md#mathjax-assets)).
|
|
253
|
+
- Register one version per package; registering a second version throws.
|
|
254
|
+
- Register each package's `controller` unless the item players are hosted
|
|
255
|
+
(`sectionPlayerRuntime.player.hosted`, or an enabled
|
|
256
|
+
`sectionPlayerRuntime.player.backend.delivery`). A player that is not hosted
|
|
257
|
+
runs `model()` in the browser and warns for each tag registered without one.
|
|
258
|
+
- Only `@pie-element/*` builds from pie-elements-ng publish
|
|
259
|
+
`./browser/delivery` and `./browser/controller`.
|
|
260
|
+
- Under TypeScript, the `package.json` import needs `resolveJsonModule`, and a
|
|
261
|
+
package version that ships no declarations for `./browser/*` needs a
|
|
262
|
+
`declare module` shim for those subpaths.
|
|
263
|
+
|
|
264
|
+
See [`strategy="preloaded"`](../../docs/item-player/loading-strategies.md#strategypreloaded)
|
|
265
|
+
for the registration contract.
|
|
266
|
+
|
|
192
267
|
## Content trust boundary
|
|
193
268
|
|
|
194
269
|
Assessment markup reaches the DOM via the underlying
|
|
195
270
|
`<pie-item-player>` element, which now sanitizes item / passage markup by
|
|
196
|
-
default through DOMPurify. See
|
|
197
|
-
[pie-item-player README](
|
|
271
|
+
default through DOMPurify. See the
|
|
272
|
+
[pie-item-player README](../item-player/README.md#content-trust-boundary)
|
|
198
273
|
for the allow-list, opt-out mechanics (`trust-markup`), and the
|
|
199
274
|
`sanitizeMarkup` property override. Assessment-player hosts forward these
|
|
200
|
-
settings by setting `
|
|
201
|
-
`
|
|
202
|
-
|
|
275
|
+
settings by setting `sectionPlayerRuntime.player.trustMarkup` /
|
|
276
|
+
`sectionPlayerRuntime.player.sanitizeMarkup` on the assessment player; it passes
|
|
277
|
+
that runtime to each section player, whose runtime flattens `runtime.player.*`
|
|
203
278
|
fields onto the embedded `<pie-item-player>` (see the section-player README
|
|
204
279
|
for the exact forwarding shape).
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Env } from '@pie-players/pie-players-shared/types';
|
|
2
2
|
import { AssessmentControllerHandle } from '../controller/AssessmentController.js';
|
|
3
3
|
import { AssessmentPlayerProgressSnapshot, AssessmentPlayerRuntimeHostContract, AssessmentPlayerSnapshot } from '../contracts/runtime-host-contract.js';
|
|
4
|
-
import { AssessmentDefinition, AssessmentPlayerHooks, AssessmentPlayerRuntimeConfig } from '../types.js';
|
|
4
|
+
import { AssessmentDefinition, AssessmentPlayerHooks, AssessmentPlayerRuntimeConfig, AssessmentSession } from '../types.js';
|
|
5
5
|
export declare class AssessmentPlayerDefaultElement extends HTMLElement implements AssessmentPlayerRuntimeHostContract {
|
|
6
6
|
static get observedAttributes(): string[];
|
|
7
7
|
private _assessmentId;
|
|
@@ -16,6 +16,13 @@ export declare class AssessmentPlayerDefaultElement extends HTMLElement implemen
|
|
|
16
16
|
private _env;
|
|
17
17
|
private _coordinator;
|
|
18
18
|
private _hooks;
|
|
19
|
+
/**
|
|
20
|
+
* The assigned session until a controller initializes from it. A later
|
|
21
|
+
* rebuild, such as one an `assessment` change causes, hydrates from the
|
|
22
|
+
* persistence strategy rather than reapplying a value the learner has since
|
|
23
|
+
* moved past.
|
|
24
|
+
*/
|
|
25
|
+
private pendingSession;
|
|
19
26
|
private _showNavigation;
|
|
20
27
|
private _sectionPlayerLayout;
|
|
21
28
|
private _playerType;
|
|
@@ -63,6 +70,12 @@ export declare class AssessmentPlayerDefaultElement extends HTMLElement implemen
|
|
|
63
70
|
set assessment(value: AssessmentDefinition | null);
|
|
64
71
|
get hooks(): AssessmentPlayerHooks | null;
|
|
65
72
|
set hooks(value: AssessmentPlayerHooks | null);
|
|
73
|
+
/**
|
|
74
|
+
* Before a controller is ready, the assigned session; after, a copy of the
|
|
75
|
+
* controller's.
|
|
76
|
+
*/
|
|
77
|
+
get session(): AssessmentSession | null;
|
|
78
|
+
set session(value: AssessmentSession | null);
|
|
66
79
|
get locale(): string;
|
|
67
80
|
set locale(value: string);
|
|
68
81
|
get env(): Env | null;
|
|
@@ -133,6 +146,10 @@ export declare class AssessmentPlayerDefaultElement extends HTMLElement implemen
|
|
|
133
146
|
private updateCurrentSectionRuntime;
|
|
134
147
|
private cleanupTtsForSectionNavigation;
|
|
135
148
|
private syncCurrentSectionSessionIntoAssessment;
|
|
149
|
+
/**
|
|
150
|
+
* `restoring` is whether the section was handed a saved session, which it
|
|
151
|
+
* applies while it creates its controller, before `engine-ready`.
|
|
152
|
+
*/
|
|
136
153
|
private attachSectionControllerReadyListener;
|
|
137
154
|
private render;
|
|
138
155
|
/** Locale and chrome changes must not remount a section or reload its attempt. */
|
|
@@ -3,6 +3,7 @@ import { AssessmentPlayerRuntimeConfig } from '../types.js';
|
|
|
3
3
|
export type ResolveAssessmentSectionPlayerRuntimeArgs = {
|
|
4
4
|
sectionPlayerRuntime?: AssessmentPlayerRuntimeConfig["sectionPlayerRuntime"];
|
|
5
5
|
playerType: "iife" | "esm" | "preloaded";
|
|
6
|
+
assessmentId?: string;
|
|
6
7
|
attemptId?: string;
|
|
7
8
|
env?: Record<string, unknown> | null;
|
|
8
9
|
coordinator?: unknown;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export declare const ASSESSMENT_PLAYER_PUBLIC_EVENTS: {
|
|
2
2
|
readonly controllerReady: "assessment-controller-ready";
|
|
3
3
|
readonly navigationRequested: "assessment-navigation-requested";
|
|
4
|
-
readonly submitRequested: "assessment-submit-requested";
|
|
5
4
|
readonly routeChanged: "assessment-route-changed";
|
|
6
5
|
readonly sessionApplied: "assessment-session-applied";
|
|
7
6
|
readonly sessionChanged: "assessment-session-changed";
|
|
@@ -83,8 +83,8 @@ export interface AssessmentControllerHandle {
|
|
|
83
83
|
* persistence strategy.
|
|
84
84
|
*
|
|
85
85
|
* Hosts call this on whatever cadence they choose (debounced on
|
|
86
|
-
* change, on visibility change, on submit).
|
|
87
|
-
* `
|
|
86
|
+
* change, on visibility change, on submit). Saves run in call order.
|
|
87
|
+
* A failed save goes to `onError` and the returned promise resolves.
|
|
88
88
|
*/
|
|
89
89
|
persist(): Promise<void>;
|
|
90
90
|
/**
|
|
@@ -123,9 +123,9 @@ export interface AssessmentControllerHandle {
|
|
|
123
123
|
*/
|
|
124
124
|
navigatePrevious(): boolean;
|
|
125
125
|
/**
|
|
126
|
-
*
|
|
127
|
-
* `assessment-submission-state-changed
|
|
128
|
-
*
|
|
126
|
+
* Save the final snapshot, then mark the assessment as submitted and
|
|
127
|
+
* emit `assessment-submission-state-changed`. A failed save goes to
|
|
128
|
+
* `onError` and rejects, and the assessment stays unsubmitted.
|
|
129
129
|
*/
|
|
130
130
|
submit(): Promise<void>;
|
|
131
131
|
/**
|
|
@@ -174,16 +174,25 @@ export declare class AssessmentController implements AssessmentControllerHandle
|
|
|
174
174
|
private session;
|
|
175
175
|
private readiness;
|
|
176
176
|
private submitted;
|
|
177
|
+
private saveQueue;
|
|
177
178
|
private persistenceStrategy?;
|
|
178
179
|
private initializationPromise?;
|
|
179
180
|
private disposalPromise?;
|
|
180
181
|
private disposed;
|
|
181
182
|
private readonly storageContext;
|
|
183
|
+
/** Taken by the first hydrate; a later `hydrate()` loads from the strategy. */
|
|
184
|
+
private initialSession;
|
|
182
185
|
constructor(args: {
|
|
183
186
|
assessmentId: string;
|
|
184
187
|
attemptId?: string;
|
|
185
188
|
assessment: AssessmentDefinition | null;
|
|
186
189
|
hooks?: AssessmentPlayerHooks;
|
|
190
|
+
/**
|
|
191
|
+
* A host-supplied session, applied by the first hydrate in place of the
|
|
192
|
+
* persistence strategy's `loadSession` result. The controller keeps a
|
|
193
|
+
* copy, so later updates never write into the host's object.
|
|
194
|
+
*/
|
|
195
|
+
initialSession?: AssessmentSession | null;
|
|
187
196
|
});
|
|
188
197
|
private emit;
|
|
189
198
|
private assertActive;
|
|
@@ -196,6 +205,11 @@ export declare class AssessmentController implements AssessmentControllerHandle
|
|
|
196
205
|
hydrate(): Promise<void>;
|
|
197
206
|
dispose(): Promise<void>;
|
|
198
207
|
persist(): Promise<void>;
|
|
208
|
+
/**
|
|
209
|
+
* Saves run one at a time, in call order, so a slow older write can never
|
|
210
|
+
* land after a newer one. A failed save rejects only its own caller.
|
|
211
|
+
*/
|
|
212
|
+
private save;
|
|
199
213
|
getSession(): AssessmentSession | null;
|
|
200
214
|
getRuntimeState(): AssessmentControllerRuntimeState;
|
|
201
215
|
private buildNavigationSnapshot;
|
|
@@ -43,6 +43,7 @@ var e = {
|
|
|
43
43
|
items: "Vragen",
|
|
44
44
|
section: "Onderdeel",
|
|
45
45
|
loadingSection: "Onderdeel wordt geladen…",
|
|
46
|
+
sectionLoadError: "Het onderdeel kon niet worden geladen.",
|
|
46
47
|
loadingPassage: "Tekst wordt geladen…",
|
|
47
48
|
configurationError: "Configuratiefout",
|
|
48
49
|
playerError: "Fout in de speler",
|
|
@@ -108,6 +109,11 @@ var e = {
|
|
|
108
109
|
centerA11y: "Venster centreren",
|
|
109
110
|
closeA11y: "Hulpmiddel sluiten"
|
|
110
111
|
},
|
|
112
|
+
placement: {
|
|
113
|
+
controlsA11y: "Verplaatsen en draaien",
|
|
114
|
+
rotateClockwiseA11y: "{degrees}° rechtsom draaien",
|
|
115
|
+
rotateCounterclockwiseA11y: "{degrees}° linksom draaien"
|
|
116
|
+
},
|
|
111
117
|
announce: {
|
|
112
118
|
movedUp: "Omhoog verplaatst naar {position}",
|
|
113
119
|
movedDown: "Omlaag verplaatst naar {position}",
|
|
@@ -135,8 +141,8 @@ var e = {
|
|
|
135
141
|
},
|
|
136
142
|
graph: {
|
|
137
143
|
name: "Grafiek",
|
|
138
|
-
description: "
|
|
139
|
-
buttonA11y: "Grafiek,
|
|
144
|
+
description: "Assenstelsel",
|
|
145
|
+
buttonA11y: "Grafiek, assenstelsel",
|
|
140
146
|
tooltip: "Grafiek",
|
|
141
147
|
toolA11y: "Grafiekhulpmiddel — punten en lijnen tekenen in een assenstelsel",
|
|
142
148
|
canvasA11y: "Tekenvlak — gebruik de hulpmiddelen om punten toe te voegen en lijnen te tekenen",
|
|
@@ -300,30 +306,6 @@ var e = {
|
|
|
300
306
|
textToSpeech: {
|
|
301
307
|
name: "Voorlezen",
|
|
302
308
|
description: "Inhoud laten voorlezen",
|
|
303
|
-
toolA11y: "Voorleeshulp",
|
|
304
|
-
title: "Voorlezen",
|
|
305
|
-
initializing: "Wordt gestart…",
|
|
306
|
-
initFailed: "Voorlezen kon niet worden gestart.",
|
|
307
|
-
selectText: "Selecteer tekst op de pagina om die te laten voorlezen.",
|
|
308
|
-
speed: "Snelheid:",
|
|
309
|
-
play: "Voorlezen",
|
|
310
|
-
pause: "Pauzeren",
|
|
311
|
-
resume: "Hervatten",
|
|
312
|
-
stop: "Stoppen",
|
|
313
|
-
speaking: "Aan het voorlezen…",
|
|
314
|
-
paused: "Gepauzeerd",
|
|
315
|
-
charactersSelected: {
|
|
316
|
-
one: "{count} teken geselecteerd",
|
|
317
|
-
other: "{count} tekens geselecteerd"
|
|
318
|
-
},
|
|
319
|
-
rate: {
|
|
320
|
-
slow: "Langzaam",
|
|
321
|
-
slower: "Langzamer",
|
|
322
|
-
normal: "Normaal",
|
|
323
|
-
faster: "Sneller",
|
|
324
|
-
fast: "Snel",
|
|
325
|
-
veryFast: "Zeer snel"
|
|
326
|
-
},
|
|
327
309
|
inline: {
|
|
328
310
|
controlsA11y: "Voorleesknoppen",
|
|
329
311
|
playbackSpeedA11y: "Voorleessnelheid",
|
|
@@ -429,6 +411,7 @@ var e = {
|
|
|
429
411
|
resolvedTools: "Toegekende hulpmiddelen (toolkit)",
|
|
430
412
|
provenanceSummary: "Overzicht van herkomst van het hulpmiddelenbeleid",
|
|
431
413
|
perToolDecisions: "Beslissingen per hulpmiddel",
|
|
414
|
+
policyDiagnostics: "Diagnose van het hulpmiddelenbeleid",
|
|
432
415
|
profileReadOnly: "PNP-profiel (alleen lezen)"
|
|
433
416
|
},
|
|
434
417
|
tts: {
|