@8btc/mditor 0.0.3 → 0.0.5
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/index.css +16 -8
- package/dist/index.js +405 -98
- package/dist/index.min.js +1 -1
- package/dist/method.d.ts +10 -10
- package/dist/method.js +3 -3
- package/dist/method.min.js +1 -1
- package/dist/ts/util/attachLineNumbers.d.ts +26 -4
- package/dist/types/index.d.ts +13 -1
- package/package.json +1 -1
- package/src/assets/less/_line-number.less +4 -4
- package/src/index.ts +17 -0
- package/src/ts/ir/input.ts +180 -66
- package/src/ts/ir/process.ts +4 -2
- package/src/ts/sv/inputEvent.ts +169 -64
- package/src/ts/sv/process.ts +4 -2
- package/src/ts/util/attachLineNumbers.ts +32 -6
- package/src/ts/wysiwyg/afterRenderEvent.ts +7 -2
- package/src/ts/wysiwyg/index.ts +494 -262
- package/src/ts/wysiwyg/input.ts +148 -64
- package/src/ts/wysiwyg/renderDomByMd.ts +26 -11
package/src/ts/ir/input.ts
CHANGED
|
@@ -1,40 +1,62 @@
|
|
|
1
|
-
import {Constants} from "../constants";
|
|
2
|
-
import {isHeadingMD, isHrMD} from "../util/fixBrowserBehavior";
|
|
1
|
+
import { Constants } from "../constants";
|
|
2
|
+
import { isHeadingMD, isHrMD } from "../util/fixBrowserBehavior";
|
|
3
3
|
import {
|
|
4
4
|
getTopList,
|
|
5
|
-
hasClosestBlock,
|
|
5
|
+
hasClosestBlock,
|
|
6
|
+
hasClosestByAttribute,
|
|
6
7
|
hasClosestByClassName,
|
|
7
8
|
} from "../util/hasClosest";
|
|
8
|
-
import {hasClosestByTag} from "../util/hasClosestByHeadings";
|
|
9
|
-
import {log} from "../util/log";
|
|
10
|
-
import {processCodeRender} from "../util/processCode";
|
|
11
|
-
import {getSelectPosition, setRangeByWbr} from "../util/selection";
|
|
12
|
-
import {renderToc} from "../util/toc";
|
|
13
|
-
import {processAfterRender} from "./process";
|
|
14
|
-
import {getMarkdown} from "../markdown/getMarkdown";
|
|
9
|
+
import { hasClosestByTag } from "../util/hasClosestByHeadings";
|
|
10
|
+
import { log } from "../util/log";
|
|
11
|
+
import { processCodeRender } from "../util/processCode";
|
|
12
|
+
import { getSelectPosition, setRangeByWbr } from "../util/selection";
|
|
13
|
+
import { renderToc } from "../util/toc";
|
|
14
|
+
import { processAfterRender } from "./process";
|
|
15
|
+
import { getMarkdown } from "../markdown/getMarkdown";
|
|
15
16
|
import { bindMathInteractionsInContainer } from "../markdown/mathContextMenu";
|
|
16
17
|
|
|
17
|
-
export const input = (
|
|
18
|
+
export const input = (
|
|
19
|
+
vditor: IVditor,
|
|
20
|
+
range: Range,
|
|
21
|
+
ignoreSpace = false,
|
|
22
|
+
event?: InputEvent
|
|
23
|
+
) => {
|
|
18
24
|
let blockElement = hasClosestBlock(range.startContainer);
|
|
19
25
|
// 前后可以输入空格
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
if (
|
|
27
|
+
blockElement &&
|
|
28
|
+
!ignoreSpace &&
|
|
29
|
+
blockElement.getAttribute("data-type") !== "code-block"
|
|
30
|
+
) {
|
|
31
|
+
if (
|
|
32
|
+
(isHrMD(blockElement.innerHTML) &&
|
|
33
|
+
blockElement.previousElementSibling) ||
|
|
34
|
+
isHeadingMD(blockElement.innerHTML)
|
|
35
|
+
) {
|
|
23
36
|
return;
|
|
24
37
|
}
|
|
25
38
|
|
|
26
39
|
// 前后空格处理
|
|
27
|
-
const startOffset = getSelectPosition(
|
|
40
|
+
const startOffset = getSelectPosition(
|
|
41
|
+
blockElement,
|
|
42
|
+
vditor.ir.element,
|
|
43
|
+
range
|
|
44
|
+
).start;
|
|
28
45
|
|
|
29
46
|
// 开始可以输入空格
|
|
30
47
|
let startSpace = true;
|
|
31
|
-
for (
|
|
48
|
+
for (
|
|
49
|
+
let i = startOffset - 1;
|
|
32
50
|
// 软换行后有空格
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
51
|
+
i >
|
|
52
|
+
blockElement.textContent.substr(0, startOffset).lastIndexOf("\n");
|
|
53
|
+
i--
|
|
54
|
+
) {
|
|
55
|
+
if (
|
|
56
|
+
blockElement.textContent.charAt(i) !== " " &&
|
|
36
57
|
// 多个 tab 前删除不形成代码块 https://github.com/Vanessa219/vditor/issues/162 1
|
|
37
|
-
blockElement.textContent.charAt(i) !== "\t"
|
|
58
|
+
blockElement.textContent.charAt(i) !== "\t"
|
|
59
|
+
) {
|
|
38
60
|
startSpace = false;
|
|
39
61
|
break;
|
|
40
62
|
}
|
|
@@ -45,8 +67,15 @@ export const input = (vditor: IVditor, range: Range, ignoreSpace = false, event?
|
|
|
45
67
|
|
|
46
68
|
// 结尾可以输入空格
|
|
47
69
|
let endSpace = true;
|
|
48
|
-
for (
|
|
49
|
-
|
|
70
|
+
for (
|
|
71
|
+
let i = startOffset - 1;
|
|
72
|
+
i < blockElement.textContent.length;
|
|
73
|
+
i++
|
|
74
|
+
) {
|
|
75
|
+
if (
|
|
76
|
+
blockElement.textContent.charAt(i) !== " " &&
|
|
77
|
+
blockElement.textContent.charAt(i) !== "\n"
|
|
78
|
+
) {
|
|
50
79
|
endSpace = false;
|
|
51
80
|
break;
|
|
52
81
|
}
|
|
@@ -65,12 +94,20 @@ export const input = (vditor: IVditor, range: Range, ignoreSpace = false, event?
|
|
|
65
94
|
}
|
|
66
95
|
|
|
67
96
|
if (endSpace) {
|
|
68
|
-
const markerElement = hasClosestByClassName(
|
|
97
|
+
const markerElement = hasClosestByClassName(
|
|
98
|
+
range.startContainer,
|
|
99
|
+
"vditor-ir__marker"
|
|
100
|
+
);
|
|
69
101
|
if (markerElement) {
|
|
70
102
|
// inline marker space https://github.com/Vanessa219/vditor/issues/239
|
|
71
103
|
} else {
|
|
72
|
-
const previousNode = range.startContainer
|
|
73
|
-
|
|
104
|
+
const previousNode = range.startContainer
|
|
105
|
+
.previousSibling as HTMLElement;
|
|
106
|
+
if (
|
|
107
|
+
previousNode &&
|
|
108
|
+
previousNode.nodeType !== 3 &&
|
|
109
|
+
previousNode.classList.contains("vditor-ir__node--expand")
|
|
110
|
+
) {
|
|
74
111
|
// FireFox https://github.com/Vanessa219/vditor/issues/239
|
|
75
112
|
previousNode.classList.remove("vditor-ir__node--expand");
|
|
76
113
|
}
|
|
@@ -82,9 +119,11 @@ export const input = (vditor: IVditor, range: Range, ignoreSpace = false, event?
|
|
|
82
119
|
}
|
|
83
120
|
}
|
|
84
121
|
|
|
85
|
-
vditor.ir.element
|
|
86
|
-
|
|
87
|
-
|
|
122
|
+
vditor.ir.element
|
|
123
|
+
.querySelectorAll(".vditor-ir__node--expand")
|
|
124
|
+
.forEach((item) => {
|
|
125
|
+
item.classList.remove("vditor-ir__node--expand");
|
|
126
|
+
});
|
|
88
127
|
|
|
89
128
|
if (!blockElement) {
|
|
90
129
|
// 使用顶级块元素,应使用 innerHTML
|
|
@@ -93,9 +132,15 @@ export const input = (vditor: IVditor, range: Range, ignoreSpace = false, event?
|
|
|
93
132
|
|
|
94
133
|
// document.exeComment insertHTML 会插入 wbr
|
|
95
134
|
if (!blockElement.querySelector("wbr")) {
|
|
96
|
-
const previewRenderElement = hasClosestByClassName(
|
|
135
|
+
const previewRenderElement = hasClosestByClassName(
|
|
136
|
+
range.startContainer,
|
|
137
|
+
"vditor-ir__preview"
|
|
138
|
+
);
|
|
97
139
|
if (previewRenderElement) {
|
|
98
|
-
previewRenderElement.previousElementSibling.insertAdjacentHTML(
|
|
140
|
+
previewRenderElement.previousElementSibling.insertAdjacentHTML(
|
|
141
|
+
"beforeend",
|
|
142
|
+
"<wbr>"
|
|
143
|
+
);
|
|
99
144
|
} else {
|
|
100
145
|
range.insertNode(document.createElement("wbr"));
|
|
101
146
|
}
|
|
@@ -112,10 +157,17 @@ export const input = (vditor: IVditor, range: Range, ignoreSpace = false, event?
|
|
|
112
157
|
}
|
|
113
158
|
|
|
114
159
|
const isIRElement = blockElement.isEqualNode(vditor.ir.element);
|
|
115
|
-
const footnoteElement = hasClosestByAttribute(
|
|
160
|
+
const footnoteElement = hasClosestByAttribute(
|
|
161
|
+
blockElement,
|
|
162
|
+
"data-type",
|
|
163
|
+
"footnotes-block"
|
|
164
|
+
);
|
|
116
165
|
let html = "";
|
|
117
166
|
if (!isIRElement) {
|
|
118
|
-
const blockquoteElement = hasClosestByTag(
|
|
167
|
+
const blockquoteElement = hasClosestByTag(
|
|
168
|
+
range.startContainer,
|
|
169
|
+
"BLOCKQUOTE"
|
|
170
|
+
);
|
|
119
171
|
// 列表需要到最顶层
|
|
120
172
|
const topListElement = getTopList(range.startContainer);
|
|
121
173
|
if (topListElement) {
|
|
@@ -123,7 +175,11 @@ export const input = (vditor: IVditor, range: Range, ignoreSpace = false, event?
|
|
|
123
175
|
}
|
|
124
176
|
|
|
125
177
|
// 应到引用层,否则 > --- 会解析为 front-matter;列表中有 blockquote 则解析 blockquote;blockquote 中有列表则解析列表
|
|
126
|
-
if (
|
|
178
|
+
if (
|
|
179
|
+
blockquoteElement &&
|
|
180
|
+
(!topListElement ||
|
|
181
|
+
(topListElement && !blockquoteElement.contains(topListElement)))
|
|
182
|
+
) {
|
|
127
183
|
blockElement = blockquoteElement;
|
|
128
184
|
}
|
|
129
185
|
|
|
@@ -138,39 +194,66 @@ export const input = (vditor: IVditor, range: Range, ignoreSpace = false, event?
|
|
|
138
194
|
// 如果为列表的话,需要把上下的列表都重绘
|
|
139
195
|
const listPrevElement = blockElement.previousElementSibling;
|
|
140
196
|
const listNextElement = blockElement.nextElementSibling;
|
|
141
|
-
if (
|
|
197
|
+
if (
|
|
198
|
+
listPrevElement &&
|
|
199
|
+
(listPrevElement.tagName === "UL" ||
|
|
200
|
+
listPrevElement.tagName === "OL")
|
|
201
|
+
) {
|
|
142
202
|
html = listPrevElement.outerHTML + html;
|
|
143
203
|
listPrevElement.remove();
|
|
144
204
|
}
|
|
145
|
-
if (
|
|
205
|
+
if (
|
|
206
|
+
listNextElement &&
|
|
207
|
+
(listNextElement.tagName === "UL" ||
|
|
208
|
+
listNextElement.tagName === "OL")
|
|
209
|
+
) {
|
|
146
210
|
html = html + listNextElement.outerHTML;
|
|
147
211
|
listNextElement.remove();
|
|
148
212
|
}
|
|
149
213
|
// firefox 列表回车不会产生新的 list item https://github.com/Vanessa219/vditor/issues/194
|
|
150
|
-
html = html.replace(
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
214
|
+
html = html.replace(
|
|
215
|
+
"<div><wbr><br></div>",
|
|
216
|
+
"<li><p><wbr><br></p></li>"
|
|
217
|
+
);
|
|
218
|
+
} else if (
|
|
219
|
+
blockElement.previousElementSibling &&
|
|
220
|
+
blockElement.previousElementSibling.textContent.replace(
|
|
221
|
+
Constants.ZWSP,
|
|
222
|
+
""
|
|
223
|
+
) !== "" &&
|
|
224
|
+
event &&
|
|
225
|
+
event.inputType === "insertParagraph"
|
|
226
|
+
) {
|
|
154
227
|
// 换行时需要处理上一段落
|
|
155
228
|
html = blockElement.previousElementSibling.outerHTML + html;
|
|
156
229
|
blockElement.previousElementSibling.remove();
|
|
157
230
|
}
|
|
158
231
|
if (!blockElement.innerText.startsWith("```")) {
|
|
159
232
|
// 添加链接引用
|
|
160
|
-
vditor.ir.element
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
233
|
+
vditor.ir.element
|
|
234
|
+
.querySelectorAll("[data-type='link-ref-defs-block']")
|
|
235
|
+
.forEach((item) => {
|
|
236
|
+
if (
|
|
237
|
+
item &&
|
|
238
|
+
!(blockElement as HTMLElement).isEqualNode(item)
|
|
239
|
+
) {
|
|
240
|
+
html += item.outerHTML;
|
|
241
|
+
item.remove();
|
|
242
|
+
}
|
|
243
|
+
});
|
|
166
244
|
|
|
167
245
|
// 添加脚注
|
|
168
|
-
vditor.ir.element
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
246
|
+
vditor.ir.element
|
|
247
|
+
.querySelectorAll("[data-type='footnotes-block']")
|
|
248
|
+
.forEach((item) => {
|
|
249
|
+
if (
|
|
250
|
+
item &&
|
|
251
|
+
!(blockElement as HTMLElement).isEqualNode(item)
|
|
252
|
+
) {
|
|
253
|
+
html += item.outerHTML;
|
|
254
|
+
item.remove();
|
|
255
|
+
}
|
|
256
|
+
});
|
|
174
257
|
}
|
|
175
258
|
} else {
|
|
176
259
|
html = blockElement.innerHTML;
|
|
@@ -187,15 +270,28 @@ export const input = (vditor: IVditor, range: Range, ignoreSpace = false, event?
|
|
|
187
270
|
|
|
188
271
|
// 更新正文中的 tip
|
|
189
272
|
if (footnoteElement) {
|
|
190
|
-
const footnoteItemElement = hasClosestByAttribute(
|
|
191
|
-
"
|
|
273
|
+
const footnoteItemElement = hasClosestByAttribute(
|
|
274
|
+
vditor.ir.element.querySelector("wbr"),
|
|
275
|
+
"data-type",
|
|
276
|
+
"footnotes-def"
|
|
277
|
+
);
|
|
192
278
|
if (footnoteItemElement) {
|
|
193
279
|
const footnoteItemText = footnoteItemElement.textContent;
|
|
194
|
-
const marker = footnoteItemText.substring(
|
|
195
|
-
|
|
280
|
+
const marker = footnoteItemText.substring(
|
|
281
|
+
1,
|
|
282
|
+
footnoteItemText.indexOf("]:")
|
|
283
|
+
);
|
|
284
|
+
const footnoteRefElement = vditor.ir.element.querySelector(
|
|
285
|
+
`sup[data-type="footnotes-ref"][data-footnotes-label="${marker}"]`
|
|
286
|
+
);
|
|
196
287
|
if (footnoteRefElement) {
|
|
197
|
-
footnoteRefElement.setAttribute(
|
|
198
|
-
|
|
288
|
+
footnoteRefElement.setAttribute(
|
|
289
|
+
"aria-label",
|
|
290
|
+
footnoteItemText
|
|
291
|
+
.substr(marker.length + 3)
|
|
292
|
+
.trim()
|
|
293
|
+
.substr(0, 24)
|
|
294
|
+
);
|
|
199
295
|
}
|
|
200
296
|
}
|
|
201
297
|
}
|
|
@@ -203,39 +299,57 @@ export const input = (vditor: IVditor, range: Range, ignoreSpace = false, event?
|
|
|
203
299
|
|
|
204
300
|
// linkref 合并及添加
|
|
205
301
|
let firstLinkRefDefElement: HTMLElement;
|
|
206
|
-
const allLinkRefDefsElement = vditor.ir.element.querySelectorAll(
|
|
302
|
+
const allLinkRefDefsElement = vditor.ir.element.querySelectorAll(
|
|
303
|
+
"[data-type='link-ref-defs-block']"
|
|
304
|
+
);
|
|
207
305
|
allLinkRefDefsElement.forEach((item: HTMLElement, index) => {
|
|
208
306
|
if (index === 0) {
|
|
209
307
|
firstLinkRefDefElement = item;
|
|
210
308
|
} else {
|
|
211
|
-
firstLinkRefDefElement.insertAdjacentHTML(
|
|
309
|
+
firstLinkRefDefElement.insertAdjacentHTML(
|
|
310
|
+
"beforeend",
|
|
311
|
+
item.innerHTML
|
|
312
|
+
);
|
|
212
313
|
item.remove();
|
|
213
314
|
}
|
|
214
315
|
});
|
|
215
316
|
if (allLinkRefDefsElement.length > 0) {
|
|
216
|
-
vditor.ir.element.insertAdjacentElement(
|
|
317
|
+
vditor.ir.element.insertAdjacentElement(
|
|
318
|
+
"beforeend",
|
|
319
|
+
allLinkRefDefsElement[0]
|
|
320
|
+
);
|
|
217
321
|
}
|
|
218
322
|
|
|
219
323
|
// 脚注合并后添加的末尾
|
|
220
324
|
let firstFootnoteElement: HTMLElement;
|
|
221
|
-
const allFootnoteElement = vditor.ir.element.querySelectorAll(
|
|
325
|
+
const allFootnoteElement = vditor.ir.element.querySelectorAll(
|
|
326
|
+
"[data-type='footnotes-block']"
|
|
327
|
+
);
|
|
222
328
|
allFootnoteElement.forEach((item: HTMLElement, index) => {
|
|
223
329
|
if (index === 0) {
|
|
224
330
|
firstFootnoteElement = item;
|
|
225
331
|
} else {
|
|
226
|
-
firstFootnoteElement.insertAdjacentHTML(
|
|
332
|
+
firstFootnoteElement.insertAdjacentHTML(
|
|
333
|
+
"beforeend",
|
|
334
|
+
item.innerHTML
|
|
335
|
+
);
|
|
227
336
|
item.remove();
|
|
228
337
|
}
|
|
229
338
|
});
|
|
230
339
|
if (allFootnoteElement.length > 0) {
|
|
231
|
-
vditor.ir.element.insertAdjacentElement(
|
|
340
|
+
vditor.ir.element.insertAdjacentElement(
|
|
341
|
+
"beforeend",
|
|
342
|
+
allFootnoteElement[0]
|
|
343
|
+
);
|
|
232
344
|
}
|
|
233
345
|
|
|
234
346
|
setRangeByWbr(vditor.ir.element, range);
|
|
235
347
|
|
|
236
|
-
vditor.ir.element
|
|
237
|
-
|
|
238
|
-
|
|
348
|
+
vditor.ir.element
|
|
349
|
+
.querySelectorAll(".vditor-ir__preview[data-render='2']")
|
|
350
|
+
.forEach((item: HTMLElement) => {
|
|
351
|
+
processCodeRender(item, vditor);
|
|
352
|
+
});
|
|
239
353
|
|
|
240
354
|
renderToc(vditor);
|
|
241
355
|
|
package/src/ts/ir/process.ts
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
} from "../util/selection";
|
|
18
18
|
import { highlightToolbarIR } from "./highlightToolbarIR";
|
|
19
19
|
import { input } from "./input";
|
|
20
|
-
import {
|
|
20
|
+
import { attachLineNumbersToBlocksThrottled } from "../util/attachLineNumbers";
|
|
21
21
|
|
|
22
22
|
export const processHint = (vditor: IVditor) => {
|
|
23
23
|
vditor.hint.render(vditor);
|
|
@@ -105,7 +105,9 @@ export const processAfterRender = (
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
try {
|
|
108
|
-
|
|
108
|
+
if (vditor.options.lineNumber) {
|
|
109
|
+
attachLineNumbersToBlocksThrottled(vditor.ir.element, text);
|
|
110
|
+
}
|
|
109
111
|
} catch {
|
|
110
112
|
void 0;
|
|
111
113
|
}
|