@pie-players/pie-assessment-toolkit 0.2.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 +520 -0
- package/dist/attempt/TestSession.d.ts +90 -0
- package/dist/attempt/TestSession.d.ts.map +1 -0
- package/dist/attempt/TestSession.js +174 -0
- package/dist/attempt/TestSession.js.map +1 -0
- package/dist/core/TypedEventBus.d.ts +48 -0
- package/dist/core/TypedEventBus.d.ts.map +1 -0
- package/dist/core/TypedEventBus.js +63 -0
- package/dist/core/TypedEventBus.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/item-loader.d.ts +45 -0
- package/dist/item-loader.d.ts.map +1 -0
- package/dist/item-loader.js +62 -0
- package/dist/item-loader.js.map +1 -0
- package/dist/player/AssessmentPlayer.d.ts +388 -0
- package/dist/player/AssessmentPlayer.d.ts.map +1 -0
- package/dist/player/AssessmentPlayer.js +965 -0
- package/dist/player/AssessmentPlayer.js.map +1 -0
- package/dist/player/index.d.ts +17 -0
- package/dist/player/index.d.ts.map +1 -0
- package/dist/player/index.js +15 -0
- package/dist/player/index.js.map +1 -0
- package/dist/player/navigation-types.d.ts +63 -0
- package/dist/player/navigation-types.d.ts.map +1 -0
- package/dist/player/navigation-types.js +7 -0
- package/dist/player/navigation-types.js.map +1 -0
- package/dist/player/qti-navigation.d.ts +29 -0
- package/dist/player/qti-navigation.d.ts.map +1 -0
- package/dist/player/qti-navigation.js +160 -0
- package/dist/player/qti-navigation.js.map +1 -0
- package/dist/reference-layout/index.d.ts +19 -0
- package/dist/reference-layout/index.d.ts.map +1 -0
- package/dist/reference-layout/index.js +20 -0
- package/dist/reference-layout/index.js.map +1 -0
- package/dist/services/AccessibilityCatalogResolver.d.ts +141 -0
- package/dist/services/AccessibilityCatalogResolver.d.ts.map +1 -0
- package/dist/services/AccessibilityCatalogResolver.js +249 -0
- package/dist/services/AccessibilityCatalogResolver.js.map +1 -0
- package/dist/services/AssessmentAuthoringService.d.ts +60 -0
- package/dist/services/AssessmentAuthoringService.d.ts.map +1 -0
- package/dist/services/AssessmentAuthoringService.js +183 -0
- package/dist/services/AssessmentAuthoringService.js.map +1 -0
- package/dist/services/ContextVariableStore.d.ts +114 -0
- package/dist/services/ContextVariableStore.d.ts.map +1 -0
- package/dist/services/ContextVariableStore.js +207 -0
- package/dist/services/ContextVariableStore.js.map +1 -0
- package/dist/services/ElementToolStateStore.d.ts +125 -0
- package/dist/services/ElementToolStateStore.d.ts.map +1 -0
- package/dist/services/ElementToolStateStore.js +200 -0
- package/dist/services/ElementToolStateStore.js.map +1 -0
- package/dist/services/HighlightCoordinator.d.ts +179 -0
- package/dist/services/HighlightCoordinator.d.ts.map +1 -0
- package/dist/services/HighlightCoordinator.js +446 -0
- package/dist/services/HighlightCoordinator.js.map +1 -0
- package/dist/services/I18nService.d.ts +121 -0
- package/dist/services/I18nService.d.ts.map +1 -0
- package/dist/services/I18nService.js +276 -0
- package/dist/services/I18nService.js.map +1 -0
- package/dist/services/PNPMapper.d.ts +71 -0
- package/dist/services/PNPMapper.d.ts.map +1 -0
- package/dist/services/PNPMapper.js +98 -0
- package/dist/services/PNPMapper.js.map +1 -0
- package/dist/services/PNPToolResolver.d.ts +127 -0
- package/dist/services/PNPToolResolver.d.ts.map +1 -0
- package/dist/services/PNPToolResolver.js +222 -0
- package/dist/services/PNPToolResolver.js.map +1 -0
- package/dist/services/SSMLExtractor.d.ts +61 -0
- package/dist/services/SSMLExtractor.d.ts.map +1 -0
- package/dist/services/SSMLExtractor.js +181 -0
- package/dist/services/SSMLExtractor.js.map +1 -0
- package/dist/services/TTSService.d.ts +162 -0
- package/dist/services/TTSService.d.ts.map +1 -0
- package/dist/services/TTSService.js +465 -0
- package/dist/services/TTSService.js.map +1 -0
- package/dist/services/ThemeProvider.d.ts +95 -0
- package/dist/services/ThemeProvider.d.ts.map +1 -0
- package/dist/services/ThemeProvider.js +299 -0
- package/dist/services/ThemeProvider.js.map +1 -0
- package/dist/services/ToolConfigResolver.d.ts +162 -0
- package/dist/services/ToolConfigResolver.d.ts.map +1 -0
- package/dist/services/ToolConfigResolver.js +230 -0
- package/dist/services/ToolConfigResolver.js.map +1 -0
- package/dist/services/ToolCoordinator.d.ts +137 -0
- package/dist/services/ToolCoordinator.d.ts.map +1 -0
- package/dist/services/ToolCoordinator.js +318 -0
- package/dist/services/ToolCoordinator.js.map +1 -0
- package/dist/services/ToolkitCoordinator.d.ts +188 -0
- package/dist/services/ToolkitCoordinator.d.ts.map +1 -0
- package/dist/services/ToolkitCoordinator.js +252 -0
- package/dist/services/ToolkitCoordinator.js.map +1 -0
- package/dist/services/interfaces.d.ts +391 -0
- package/dist/services/interfaces.d.ts.map +1 -0
- package/dist/services/interfaces.js +12 -0
- package/dist/services/interfaces.js.map +1 -0
- package/dist/services/tool-providers/DesmosToolProvider.d.ts +103 -0
- package/dist/services/tool-providers/DesmosToolProvider.d.ts.map +1 -0
- package/dist/services/tool-providers/DesmosToolProvider.js +127 -0
- package/dist/services/tool-providers/DesmosToolProvider.js.map +1 -0
- package/dist/services/tool-providers/IToolProvider.d.ts +137 -0
- package/dist/services/tool-providers/IToolProvider.d.ts.map +1 -0
- package/dist/services/tool-providers/IToolProvider.js +13 -0
- package/dist/services/tool-providers/IToolProvider.js.map +1 -0
- package/dist/services/tool-providers/TIToolProvider.d.ts +107 -0
- package/dist/services/tool-providers/TIToolProvider.d.ts.map +1 -0
- package/dist/services/tool-providers/TIToolProvider.js +123 -0
- package/dist/services/tool-providers/TIToolProvider.js.map +1 -0
- package/dist/services/tool-providers/TTSToolProvider.d.ts +143 -0
- package/dist/services/tool-providers/TTSToolProvider.d.ts.map +1 -0
- package/dist/services/tool-providers/TTSToolProvider.js +168 -0
- package/dist/services/tool-providers/TTSToolProvider.js.map +1 -0
- package/dist/services/tool-providers/ToolProviderRegistry.d.ts +165 -0
- package/dist/services/tool-providers/ToolProviderRegistry.d.ts.map +1 -0
- package/dist/services/tool-providers/ToolProviderRegistry.js +240 -0
- package/dist/services/tool-providers/ToolProviderRegistry.js.map +1 -0
- package/dist/services/tool-providers/index.d.ts +18 -0
- package/dist/services/tool-providers/index.d.ts.map +1 -0
- package/dist/services/tool-providers/index.js +15 -0
- package/dist/services/tool-providers/index.js.map +1 -0
- package/dist/services/tts/browser-provider.d.ts +24 -0
- package/dist/services/tts/browser-provider.d.ts.map +1 -0
- package/dist/services/tts/browser-provider.js +177 -0
- package/dist/services/tts/browser-provider.js.map +1 -0
- package/dist/services/tts/provider-interface.d.ts +131 -0
- package/dist/services/tts/provider-interface.d.ts.map +1 -0
- package/dist/services/tts/provider-interface.js +10 -0
- package/dist/services/tts/provider-interface.js.map +1 -0
- package/dist/tools/calculators/desmos-provider.d.ts +54 -0
- package/dist/tools/calculators/desmos-provider.d.ts.map +1 -0
- package/dist/tools/calculators/desmos-provider.js +384 -0
- package/dist/tools/calculators/desmos-provider.js.map +1 -0
- package/dist/tools/calculators/mathjs-provider.d.ts +50 -0
- package/dist/tools/calculators/mathjs-provider.d.ts.map +1 -0
- package/dist/tools/calculators/mathjs-provider.js +660 -0
- package/dist/tools/calculators/mathjs-provider.js.map +1 -0
- package/dist/tools/calculators/ti-provider.d.ts +122 -0
- package/dist/tools/calculators/ti-provider.d.ts.map +1 -0
- package/dist/tools/calculators/ti-provider.js +587 -0
- package/dist/tools/calculators/ti-provider.js.map +1 -0
- package/dist/tools/client.d.ts +17 -0
- package/dist/tools/client.d.ts.map +1 -0
- package/dist/tools/client.js +26 -0
- package/dist/tools/client.js.map +1 -0
- package/dist/tools/index.d.ts +8 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +10 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/library-loader.d.ts +63 -0
- package/dist/tools/library-loader.d.ts.map +1 -0
- package/dist/tools/library-loader.js +292 -0
- package/dist/tools/library-loader.js.map +1 -0
- package/dist/tools/response-discovery.d.ts +72 -0
- package/dist/tools/response-discovery.d.ts.map +1 -0
- package/dist/tools/response-discovery.js +183 -0
- package/dist/tools/response-discovery.js.map +1 -0
- package/dist/tools/tool-coordinator.d.ts +76 -0
- package/dist/tools/tool-coordinator.d.ts.map +1 -0
- package/dist/tools/tool-coordinator.js +197 -0
- package/dist/tools/tool-coordinator.js.map +1 -0
- package/dist/tools/types.d.ts +427 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +13 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/variant-resolver.d.ts +48 -0
- package/dist/tools/variant-resolver.d.ts.map +1 -0
- package/dist/tools/variant-resolver.js +214 -0
- package/dist/tools/variant-resolver.js.map +1 -0
- package/dist/types/events.d.ts +157 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +11 -0
- package/dist/types/events.js.map +1 -0
- package/dist/utils/logger.d.ts +7 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +11 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +71 -0
- package/src/README.md +626 -0
- package/src/components/QuestionToolBar.svelte +406 -0
- package/src/player/AssessmentLayout.svelte +68 -0
- package/src/player/README.md +154 -0
- package/src/reference-layout/README.md +135 -0
- package/src/reference-layout/ReferenceLayout.svelte +209 -0
- package/src/reference-layout/components/AssessmentContent.svelte +259 -0
- package/src/reference-layout/components/AssessmentFooter.svelte +89 -0
- package/src/reference-layout/components/AssessmentHeader.svelte +250 -0
- package/src/reference-layout/components/AssessmentNavigation.svelte +134 -0
- package/src/reference-layout/components/AssessmentToolsBar.svelte +176 -0
- package/src/reference-layout/components/ItemPanel.svelte +200 -0
- package/src/reference-layout/components/NotesPanel.svelte +179 -0
- package/src/reference-layout/components/PassagePanel.svelte +76 -0
- package/src/tools/README.md +616 -0
- package/src/tools/calculators/README.md +395 -0
package/README.md
ADDED
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
# PIE Assessment Toolkit
|
|
2
|
+
|
|
3
|
+
**Independent, composable services** for coordinating tools, accommodations, and item players in assessment applications.
|
|
4
|
+
|
|
5
|
+
This is not an opinionated framework or monolithic "player" - it's a toolkit that solves specific problems through centralized service management.
|
|
6
|
+
|
|
7
|
+
## What's New: ToolkitCoordinator
|
|
8
|
+
|
|
9
|
+
✨ **Centralized Service Management**: The new `ToolkitCoordinator` provides a single entry point for all toolkit services, simplifying initialization and configuration.
|
|
10
|
+
|
|
11
|
+
**Before** (scattered services):
|
|
12
|
+
```typescript
|
|
13
|
+
// Create 5+ services independently
|
|
14
|
+
const ttsService = new TTSService();
|
|
15
|
+
const toolCoordinator = new ToolCoordinator();
|
|
16
|
+
const highlightCoordinator = new HighlightCoordinator();
|
|
17
|
+
const catalogResolver = new AccessibilityCatalogResolver([...]);
|
|
18
|
+
// Missing: ElementToolStateStore
|
|
19
|
+
|
|
20
|
+
await ttsService.initialize(new BrowserTTSProvider());
|
|
21
|
+
ttsService.setCatalogResolver(catalogResolver);
|
|
22
|
+
|
|
23
|
+
// Pass all services separately
|
|
24
|
+
player.ttsService = ttsService;
|
|
25
|
+
player.toolCoordinator = toolCoordinator;
|
|
26
|
+
// ...
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**After** (coordinator orchestrates):
|
|
30
|
+
```typescript
|
|
31
|
+
// Create one coordinator with configuration
|
|
32
|
+
const toolkitCoordinator = new ToolkitCoordinator({
|
|
33
|
+
assessmentId: 'my-assessment',
|
|
34
|
+
tools: {
|
|
35
|
+
tts: { enabled: true },
|
|
36
|
+
answerEliminator: { enabled: true }
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Pass single coordinator to player
|
|
41
|
+
player.toolkitCoordinator = toolkitCoordinator;
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## What Does It Solve?
|
|
45
|
+
|
|
46
|
+
- **Centralized service management**: One coordinator owns all toolkit services
|
|
47
|
+
- **Tool coordination**: z-index management, visibility state, element-level state
|
|
48
|
+
- **Accommodation support**: IEP/504 tool configuration logic
|
|
49
|
+
- **TTS + annotation coordination**: Prevent conflicts between highlights
|
|
50
|
+
- **Event communication**: Standard contracts between components
|
|
51
|
+
- **Accessibility theming**: Consistent high-contrast, font sizing
|
|
52
|
+
- **State separation**: Ephemeral tool state separate from persistent session data
|
|
53
|
+
|
|
54
|
+
## Architecture Overview
|
|
55
|
+
|
|
56
|
+
See [ToolkitCoordinator Architecture](../../docs/architecture/TOOLKIT_COORDINATOR.md) for complete design documentation.
|
|
57
|
+
|
|
58
|
+
### Core Principles
|
|
59
|
+
|
|
60
|
+
1. **Centralized Coordination**: ToolkitCoordinator orchestrates all services
|
|
61
|
+
2. **Composable Services**: Import only what you need (or use coordinator for convenience)
|
|
62
|
+
3. **No Framework Lock-in**: Works with any JavaScript framework
|
|
63
|
+
4. **Product Control**: Products control navigation, persistence, layout, backend
|
|
64
|
+
5. **Standard Contracts**: Well-defined event types for component communication
|
|
65
|
+
6. **Element-Level Granularity**: Tool state tracked per PIE element, not per item
|
|
66
|
+
7. **State Separation**: Tool state (ephemeral) separate from PIE session data (persistent)
|
|
67
|
+
|
|
68
|
+
## Quick Start
|
|
69
|
+
|
|
70
|
+
### Option 1: Use ToolkitCoordinator (Recommended)
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { ToolkitCoordinator } from '@pie-players/pie-assessment-toolkit';
|
|
74
|
+
|
|
75
|
+
// Create coordinator with configuration
|
|
76
|
+
const coordinator = new ToolkitCoordinator({
|
|
77
|
+
assessmentId: 'demo-assessment',
|
|
78
|
+
tools: {
|
|
79
|
+
tts: { enabled: true, defaultVoice: 'en-US' },
|
|
80
|
+
answerEliminator: { enabled: true }
|
|
81
|
+
},
|
|
82
|
+
accessibility: {
|
|
83
|
+
catalogs: assessment.accessibilityCatalogs || [],
|
|
84
|
+
language: 'en-US'
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Pass to section player
|
|
89
|
+
const player = document.getElementById('player');
|
|
90
|
+
player.toolkitCoordinator = coordinator;
|
|
91
|
+
|
|
92
|
+
// Access services directly if needed
|
|
93
|
+
const ttsService = coordinator.ttsService;
|
|
94
|
+
const toolState = coordinator.elementToolStateStore.getAllState();
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Option 2: Create Services Manually (Advanced)
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
import {
|
|
101
|
+
TTSService,
|
|
102
|
+
BrowserTTSProvider,
|
|
103
|
+
ToolCoordinator,
|
|
104
|
+
HighlightCoordinator,
|
|
105
|
+
AccessibilityCatalogResolver,
|
|
106
|
+
ElementToolStateStore
|
|
107
|
+
} from '@pie-players/pie-assessment-toolkit';
|
|
108
|
+
|
|
109
|
+
// Initialize each service independently
|
|
110
|
+
const ttsService = new TTSService();
|
|
111
|
+
const toolCoordinator = new ToolCoordinator();
|
|
112
|
+
const highlightCoordinator = new HighlightCoordinator();
|
|
113
|
+
const elementToolStateStore = new ElementToolStateStore();
|
|
114
|
+
const catalogResolver = new AccessibilityCatalogResolver([], 'en-US');
|
|
115
|
+
|
|
116
|
+
await ttsService.initialize(new BrowserTTSProvider());
|
|
117
|
+
ttsService.setCatalogResolver(catalogResolver);
|
|
118
|
+
|
|
119
|
+
// Pass services individually
|
|
120
|
+
player.ttsService = ttsService;
|
|
121
|
+
player.toolCoordinator = toolCoordinator;
|
|
122
|
+
// ...
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Implementation Status
|
|
126
|
+
|
|
127
|
+
### ✅ Core Infrastructure
|
|
128
|
+
|
|
129
|
+
- **TypedEventBus**: Type-safe event bus built on native EventTarget
|
|
130
|
+
- **Event Types**: Complete event definitions (player, tools, navigation, state, interaction)
|
|
131
|
+
|
|
132
|
+
### ✅ Toolkit Services
|
|
133
|
+
|
|
134
|
+
- **ToolkitCoordinator**: ⭐ NEW - Centralized service orchestration
|
|
135
|
+
- **ElementToolStateStore**: ⭐ NEW - Element-level ephemeral tool state management
|
|
136
|
+
- **ToolCoordinator**: Manages z-index layering and visibility for floating tools
|
|
137
|
+
- **HighlightCoordinator**: Separate highlight layers for TTS (temporary) and annotations (persistent)
|
|
138
|
+
- **TTSService**: Text-to-speech with QTI 3.0 catalog support
|
|
139
|
+
- **AccessibilityCatalogResolver**: QTI 3.0 accessibility catalog management
|
|
140
|
+
- **SSMLExtractor**: Automatic extraction of embedded `<speak>` tags
|
|
141
|
+
- **ThemeProvider**: Consistent accessibility theming
|
|
142
|
+
- **PNPToolResolver**: QTI 3.0 Personal Needs Profile tool resolution
|
|
143
|
+
|
|
144
|
+
### ✅ Section Player Integration
|
|
145
|
+
|
|
146
|
+
The toolkit integrates seamlessly with the **PIE Section Player**:
|
|
147
|
+
|
|
148
|
+
- **Primary Interface**: Section player is the main integration point
|
|
149
|
+
- **Default Coordinator**: Creates ToolkitCoordinator automatically if not provided
|
|
150
|
+
- **Automatic SSML Extraction**: Extracts embedded `<speak>` tags from passages and items
|
|
151
|
+
- **Catalog Lifecycle**: Manages item-level catalogs automatically
|
|
152
|
+
- **Service Coordination**: All toolkit services work together automatically
|
|
153
|
+
|
|
154
|
+
## ToolkitCoordinator API
|
|
155
|
+
|
|
156
|
+
### Configuration
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
export interface ToolkitCoordinatorConfig {
|
|
160
|
+
assessmentId: string; // Required: unique assessment identifier
|
|
161
|
+
tools?: {
|
|
162
|
+
tts?: {
|
|
163
|
+
enabled?: boolean;
|
|
164
|
+
defaultVoice?: string;
|
|
165
|
+
rate?: number;
|
|
166
|
+
provider?: 'browser' | 'server';
|
|
167
|
+
};
|
|
168
|
+
answerEliminator?: {
|
|
169
|
+
enabled?: boolean;
|
|
170
|
+
strategy?: 'strikethrough' | 'hide';
|
|
171
|
+
};
|
|
172
|
+
highlighter?: { enabled?: boolean };
|
|
173
|
+
// ... other tools
|
|
174
|
+
};
|
|
175
|
+
accessibility?: {
|
|
176
|
+
catalogs?: any[];
|
|
177
|
+
language?: string;
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Methods
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
// Get all services as a bundle
|
|
186
|
+
const services = coordinator.getServiceBundle();
|
|
187
|
+
// Returns: { ttsService, toolCoordinator, highlightCoordinator, elementToolStateStore, catalogResolver }
|
|
188
|
+
|
|
189
|
+
// Tool configuration
|
|
190
|
+
coordinator.isToolEnabled('tts'); // Check if tool is enabled
|
|
191
|
+
coordinator.getToolConfig('tts'); // Get tool-specific config
|
|
192
|
+
coordinator.updateToolConfig('tts', { rate: 1.5 }); // Update tool config
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Direct Service Access
|
|
196
|
+
|
|
197
|
+
All services are public properties for direct access:
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
coordinator.ttsService // TTSService instance
|
|
201
|
+
coordinator.toolCoordinator // ToolCoordinator instance
|
|
202
|
+
coordinator.highlightCoordinator // HighlightCoordinator instance
|
|
203
|
+
coordinator.elementToolStateStore // ElementToolStateStore instance
|
|
204
|
+
coordinator.catalogResolver // AccessibilityCatalogResolver instance
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## ElementToolStateStore API
|
|
208
|
+
|
|
209
|
+
The `ElementToolStateStore` manages ephemeral tool state at the element level using globally unique composite keys.
|
|
210
|
+
|
|
211
|
+
### Key Concepts
|
|
212
|
+
|
|
213
|
+
- **Global Element ID**: Composite key format: `${assessmentId}:${sectionId}:${itemId}:${elementId}`
|
|
214
|
+
- **Element-Level Granularity**: State tracked per PIE element (not per item)
|
|
215
|
+
- **Ephemeral State**: Tool state is client-only, separate from PIE session data
|
|
216
|
+
- **Cross-Section Persistence**: State persists when navigating between sections
|
|
217
|
+
|
|
218
|
+
### ID Utilities
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
// Generate global element ID
|
|
222
|
+
const globalElementId = store.getGlobalElementId(
|
|
223
|
+
'demo-assessment',
|
|
224
|
+
'section-1',
|
|
225
|
+
'question-1',
|
|
226
|
+
'mc1'
|
|
227
|
+
);
|
|
228
|
+
// Returns: "demo-assessment:section-1:question-1:mc1"
|
|
229
|
+
|
|
230
|
+
// Parse global element ID
|
|
231
|
+
const components = store.parseGlobalElementId(globalElementId);
|
|
232
|
+
// Returns: { assessmentId, sectionId, itemId, elementId }
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### CRUD Operations
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
// Set state for a tool on an element
|
|
239
|
+
store.setState(globalElementId, 'answerEliminator', {
|
|
240
|
+
eliminatedChoices: ['choice-a', 'choice-c']
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// Get state for a specific tool
|
|
244
|
+
const state = store.getState(globalElementId, 'answerEliminator');
|
|
245
|
+
|
|
246
|
+
// Get all tool states for an element
|
|
247
|
+
const elementState = store.getElementState(globalElementId);
|
|
248
|
+
|
|
249
|
+
// Get all states across all elements
|
|
250
|
+
const allState = store.getAllState();
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Cleanup Operations
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
// Clear state for a specific element
|
|
257
|
+
store.clearElement(globalElementId);
|
|
258
|
+
|
|
259
|
+
// Clear state for a specific tool across all elements
|
|
260
|
+
store.clearTool('answerEliminator');
|
|
261
|
+
|
|
262
|
+
// Clear all elements in a specific section
|
|
263
|
+
store.clearSection('demo-assessment', 'section-1');
|
|
264
|
+
|
|
265
|
+
// Clear all state
|
|
266
|
+
store.clearAll();
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Persistence Integration
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
// Set callback for persistence (e.g., localStorage)
|
|
273
|
+
store.setOnStateChange((state) => {
|
|
274
|
+
localStorage.setItem('tool-state', JSON.stringify(state));
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// Load state from persistence
|
|
278
|
+
const saved = localStorage.getItem('tool-state');
|
|
279
|
+
if (saved) {
|
|
280
|
+
store.loadState(JSON.parse(saved));
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Reactivity
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
// Subscribe to state changes
|
|
288
|
+
const unsubscribe = store.subscribe((state) => {
|
|
289
|
+
console.log('State changed:', state);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// Unsubscribe when done
|
|
293
|
+
unsubscribe();
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## Service APIs
|
|
297
|
+
|
|
298
|
+
### TTSService
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
const ttsService = new TTSService();
|
|
302
|
+
|
|
303
|
+
// Initialize with provider
|
|
304
|
+
await ttsService.initialize(new BrowserTTSProvider());
|
|
305
|
+
|
|
306
|
+
// Set catalog resolver for SSML support
|
|
307
|
+
ttsService.setCatalogResolver(catalogResolver);
|
|
308
|
+
|
|
309
|
+
// Playback
|
|
310
|
+
await ttsService.speak('Read this text', {
|
|
311
|
+
catalogId: 'prompt-001',
|
|
312
|
+
language: 'en-US'
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// Controls
|
|
316
|
+
ttsService.pause();
|
|
317
|
+
ttsService.resume();
|
|
318
|
+
ttsService.stop();
|
|
319
|
+
|
|
320
|
+
// Settings
|
|
321
|
+
await ttsService.updateSettings({
|
|
322
|
+
rate: 1.5,
|
|
323
|
+
voice: 'Matthew'
|
|
324
|
+
});
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### ToolCoordinator
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
const toolCoordinator = new ToolCoordinator();
|
|
331
|
+
|
|
332
|
+
// Register tools
|
|
333
|
+
toolCoordinator.registerTool('calculator', 'Calculator', element);
|
|
334
|
+
|
|
335
|
+
// Manage visibility
|
|
336
|
+
toolCoordinator.showTool('calculator');
|
|
337
|
+
toolCoordinator.hideTool('calculator');
|
|
338
|
+
toolCoordinator.toggleTool('calculator');
|
|
339
|
+
|
|
340
|
+
// Z-index management
|
|
341
|
+
toolCoordinator.bringToFront(element);
|
|
342
|
+
|
|
343
|
+
// Check state
|
|
344
|
+
const isVisible = toolCoordinator.isToolVisible('calculator');
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### HighlightCoordinator
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
const highlightCoordinator = new HighlightCoordinator();
|
|
351
|
+
|
|
352
|
+
// TTS highlights (temporary)
|
|
353
|
+
highlightCoordinator.highlightTTSWord(textNode, start, end);
|
|
354
|
+
highlightCoordinator.highlightTTSSentence([range1, range2]);
|
|
355
|
+
highlightCoordinator.clearTTS();
|
|
356
|
+
|
|
357
|
+
// Annotation highlights (persistent)
|
|
358
|
+
const id = highlightCoordinator.addAnnotation(range, 'yellow');
|
|
359
|
+
highlightCoordinator.removeAnnotation(id);
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### AccessibilityCatalogResolver
|
|
363
|
+
|
|
364
|
+
```typescript
|
|
365
|
+
const resolver = new AccessibilityCatalogResolver(
|
|
366
|
+
assessment.accessibilityCatalogs,
|
|
367
|
+
'en-US'
|
|
368
|
+
);
|
|
369
|
+
|
|
370
|
+
// Add item-level catalogs
|
|
371
|
+
resolver.addItemCatalogs(item.accessibilityCatalogs);
|
|
372
|
+
|
|
373
|
+
// Get alternative representation
|
|
374
|
+
const alternative = resolver.getAlternative('prompt-001', {
|
|
375
|
+
type: 'spoken',
|
|
376
|
+
language: 'en-US'
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
// Clear item catalogs when navigating away
|
|
380
|
+
resolver.clearItemCatalogs();
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### SSMLExtractor
|
|
384
|
+
|
|
385
|
+
```typescript
|
|
386
|
+
const extractor = new SSMLExtractor();
|
|
387
|
+
|
|
388
|
+
// Extract from item config
|
|
389
|
+
const result = extractor.extractFromItemConfig(item.config);
|
|
390
|
+
|
|
391
|
+
// Update item with cleaned config
|
|
392
|
+
item.config = result.cleanedConfig;
|
|
393
|
+
item.config.extractedCatalogs = result.catalogs;
|
|
394
|
+
|
|
395
|
+
// Register with catalog resolver
|
|
396
|
+
catalogResolver.addItemCatalogs(result.catalogs);
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
## Integration with Section Player
|
|
400
|
+
|
|
401
|
+
The section player provides automatic ToolkitCoordinator integration:
|
|
402
|
+
|
|
403
|
+
```html
|
|
404
|
+
<pie-section-player id="player"></pie-section-player>
|
|
405
|
+
|
|
406
|
+
<script type="module">
|
|
407
|
+
import { ToolkitCoordinator } from '@pie-players/pie-assessment-toolkit';
|
|
408
|
+
|
|
409
|
+
// Create coordinator
|
|
410
|
+
const coordinator = new ToolkitCoordinator({
|
|
411
|
+
assessmentId: 'my-assessment',
|
|
412
|
+
tools: { tts: { enabled: true } }
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
// Pass to player
|
|
416
|
+
const player = document.getElementById('player');
|
|
417
|
+
player.toolkitCoordinator = coordinator;
|
|
418
|
+
player.section = mySection;
|
|
419
|
+
|
|
420
|
+
// Player automatically:
|
|
421
|
+
// - Extracts services from coordinator
|
|
422
|
+
// - Generates section ID
|
|
423
|
+
// - Passes services to all child components
|
|
424
|
+
// - Manages SSML extraction
|
|
425
|
+
// - Handles catalog lifecycle
|
|
426
|
+
</script>
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### Standalone Sections (No Coordinator Provided)
|
|
430
|
+
|
|
431
|
+
If no coordinator is provided, the section player creates a default one:
|
|
432
|
+
|
|
433
|
+
```javascript
|
|
434
|
+
// No coordinator provided - section player creates default
|
|
435
|
+
player.section = mySection;
|
|
436
|
+
|
|
437
|
+
// Internally creates:
|
|
438
|
+
// new ToolkitCoordinator({
|
|
439
|
+
// assessmentId: 'anon_...', // auto-generated
|
|
440
|
+
// tools: { tts: { enabled: true }, answerEliminator: { enabled: true } }
|
|
441
|
+
// })
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
## State Separation: Tool State vs Session Data
|
|
445
|
+
|
|
446
|
+
The toolkit enforces a clear separation between ephemeral tool state and persistent session data:
|
|
447
|
+
|
|
448
|
+
### Tool State (Ephemeral - ElementToolStateStore)
|
|
449
|
+
|
|
450
|
+
**Client-only**, never sent to server for scoring:
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
{
|
|
454
|
+
"demo-assessment:section-1:question-1:mc1": {
|
|
455
|
+
"answerEliminator": {
|
|
456
|
+
"eliminatedChoices": ["choice-b", "choice-d"]
|
|
457
|
+
},
|
|
458
|
+
"highlighter": {
|
|
459
|
+
"annotations": [...]
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
**Use for:**
|
|
466
|
+
- Answer eliminations
|
|
467
|
+
- Highlighting/annotations
|
|
468
|
+
- Tool preferences
|
|
469
|
+
- UI state
|
|
470
|
+
|
|
471
|
+
### PIE Session Data (Persistent)
|
|
472
|
+
|
|
473
|
+
**Sent to server** for scoring:
|
|
474
|
+
|
|
475
|
+
```typescript
|
|
476
|
+
{
|
|
477
|
+
"question-1": {
|
|
478
|
+
"id": "session-123",
|
|
479
|
+
"data": [
|
|
480
|
+
{ "id": "mc1", "element": "multiple-choice", "value": ["choice-a"] }
|
|
481
|
+
]
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
**Use for:**
|
|
487
|
+
- Student responses
|
|
488
|
+
- Scoring data
|
|
489
|
+
- Assessment outcomes
|
|
490
|
+
|
|
491
|
+
## Examples
|
|
492
|
+
|
|
493
|
+
See the [section-demos](../../apps/section-demos/) for complete examples:
|
|
494
|
+
|
|
495
|
+
- **Three Questions Demo**: Element-level answer eliminator with state persistence
|
|
496
|
+
- **TTS Integration Demo**: Toolkit coordinator with TTS service
|
|
497
|
+
- **Paired Passages Demo**: Multi-section assessment with cross-section state
|
|
498
|
+
|
|
499
|
+
## TypeScript Support
|
|
500
|
+
|
|
501
|
+
Full TypeScript definitions included:
|
|
502
|
+
|
|
503
|
+
```typescript
|
|
504
|
+
import type {
|
|
505
|
+
IToolkitCoordinator,
|
|
506
|
+
IElementToolStateStore,
|
|
507
|
+
ToolkitCoordinatorConfig,
|
|
508
|
+
ToolkitServiceBundle
|
|
509
|
+
} from '@pie-players/pie-assessment-toolkit';
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
## Related Documentation
|
|
513
|
+
|
|
514
|
+
- [ToolkitCoordinator Architecture](../../docs/architecture/TOOLKIT_COORDINATOR.md) - Design decisions and patterns
|
|
515
|
+
- [Section Player README](../section-player/README.md) - Section player integration
|
|
516
|
+
- [Architecture Overview](../../docs/ARCHITECTURE.md) - Complete system architecture
|
|
517
|
+
|
|
518
|
+
## License
|
|
519
|
+
|
|
520
|
+
MIT
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export interface StorageLike {
|
|
2
|
+
getItem(key: string): string | null;
|
|
3
|
+
setItem(key: string, value: string): void;
|
|
4
|
+
removeItem(key: string): void;
|
|
5
|
+
}
|
|
6
|
+
export interface TestSessionNavigationState {
|
|
7
|
+
currentItemIndex: number;
|
|
8
|
+
visitedItemIdentifiers: string[];
|
|
9
|
+
currentSectionIdentifier?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface TestSessionRealization {
|
|
12
|
+
/**
|
|
13
|
+
* Deterministic seed for shuffling/selection.
|
|
14
|
+
* (Future: use for QTI ordering.shuffle / selection rules.)
|
|
15
|
+
*/
|
|
16
|
+
seed: string;
|
|
17
|
+
/**
|
|
18
|
+
* Realized item order for this attempt (QTI item identifiers).
|
|
19
|
+
*/
|
|
20
|
+
itemIdentifiers: string[];
|
|
21
|
+
}
|
|
22
|
+
export interface ItemSession {
|
|
23
|
+
/**
|
|
24
|
+
* QTI assessmentItemRef identifier (same as questionRef.identifier).
|
|
25
|
+
*/
|
|
26
|
+
itemIdentifier: string;
|
|
27
|
+
/**
|
|
28
|
+
* PIE session id for the underlying item attempt (if/when created).
|
|
29
|
+
*/
|
|
30
|
+
pieSessionId?: string;
|
|
31
|
+
attemptCount: number;
|
|
32
|
+
isCompleted: boolean;
|
|
33
|
+
startedAt?: string;
|
|
34
|
+
updatedAt?: string;
|
|
35
|
+
completedAt?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface TestSession {
|
|
38
|
+
version: 1;
|
|
39
|
+
/**
|
|
40
|
+
* QTI-like identifier for the delivery attempt (administration).
|
|
41
|
+
*/
|
|
42
|
+
testSessionIdentifier: string;
|
|
43
|
+
assessmentId: string;
|
|
44
|
+
startedAt: string;
|
|
45
|
+
updatedAt: string;
|
|
46
|
+
completedAt?: string;
|
|
47
|
+
navigationState: TestSessionNavigationState;
|
|
48
|
+
realization: TestSessionRealization;
|
|
49
|
+
/**
|
|
50
|
+
* Keyed by QTI item identifier (questionRef.identifier).
|
|
51
|
+
*/
|
|
52
|
+
itemSessions: Record<string, ItemSession>;
|
|
53
|
+
/**
|
|
54
|
+
* QTI 3.0 context variables (global assessment-level variables).
|
|
55
|
+
* Managed by ContextVariableStore.
|
|
56
|
+
*/
|
|
57
|
+
contextVariables?: Record<string, any>;
|
|
58
|
+
}
|
|
59
|
+
export declare function createMemoryStorage(initial?: Record<string, string>): StorageLike;
|
|
60
|
+
export declare function getBrowserLocalStorage(): StorageLike | null;
|
|
61
|
+
export declare function getOrCreateAnonymousDeviceId(storage: StorageLike): string;
|
|
62
|
+
export declare function createTestSessionIdentifier(args: {
|
|
63
|
+
assessmentId: string;
|
|
64
|
+
assignmentId?: string | null;
|
|
65
|
+
userId?: string | null;
|
|
66
|
+
storage: StorageLike;
|
|
67
|
+
}): {
|
|
68
|
+
testSessionIdentifier: string;
|
|
69
|
+
seed: string;
|
|
70
|
+
};
|
|
71
|
+
export declare function getTestSessionStorageKey(testSessionIdentifier: string): string;
|
|
72
|
+
export declare function loadTestSession(storage: StorageLike, testSessionIdentifier: string): TestSession | null;
|
|
73
|
+
export declare function saveTestSession(storage: StorageLike, session: TestSession): void;
|
|
74
|
+
export declare function createNewTestSession(args: {
|
|
75
|
+
testSessionIdentifier: string;
|
|
76
|
+
assessmentId: string;
|
|
77
|
+
seed: string;
|
|
78
|
+
itemIdentifiers: string[];
|
|
79
|
+
}): TestSession;
|
|
80
|
+
export declare function upsertVisitedItem(session: TestSession, itemIdentifier: string): TestSession;
|
|
81
|
+
export declare function setCurrentPosition(session: TestSession, args: {
|
|
82
|
+
currentItemIndex: number;
|
|
83
|
+
currentSectionIdentifier?: string;
|
|
84
|
+
}): TestSession;
|
|
85
|
+
export declare function upsertItemSessionFromPieSessionChange(session: TestSession, args: {
|
|
86
|
+
itemIdentifier: string;
|
|
87
|
+
pieSessionId: string;
|
|
88
|
+
isCompleted?: boolean;
|
|
89
|
+
}): TestSession;
|
|
90
|
+
//# sourceMappingURL=TestSession.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TestSession.d.ts","sourceRoot":"","sources":["../../src/attempt/TestSession.ts"],"names":[],"mappings":"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"}
|