@pie-players/pie-tool-answer-eliminator 0.3.75 → 1.0.0-beta.1
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 +81 -75
- package/custom-elements.json +127 -0
- package/dist/tool-answer-eliminator.js +1115 -1100
- package/package.json +7 -9
- package/dist/adapters/adapter-registry.d.ts +0 -25
- package/dist/adapters/adapter-registry.js +0 -50
- package/dist/adapters/choice-adapter.d.ts +0 -55
- package/dist/adapters/choice-adapter.js +0 -1
- package/dist/adapters/ebsr-adapter.d.ts +0 -21
- package/dist/adapters/ebsr-adapter.js +0 -69
- package/dist/adapters/inline-dropdown-adapter.d.ts +0 -17
- package/dist/adapters/inline-dropdown-adapter.js +0 -35
- package/dist/adapters/multiple-choice-adapter.d.ts +0 -31
- package/dist/adapters/multiple-choice-adapter.js +0 -130
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Test-taking strategy tool that allows students to eliminate answer choices they
|
|
|
7
7
|
- **Element-Level State**: Answer eliminations tracked per PIE element (not per item)
|
|
8
8
|
- **Visual Feedback**: Strikethrough styling for eliminated choices
|
|
9
9
|
- **Global Uniqueness**: Uses composite keys for state management across sections
|
|
10
|
-
- **
|
|
10
|
+
- **Separate from session data**: Eliminations never enter the PIE session; the coordinator's `saveToolState` hook persists them ([Persistence Integration](#persistence-integration))
|
|
11
11
|
- **ElementToolStateStore Integration**: Works with Assessment Toolkit's state management
|
|
12
12
|
|
|
13
13
|
## Installation
|
|
@@ -28,14 +28,9 @@ The answer eliminator is automatically integrated when using the PIE Section Pla
|
|
|
28
28
|
<script type="module">
|
|
29
29
|
import '@pie-players/pie-section-player';
|
|
30
30
|
import { ToolkitCoordinator } from '@pie-players/pie-assessment-toolkit';
|
|
31
|
-
import {
|
|
32
|
-
createPackagedToolRegistry,
|
|
33
|
-
DEFAULT_TOOL_MODULE_LOADERS,
|
|
34
|
-
} from '@pie-players/pie-default-tool-loaders';
|
|
31
|
+
import { createPackagedToolRegistry } from '@pie-players/pie-default-tool-loaders';
|
|
35
32
|
|
|
36
|
-
const toolRegistry = createPackagedToolRegistry(
|
|
37
|
-
toolModuleLoaders: DEFAULT_TOOL_MODULE_LOADERS,
|
|
38
|
-
});
|
|
33
|
+
const toolRegistry = createPackagedToolRegistry();
|
|
39
34
|
const coordinator = new ToolkitCoordinator({
|
|
40
35
|
assessmentId: 'my-assessment',
|
|
41
36
|
toolRegistry,
|
|
@@ -54,7 +49,7 @@ The answer eliminator is automatically integrated when using the PIE Section Pla
|
|
|
54
49
|
|
|
55
50
|
The section player automatically:
|
|
56
51
|
- Renders answer eliminator buttons in question toolbars
|
|
57
|
-
-
|
|
52
|
+
- Passes each element's composite state key to the tool as `elementStateKeys`
|
|
58
53
|
- Manages state lifecycle
|
|
59
54
|
|
|
60
55
|
The tool reads its coordinator and the `ElementToolStateStore` from the toolkit
|
|
@@ -62,7 +57,7 @@ runtime context, so it has to sit inside `<pie-assessment-toolkit>`.
|
|
|
62
57
|
|
|
63
58
|
### Manual Integration (Advanced)
|
|
64
59
|
|
|
65
|
-
For a custom layout inside the toolkit:
|
|
60
|
+
For a custom layout inside the toolkit. The tool detects choices under the item root its enclosing `<pie-item-scope>` provides, and with none it warns and injects nothing:
|
|
66
61
|
|
|
67
62
|
```html
|
|
68
63
|
<script type="module">
|
|
@@ -71,21 +66,23 @@ For a custom layout inside the toolkit:
|
|
|
71
66
|
const tool = document.querySelector('pie-tool-answer-eliminator');
|
|
72
67
|
// Store key per PIE element in the question, by model id
|
|
73
68
|
tool.elementStateKeys = {
|
|
74
|
-
mc1: 'my-assessment:section-1:question-1:mc1',
|
|
75
|
-
mc2: 'my-assessment:section-1:question-1:mc2',
|
|
69
|
+
mc1: 'my-assessment:section-1:attempt-1:question-1:mc1',
|
|
70
|
+
mc2: 'my-assessment:section-1:attempt-1:question-1:mc2',
|
|
76
71
|
};
|
|
77
|
-
tool.scopeElement = document.querySelector('.question-content');
|
|
78
72
|
tool.visible = true; // or alwaysOn = true; the tool injects no buttons while neither is set
|
|
79
73
|
</script>
|
|
80
74
|
|
|
81
75
|
<pie-assessment-toolkit>
|
|
82
|
-
<pie-
|
|
76
|
+
<pie-item-scope item-id="question-1">
|
|
77
|
+
<!-- the item's rendered content -->
|
|
78
|
+
<pie-tool-answer-eliminator></pie-tool-answer-eliminator>
|
|
79
|
+
</pie-item-scope>
|
|
83
80
|
</pie-assessment-toolkit>
|
|
84
81
|
```
|
|
85
82
|
|
|
86
83
|
## Props/Attributes
|
|
87
84
|
|
|
88
|
-
`elementStateKeys`
|
|
85
|
+
`elementStateKeys` is a JS property only; the others also take the attribute shown.
|
|
89
86
|
|
|
90
87
|
| Property | Attribute | Type | Default | Description |
|
|
91
88
|
|----------|-----------|------|---------|-------------|
|
|
@@ -93,42 +90,40 @@ For a custom layout inside the toolkit:
|
|
|
93
90
|
| `alwaysOn` | `always-on` | `boolean` | `false` | Shows the buttons regardless of `visible`, for a profile-based accommodation |
|
|
94
91
|
| `strategy` | `strategy` | `'strikethrough' \| 'mask'` | `'strikethrough'` | Elimination styling; any other value uses `strikethrough` |
|
|
95
92
|
| `buttonAlignment` | `button-alignment` | `'left' \| 'right' \| 'inline'` | `'right'` | Button placement relative to the choice |
|
|
96
|
-
| `
|
|
97
|
-
| `elementStateKeys` | | `Record<string, string>` | `{}` | Composite key `assessmentId:sectionId:itemId:elementId` per PIE element, by model id, into the runtime context's element tool state store. A choice is tracked under its nearest ancestor with a listed id and persists under that key; choices outside a listed element are kept in memory only |
|
|
98
|
-
| `scopeElement` | | `HTMLElement` | | Root to detect choices in. Without it the tool uses the root its enclosing `pie-item-scope` provides, and with neither it warns and injects nothing |
|
|
93
|
+
| `elementStateKeys` | | `Record<string, string>` | `{}` | Composite key `assessmentId:sectionId:attemptId:itemId:elementId` per PIE element, by model id, into the runtime context's element tool state store. A choice is tracked under its nearest ancestor with a listed id and persists under that key; choices outside a listed element are kept in memory only |
|
|
99
94
|
|
|
100
95
|
## Global Element ID Format
|
|
101
96
|
|
|
102
97
|
The tool uses globally unique composite keys for state management:
|
|
103
98
|
|
|
104
99
|
```
|
|
105
|
-
${assessmentId}:${sectionId}:${itemId}:${elementId}
|
|
100
|
+
${assessmentId}:${sectionId}:${attemptId}:${itemId}:${elementId}
|
|
106
101
|
```
|
|
107
102
|
|
|
108
103
|
**Example:**
|
|
109
104
|
```typescript
|
|
110
|
-
"demo-assessment:section-1:question-1:mc1"
|
|
111
|
-
"biology-exam:section-2:genetics-q1:ebsr1"
|
|
105
|
+
"demo-assessment:section-1:attempt-1:question-1:mc1"
|
|
106
|
+
"biology-exam:section-2:attempt-1:genetics-q1:ebsr1"
|
|
112
107
|
```
|
|
113
108
|
|
|
114
109
|
### Benefits of Composite Keys
|
|
115
110
|
|
|
116
|
-
-
|
|
117
|
-
-
|
|
118
|
-
-
|
|
119
|
-
-
|
|
111
|
+
- **Element-Level Granularity**: Each PIE element has independent eliminations
|
|
112
|
+
- **No Cross-Item Contamination**: Eliminations from question 1 don't appear on question 2
|
|
113
|
+
- **Cross-Section Persistence**: State persists when navigating between sections
|
|
114
|
+
- **Global Uniqueness**: No ID collisions across entire assessment
|
|
120
115
|
|
|
121
116
|
### Why Element-Level?
|
|
122
117
|
|
|
123
118
|
Items can contain **multiple interactive elements** whose choice ids repeat (two multiple-choice elements both have a choice `a`). Each element needs independent state:
|
|
124
119
|
|
|
125
120
|
```typescript
|
|
126
|
-
//
|
|
121
|
+
// Element-level state
|
|
127
122
|
{
|
|
128
|
-
"demo:section-1:question-1:mc1": {
|
|
123
|
+
"demo:section-1:attempt-1:question-1:mc1": {
|
|
129
124
|
"answerEliminator": { "eliminatedChoices": ["a", "c"] }
|
|
130
125
|
},
|
|
131
|
-
"demo:section-1:question-1:mc2": {
|
|
126
|
+
"demo:section-1:attempt-1:question-1:mc2": {
|
|
132
127
|
"answerEliminator": { "eliminatedChoices": ["a"] }
|
|
133
128
|
}
|
|
134
129
|
}
|
|
@@ -136,14 +131,14 @@ Items can contain **multiple interactive elements** whose choice ids repeat (two
|
|
|
136
131
|
|
|
137
132
|
## State Management
|
|
138
133
|
|
|
139
|
-
###
|
|
134
|
+
### Tool state and session data
|
|
140
135
|
|
|
141
|
-
The answer eliminator stores
|
|
136
|
+
The answer eliminator stores eliminations in the toolkit's **ElementToolStateStore**, apart from the PIE session. They leave the browser only through the coordinator's `saveToolState` hook.
|
|
142
137
|
|
|
143
|
-
**Tool
|
|
138
|
+
**Tool state (not part of the session, never scored):**
|
|
144
139
|
```typescript
|
|
145
140
|
{
|
|
146
|
-
"demo:section-1:question-1:mc1": {
|
|
141
|
+
"demo:section-1:attempt-1:question-1:mc1": {
|
|
147
142
|
"answerEliminator": {
|
|
148
143
|
"eliminatedChoices": ["choice-b", "choice-d"]
|
|
149
144
|
}
|
|
@@ -168,46 +163,65 @@ The answer eliminator stores state in **ElementToolStateStore** (ephemeral, clie
|
|
|
168
163
|
To persist tool state across page refreshes:
|
|
169
164
|
|
|
170
165
|
```typescript
|
|
171
|
-
import {
|
|
172
|
-
|
|
173
|
-
DEFAULT_TOOL_MODULE_LOADERS,
|
|
174
|
-
} from '@pie-players/pie-default-tool-loaders';
|
|
166
|
+
import { ToolkitCoordinator } from '@pie-players/pie-assessment-toolkit';
|
|
167
|
+
import { createPackagedToolRegistry } from '@pie-players/pie-default-tool-loaders';
|
|
175
168
|
|
|
176
|
-
const
|
|
177
|
-
toolModuleLoaders: DEFAULT_TOOL_MODULE_LOADERS,
|
|
178
|
-
});
|
|
169
|
+
const storageKey = 'tool-state:my-assessment';
|
|
179
170
|
const coordinator = new ToolkitCoordinator({
|
|
180
171
|
assessmentId: 'my-assessment',
|
|
181
|
-
toolRegistry,
|
|
182
|
-
tools: { placement: { item: ['answerEliminator'] } }
|
|
172
|
+
toolRegistry: createPackagedToolRegistry(),
|
|
173
|
+
tools: { placement: { item: ['answerEliminator'] } },
|
|
174
|
+
hooks: {
|
|
175
|
+
loadToolState: () => JSON.parse(localStorage.getItem(storageKey) ?? 'null'),
|
|
176
|
+
saveToolState: (state) => localStorage.setItem(storageKey, JSON.stringify(state)),
|
|
177
|
+
},
|
|
183
178
|
});
|
|
179
|
+
```
|
|
184
180
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
181
|
+
## How It Works
|
|
182
|
+
|
|
183
|
+
### 1. Choice Detection
|
|
184
|
+
|
|
185
|
+
Elements supply their own choices. An element takes the eliminator by declaring the AfA PNP 3.0 support term `answer-masking` on its class and answering `pieSupportTargets('answer-masking')` on its instances:
|
|
190
186
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
187
|
+
```typescript
|
|
188
|
+
class ChoiceGrid extends HTMLElement {
|
|
189
|
+
static pieSupports = ['answer-masking'];
|
|
190
|
+
|
|
191
|
+
pieSupportTargets(term: string) {
|
|
192
|
+
if (term !== 'answer-masking') return [];
|
|
193
|
+
return this.rows.map((row) => ({
|
|
194
|
+
id: row.value,
|
|
195
|
+
label: row.text,
|
|
196
|
+
container: row.element,
|
|
197
|
+
content: row.labelElement,
|
|
198
|
+
isSelected: () => this.isChosen(row.value),
|
|
199
|
+
isEliminable: () => this.mode === 'gather' && !this.isChosen(row.value),
|
|
200
|
+
setEliminated: (eliminated: boolean) => this.block(row.value, eliminated),
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
195
203
|
}
|
|
196
204
|
```
|
|
197
205
|
|
|
198
|
-
|
|
206
|
+
Every field is required, and a choice missing one is skipped with a console warning:
|
|
199
207
|
|
|
200
|
-
|
|
208
|
+
| Field | Contract |
|
|
209
|
+
| --- | --- |
|
|
210
|
+
| `id` | Unique within the element and stable across renders: eliminations persist by it. |
|
|
211
|
+
| `label` | The choice's accessible name; the toggle is announced as "Toggle elimination for `label`". |
|
|
212
|
+
| `container` | Receives the toggle and the eliminated state. The tool sets `position: relative` on it. An inline container, such as a token in running text, takes the toggle in the line. |
|
|
213
|
+
| `content` | The part that is struck through or masked. It must be inside `container`. |
|
|
214
|
+
| `isSelected()` | Whether the learner has chosen it. A selected choice hides its toggle and is never eliminated. |
|
|
215
|
+
| `isEliminable()` | False in evaluate and view modes, and for disabled or selected choices. |
|
|
216
|
+
| `setEliminated(eliminated)` | Blocks or restores the learner's selection of the choice. The element owns this: the tool never disables controls it did not render. A call with the value the choice already has changes nothing. |
|
|
201
217
|
|
|
202
|
-
The
|
|
218
|
+
The toolbar reads the same `static pieSupports` declaration to decide whether to offer the eliminator, so an element built outside this repository needs no change here. A declaration that omits `answer-masking`, including `[]`, means the element takes no eliminator.
|
|
203
219
|
|
|
204
|
-
|
|
205
|
-
| --- | --- | --- |
|
|
206
|
-
| `MultipleChoiceAdapter` | `multiple-choice` (single- or multi-select) | `.corespring-checkbox` / `.corespring-radio-button` choices |
|
|
207
|
-
| `EBSRAdapter` | `ebsr` | delegates to the multiple-choice adapter for each `ebsr-multiple-choice` part (Part A/B), prefixing choice IDs with the part |
|
|
208
|
-
| `InlineDropdownAdapter` | `inline-dropdown` | dropdown items with `role="option"` |
|
|
220
|
+
An element may replace its choices' markup on any render, as select-text does. When a container leaves the document, the tool asks for the choices again and keeps their eliminations by id, moving focus to the replacement toggle. It does not call `setEliminated` again on the same element instance, so an element that re-renders from `setEliminated` settles; a new instance is asked to block its eliminated choices, and a choice no longer supplied is restored.
|
|
209
221
|
|
|
210
|
-
The
|
|
222
|
+
The outermost declaring element under the item owns its subtree: an element composed of declaring parts answers for them, prefixing ids with the part where they would collide, as EBSR does with `a-` and `b-`. Eliminations persist under the key of the nearest element listed in `elementStateKeys`, starting from the declaring element.
|
|
223
|
+
|
|
224
|
+
Elements that declare nothing fall back to the multiple-choice and EBSR markup this package reads (`.corespring-checkbox` and `.corespring-radio-button` choices, and the `ebsr-multiple-choice` parts with ids `a` and `b`). That fallback serves legacy pie-elements and pie-elements-ng releases from before elements declared their supports, and never runs inside a declaring element.
|
|
211
225
|
|
|
212
226
|
### 2. State Storage
|
|
213
227
|
|
|
@@ -226,28 +240,28 @@ Elimination styling is applied by a pluggable `EliminationStrategy` built on the
|
|
|
226
240
|
- `strikethrough` (default): a `::highlight(pie-answer-eliminated-<id>)` rule renders a line-through over the choice label.
|
|
227
241
|
- `mask`: a `::highlight(pie-answer-masked-<id>)` rule dims and blurs the choice.
|
|
228
242
|
|
|
229
|
-
Images need separate treatment: they are replaced elements, so neither `::highlight()` nor `text-decoration` paints on them and a picture choice would look untouched. The `strikethrough` strategy therefore wraps each `img` in the eliminated choice in a `span.pie-answer-eliminator-image-strike` (marked with `data-pie-answer-eliminator-image-strike`) and overlays a decorative, `pointer-events: none` SVG that draws an X corner to corner — upper-left to lower-right and lower-left to upper-right. Restoring the choice unwraps the image and returns the DOM to its original shape. Each diagonal is painted over a wider light casing line (`--pie-answer-eliminator-image-strike-casing-color
|
|
243
|
+
Images need separate treatment: they are replaced elements, so neither `::highlight()` nor `text-decoration` paints on them and a picture choice would look untouched. The `strikethrough` strategy therefore wraps each `img` in the eliminated choice in a `span.pie-answer-eliminator-image-strike` (marked with `data-pie-answer-eliminator-image-strike`) and overlays a decorative, `pointer-events: none` SVG that draws an X corner to corner — upper-left to lower-right and lower-left to upper-right. Restoring the choice unwraps the image and returns the DOM to its original shape. Each diagonal is painted over a wider light casing line (`--pie-answer-eliminator-image-strike-casing-color`, package-private with no compatibility guarantee) so it stays legible over dark artwork.
|
|
230
244
|
|
|
231
245
|
MathJax-rendered math needs its own mark for the same reason. MathJax's CHTML output draws each glyph as an `mjx-c` element with empty `textContent` (the character comes from `::before` generated content, which belongs to no Range), and its SVG output has no text at all — so the highlight had nothing to decorate and a math-only choice looked untouched. For each `mjx-container` in the eliminated choice, the `strikethrough` strategy marks the inner `mjx-math` box with `pie-answer-eliminator-math-strike` plus one of two modifiers, and the theme paints it:
|
|
232
246
|
|
|
233
247
|
| expression | mark | `data-pie-answer-eliminator-math-strike` |
|
|
234
248
|
| --- | --- | --- |
|
|
235
|
-
| single row of symbols |
|
|
249
|
+
| single row of symbols | centered line-through, as the prose gets | `line` |
|
|
236
250
|
| contains a fraction bar or table rule | diagonals, as an eliminated image gets | `cross` |
|
|
237
251
|
|
|
238
|
-
A
|
|
252
|
+
A centered line on a fraction lands on the math axis — exactly where the fraction bar already sits — so it reads as a recolored bar rather than an elimination. The split is structural (`mjx-mfrac`, `mjx-mtable`), not height-based: an inline `a/b` is only 1.16× its font size, indistinguishable in height from a radical or a parenthesised row, yet it is precisely the colliding case. Radicals and stacked limits keep the line, since their bars sit at the top or the strike simply crosses the base.
|
|
239
253
|
|
|
240
254
|
The inner `mjx-math` box is the paint target, not the container: for inline math `mjx-container` is `display: inline`, so its rect is the surrounding line box while the expression itself overflows it — a fraction sticks out several pixels above and below.
|
|
241
255
|
|
|
242
256
|
Only MathJax containers are marked: natively rendered MathML keeps real text in `mi`/`mn`/`mo`, so the highlight already strikes every token there.
|
|
243
257
|
|
|
244
|
-
All three treatments — the text line-through, the diagonals over an image, the line over math — are drawn in one
|
|
258
|
+
All three treatments — the text line-through, the diagonals over an image, the line over math — are drawn in one color, `--pie-answer-eliminator-strike-color` (a registered `component-public` token, defaulting to `--pie-incorrect`), so a choice mixing prose, pictures, and math reads as a single strike and can be restyled from one place.
|
|
245
259
|
|
|
246
260
|
For browsers without the Highlight API, each strategy falls back to a class on the choice container. Either way the eliminated choice also receives ARIA hooks (`data-pie-answer-eliminated`, plus `aria-disabled`/`aria-hidden` and an offscreen "(eliminated)" announcement) for assistive technology.
|
|
247
261
|
|
|
248
262
|
### 4. Toggle Behavior
|
|
249
263
|
|
|
250
|
-
Each
|
|
264
|
+
Each choice gets its own elimination toggle button (class `pie-answer-eliminator-toggle`, rendered as `⊗`) appended to its `container`. Clicking the button toggles that choice through the active strategy and calls `setEliminated`. Eliminating is blocked while `isEliminable()` returns false. An active button is marked with `pie-answer-eliminator-toggle--active` and `aria-pressed="true"`; clicking again restores the choice.
|
|
251
265
|
|
|
252
266
|
## Cleanup
|
|
253
267
|
|
|
@@ -255,7 +269,7 @@ The ElementToolStateStore provides cleanup methods:
|
|
|
255
269
|
|
|
256
270
|
```typescript
|
|
257
271
|
// Clear state for a specific element
|
|
258
|
-
store.clearElement('demo:section-1:question-1:mc1');
|
|
272
|
+
store.clearElement('demo:section-1:attempt-1:question-1:mc1');
|
|
259
273
|
|
|
260
274
|
// Clear all answer eliminator state across all elements
|
|
261
275
|
store.clearTool('answerEliminator');
|
|
@@ -279,24 +293,16 @@ interface AnswerEliminatorState {
|
|
|
279
293
|
}
|
|
280
294
|
```
|
|
281
295
|
|
|
282
|
-
## Browser Support
|
|
283
|
-
|
|
284
|
-
- Chrome/Edge 90+
|
|
285
|
-
- Firefox 88+
|
|
286
|
-
- Safari 14+
|
|
287
|
-
|
|
288
|
-
Requires ES2020+ support (native ES modules, optional chaining, nullish coalescing).
|
|
289
|
-
|
|
290
296
|
## Examples
|
|
291
297
|
|
|
292
298
|
See the [section-demos](../../apps/section-demos/) for complete examples:
|
|
293
299
|
|
|
294
300
|
- **Three Questions Demo**: Element-level answer eliminator with state persistence
|
|
295
|
-
- **
|
|
301
|
+
- **Two Passages Demo**: Multi-section assessment with cross-section state
|
|
296
302
|
|
|
297
303
|
## Related Documentation
|
|
298
304
|
|
|
299
|
-
- [
|
|
305
|
+
- [Assessment toolkit architecture](../../docs/architecture/architecture.md#assessment-toolkit): the coordinator and element-level tool state
|
|
300
306
|
- [Assessment Toolkit README](../assessment-toolkit/README.md) - Toolkit overview
|
|
301
307
|
- [Section Player README](../section-player/README.md) - Integration guide
|
|
302
308
|
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": "2.1.0",
|
|
3
|
+
"modules": [
|
|
4
|
+
{
|
|
5
|
+
"kind": "javascript-module",
|
|
6
|
+
"path": "dist/tool-answer-eliminator.js",
|
|
7
|
+
"declarations": [
|
|
8
|
+
{
|
|
9
|
+
"kind": "class",
|
|
10
|
+
"description": "Process-of-elimination tool for the item in its enclosing `<pie-item-scope>`: it adds a toggle beside each choice an element supplies for `answer-masking` that strikes the choice through or masks it, per `strategy`. It renders nothing of its own and is active while `visible` or `always-on` is set. Eliminations persist in the runtime context's element tool state store, under the key `elementStateKeys` gives each PIE element.",
|
|
11
|
+
"name": "ToolAnswerEliminator",
|
|
12
|
+
"tagName": "pie-tool-answer-eliminator",
|
|
13
|
+
"customElement": true,
|
|
14
|
+
"members": [
|
|
15
|
+
{
|
|
16
|
+
"kind": "field",
|
|
17
|
+
"name": "visible",
|
|
18
|
+
"type": {
|
|
19
|
+
"text": "boolean"
|
|
20
|
+
},
|
|
21
|
+
"default": "false",
|
|
22
|
+
"attribute": "visible"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"kind": "field",
|
|
26
|
+
"name": "strategy",
|
|
27
|
+
"type": {
|
|
28
|
+
"text": "'strikethrough' | 'mask'"
|
|
29
|
+
},
|
|
30
|
+
"default": "'strikethrough'",
|
|
31
|
+
"attribute": "strategy"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"kind": "field",
|
|
35
|
+
"name": "alwaysOn",
|
|
36
|
+
"type": {
|
|
37
|
+
"text": "boolean"
|
|
38
|
+
},
|
|
39
|
+
"default": "false",
|
|
40
|
+
"attribute": "always-on"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"kind": "field",
|
|
44
|
+
"name": "buttonAlignment",
|
|
45
|
+
"type": {
|
|
46
|
+
"text": "'left' | 'right' | 'inline'"
|
|
47
|
+
},
|
|
48
|
+
"default": "'right'",
|
|
49
|
+
"attribute": "button-alignment"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"kind": "field",
|
|
53
|
+
"name": "elementStateKeys",
|
|
54
|
+
"type": {
|
|
55
|
+
"text": "ElementStateKeys"
|
|
56
|
+
},
|
|
57
|
+
"default": "{}",
|
|
58
|
+
"description": "Store key per PIE element, by model id (JS property only)",
|
|
59
|
+
"attribute": "elementstatekeys"
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
"attributes": [
|
|
63
|
+
{
|
|
64
|
+
"name": "visible",
|
|
65
|
+
"type": {
|
|
66
|
+
"text": "boolean"
|
|
67
|
+
},
|
|
68
|
+
"default": "false",
|
|
69
|
+
"fieldName": "visible"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"name": "strategy",
|
|
73
|
+
"type": {
|
|
74
|
+
"text": "string"
|
|
75
|
+
},
|
|
76
|
+
"default": "'strikethrough'",
|
|
77
|
+
"fieldName": "strategy"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"name": "always-on",
|
|
81
|
+
"type": {
|
|
82
|
+
"text": "boolean"
|
|
83
|
+
},
|
|
84
|
+
"default": "false",
|
|
85
|
+
"fieldName": "alwaysOn"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"name": "button-alignment",
|
|
89
|
+
"type": {
|
|
90
|
+
"text": "string"
|
|
91
|
+
},
|
|
92
|
+
"default": "'right'",
|
|
93
|
+
"fieldName": "buttonAlignment"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"name": "elementstatekeys",
|
|
97
|
+
"type": {
|
|
98
|
+
"text": "ElementStateKeys"
|
|
99
|
+
},
|
|
100
|
+
"default": "{}",
|
|
101
|
+
"description": "Store key per PIE element, by model id (JS property only)",
|
|
102
|
+
"fieldName": "elementStateKeys"
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
"cssProperties": [
|
|
106
|
+
{
|
|
107
|
+
"name": "--pie-answer-eliminator-strike-color",
|
|
108
|
+
"description": "Single colour for every part of an elimination: the text line-through, the diagonals over an image, and the line or diagonals over rendered math, so one choice reads as one treatment. Must fall back through canonical --pie-incorrect so a host that themes only the canonical feedback tokens still gets a coherent strike."
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
"x-pie": {
|
|
112
|
+
"shadow": "open"
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
],
|
|
116
|
+
"exports": [
|
|
117
|
+
{
|
|
118
|
+
"kind": "custom-element-definition",
|
|
119
|
+
"name": "pie-tool-answer-eliminator",
|
|
120
|
+
"declaration": {
|
|
121
|
+
"name": "ToolAnswerEliminator"
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
]
|
|
127
|
+
}
|