postext 1.58.2 → 1.59.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/dist/__tests__/exercises/config.test.d.ts +2 -0
- package/dist/__tests__/exercises/config.test.d.ts.map +1 -0
- package/dist/__tests__/exercises/config.test.js +63 -0
- package/dist/__tests__/exercises/config.test.js.map +1 -0
- package/dist/__tests__/exercises/digital.test.d.ts +2 -0
- package/dist/__tests__/exercises/digital.test.d.ts.map +1 -0
- package/dist/__tests__/exercises/digital.test.js +163 -0
- package/dist/__tests__/exercises/digital.test.js.map +1 -0
- package/dist/__tests__/exercises/languages.test.d.ts +2 -0
- package/dist/__tests__/exercises/languages.test.d.ts.map +1 -0
- package/dist/__tests__/exercises/languages.test.js +109 -0
- package/dist/__tests__/exercises/languages.test.js.map +1 -0
- package/dist/__tests__/exercises/layout.test.d.ts +2 -0
- package/dist/__tests__/exercises/layout.test.d.ts.map +1 -0
- package/dist/__tests__/exercises/layout.test.js +77 -0
- package/dist/__tests__/exercises/layout.test.js.map +1 -0
- package/dist/__tests__/exercises/model.test.d.ts +2 -0
- package/dist/__tests__/exercises/model.test.d.ts.map +1 -0
- package/dist/__tests__/exercises/model.test.js +90 -0
- package/dist/__tests__/exercises/model.test.js.map +1 -0
- package/dist/__tests__/exercises/parse.test.d.ts +2 -0
- package/dist/__tests__/exercises/parse.test.d.ts.map +1 -0
- package/dist/__tests__/exercises/parse.test.js +37 -0
- package/dist/__tests__/exercises/parse.test.js.map +1 -0
- package/dist/__tests__/exercises/refs.test.d.ts +2 -0
- package/dist/__tests__/exercises/refs.test.d.ts.map +1 -0
- package/dist/__tests__/exercises/refs.test.js +46 -0
- package/dist/__tests__/exercises/refs.test.js.map +1 -0
- package/dist/__tests__/exercises/solutions.test.d.ts +2 -0
- package/dist/__tests__/exercises/solutions.test.d.ts.map +1 -0
- package/dist/__tests__/exercises/solutions.test.js +53 -0
- package/dist/__tests__/exercises/solutions.test.js.map +1 -0
- package/dist/__tests__/exports.test.js +14 -0
- package/dist/__tests__/exports.test.js.map +1 -1
- package/dist/__tests__/parse/containers.test.js +2 -2
- package/dist/__tests__/parse/containers.test.js.map +1 -1
- package/dist/__tests__/pipeline/pageShorterThanLine.test.d.ts +2 -0
- package/dist/__tests__/pipeline/pageShorterThanLine.test.d.ts.map +1 -0
- package/dist/__tests__/pipeline/pageShorterThanLine.test.js +29 -0
- package/dist/__tests__/pipeline/pageShorterThanLine.test.js.map +1 -0
- package/dist/__tests__/pipeline/spanHeadingMidPage.test.js +11 -0
- package/dist/__tests__/pipeline/spanHeadingMidPage.test.js.map +1 -1
- package/dist/canvas-backend/blockRender.d.ts.map +1 -1
- package/dist/canvas-backend/blockRender.js +18 -0
- package/dist/canvas-backend/blockRender.js.map +1 -1
- package/dist/canvas-backend/chip.d.ts +3 -0
- package/dist/canvas-backend/chip.d.ts.map +1 -1
- package/dist/canvas-backend/chip.js +31 -1
- package/dist/canvas-backend/chip.js.map +1 -1
- package/dist/configWarnings.d.ts +3 -1
- package/dist/configWarnings.d.ts.map +1 -1
- package/dist/configWarnings.js +5 -1
- package/dist/configWarnings.js.map +1 -1
- package/dist/defaults/chipStyles.d.ts.map +1 -1
- package/dist/defaults/chipStyles.js +7 -0
- package/dist/defaults/chipStyles.js.map +1 -1
- package/dist/defaults/exercises.d.ts +111 -0
- package/dist/defaults/exercises.d.ts.map +1 -0
- package/dist/defaults/exercises.js +255 -0
- package/dist/defaults/exercises.js.map +1 -0
- package/dist/defaults/index.d.ts +2 -0
- package/dist/defaults/index.d.ts.map +1 -1
- package/dist/defaults/index.js +16 -0
- package/dist/defaults/index.js.map +1 -1
- package/dist/defaults/shared.d.ts +4 -0
- package/dist/defaults/shared.d.ts.map +1 -1
- package/dist/defaults/shared.js +6 -0
- package/dist/defaults/shared.js.map +1 -1
- package/dist/design/elementKeys.d.ts +2 -0
- package/dist/design/elementKeys.d.ts.map +1 -1
- package/dist/design/elementKeys.js +1 -1
- package/dist/design/elementKeys.js.map +1 -1
- package/dist/exercises/build.d.ts +60 -0
- package/dist/exercises/build.d.ts.map +1 -0
- package/dist/exercises/build.js +177 -0
- package/dist/exercises/build.js.map +1 -0
- package/dist/exercises/configWarnings.d.ts +11 -0
- package/dist/exercises/configWarnings.d.ts.map +1 -0
- package/dist/exercises/configWarnings.js +175 -0
- package/dist/exercises/configWarnings.js.map +1 -0
- package/dist/exercises/designs.d.ts +38 -0
- package/dist/exercises/designs.d.ts.map +1 -0
- package/dist/exercises/designs.js +143 -0
- package/dist/exercises/designs.js.map +1 -0
- package/dist/exercises/digital.d.ts +69 -0
- package/dist/exercises/digital.d.ts.map +1 -0
- package/dist/exercises/digital.js +58 -0
- package/dist/exercises/digital.js.map +1 -0
- package/dist/exercises/expand.d.ts +74 -0
- package/dist/exercises/expand.d.ts.map +1 -0
- package/dist/exercises/expand.js +1089 -0
- package/dist/exercises/expand.js.map +1 -0
- package/dist/exercises/grids.d.ts +62 -0
- package/dist/exercises/grids.d.ts.map +1 -0
- package/dist/exercises/grids.js +535 -0
- package/dist/exercises/grids.js.map +1 -0
- package/dist/exercises/model.d.ts +24 -0
- package/dist/exercises/model.d.ts.map +1 -0
- package/dist/exercises/model.js +360 -0
- package/dist/exercises/model.js.map +1 -0
- package/dist/exercises/record.d.ts +94 -0
- package/dist/exercises/record.d.ts.map +1 -0
- package/dist/exercises/record.js +9 -0
- package/dist/exercises/record.js.map +1 -0
- package/dist/exercises/runtime.d.ts +65 -0
- package/dist/exercises/runtime.d.ts.map +1 -0
- package/dist/exercises/runtime.js +1261 -0
- package/dist/exercises/runtime.js.map +1 -0
- package/dist/exercises/shuffle.d.ts +13 -0
- package/dist/exercises/shuffle.d.ts.map +1 -0
- package/dist/exercises/shuffle.js +56 -0
- package/dist/exercises/shuffle.js.map +1 -0
- package/dist/exercises/styles.d.ts +51 -0
- package/dist/exercises/styles.d.ts.map +1 -0
- package/dist/exercises/styles.js +221 -0
- package/dist/exercises/styles.js.map +1 -0
- package/dist/exercises/text.d.ts +31 -0
- package/dist/exercises/text.d.ts.map +1 -0
- package/dist/exercises/text.js +82 -0
- package/dist/exercises/text.js.map +1 -0
- package/dist/exercises/types.d.ts +125 -0
- package/dist/exercises/types.d.ts.map +1 -0
- package/dist/exercises/types.js +9 -0
- package/dist/exercises/types.js.map +1 -0
- package/dist/exercises/warnings.d.ts +16 -0
- package/dist/exercises/warnings.d.ts.map +1 -0
- package/dist/exercises/warnings.js +55 -0
- package/dist/exercises/warnings.js.map +1 -0
- package/dist/html-backend.d.ts +6 -0
- package/dist/html-backend.d.ts.map +1 -1
- package/dist/html-backend.js +67 -6
- package/dist/html-backend.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/measure/cache.d.ts.map +1 -1
- package/dist/measure/cache.js +6 -1
- package/dist/measure/cache.js.map +1 -1
- package/dist/measure/rich.d.ts.map +1 -1
- package/dist/measure/rich.js +11 -1
- package/dist/measure/rich.js.map +1 -1
- package/dist/migrate/markdownRuns.js +1 -1
- package/dist/migrate/markdownRuns.js.map +1 -1
- package/dist/numbering.d.ts +3 -0
- package/dist/numbering.d.ts.map +1 -1
- package/dist/numbering.js +6 -0
- package/dist/numbering.js.map +1 -1
- package/dist/parse/blockParser.d.ts.map +1 -1
- package/dist/parse/blockParser.js +47 -4
- package/dist/parse/blockParser.js.map +1 -1
- package/dist/parse/exerciseGaps.d.ts +50 -0
- package/dist/parse/exerciseGaps.d.ts.map +1 -0
- package/dist/parse/exerciseGaps.js +151 -0
- package/dist/parse/exerciseGaps.js.map +1 -0
- package/dist/parse/index.d.ts +1 -1
- package/dist/parse/index.d.ts.map +1 -1
- package/dist/parse/index.js.map +1 -1
- package/dist/parse/sourceMapping.d.ts.map +1 -1
- package/dist/parse/sourceMapping.js +21 -0
- package/dist/parse/sourceMapping.js.map +1 -1
- package/dist/parse/types.d.ts +49 -1
- package/dist/parse/types.d.ts.map +1 -1
- package/dist/pipeline/build.d.ts.map +1 -1
- package/dist/pipeline/build.js +51 -9
- package/dist/pipeline/build.js.map +1 -1
- package/dist/pipeline/calloutLayout.d.ts.map +1 -1
- package/dist/pipeline/calloutLayout.js +1 -0
- package/dist/pipeline/calloutLayout.js.map +1 -1
- package/dist/pipeline/chips.d.ts.map +1 -1
- package/dist/pipeline/chips.js +2 -0
- package/dist/pipeline/chips.js.map +1 -1
- package/dist/pipeline/config.d.ts.map +1 -1
- package/dist/pipeline/config.js +6 -0
- package/dist/pipeline/config.js.map +1 -1
- package/dist/pipeline/contentWarnings.d.ts.map +1 -1
- package/dist/pipeline/contentWarnings.js +29 -1
- package/dist/pipeline/contentWarnings.js.map +1 -1
- package/dist/pipeline/continuation.d.ts.map +1 -1
- package/dist/pipeline/continuation.js +21 -6
- package/dist/pipeline/continuation.js.map +1 -1
- package/dist/pipeline/measureContentBlock.d.ts.map +1 -1
- package/dist/pipeline/measureContentBlock.js +3 -2
- package/dist/pipeline/measureContentBlock.js.map +1 -1
- package/dist/pipeline/outline.d.ts.map +1 -1
- package/dist/pipeline/outline.js +1 -0
- package/dist/pipeline/outline.js.map +1 -1
- package/dist/pipeline/textWrap.js +1 -1
- package/dist/pipeline/textWrap.js.map +1 -1
- package/dist/types.d.ts +303 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/vdt.d.ts +67 -0
- package/dist/vdt.d.ts.map +1 -1
- package/dist/vdt.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs of inline text for the exercise expansion (#1225): a block's plain
|
|
3
|
+
* text, its spans and its source map kept together, so a piece cut from a
|
|
4
|
+
* block (an option, the right side of a pair) or a word the engine adds (a
|
|
5
|
+
* label, a number) stays mapped to the source the Sandbox points at.
|
|
6
|
+
*/
|
|
7
|
+
import { sliceSpan } from '../parse/links.js';
|
|
8
|
+
export const EMPTY_RUN = { text: '', spans: [], sourceMap: [] };
|
|
9
|
+
export function runOf(block) {
|
|
10
|
+
return { text: block.text, spans: block.spans, sourceMap: block.sourceMap };
|
|
11
|
+
}
|
|
12
|
+
/** `[start, end)` of a run. */
|
|
13
|
+
export function sliceRun(run, start, end = run.text.length) {
|
|
14
|
+
start = Math.max(0, Math.min(start, run.text.length));
|
|
15
|
+
end = Math.max(start, Math.min(end, run.text.length));
|
|
16
|
+
const spans = [];
|
|
17
|
+
let at = 0;
|
|
18
|
+
for (const s of run.spans) {
|
|
19
|
+
const a = at;
|
|
20
|
+
const b = at + s.text.length;
|
|
21
|
+
at = b;
|
|
22
|
+
if (b <= start || a >= end)
|
|
23
|
+
continue;
|
|
24
|
+
const from = Math.max(start, a) - a;
|
|
25
|
+
const to = Math.min(end, b) - a;
|
|
26
|
+
spans.push(from === 0 && to === s.text.length ? s : sliceSpan(s, from, to));
|
|
27
|
+
}
|
|
28
|
+
return { text: run.text.slice(start, end), spans, sourceMap: run.sourceMap.slice(start, end) };
|
|
29
|
+
}
|
|
30
|
+
/** The runs one after another. */
|
|
31
|
+
export function joinRuns(...runs) {
|
|
32
|
+
const out = { text: '', spans: [], sourceMap: [] };
|
|
33
|
+
for (const r of runs) {
|
|
34
|
+
out.text += r.text;
|
|
35
|
+
out.spans.push(...r.spans);
|
|
36
|
+
out.sourceMap.push(...r.sourceMap);
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
/** Words the engine sets (a label, a number), mapped to `at`. */
|
|
41
|
+
export function textRun(text, at, style = {}) {
|
|
42
|
+
if (text === '')
|
|
43
|
+
return EMPTY_RUN;
|
|
44
|
+
return { text, spans: [{ text, bold: false, italic: false, ...style }], sourceMap: new Array(text.length).fill(at) };
|
|
45
|
+
}
|
|
46
|
+
/** A run whose spans are all set bold (or `italic`). */
|
|
47
|
+
export function styledRun(run, style) {
|
|
48
|
+
return { ...run, spans: run.spans.map((s) => ({ ...s, ...style })) };
|
|
49
|
+
}
|
|
50
|
+
/** The run with the white space at its ends taken off. */
|
|
51
|
+
export function trimRun(run) {
|
|
52
|
+
let a = 0;
|
|
53
|
+
let b = run.text.length;
|
|
54
|
+
while (a < b && /\s/u.test(run.text[a]))
|
|
55
|
+
a++;
|
|
56
|
+
while (b > a && /\s/u.test(run.text[b - 1]))
|
|
57
|
+
b--;
|
|
58
|
+
return a === 0 && b === run.text.length ? run : sliceRun(run, a, b);
|
|
59
|
+
}
|
|
60
|
+
/** The run cut at every match of `sep` (a plain-text pattern), trimmed. */
|
|
61
|
+
export function splitRun(run, sep) {
|
|
62
|
+
const out = [];
|
|
63
|
+
const re = new RegExp(sep.source, sep.flags.includes('g') ? sep.flags : sep.flags + 'g');
|
|
64
|
+
let last = 0;
|
|
65
|
+
for (let m = re.exec(run.text); m; m = re.exec(run.text)) {
|
|
66
|
+
if (m[0].length === 0) {
|
|
67
|
+
re.lastIndex++;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
out.push(trimRun(sliceRun(run, last, m.index)));
|
|
71
|
+
last = m.index + m[0].length;
|
|
72
|
+
}
|
|
73
|
+
out.push(trimRun(sliceRun(run, last)));
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
/** A content block of `type` holding `run`. */
|
|
77
|
+
export function blockOfRun(type, run, fields = {}) {
|
|
78
|
+
const start = run.sourceMap.length > 0 ? Math.min(...run.sourceMap) : (fields.sourceStart ?? 0);
|
|
79
|
+
const end = run.sourceMap.length > 0 ? Math.max(...run.sourceMap) + 1 : (fields.sourceEnd ?? start);
|
|
80
|
+
return { type, text: run.text, spans: run.spans, sourceMap: run.sourceMap, sourceStart: start, sourceEnd: end, ...fields };
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/exercises/text.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAU9C,MAAM,CAAC,MAAM,SAAS,GAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;AAErE,MAAM,UAAU,KAAK,CAAC,KAAyD;IAC7E,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC;AAC9E,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,QAAQ,CAAC,GAAQ,EAAE,KAAa,EAAE,MAAc,GAAG,CAAC,IAAI,CAAC,MAAM;IAC7E,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IACtD,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IACtD,MAAM,KAAK,GAAiB,EAAE,CAAC;IAC/B,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;QAC7B,EAAE,GAAG,CAAC,CAAC;QACP,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,GAAG;YAAE,SAAS;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;AACjG,CAAC;AAED,kCAAkC;AAClC,MAAM,UAAU,QAAQ,CAAC,GAAG,IAAW;IACrC,MAAM,GAAG,GAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IACxD,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC;QACnB,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QAC3B,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,EAAU,EAAE,QAA6B,EAAE;IAC/E,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAClC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,KAAK,CAAS,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;AAC/H,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,SAAS,CAAC,GAAQ,EAAE,KAAmD;IACrF,OAAO,EAAE,GAAG,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC;AACvE,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,OAAO,CAAC,GAAQ;IAC9B,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;IACxB,OAAO,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC;QAAE,CAAC,EAAE,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC;QAAE,CAAC,EAAE,CAAC;IAClD,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACtE,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,QAAQ,CAAC,GAAQ,EAAE,GAAW;IAC5C,MAAM,GAAG,GAAU,EAAE,CAAC;IACtB,MAAM,EAAE,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC;IACzF,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACzD,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAAC,EAAE,CAAC,SAAS,EAAE,CAAC;YAAC,SAAS;QAAC,CAAC;QACpD,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAChD,IAAI,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC/B,CAAC;IACD,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IACvC,OAAO,GAAG,CAAC;AACb,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,UAAU,CAAC,IAA0B,EAAE,GAAQ,EAAE,SAAgC,EAAE;IACjG,MAAM,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;IAChG,MAAM,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC;IACpG,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC;AAC7H,CAAC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The model of an exercise (#1225): what the Markdown of a `:::exercise`
|
|
3
|
+
* asks and answers, read once from the parsed blocks and shared by the
|
|
4
|
+
* page layout, the solutions and the digital outputs.
|
|
5
|
+
*/
|
|
6
|
+
import type { DirectiveAttrs, ExerciseGap } from '../parse/index.js';
|
|
7
|
+
import type { Run } from './text.js';
|
|
8
|
+
export declare const EXERCISE_KINDS: readonly ["choice", "truefalse", "gaps", "match", "order", "scramble", "sort", "mark", "open", "wordsearch", "crossword", "arithmetic"];
|
|
9
|
+
/** What an exercise asks (`:::exercise{type=…}`). */
|
|
10
|
+
export type ExerciseKind = typeof EXERCISE_KINDS[number];
|
|
11
|
+
/** An option of a question (`- [x] Lisbon`). */
|
|
12
|
+
export interface ExerciseOption {
|
|
13
|
+
/** The task item's block index. */
|
|
14
|
+
block: number;
|
|
15
|
+
correct: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** A question of a `choice` exercise: its stem (a list item with the
|
|
18
|
+
* options under it) and its options; or a statement of a `truefalse`
|
|
19
|
+
* exercise (one option, ticked when true). */
|
|
20
|
+
export interface ExerciseQuestion {
|
|
21
|
+
stem?: number;
|
|
22
|
+
options: ExerciseOption[];
|
|
23
|
+
/** More than one right option, or `select="many"`. */
|
|
24
|
+
multiple: boolean;
|
|
25
|
+
}
|
|
26
|
+
/** A `[[…]]` of the exercise. */
|
|
27
|
+
export interface ExerciseGapRef {
|
|
28
|
+
block: number;
|
|
29
|
+
/** Index of the gap's span in the block's spans. */
|
|
30
|
+
span: number;
|
|
31
|
+
gap: ExerciseGap;
|
|
32
|
+
/** 1-based, in Markdown order. */
|
|
33
|
+
n: number;
|
|
34
|
+
}
|
|
35
|
+
/** A pair of a `match` exercise (`- Bee -> Hive`); `left` empty for a
|
|
36
|
+
* distractor of the right column (`- -> Cave`). */
|
|
37
|
+
export interface ExercisePair {
|
|
38
|
+
block: number;
|
|
39
|
+
left: Run;
|
|
40
|
+
right: Run;
|
|
41
|
+
}
|
|
42
|
+
/** A category of a `sort` exercise (`- Mammals: dog, whale`). */
|
|
43
|
+
export interface ExerciseCategory {
|
|
44
|
+
block: number;
|
|
45
|
+
name: Run;
|
|
46
|
+
items: Run[];
|
|
47
|
+
}
|
|
48
|
+
/** A word of a `wordsearch` (`- MERCURY`) or an entry of a `crossword`
|
|
49
|
+
* (`- SUN: The star of the solar system`). */
|
|
50
|
+
export interface ExerciseEntry {
|
|
51
|
+
block: number;
|
|
52
|
+
/** The word as written, its spaces and hyphens taken out. */
|
|
53
|
+
word: string;
|
|
54
|
+
clue?: Run;
|
|
55
|
+
}
|
|
56
|
+
/** An operation of an `arithmetic` exercise (`- 345 + 278`). */
|
|
57
|
+
export interface ExerciseOperation {
|
|
58
|
+
block: number;
|
|
59
|
+
a: string;
|
|
60
|
+
b: string;
|
|
61
|
+
op: '+' | '-' | '×' | '÷';
|
|
62
|
+
/** The sign as the operation prints it (`×` or `·`, `÷` or `:`). */
|
|
63
|
+
sign?: string;
|
|
64
|
+
/** The result in the digits written; a division's quotient. */
|
|
65
|
+
result: string;
|
|
66
|
+
/** A division's remainder, when not zero. */
|
|
67
|
+
remainder?: string;
|
|
68
|
+
}
|
|
69
|
+
/** A sentence of a `scramble` exercise, cut into its pieces. */
|
|
70
|
+
export interface ExerciseSentence {
|
|
71
|
+
block: number;
|
|
72
|
+
pieces: Run[];
|
|
73
|
+
}
|
|
74
|
+
export type ExerciseIssueKind = 'exerciseUnknownType' | 'exerciseNoAnswer' | 'exerciseUnreadItem' | 'exerciseNested'
|
|
75
|
+
/** A word a crossword or a word search could not place (`detail`). */
|
|
76
|
+
| 'exerciseWordUnplaced' | 'solutionOutside';
|
|
77
|
+
export interface ExerciseIssue {
|
|
78
|
+
kind: ExerciseIssueKind;
|
|
79
|
+
/** The exercise's container id (absent for a solution outside one). */
|
|
80
|
+
exercise?: number;
|
|
81
|
+
/** What was written (an unknown type, an item read as nothing). */
|
|
82
|
+
detail?: string;
|
|
83
|
+
sourceStart: number;
|
|
84
|
+
sourceEnd: number;
|
|
85
|
+
}
|
|
86
|
+
export interface ExerciseModel {
|
|
87
|
+
/** The fence's container id. */
|
|
88
|
+
id: number;
|
|
89
|
+
/** 0-based, among the document's exercises. */
|
|
90
|
+
ordinal: number;
|
|
91
|
+
kind: ExerciseKind;
|
|
92
|
+
attrs: DirectiveAttrs;
|
|
93
|
+
/** Indices of the opening and closing markers. */
|
|
94
|
+
start: number;
|
|
95
|
+
end: number;
|
|
96
|
+
/** The leading paragraphs. */
|
|
97
|
+
instruction: number[];
|
|
98
|
+
/** Every block between the markers that is not the instruction, a
|
|
99
|
+
* solution, a hint or a bank, in order. */
|
|
100
|
+
body: number[];
|
|
101
|
+
/** The blocks the kind reads as items (options, pairs, words…). */
|
|
102
|
+
items: Set<number>;
|
|
103
|
+
/** `:::solution` and `:::hint` ranges (marker indices). */
|
|
104
|
+
solutions: Array<{
|
|
105
|
+
start: number;
|
|
106
|
+
end: number;
|
|
107
|
+
}>;
|
|
108
|
+
hints: Array<{
|
|
109
|
+
start: number;
|
|
110
|
+
end: number;
|
|
111
|
+
}>;
|
|
112
|
+
banks: number[];
|
|
113
|
+
gaps: ExerciseGapRef[];
|
|
114
|
+
questions: ExerciseQuestion[];
|
|
115
|
+
pairs: ExercisePair[];
|
|
116
|
+
/** `order`: the items' blocks in the right order. */
|
|
117
|
+
sequence: number[];
|
|
118
|
+
sentences: ExerciseSentence[];
|
|
119
|
+
categories: ExerciseCategory[];
|
|
120
|
+
entries: ExerciseEntry[];
|
|
121
|
+
operations: ExerciseOperation[];
|
|
122
|
+
sourceStart: number;
|
|
123
|
+
sourceEnd: number;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/exercises/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The model of an exercise (#1225): what the Markdown of a `:::exercise`
|
|
3
|
+
* asks and answers, read once from the parsed blocks and shared by the
|
|
4
|
+
* page layout, the solutions and the digital outputs.
|
|
5
|
+
*/
|
|
6
|
+
export const EXERCISE_KINDS = [
|
|
7
|
+
'choice', 'truefalse', 'gaps', 'match', 'order', 'scramble', 'sort', 'mark', 'open', 'wordsearch', 'crossword', 'arithmetic',
|
|
8
|
+
];
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/exercises/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY;CACpH,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the Markdown of a document's exercises says that the engine cannot
|
|
3
|
+
* read (#1225), as content warnings: an unknown kind or style, a graded
|
|
4
|
+
* exercise with no right answer, an item its kind cannot read, a word a
|
|
5
|
+
* grid cannot place, a solution outside an exercise.
|
|
6
|
+
*/
|
|
7
|
+
import type { ContentBlock } from '../parse/index.js';
|
|
8
|
+
import type { PostextConfig } from '../types.js';
|
|
9
|
+
import type { ContentWarning } from '../vdt.js';
|
|
10
|
+
type Located<T> = T & {
|
|
11
|
+
sourceStart: number;
|
|
12
|
+
sourceEnd: number;
|
|
13
|
+
};
|
|
14
|
+
export declare function exerciseContentWarnings(blocks: readonly ContentBlock[], config: PostextConfig | undefined): Located<ContentWarning>[];
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=warnings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warnings.d.ts","sourceRoot":"","sources":["../../src/exercises/warnings.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAMhD,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,EAAE,MAAM,EAAE,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC,cAAc,CAAC,EAAE,CAgCrI"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the Markdown of a document's exercises says that the engine cannot
|
|
3
|
+
* read (#1225), as content warnings: an unknown kind or style, a graded
|
|
4
|
+
* exercise with no right answer, an item its kind cannot read, a word a
|
|
5
|
+
* grid cannot place, a solution outside an exercise.
|
|
6
|
+
*/
|
|
7
|
+
import { resolveAllConfig } from '../pipeline/config.js';
|
|
8
|
+
import { exerciseSettingsFor } from './build.js';
|
|
9
|
+
import { readExercises } from './model.js';
|
|
10
|
+
import { gridBox } from './grids.js';
|
|
11
|
+
export function exerciseContentWarnings(blocks, config) {
|
|
12
|
+
const { exercises, issues } = readExercises(blocks);
|
|
13
|
+
const out = [];
|
|
14
|
+
const at = (i) => ({ sourceStart: i.sourceStart, sourceEnd: i.sourceEnd });
|
|
15
|
+
for (const i of issues) {
|
|
16
|
+
switch (i.kind) {
|
|
17
|
+
case 'exerciseUnknownType':
|
|
18
|
+
out.push({ kind: 'exerciseUnknownType', type: i.detail ?? '', ...at(i) });
|
|
19
|
+
break;
|
|
20
|
+
case 'exerciseNoAnswer': {
|
|
21
|
+
const ex = exercises.find((e) => e.id === i.exercise);
|
|
22
|
+
out.push({ kind: 'exerciseNoAnswer', exerciseKind: ex?.kind ?? '', ...at(i) });
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
case 'exerciseUnreadItem':
|
|
26
|
+
out.push({ kind: 'exerciseUnreadItem', text: i.detail ?? '', ...at(i) });
|
|
27
|
+
break;
|
|
28
|
+
case 'exerciseNested':
|
|
29
|
+
out.push({ kind: 'exerciseNested', ...at(i) });
|
|
30
|
+
break;
|
|
31
|
+
case 'solutionOutside':
|
|
32
|
+
out.push({ kind: 'solutionOutside', ...at(i) });
|
|
33
|
+
break;
|
|
34
|
+
case 'exerciseWordUnplaced':
|
|
35
|
+
out.push({ kind: 'exerciseWordUnplaced', word: i.detail ?? '', ...at(i) });
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const settings = exerciseSettingsFor(resolveAllConfig(config));
|
|
40
|
+
const styles = new Set((config?.exerciseStyles ?? []).map((s) => s.id));
|
|
41
|
+
for (const ex of exercises) {
|
|
42
|
+
if (config?.exerciseStyles && ex.attrs.style !== undefined && !styles.has(ex.attrs.style)) {
|
|
43
|
+
out.push({ kind: 'exerciseUnknownStyle', style: ex.attrs.style, sourceStart: ex.sourceStart, sourceEnd: ex.sourceStart });
|
|
44
|
+
}
|
|
45
|
+
// A grid places its words whatever the page: generated here with the
|
|
46
|
+
// first style, words that do not fit reported.
|
|
47
|
+
if (ex.kind === 'crossword' || ex.kind === 'wordsearch') {
|
|
48
|
+
const box = gridBox({ kind: ex.kind, id: 'check', style: settings.styles[0], exercise: ex, blocks, seed: settings.exercises.seed, bodySizePt: 10, lineHeightPt: 12, measurePt: 1e6 });
|
|
49
|
+
for (const word of box.unplaced ?? [])
|
|
50
|
+
out.push({ kind: 'exerciseWordUnplaced', word, sourceStart: ex.sourceStart, sourceEnd: ex.sourceEnd });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=warnings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warnings.js","sourceRoot":"","sources":["../../src/exercises/warnings.ts"],"names":[],"mappings":"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"}
|
package/dist/html-backend.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { VDTDocument, RenderWarning } from './vdt.js';
|
|
2
2
|
import { type SvgFontSyncProvider } from './svg/fonts.js';
|
|
3
|
+
import { type ExerciseData } from './exercises/digital.js';
|
|
3
4
|
export interface RenderHtmlOptions {
|
|
4
5
|
/** Layout mode: single vertical column or many columns laid out horizontally. */
|
|
5
6
|
mode?: 'single' | 'multi';
|
|
@@ -119,6 +120,11 @@ export interface HtmlRenderIndex {
|
|
|
119
120
|
html: string;
|
|
120
121
|
mode: 'single' | 'multi';
|
|
121
122
|
pages: HtmlRenderIndexPage[];
|
|
123
|
+
/** The document's exercises for the exercise script (#1230), as `html`
|
|
124
|
+
* writes them in its `<script class="pt-exercises">`: a host that
|
|
125
|
+
* patches the pages instead of setting `html` hands them to
|
|
126
|
+
* `attachExercises` itself. Absent when it has none. */
|
|
127
|
+
exercises?: ExerciseData;
|
|
122
128
|
}
|
|
123
129
|
/**
|
|
124
130
|
* CSS declarations (a `prop:value;` list) that reset the inherited text
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-backend.d.ts","sourceRoot":"","sources":["../src/html-backend.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EAwBX,aAAa,EACd,MAAM,UAAU,CAAC;AAKlB,OAAO,EAA8B,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"html-backend.d.ts","sourceRoot":"","sources":["../src/html-backend.ts"],"names":[],"mappings":"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"}
|
package/dist/html-backend.js
CHANGED
|
@@ -32,6 +32,7 @@ import { altWithLabels } from './composed/labelText.js';
|
|
|
32
32
|
import { figureLabelLeaderPaths, figureLabelMatrix, undrawnLabels, unmirrorLabelLayout } from './composed/labels.js';
|
|
33
33
|
import { comicFramePaintOrder, composedFrameBlockIds, composedPaintOrder, composedReadingOrder, composedSheetClip, composedSheetClipOnSheet, decorationOver, decorationUnder, frameClips, frameContentRect, frameMatrix } from './composed/paint.js';
|
|
34
34
|
import { taskBoxSvgBody, taskBoxText } from './taskBox.js';
|
|
35
|
+
import { exerciseDataJson, exerciseDataOf } from './exercises/digital.js';
|
|
35
36
|
/**
|
|
36
37
|
* Declarations of every box of CJK text measured with no punctuation
|
|
37
38
|
* trimming: the browser adds and removes nothing. Chrome's
|
|
@@ -1763,14 +1764,28 @@ function renderChip(chip, x, baselineOffset, lineFont, lineColor, inkFor,
|
|
|
1763
1764
|
rootDir = 'ltr') {
|
|
1764
1765
|
const bx = x + chip.marginLeft;
|
|
1765
1766
|
const parts = [];
|
|
1767
|
+
const boxGeometry = `position:absolute;left:${bx.toFixed(3)}px;top:${(baselineOffset - chip.ascent).toFixed(3)}px;` +
|
|
1768
|
+
`width:${chip.boxWidth.toFixed(3)}px;height:${(chip.ascent + chip.descent).toFixed(3)}px;box-sizing:border-box;`;
|
|
1766
1769
|
if (chip.background || (chip.borderColor && chip.borderWidth > 0)) {
|
|
1767
|
-
|
|
1768
|
-
|
|
1770
|
+
// An underline (#1227) is the box's bottom border alone.
|
|
1771
|
+
const border = chip.borderColor && chip.borderWidth > 0
|
|
1772
|
+
? `${chip.underline ? 'border-bottom' : 'border'}:${chip.borderWidth.toFixed(3)}px ${chip.underline && chip.underline !== 'solid' ? chip.underline : 'solid'} ${chip.borderColor};`
|
|
1773
|
+
: '';
|
|
1774
|
+
parts.push(`<span aria-hidden="true" style="${boxGeometry}` +
|
|
1769
1775
|
(chip.background ? `background:${chip.background};` : '') +
|
|
1770
|
-
|
|
1771
|
-
(chip.borderRadius > 0 ? `border-radius:${chip.borderRadius.toFixed(3)}px;` : '') +
|
|
1776
|
+
border +
|
|
1777
|
+
(chip.borderRadius > 0 && !chip.underline ? `border-radius:${chip.borderRadius.toFixed(3)}px;` : '') +
|
|
1772
1778
|
`"></span>`);
|
|
1773
1779
|
}
|
|
1780
|
+
// Where an exercise is answered (#1230): a box the digital outputs find
|
|
1781
|
+
// by its slot. A blank reads as what it is; its answer is not written.
|
|
1782
|
+
if (chip.exercise || chip.blank) {
|
|
1783
|
+
const data = chip.exercise ? ` data-pt-ex="${chip.exercise.ex}" data-pt-slot="${esc(chip.exercise.slot)}"` : '';
|
|
1784
|
+
const label = chip.blank ? ` role="img" aria-label="${esc(chip.blankLabel ?? 'blank')}"` : '';
|
|
1785
|
+
parts.push(`<span class="pt-ex-slot${chip.blank ? ' pt-ex-blank' : ''}"${data}${label} style="${boxGeometry}"></span>`);
|
|
1786
|
+
}
|
|
1787
|
+
if (chip.blank)
|
|
1788
|
+
return parts.join('');
|
|
1774
1789
|
let tx = bx + chip.borderWidth + chip.paddingX;
|
|
1775
1790
|
// The runs in the chip's paint order (`VDTChip.order`); a right-to-left
|
|
1776
1791
|
// run's box reads right to left.
|
|
@@ -3252,11 +3267,51 @@ function renderBlock(block, options, extra = '') {
|
|
|
3252
3267
|
const note = block.footnoteNote !== undefined && !block.hidden
|
|
3253
3268
|
? zeroSizeAnchor(footnoteElementId(block.footnoteNote), block.bbox.x, block.bbox.y)
|
|
3254
3269
|
: '';
|
|
3255
|
-
|
|
3270
|
+
// A box printed upside down (#1229): a positioned layer at the page's
|
|
3271
|
+
// origin, turned about the box's centre.
|
|
3272
|
+
const style = block.turn
|
|
3273
|
+
? `position:absolute;left:0;top:0;width:0;height:0;transform-origin:${block.turn.cx.toFixed(3)}px ${block.turn.cy.toFixed(3)}px;transform:rotate(180deg);`
|
|
3274
|
+
: 'display:contents;';
|
|
3275
|
+
return (`<div class="pt-block" data-block-id="${esc(block.id)}" style="${style}">` +
|
|
3256
3276
|
note +
|
|
3257
3277
|
(block.comic && block.stripCaption && !block.hidden ? renderStripBlockHtml(block, options, extra) : renderBlockInner(block, options) + extra) +
|
|
3278
|
+
exerciseBoxHtml(block, options) +
|
|
3258
3279
|
`</div>`);
|
|
3259
3280
|
}
|
|
3281
|
+
/** The boxes of the document's exercises by their own container id (see
|
|
3282
|
+
* {@link HtmlPaint.exerciseBoxes}); `undefined` when it has none. */
|
|
3283
|
+
function exerciseBoxesOf(data) {
|
|
3284
|
+
if (!data)
|
|
3285
|
+
return undefined;
|
|
3286
|
+
const out = new Map();
|
|
3287
|
+
for (const r of data.exercises) {
|
|
3288
|
+
out.set(r.id, { ex: r.id, outer: true });
|
|
3289
|
+
for (const s of r.slots)
|
|
3290
|
+
if (s.box !== undefined && !out.has(s.box))
|
|
3291
|
+
out.set(s.box, { ex: r.id, outer: false });
|
|
3292
|
+
for (const g of r.grids ?? [])
|
|
3293
|
+
if (!out.has(g.box))
|
|
3294
|
+
out.set(g.box, { ex: r.id, outer: false });
|
|
3295
|
+
}
|
|
3296
|
+
return out;
|
|
3297
|
+
}
|
|
3298
|
+
/** Where an exercise's box lies (#1230): an empty element over a callout
|
|
3299
|
+
* frame of an exercise — its outer box, a writing area, a grid — that the
|
|
3300
|
+
* exercise script finds by `data-pt-box` and lays its inputs, lines and
|
|
3301
|
+
* bar in. Not on a vertical page, whose flow is turned. */
|
|
3302
|
+
function exerciseBoxHtml(block, options) {
|
|
3303
|
+
const boxes = options.exerciseBoxes;
|
|
3304
|
+
if (!boxes || block.type !== 'callout' || !block.callout || block.hidden || options.vertical)
|
|
3305
|
+
return '';
|
|
3306
|
+
const own = block.calloutPath && block.calloutPath.length > 0 ? block.calloutPath[block.calloutPath.length - 1] : block.containerId;
|
|
3307
|
+
const box = own !== undefined ? boxes.get(own) : undefined;
|
|
3308
|
+
if (!box)
|
|
3309
|
+
return '';
|
|
3310
|
+
const { x, y, width, height } = block.bbox;
|
|
3311
|
+
const part = block.callout.part !== undefined ? ` data-pt-part="${block.callout.part}"${block.callout.continued ? ' data-pt-continued=""' : ''}` : '';
|
|
3312
|
+
return `<div class="pt-ex-box" data-pt-box="${own}" data-pt-ex="${box.ex}"${box.outer ? ` data-pt-exercise="${box.ex}"` : ''}${part} ` +
|
|
3313
|
+
`style="position:absolute;left:${x}px;top:${y}px;width:${width}px;height:${height}px;pointer-events:none;"></div>`;
|
|
3314
|
+
}
|
|
3260
3315
|
/** An empty element with an id at a point of the page: the target of an
|
|
3261
3316
|
* in-document link. */
|
|
3262
3317
|
function zeroSizeAnchor(id, x, y) {
|
|
@@ -3617,7 +3672,12 @@ export function renderToHtmlIndexed(doc, options = {}) {
|
|
|
3617
3672
|
const linkTargets = anchoredResourceIds(doc);
|
|
3618
3673
|
for (const id of options.refTargets ?? [])
|
|
3619
3674
|
linkTargets.add(id);
|
|
3675
|
+
// The exercises (#1230): their boxes are marked on the pages, their
|
|
3676
|
+
// records written once for the exercise script.
|
|
3677
|
+
const exercises = exerciseDataOf(doc);
|
|
3678
|
+
const exerciseBoxes = exerciseBoxesOf(exercises);
|
|
3620
3679
|
const anchorPaint = {
|
|
3680
|
+
...(exerciseBoxes ? { exerciseBoxes } : {}),
|
|
3621
3681
|
...(doc.config.comics?.cast.length ? { comicCast: doc.config.comics.cast } : {}),
|
|
3622
3682
|
...(doc.anchors ? { anchors: doc.anchors } : {}),
|
|
3623
3683
|
pageIndexOffset: doc.pageIndexOffset ?? 0,
|
|
@@ -3677,8 +3737,9 @@ export function renderToHtmlIndexed(doc, options = {}) {
|
|
|
3677
3737
|
// escaped, they cannot leave their attributes.
|
|
3678
3738
|
const html = `<div class="pt-doc"${docLang !== undefined ? ` lang="${docLang}"` : ''}${rtl ? ' dir="rtl"' : ''} data-mode="${esc(mode)}" style="${esc(reset + docStyle)}">` +
|
|
3679
3739
|
pageHtmlParts.join('') +
|
|
3740
|
+
(exercises ? `<script type="application/json" class="pt-exercises">${exerciseDataJson(exercises)}</script>` : '') +
|
|
3680
3741
|
`</div>`;
|
|
3681
|
-
return { html, mode, pages: indexedPages };
|
|
3742
|
+
return { html, mode, pages: indexedPages, ...(exercises ? { exercises } : {}) };
|
|
3682
3743
|
}
|
|
3683
3744
|
export function renderToHtml(doc, options = {}) {
|
|
3684
3745
|
return renderToHtmlIndexed(doc, options).html;
|