@pie-players/pie-tool-answer-eliminator 0.2.8 → 0.2.10
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/adapters/multiple-choice-adapter.ts +62 -14
- package/answer-eliminator-core.ts +12 -85
- package/dist/adapters/multiple-choice-adapter.d.ts +8 -0
- package/dist/adapters/multiple-choice-adapter.d.ts.map +1 -1
- package/dist/answer-eliminator-core.d.ts +3 -8
- package/dist/answer-eliminator-core.d.ts.map +1 -1
- package/dist/strategies/mask-strategy.d.ts +7 -2
- package/dist/strategies/mask-strategy.d.ts.map +1 -1
- package/dist/strategies/strikethrough-strategy.d.ts +10 -2
- package/dist/strategies/strikethrough-strategy.d.ts.map +1 -1
- package/dist/tool-answer-eliminator.js +2647 -1443
- package/dist/vite.config.d.ts.map +1 -1
- package/package.json +15 -6
- package/strategies/mask-strategy.ts +33 -42
- package/strategies/strikethrough-strategy.ts +53 -69
- package/tool-answer-eliminator.svelte +77 -104
- package/dist/tool-answer-eliminator.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite.config.d.ts","sourceRoot":"","sources":["../vite.config.ts"],"names":[],"mappings":";AAKA,
|
|
1
|
+
{"version":3,"file":"vite.config.d.ts","sourceRoot":"","sources":["../vite.config.ts"],"names":[],"mappings":";AAKA,wBAkCG"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pie-players/pie-tool-answer-eliminator",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Answer eliminator tool for PIE assessment player - supports process-of-elimination test-taking strategy",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/pie-framework/pie-players.git"
|
|
8
|
+
"url": "git+https://github.com/pie-framework/pie-players.git",
|
|
9
|
+
"directory": "packages/tool-answer-eliminator"
|
|
9
10
|
},
|
|
10
11
|
"publishConfig": {
|
|
11
12
|
"access": "public"
|
|
@@ -48,9 +49,9 @@
|
|
|
48
49
|
"unpkg": "./dist/tool-answer-eliminator.js",
|
|
49
50
|
"jsdelivr": "./dist/tool-answer-eliminator.js",
|
|
50
51
|
"dependencies": {
|
|
51
|
-
"@pie-players/pie-assessment-toolkit": "0.2.
|
|
52
|
-
"@pie-players/pie-
|
|
53
|
-
"@
|
|
52
|
+
"@pie-players/pie-assessment-toolkit": "0.2.10",
|
|
53
|
+
"@pie-players/pie-context": "0.1.2",
|
|
54
|
+
"@pie-players/pie-players-shared": "0.2.6",
|
|
54
55
|
"daisyui": "^5.5.18"
|
|
55
56
|
},
|
|
56
57
|
"types": "./dist/index.d.ts",
|
|
@@ -67,5 +68,13 @@
|
|
|
67
68
|
"typescript": "^5.7.0",
|
|
68
69
|
"vite": "^7.0.8",
|
|
69
70
|
"vite-plugin-dts": "^4.5.3"
|
|
70
|
-
}
|
|
71
|
+
},
|
|
72
|
+
"homepage": "https://github.com/pie-framework/pie-players/tree/master/packages/tool-answer-eliminator#readme",
|
|
73
|
+
"bugs": {
|
|
74
|
+
"url": "https://github.com/pie-framework/pie-players/issues"
|
|
75
|
+
},
|
|
76
|
+
"engines": {
|
|
77
|
+
"node": ">=18.0.0"
|
|
78
|
+
},
|
|
79
|
+
"sideEffects": true
|
|
71
80
|
}
|
|
@@ -5,18 +5,27 @@ import type { EliminationStrategy } from "./elimination-strategy.js";
|
|
|
5
5
|
* Partially hides/grays eliminated choices
|
|
6
6
|
*/
|
|
7
7
|
export class MaskStrategy implements EliminationStrategy {
|
|
8
|
+
private static readonly HIGHLIGHT_STYLE_PREFIX =
|
|
9
|
+
"pie-answer-eliminator-mask-highlight-";
|
|
10
|
+
private static readonly HIGHLIGHT_NAME_PREFIX = "pie-answer-masked-";
|
|
11
|
+
private static readonly FALLBACK_CLASS = "pie-answer-masked-fallback";
|
|
12
|
+
private static readonly CHOICE_HOOK_ATTR =
|
|
13
|
+
"data-pie-answer-eliminator-choice";
|
|
14
|
+
private static readonly ELIMINATED_ATTR = "data-pie-answer-eliminated";
|
|
15
|
+
private static readonly ELIMINATED_ID_ATTR = "data-pie-answer-eliminated-id";
|
|
16
|
+
|
|
8
17
|
readonly name = "mask";
|
|
9
18
|
|
|
10
19
|
private highlights = new Map<string, Highlight>();
|
|
11
20
|
private ranges = new Map<string, Range>();
|
|
21
|
+
private fallbackContainers = new Map<string, HTMLElement>();
|
|
12
22
|
|
|
13
23
|
initialize(): void {
|
|
14
|
-
|
|
24
|
+
// No-op: shared fallback styles are owned by @pie-players/pie-theme/components.css.
|
|
15
25
|
}
|
|
16
26
|
|
|
17
27
|
destroy(): void {
|
|
18
28
|
this.clearAll();
|
|
19
|
-
this.removeCSS();
|
|
20
29
|
}
|
|
21
30
|
|
|
22
31
|
apply(choiceId: string, range: Range): void {
|
|
@@ -29,7 +38,10 @@ export class MaskStrategy implements EliminationStrategy {
|
|
|
29
38
|
this.injectHighlightCSS(choiceId);
|
|
30
39
|
|
|
31
40
|
const highlight = new Highlight(range);
|
|
32
|
-
CSS.highlights.set(
|
|
41
|
+
CSS.highlights.set(
|
|
42
|
+
`${MaskStrategy.HIGHLIGHT_NAME_PREFIX}${choiceId}`,
|
|
43
|
+
highlight,
|
|
44
|
+
);
|
|
33
45
|
|
|
34
46
|
this.highlights.set(choiceId, highlight);
|
|
35
47
|
this.ranges.set(choiceId, range);
|
|
@@ -43,7 +55,7 @@ export class MaskStrategy implements EliminationStrategy {
|
|
|
43
55
|
return;
|
|
44
56
|
}
|
|
45
57
|
|
|
46
|
-
CSS.highlights.delete(
|
|
58
|
+
CSS.highlights.delete(`${MaskStrategy.HIGHLIGHT_NAME_PREFIX}${choiceId}`);
|
|
47
59
|
|
|
48
60
|
// Remove CSS for this specific highlight
|
|
49
61
|
this.removeHighlightCSS(choiceId);
|
|
@@ -55,6 +67,7 @@ export class MaskStrategy implements EliminationStrategy {
|
|
|
55
67
|
|
|
56
68
|
this.highlights.delete(choiceId);
|
|
57
69
|
this.ranges.delete(choiceId);
|
|
70
|
+
this.fallbackContainers.delete(choiceId);
|
|
58
71
|
}
|
|
59
72
|
|
|
60
73
|
isEliminated(choiceId: string): boolean {
|
|
@@ -65,6 +78,7 @@ export class MaskStrategy implements EliminationStrategy {
|
|
|
65
78
|
for (const choiceId of this.highlights.keys()) {
|
|
66
79
|
this.remove(choiceId);
|
|
67
80
|
}
|
|
81
|
+
this.fallbackContainers.clear();
|
|
68
82
|
}
|
|
69
83
|
|
|
70
84
|
getEliminatedIds(): string[] {
|
|
@@ -75,33 +89,14 @@ export class MaskStrategy implements EliminationStrategy {
|
|
|
75
89
|
return typeof CSS !== "undefined" && "highlights" in CSS;
|
|
76
90
|
}
|
|
77
91
|
|
|
78
|
-
private injectCSS(): void {
|
|
79
|
-
const styleId = "answer-eliminator-mask-styles";
|
|
80
|
-
if (document.getElementById(styleId)) return;
|
|
81
|
-
|
|
82
|
-
const style = document.createElement("style");
|
|
83
|
-
style.id = styleId;
|
|
84
|
-
// CSS Custom Highlight API: Each registered highlight gets its own ::highlight() selector
|
|
85
|
-
// We inject choice-specific styles dynamically in injectHighlightCSS()
|
|
86
|
-
style.textContent = `
|
|
87
|
-
/* Fallback */
|
|
88
|
-
.answer-masked-fallback {
|
|
89
|
-
opacity: 0.2;
|
|
90
|
-
filter: blur(2px);
|
|
91
|
-
}
|
|
92
|
-
`;
|
|
93
|
-
|
|
94
|
-
document.head.appendChild(style);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
92
|
private injectHighlightCSS(choiceId: string): void {
|
|
98
|
-
const styleId =
|
|
93
|
+
const styleId = `${MaskStrategy.HIGHLIGHT_STYLE_PREFIX}${choiceId}`;
|
|
99
94
|
if (document.getElementById(styleId)) return;
|
|
100
95
|
|
|
101
96
|
const style = document.createElement("style");
|
|
102
97
|
style.id = styleId;
|
|
103
98
|
style.textContent = `
|
|
104
|
-
::highlight(answer-masked-${choiceId}) {
|
|
99
|
+
::highlight(pie-answer-masked-${choiceId}) {
|
|
105
100
|
opacity: 0.2;
|
|
106
101
|
filter: blur(2px);
|
|
107
102
|
}
|
|
@@ -111,19 +106,15 @@ export class MaskStrategy implements EliminationStrategy {
|
|
|
111
106
|
|
|
112
107
|
private removeHighlightCSS(choiceId: string): void {
|
|
113
108
|
document
|
|
114
|
-
.getElementById(
|
|
109
|
+
.getElementById(`${MaskStrategy.HIGHLIGHT_STYLE_PREFIX}${choiceId}`)
|
|
115
110
|
?.remove();
|
|
116
111
|
}
|
|
117
112
|
|
|
118
|
-
private removeCSS(): void {
|
|
119
|
-
document.getElementById("answer-eliminator-mask-styles")?.remove();
|
|
120
|
-
}
|
|
121
|
-
|
|
122
113
|
private addAriaAttributes(range: Range): void {
|
|
123
114
|
const container = this.findChoiceContainer(range);
|
|
124
115
|
if (!container) return;
|
|
125
116
|
|
|
126
|
-
container.setAttribute(
|
|
117
|
+
container.setAttribute(MaskStrategy.ELIMINATED_ATTR, "true");
|
|
127
118
|
container.setAttribute("aria-hidden", "true");
|
|
128
119
|
}
|
|
129
120
|
|
|
@@ -131,7 +122,7 @@ export class MaskStrategy implements EliminationStrategy {
|
|
|
131
122
|
const container = this.findChoiceContainer(range);
|
|
132
123
|
if (!container) return;
|
|
133
124
|
|
|
134
|
-
container.removeAttribute(
|
|
125
|
+
container.removeAttribute(MaskStrategy.ELIMINATED_ATTR);
|
|
135
126
|
container.removeAttribute("aria-hidden");
|
|
136
127
|
}
|
|
137
128
|
|
|
@@ -144,7 +135,7 @@ export class MaskStrategy implements EliminationStrategy {
|
|
|
144
135
|
}
|
|
145
136
|
|
|
146
137
|
while (element && element !== document.body) {
|
|
147
|
-
if (element.
|
|
138
|
+
if (element.getAttribute(MaskStrategy.CHOICE_HOOK_ATTR) === "true") {
|
|
148
139
|
return element;
|
|
149
140
|
}
|
|
150
141
|
element = element.parentElement;
|
|
@@ -157,24 +148,24 @@ export class MaskStrategy implements EliminationStrategy {
|
|
|
157
148
|
const container = this.findChoiceContainer(range);
|
|
158
149
|
if (!container) return;
|
|
159
150
|
|
|
160
|
-
container.classList.add(
|
|
161
|
-
container.setAttribute(
|
|
162
|
-
container.setAttribute(
|
|
151
|
+
container.classList.add(MaskStrategy.FALLBACK_CLASS);
|
|
152
|
+
container.setAttribute(MaskStrategy.ELIMINATED_ATTR, "true");
|
|
153
|
+
container.setAttribute(MaskStrategy.ELIMINATED_ID_ATTR, choiceId);
|
|
154
|
+
this.fallbackContainers.set(choiceId, container);
|
|
163
155
|
this.addAriaAttributes(range);
|
|
164
156
|
}
|
|
165
157
|
|
|
166
158
|
private removeFallback(choiceId: string): void {
|
|
167
|
-
const container =
|
|
168
|
-
`[data-eliminated-id="${choiceId}"]`,
|
|
169
|
-
);
|
|
159
|
+
const container = this.fallbackContainers.get(choiceId);
|
|
170
160
|
if (!container) return;
|
|
171
161
|
|
|
172
|
-
container.classList.remove(
|
|
173
|
-
container.removeAttribute(
|
|
174
|
-
container.removeAttribute(
|
|
162
|
+
container.classList.remove(MaskStrategy.FALLBACK_CLASS);
|
|
163
|
+
container.removeAttribute(MaskStrategy.ELIMINATED_ATTR);
|
|
164
|
+
container.removeAttribute(MaskStrategy.ELIMINATED_ID_ATTR);
|
|
175
165
|
|
|
176
166
|
const range = document.createRange();
|
|
177
167
|
range.selectNodeContents(container);
|
|
178
168
|
this.removeAriaAttributes(range);
|
|
169
|
+
this.fallbackContainers.delete(choiceId);
|
|
179
170
|
}
|
|
180
171
|
}
|
|
@@ -8,25 +8,33 @@ import type { EliminationStrategy } from "./elimination-strategy.js";
|
|
|
8
8
|
* WCAG Compliance: Maintains info structure (1.3.1), no layout shift (2.4.3)
|
|
9
9
|
*/
|
|
10
10
|
export class StrikethroughStrategy implements EliminationStrategy {
|
|
11
|
+
private static readonly HIGHLIGHT_STYLE_PREFIX =
|
|
12
|
+
"pie-answer-eliminator-highlight-";
|
|
13
|
+
private static readonly HIGHLIGHT_NAME_PREFIX = "pie-answer-eliminated-";
|
|
14
|
+
private static readonly FALLBACK_CLASS =
|
|
15
|
+
"pie-answer-eliminator-eliminated-fallback";
|
|
16
|
+
private static readonly SR_CLASS = "pie-answer-eliminator-sr-announcement";
|
|
17
|
+
private static readonly CHOICE_HOOK_ATTR =
|
|
18
|
+
"data-pie-answer-eliminator-choice";
|
|
19
|
+
private static readonly LABEL_HOOK_ATTR = "data-pie-answer-eliminator-label";
|
|
20
|
+
private static readonly ELIMINATED_ATTR = "data-pie-answer-eliminated";
|
|
21
|
+
private static readonly ELIMINATED_ID_ATTR = "data-pie-answer-eliminated-id";
|
|
22
|
+
|
|
11
23
|
readonly name = "strikethrough";
|
|
12
24
|
|
|
13
25
|
private highlights = new Map<string, Highlight>();
|
|
14
26
|
private ranges = new Map<string, Range>();
|
|
27
|
+
private fallbackContainers = new Map<string, HTMLElement>();
|
|
15
28
|
|
|
16
29
|
initialize(): void {
|
|
17
30
|
// Check browser support
|
|
18
31
|
if (!this.isSupported()) {
|
|
19
32
|
console.warn("CSS Custom Highlight API not supported, using fallback");
|
|
20
|
-
return;
|
|
21
33
|
}
|
|
22
|
-
|
|
23
|
-
// Inject CSS for highlight styling
|
|
24
|
-
this.injectCSS();
|
|
25
34
|
}
|
|
26
35
|
|
|
27
36
|
destroy(): void {
|
|
28
37
|
this.clearAll();
|
|
29
|
-
this.removeCSS();
|
|
30
38
|
}
|
|
31
39
|
|
|
32
40
|
apply(choiceId: string, range: Range): void {
|
|
@@ -42,7 +50,10 @@ export class StrikethroughStrategy implements EliminationStrategy {
|
|
|
42
50
|
const highlight = new Highlight(range);
|
|
43
51
|
|
|
44
52
|
// Register in CSS.highlights with unique name
|
|
45
|
-
CSS.highlights.set(
|
|
53
|
+
CSS.highlights.set(
|
|
54
|
+
`${StrikethroughStrategy.HIGHLIGHT_NAME_PREFIX}${choiceId}`,
|
|
55
|
+
highlight,
|
|
56
|
+
);
|
|
46
57
|
|
|
47
58
|
// Track internally
|
|
48
59
|
this.highlights.set(choiceId, highlight);
|
|
@@ -59,7 +70,9 @@ export class StrikethroughStrategy implements EliminationStrategy {
|
|
|
59
70
|
}
|
|
60
71
|
|
|
61
72
|
// Remove from CSS.highlights
|
|
62
|
-
CSS.highlights.delete(
|
|
73
|
+
CSS.highlights.delete(
|
|
74
|
+
`${StrikethroughStrategy.HIGHLIGHT_NAME_PREFIX}${choiceId}`,
|
|
75
|
+
);
|
|
63
76
|
|
|
64
77
|
// Remove CSS for this specific highlight
|
|
65
78
|
this.removeHighlightCSS(choiceId);
|
|
@@ -72,6 +85,7 @@ export class StrikethroughStrategy implements EliminationStrategy {
|
|
|
72
85
|
|
|
73
86
|
this.highlights.delete(choiceId);
|
|
74
87
|
this.ranges.delete(choiceId);
|
|
88
|
+
this.fallbackContainers.delete(choiceId);
|
|
75
89
|
}
|
|
76
90
|
|
|
77
91
|
isEliminated(choiceId: string): boolean {
|
|
@@ -83,6 +97,7 @@ export class StrikethroughStrategy implements EliminationStrategy {
|
|
|
83
97
|
for (const choiceId of this.highlights.keys()) {
|
|
84
98
|
this.remove(choiceId);
|
|
85
99
|
}
|
|
100
|
+
this.fallbackContainers.clear();
|
|
86
101
|
}
|
|
87
102
|
|
|
88
103
|
getEliminatedIds(): string[] {
|
|
@@ -93,48 +108,14 @@ export class StrikethroughStrategy implements EliminationStrategy {
|
|
|
93
108
|
return typeof CSS !== "undefined" && "highlights" in CSS;
|
|
94
109
|
}
|
|
95
110
|
|
|
96
|
-
private injectCSS(): void {
|
|
97
|
-
const styleId = "answer-eliminator-strikethrough-styles";
|
|
98
|
-
|
|
99
|
-
// Don't inject if already exists
|
|
100
|
-
if (document.getElementById(styleId)) return;
|
|
101
|
-
|
|
102
|
-
const style = document.createElement("style");
|
|
103
|
-
style.id = styleId;
|
|
104
|
-
// CSS Custom Highlight API: Each registered highlight gets its own ::highlight() selector
|
|
105
|
-
// Since we register highlights with names like 'answer-eliminated-{choiceId}',
|
|
106
|
-
// we need to inject CSS for each one dynamically, OR use a shared attribute approach.
|
|
107
|
-
// For performance, we inject a base style and add choice-specific styles dynamically.
|
|
108
|
-
style.textContent = `
|
|
109
|
-
/* Fallback for browsers without CSS Highlight API */
|
|
110
|
-
.answer-eliminated-fallback {
|
|
111
|
-
text-decoration: line-through;
|
|
112
|
-
text-decoration-thickness: 2px;
|
|
113
|
-
text-decoration-color: var(--pie-incorrect, #ff9800);
|
|
114
|
-
opacity: 0.6;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/* Screen reader only text */
|
|
118
|
-
.sr-announcement {
|
|
119
|
-
position: absolute;
|
|
120
|
-
left: -10000px;
|
|
121
|
-
width: 1px;
|
|
122
|
-
height: 1px;
|
|
123
|
-
overflow: hidden;
|
|
124
|
-
}
|
|
125
|
-
`;
|
|
126
|
-
|
|
127
|
-
document.head.appendChild(style);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
111
|
private injectHighlightCSS(choiceId: string): void {
|
|
131
|
-
const styleId =
|
|
112
|
+
const styleId = `${StrikethroughStrategy.HIGHLIGHT_STYLE_PREFIX}${choiceId}`;
|
|
132
113
|
if (document.getElementById(styleId)) return;
|
|
133
114
|
|
|
134
115
|
const style = document.createElement("style");
|
|
135
116
|
style.id = styleId;
|
|
136
117
|
style.textContent = `
|
|
137
|
-
::highlight(answer-eliminated-${choiceId}) {
|
|
118
|
+
::highlight(pie-answer-eliminated-${choiceId}) {
|
|
138
119
|
text-decoration: line-through;
|
|
139
120
|
text-decoration-thickness: 2px;
|
|
140
121
|
text-decoration-color: var(--pie-incorrect, #ff9800);
|
|
@@ -146,30 +127,25 @@ export class StrikethroughStrategy implements EliminationStrategy {
|
|
|
146
127
|
|
|
147
128
|
private removeHighlightCSS(choiceId: string): void {
|
|
148
129
|
document
|
|
149
|
-
.getElementById(
|
|
130
|
+
.getElementById(
|
|
131
|
+
`${StrikethroughStrategy.HIGHLIGHT_STYLE_PREFIX}${choiceId}`,
|
|
132
|
+
)
|
|
150
133
|
?.remove();
|
|
151
134
|
}
|
|
152
135
|
|
|
153
|
-
private removeCSS(): void {
|
|
154
|
-
const style = document.getElementById(
|
|
155
|
-
"answer-eliminator-strikethrough-styles",
|
|
156
|
-
);
|
|
157
|
-
style?.remove();
|
|
158
|
-
}
|
|
159
|
-
|
|
160
136
|
private addAriaAttributes(range: Range): void {
|
|
161
137
|
// Find the choice container element
|
|
162
138
|
const container = this.findChoiceContainer(range);
|
|
163
139
|
if (!container) return;
|
|
164
140
|
|
|
165
|
-
container.setAttribute(
|
|
141
|
+
container.setAttribute(StrikethroughStrategy.ELIMINATED_ATTR, "true");
|
|
166
142
|
container.setAttribute("aria-disabled", "true");
|
|
167
143
|
|
|
168
144
|
// Add screen reader announcement
|
|
169
|
-
const label =
|
|
170
|
-
if (label && !label.querySelector(
|
|
145
|
+
const label = this.resolveLabelElement(container);
|
|
146
|
+
if (label && !label.querySelector(`.${StrikethroughStrategy.SR_CLASS}`)) {
|
|
171
147
|
const announcement = document.createElement("span");
|
|
172
|
-
announcement.className =
|
|
148
|
+
announcement.className = StrikethroughStrategy.SR_CLASS;
|
|
173
149
|
announcement.textContent = " (eliminated)";
|
|
174
150
|
label.appendChild(announcement);
|
|
175
151
|
}
|
|
@@ -179,11 +155,13 @@ export class StrikethroughStrategy implements EliminationStrategy {
|
|
|
179
155
|
const container = this.findChoiceContainer(range);
|
|
180
156
|
if (!container) return;
|
|
181
157
|
|
|
182
|
-
container.removeAttribute(
|
|
158
|
+
container.removeAttribute(StrikethroughStrategy.ELIMINATED_ATTR);
|
|
183
159
|
container.removeAttribute("aria-disabled");
|
|
184
160
|
|
|
185
161
|
// Remove screen reader announcement
|
|
186
|
-
const announcement = container.querySelector(
|
|
162
|
+
const announcement = container.querySelector(
|
|
163
|
+
`.${StrikethroughStrategy.SR_CLASS}`,
|
|
164
|
+
);
|
|
187
165
|
announcement?.remove();
|
|
188
166
|
}
|
|
189
167
|
|
|
@@ -198,9 +176,7 @@ export class StrikethroughStrategy implements EliminationStrategy {
|
|
|
198
176
|
|
|
199
177
|
while (element && element !== document.body) {
|
|
200
178
|
if (
|
|
201
|
-
element.
|
|
202
|
-
element.classList?.contains("corespring-checkbox") ||
|
|
203
|
-
element.classList?.contains("corespring-radio-button")
|
|
179
|
+
element.getAttribute(StrikethroughStrategy.CHOICE_HOOK_ATTR) === "true"
|
|
204
180
|
) {
|
|
205
181
|
return element;
|
|
206
182
|
}
|
|
@@ -215,25 +191,33 @@ export class StrikethroughStrategy implements EliminationStrategy {
|
|
|
215
191
|
const container = this.findChoiceContainer(range);
|
|
216
192
|
if (!container) return;
|
|
217
193
|
|
|
218
|
-
container.classList.add(
|
|
219
|
-
container.setAttribute(
|
|
220
|
-
container.setAttribute(
|
|
194
|
+
container.classList.add(StrikethroughStrategy.FALLBACK_CLASS);
|
|
195
|
+
container.setAttribute(StrikethroughStrategy.ELIMINATED_ATTR, "true");
|
|
196
|
+
container.setAttribute(StrikethroughStrategy.ELIMINATED_ID_ATTR, choiceId);
|
|
197
|
+
this.fallbackContainers.set(choiceId, container);
|
|
221
198
|
this.addAriaAttributes(range);
|
|
222
199
|
}
|
|
223
200
|
|
|
224
201
|
private removeFallback(choiceId: string): void {
|
|
225
|
-
const container =
|
|
226
|
-
`[data-eliminated-id="${choiceId}"]`,
|
|
227
|
-
);
|
|
202
|
+
const container = this.fallbackContainers.get(choiceId);
|
|
228
203
|
if (!container) return;
|
|
229
204
|
|
|
230
|
-
container.classList.remove(
|
|
231
|
-
container.removeAttribute(
|
|
232
|
-
container.removeAttribute(
|
|
205
|
+
container.classList.remove(StrikethroughStrategy.FALLBACK_CLASS);
|
|
206
|
+
container.removeAttribute(StrikethroughStrategy.ELIMINATED_ATTR);
|
|
207
|
+
container.removeAttribute(StrikethroughStrategy.ELIMINATED_ID_ATTR);
|
|
233
208
|
|
|
234
209
|
// Create fake range for aria removal
|
|
235
210
|
const range = document.createRange();
|
|
236
211
|
range.selectNodeContents(container);
|
|
237
212
|
this.removeAriaAttributes(range);
|
|
213
|
+
this.fallbackContainers.delete(choiceId);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
private resolveLabelElement(container: HTMLElement): HTMLElement | null {
|
|
217
|
+
return (
|
|
218
|
+
container.querySelector<HTMLElement>(
|
|
219
|
+
`[${StrikethroughStrategy.LABEL_HOOK_ATTR}="true"]`,
|
|
220
|
+
) || container.querySelector<HTMLElement>("label")
|
|
221
|
+
);
|
|
238
222
|
}
|
|
239
223
|
}
|