@diplodoc/transform 4.65.3 → 4.66.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/css/_yfm-only.css.map +1 -1
- package/dist/css/_yfm-only.min.css.map +1 -1
- package/dist/css/base.css.map +1 -1
- package/dist/css/base.min.css.map +1 -1
- package/dist/css/print.css.map +1 -1
- package/dist/css/yfm.css.map +1 -1
- package/dist/css/yfm.min.css.map +1 -1
- package/lib/plugins/checkbox/checkbox.js +83 -23
- package/lib/plugins/checkbox/checkbox.js.map +1 -1
- package/package.json +1 -1
- package/src/transform/plugins/checkbox/checkbox.ts +104 -26
|
@@ -15,12 +15,20 @@ export const CheckboxTokenType = {
|
|
|
15
15
|
CheckboxLabelClose: 'checkbox_label_close',
|
|
16
16
|
} as const;
|
|
17
17
|
|
|
18
|
+
type ParsedCheckbox = {
|
|
19
|
+
tokens: Token[];
|
|
20
|
+
startLine: number;
|
|
21
|
+
endLine: number;
|
|
22
|
+
checked: boolean;
|
|
23
|
+
};
|
|
24
|
+
|
|
18
25
|
function matchOpenToken(tokens: Token[], i: number) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
if (tokens[i].type !== 'paragraph_open' || tokens[i + 1].type !== 'inline') {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const firstInline = tokens[i + 1].children?.[0];
|
|
31
|
+
return firstInline?.type === 'text' && pattern.test(firstInline.content);
|
|
24
32
|
}
|
|
25
33
|
|
|
26
34
|
export type CheckboxOptions = {
|
|
@@ -39,16 +47,16 @@ export const checkboxReplace = function (_md: MarkdownIt, opts?: CheckboxOptions
|
|
|
39
47
|
};
|
|
40
48
|
const options = Object.assign(defaults, opts);
|
|
41
49
|
|
|
42
|
-
const createTokens = function (state: StateCore,
|
|
50
|
+
const createTokens = function (state: StateCore, checkbox: ParsedCheckbox): Token[] {
|
|
43
51
|
let token: Token;
|
|
44
|
-
const nodes = [];
|
|
52
|
+
const nodes: Token[] = [];
|
|
45
53
|
|
|
46
54
|
/**
|
|
47
55
|
* <div class="checkbox">
|
|
48
56
|
*/
|
|
49
57
|
token = new state.Token(CheckboxTokenType.CheckboxOpen, 'div', 1);
|
|
50
58
|
token.block = true;
|
|
51
|
-
token.map =
|
|
59
|
+
token.map = [checkbox.startLine, checkbox.endLine];
|
|
52
60
|
token.attrs = [['class', options.divClass]];
|
|
53
61
|
nodes.push(token);
|
|
54
62
|
|
|
@@ -59,7 +67,7 @@ export const checkboxReplace = function (_md: MarkdownIt, opts?: CheckboxOptions
|
|
|
59
67
|
lastId += 1;
|
|
60
68
|
token = new state.Token(CheckboxTokenType.CheckboxInput, 'input', 0);
|
|
61
69
|
token.block = true;
|
|
62
|
-
token.map =
|
|
70
|
+
token.map = [checkbox.startLine, checkbox.endLine];
|
|
63
71
|
token.attrs = [
|
|
64
72
|
['type', 'checkbox'],
|
|
65
73
|
['id', id],
|
|
@@ -67,7 +75,7 @@ export const checkboxReplace = function (_md: MarkdownIt, opts?: CheckboxOptions
|
|
|
67
75
|
if (options.disabled) {
|
|
68
76
|
token.attrSet('disabled', '');
|
|
69
77
|
}
|
|
70
|
-
if (checked === true) {
|
|
78
|
+
if (checkbox.checked === true) {
|
|
71
79
|
token.attrSet('checked', 'true');
|
|
72
80
|
}
|
|
73
81
|
nodes.push(token);
|
|
@@ -82,41 +90,111 @@ export const checkboxReplace = function (_md: MarkdownIt, opts?: CheckboxOptions
|
|
|
82
90
|
/**
|
|
83
91
|
* content of label tag
|
|
84
92
|
*/
|
|
85
|
-
|
|
86
|
-
nodes.push(token);
|
|
93
|
+
nodes.push(...checkbox.tokens);
|
|
87
94
|
|
|
88
95
|
/**
|
|
89
96
|
* closing tags
|
|
90
97
|
*/
|
|
91
98
|
token = new state.Token(CheckboxTokenType.CheckboxLabelClose, 'label', -1);
|
|
92
99
|
token.block = true;
|
|
93
|
-
token.map =
|
|
100
|
+
token.map = [checkbox.startLine, checkbox.endLine];
|
|
94
101
|
nodes.push(token);
|
|
95
102
|
token = new state.Token(CheckboxTokenType.CheckboxClose, 'div', -1);
|
|
96
103
|
token.block = true;
|
|
97
|
-
token.map =
|
|
104
|
+
token.map = [checkbox.startLine, checkbox.endLine];
|
|
98
105
|
nodes.push(token);
|
|
99
106
|
|
|
100
107
|
return nodes;
|
|
101
108
|
};
|
|
102
|
-
const splitTextToken = function (state: StateCore, matches: RegExpMatchArray, i: number) {
|
|
103
|
-
let checked = false;
|
|
104
|
-
const value = matches[1];
|
|
105
|
-
const label = matches[2];
|
|
106
|
-
if (value === 'X' || value === 'x') {
|
|
107
|
-
checked = true;
|
|
108
|
-
}
|
|
109
|
-
return createTokens(state, checked, label, i);
|
|
110
|
-
};
|
|
111
109
|
return function (state) {
|
|
112
110
|
const blockTokens = state.tokens;
|
|
113
111
|
for (let i = 0; i < blockTokens.length; i++) {
|
|
114
|
-
|
|
115
|
-
if (!match) {
|
|
112
|
+
if (!matchOpenToken(blockTokens, i)) {
|
|
116
113
|
continue;
|
|
117
114
|
}
|
|
118
115
|
|
|
119
|
-
|
|
116
|
+
const pToken = blockTokens[i];
|
|
117
|
+
const startLine = pToken.map?.[0] ?? NaN;
|
|
118
|
+
|
|
119
|
+
const checkboxes = parseInlineContent(blockTokens[i + 1], startLine);
|
|
120
|
+
|
|
121
|
+
const checkboxTokens: Token[] = [];
|
|
122
|
+
for (const checkbox of checkboxes) {
|
|
123
|
+
const first = checkbox.tokens[0];
|
|
124
|
+
// remove checkbox markup [X]␣ at start of text content
|
|
125
|
+
first.content = first.content.slice(4);
|
|
126
|
+
checkboxTokens.push(...createTokens(state, checkbox));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// replace paragraph tokens with checkbox tokens
|
|
130
|
+
if (checkboxTokens.length > 0) {
|
|
131
|
+
blockTokens.splice(i, 3, ...checkboxTokens);
|
|
132
|
+
i += checkboxTokens.length - 1;
|
|
133
|
+
}
|
|
120
134
|
}
|
|
121
135
|
};
|
|
122
136
|
};
|
|
137
|
+
|
|
138
|
+
function parseInlineContent(inlineToken: Token, startLine: number): ParsedCheckbox[] {
|
|
139
|
+
const children = inlineToken.children || [];
|
|
140
|
+
const lines = splitInlineTokensByBreaks(children);
|
|
141
|
+
return parseCheckboxesByLines(lines, startLine);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function splitInlineTokensByBreaks(tokens: Token[]): Token[][] {
|
|
145
|
+
const lines: Token[][] = [];
|
|
146
|
+
let lineIdx = 0;
|
|
147
|
+
for (const token of tokens) {
|
|
148
|
+
lines[lineIdx] ||= [];
|
|
149
|
+
lines[lineIdx].push(token);
|
|
150
|
+
|
|
151
|
+
if (isBreakToken(token)) {
|
|
152
|
+
lineIdx += 1;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return lines;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function parseCheckboxesByLines(lines: Token[][], startLine: number): ParsedCheckbox[] {
|
|
160
|
+
const checkboxes: ParsedCheckbox[] = [];
|
|
161
|
+
|
|
162
|
+
let checkboxIdx = -1;
|
|
163
|
+
for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
|
|
164
|
+
const line = lines[lineIdx];
|
|
165
|
+
const first = line?.[0];
|
|
166
|
+
if (!first) {
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
let match;
|
|
171
|
+
if (first.type === 'text' && (match = first.content.match(pattern))) {
|
|
172
|
+
const prevLastToken = checkboxes[checkboxIdx]?.tokens.at(-1);
|
|
173
|
+
if (prevLastToken && isBreakToken(prevLastToken)) {
|
|
174
|
+
// remove hanging line breaks
|
|
175
|
+
checkboxes[checkboxIdx].tokens.splice(-1);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
checkboxIdx += 1;
|
|
179
|
+
checkboxes[checkboxIdx] ||= {
|
|
180
|
+
tokens: [],
|
|
181
|
+
checked: isChecked(match[1]),
|
|
182
|
+
startLine: startLine + lineIdx,
|
|
183
|
+
endLine: startLine + lineIdx + 1,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
checkboxes[checkboxIdx].tokens.push(...line);
|
|
188
|
+
checkboxes[checkboxIdx].endLine = startLine + lineIdx + 1;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return checkboxes;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function isChecked(value: string): boolean {
|
|
195
|
+
return value === 'X' || value === 'x';
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function isBreakToken(token: Token): boolean {
|
|
199
|
+
return token.type === 'softbreak' || token.type === 'hardbreak';
|
|
200
|
+
}
|