vditor 3.11.2 → 3.11.3
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 +11 -1
- package/dist/css/content-theme/ant-design.css +10 -0
- package/dist/css/content-theme/dark.css +10 -0
- package/dist/css/content-theme/light.css +13 -0
- package/dist/css/content-theme/wechat.css +10 -0
- package/dist/index.css +133 -4
- package/dist/index.js +587 -36
- package/dist/index.min.js +1 -1
- package/dist/js/i18n/ja_JP.js +2 -2
- package/dist/js/i18n/zh_TW.js +8 -8
- package/dist/js/lute/lute.min.js +75 -60
- package/dist/js/mermaid/mermaid.min.js +2027 -1047
- package/dist/js/wavedrom/LICENSE.WaveDrom +21 -0
- package/dist/js/wavedrom/wavedrom.min.js +9 -0
- package/dist/method.d.ts +2 -0
- package/dist/method.js +311 -6
- package/dist/method.min.js +1 -1
- package/dist/ts/constants.d.ts +4 -0
- package/dist/ts/markdown/adapterRender.d.ts +4 -0
- package/dist/ts/markdown/imageCaptionRender.d.ts +2 -0
- package/dist/ts/markdown/wavedromRender.d.ts +1 -0
- package/dist/ts/util/fixBrowserBehavior.d.ts +1 -0
- package/dist/types/index.d.ts +15 -0
- package/package.json +7 -4
- package/src/assets/less/_reset.less +103 -2
- package/src/assets/less/index.less +20 -0
- package/src/index.ts +3 -0
- package/src/method.ts +3 -0
- package/src/ts/constants.ts +5 -1
- package/src/ts/export/index.ts +2 -0
- package/src/ts/ir/index.ts +26 -0
- package/src/ts/ir/process.ts +24 -1
- package/src/ts/markdown/adapterRender.ts +4 -0
- package/src/ts/markdown/getHTML.ts +6 -3
- package/src/ts/markdown/imageCaptionRender.ts +175 -0
- package/src/ts/markdown/mermaidRender.ts +1 -1
- package/src/ts/markdown/previewRender.ts +7 -1
- package/src/ts/markdown/setLute.ts +3 -0
- package/src/ts/markdown/wavedromRender.ts +54 -0
- package/src/ts/preview/index.ts +5 -0
- package/src/ts/util/Options.ts +1 -1
- package/src/ts/util/fixBrowserBehavior.ts +91 -15
- package/src/ts/util/processCode.ts +3 -0
- package/src/ts/wysiwyg/afterRenderEvent.ts +2 -0
- package/src/ts/wysiwyg/highlightToolbarWYSIWYG.ts +5 -1
- package/src/ts/wysiwyg/input.ts +5 -0
- package/src/ts/wysiwyg/setHeading.ts +110 -6
|
@@ -453,6 +453,41 @@ export const execAfterRender = (vditor: IVditor, options = {
|
|
|
453
453
|
}
|
|
454
454
|
};
|
|
455
455
|
|
|
456
|
+
const isEmptyListItem = (liElement: HTMLElement) => {
|
|
457
|
+
if (liElement.textContent.split(Constants.ZWSP).join("").trim() !== "") {
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
return !liElement.querySelector([
|
|
461
|
+
"audio", "canvas", "embed", "hr", "iframe", "img", "object", "ol", "pre", "svg", "table", "ul", "video",
|
|
462
|
+
"input:not([type='checkbox'])",
|
|
463
|
+
].join(", "));
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
export const exitEmptyListItem = (liElement: HTMLElement) => {
|
|
467
|
+
const listElement = liElement.parentElement;
|
|
468
|
+
const listParent = listElement.parentElement;
|
|
469
|
+
const paragraphElement = document.createElement("p");
|
|
470
|
+
paragraphElement.setAttribute("data-block", "0");
|
|
471
|
+
paragraphElement.innerHTML = "<wbr>";
|
|
472
|
+
|
|
473
|
+
let trailingListElement: HTMLElement | undefined;
|
|
474
|
+
if (liElement.nextElementSibling) {
|
|
475
|
+
trailingListElement = listElement.cloneNode(false) as HTMLElement;
|
|
476
|
+
while (liElement.nextElementSibling) {
|
|
477
|
+
trailingListElement.appendChild(liElement.nextElementSibling);
|
|
478
|
+
}
|
|
479
|
+
listParent.insertBefore(trailingListElement, listElement.nextSibling);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
liElement.remove();
|
|
483
|
+
if (listElement.childElementCount === 0) {
|
|
484
|
+
listParent.replaceChild(paragraphElement, listElement);
|
|
485
|
+
} else {
|
|
486
|
+
listParent.insertBefore(paragraphElement, trailingListElement || listElement.nextSibling);
|
|
487
|
+
}
|
|
488
|
+
return paragraphElement;
|
|
489
|
+
};
|
|
490
|
+
|
|
456
491
|
export const fixList = (range: Range, vditor: IVditor, pElement: HTMLElement | false, event: KeyboardEvent) => {
|
|
457
492
|
const startContainer = range.startContainer;
|
|
458
493
|
const liElement = hasClosestByMatchTag(startContainer, "LI");
|
|
@@ -471,6 +506,28 @@ export const fixList = (range: Range, vditor: IVditor, pElement: HTMLElement | f
|
|
|
471
506
|
return true;
|
|
472
507
|
}
|
|
473
508
|
|
|
509
|
+
// 嵌套列表末尾的空列表项回车后转为父列表项中的段落
|
|
510
|
+
// https://github.com/Vanessa219/vditor/issues/939
|
|
511
|
+
if (!isCtrl(event) && !event.shiftKey && !event.altKey && event.key === "Enter" && range.collapsed &&
|
|
512
|
+
!liElement.nextElementSibling && liElement.parentElement.parentElement.tagName === "LI" &&
|
|
513
|
+
isEmptyListItem(liElement)) {
|
|
514
|
+
const paragraphElement = exitEmptyListItem(liElement);
|
|
515
|
+
setRangeByWbr(paragraphElement, range);
|
|
516
|
+
execAfterRender(vditor);
|
|
517
|
+
event.preventDefault();
|
|
518
|
+
return true;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// 空列表项删除标记后退出当前列表
|
|
522
|
+
if (!isCtrl(event) && !event.shiftKey && !event.altKey && event.key === "Backspace" &&
|
|
523
|
+
liElement.textContent.trim().replace(Constants.ZWSP, "") === "" && range.toString() === "") {
|
|
524
|
+
const paragraphElement = exitEmptyListItem(liElement);
|
|
525
|
+
setRangeByWbr(paragraphElement, range);
|
|
526
|
+
execAfterRender(vditor);
|
|
527
|
+
event.preventDefault();
|
|
528
|
+
return true;
|
|
529
|
+
}
|
|
530
|
+
|
|
474
531
|
if (!isCtrl(event) && !event.shiftKey && !event.altKey && event.key === "Backspace" &&
|
|
475
532
|
!liElement.previousElementSibling && range.toString() === "" &&
|
|
476
533
|
getSelectPosition(liElement, vditor[vditor.currentMode].element, range).start === 0) {
|
|
@@ -488,20 +545,6 @@ export const fixList = (range: Range, vditor: IVditor, pElement: HTMLElement | f
|
|
|
488
545
|
return true;
|
|
489
546
|
}
|
|
490
547
|
|
|
491
|
-
// 空列表删除后与上一级段落对齐
|
|
492
|
-
if (!isCtrl(event) && !event.shiftKey && !event.altKey && event.key === "Backspace" &&
|
|
493
|
-
liElement.textContent.trim().replace(Constants.ZWSP, "") === "" &&
|
|
494
|
-
range.toString() === "" && liElement.previousElementSibling?.tagName === "LI") {
|
|
495
|
-
liElement.previousElementSibling.insertAdjacentText("beforeend", "\n\n");
|
|
496
|
-
range.selectNodeContents(liElement.previousElementSibling);
|
|
497
|
-
range.collapse(false);
|
|
498
|
-
liElement.remove();
|
|
499
|
-
setRangeByWbr(vditor[vditor.currentMode].element, range);
|
|
500
|
-
execAfterRender(vditor);
|
|
501
|
-
event.preventDefault();
|
|
502
|
-
return true;
|
|
503
|
-
}
|
|
504
|
-
|
|
505
548
|
if (!isCtrl(event) && !event.altKey && event.key === "Tab") {
|
|
506
549
|
// 光标位于第一/零字符时,tab 用于列表的缩进
|
|
507
550
|
let isFirst = false;
|
|
@@ -1021,6 +1064,27 @@ export const fixBlockquote = (vditor: IVditor, range: Range, event: KeyboardEven
|
|
|
1021
1064
|
const startContainer = range.startContainer;
|
|
1022
1065
|
const blockquoteElement = hasClosestByMatchTag(startContainer, "BLOCKQUOTE");
|
|
1023
1066
|
if (blockquoteElement && range.toString() === "") {
|
|
1067
|
+
if (pElement && event.key === "Enter" && !isCtrl(event) && !event.shiftKey && !event.altKey &&
|
|
1068
|
+
pElement.parentElement.isSameNode(blockquoteElement) &&
|
|
1069
|
+
hasClosestByMatchTag(blockquoteElement.parentElement, "LI") &&
|
|
1070
|
+
(range.collapsed || !range.cloneContents().firstElementChild) &&
|
|
1071
|
+
pElement.innerHTML.replace(Constants.ZWSP, "") !== "\n" &&
|
|
1072
|
+
pElement.innerHTML.replace(Constants.ZWSP, "") !== "") {
|
|
1073
|
+
// 列表内的引用由浏览器处理回车时会新建列表项 https://github.com/Vanessa219/vditor/issues/1925
|
|
1074
|
+
const trailingRange = range.cloneRange();
|
|
1075
|
+
trailingRange.setEnd(pElement, pElement.childNodes.length);
|
|
1076
|
+
const paragraphElement = document.createElement("p");
|
|
1077
|
+
paragraphElement.setAttribute("data-block", "0");
|
|
1078
|
+
paragraphElement.appendChild(trailingRange.extractContents());
|
|
1079
|
+
pElement.insertAdjacentElement("afterend", paragraphElement);
|
|
1080
|
+
range.setStart(paragraphElement, 0);
|
|
1081
|
+
range.collapse(true);
|
|
1082
|
+
setSelectionFocus(range);
|
|
1083
|
+
execAfterRender(vditor);
|
|
1084
|
+
event.preventDefault();
|
|
1085
|
+
return true;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1024
1088
|
if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey &&
|
|
1025
1089
|
getSelectPosition(blockquoteElement, vditor[vditor.currentMode].element, range).start === 0) {
|
|
1026
1090
|
// Backspace: 光标位于引用中的第零个字符,仅删除引用标签
|
|
@@ -1068,9 +1132,15 @@ export const fixBlockquote = (vditor: IVditor, range: Range, event: KeyboardEven
|
|
|
1068
1132
|
return true;
|
|
1069
1133
|
}
|
|
1070
1134
|
|
|
1071
|
-
|
|
1135
|
+
const itemElement = blockquoteElement.parentElement.tagName === "LI" ? blockquoteElement.parentElement : null;
|
|
1136
|
+
const afterBlockElement = !blockquoteElement.nextElementSibling && itemElement?.nextElementSibling?.tagName === "LI" ?
|
|
1137
|
+
itemElement : blockquoteElement;
|
|
1138
|
+
if (insertAfterBlock(vditor, event, range, blockquoteElement, afterBlockElement)) {
|
|
1072
1139
|
return true;
|
|
1073
1140
|
}
|
|
1141
|
+
if (event.key === "ArrowUp" && itemElement && !blockquoteElement.previousElementSibling) {
|
|
1142
|
+
return false;
|
|
1143
|
+
}
|
|
1074
1144
|
if (insertBeforeBlock(vditor, event, range, blockquoteElement, blockquoteElement)) {
|
|
1075
1145
|
return true;
|
|
1076
1146
|
}
|
|
@@ -1290,6 +1360,12 @@ export const paste = async (vditor: IVditor, event: (ClipboardEvent | DragEvent)
|
|
|
1290
1360
|
return ["", Lute.WalkContinue];
|
|
1291
1361
|
}
|
|
1292
1362
|
|
|
1363
|
+
const parent = node.__internal_object__.Parent;
|
|
1364
|
+
// 链接引用的目标地址由定义节点提供,不在引用位置重复渲染
|
|
1365
|
+
if (parent.Type === 33 && parent.LinkType === 3) {
|
|
1366
|
+
return ["", Lute.WalkContinue];
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1293
1369
|
if (vditor.options.upload.renderLinkDest) {
|
|
1294
1370
|
return vditor.options.upload.renderLinkDest(vditor, node, entering);
|
|
1295
1371
|
}
|
|
@@ -10,6 +10,7 @@ import {markmapRender} from "../markdown/markmapRender";
|
|
|
10
10
|
import {mindmapRender} from "../markdown/mindmapRender";
|
|
11
11
|
import {plantumlRender} from "../markdown/plantumlRender";
|
|
12
12
|
import {SMILESRender} from "../markdown/SMILESRender";
|
|
13
|
+
import {wavedromRender} from "../markdown/wavedromRender";
|
|
13
14
|
|
|
14
15
|
export const processPasteCode = (html: string, text: string, type = "sv") => {
|
|
15
16
|
const tempElement = document.createElement("div");
|
|
@@ -82,6 +83,8 @@ export const processCodeRender = (previewPanel: HTMLElement, vditor: IVditor) =>
|
|
|
82
83
|
plantumlRender(previewPanel, vditor.options.cdn);
|
|
83
84
|
} else if (language === "graphviz") {
|
|
84
85
|
graphvizRender(previewPanel, vditor.options.cdn);
|
|
86
|
+
} else if (language === "wavedrom") {
|
|
87
|
+
wavedromRender(previewPanel, vditor.options.cdn);
|
|
85
88
|
} else if (language === "math") {
|
|
86
89
|
mathRender(previewPanel, {cdn: vditor.options.cdn, math: vditor.options.preview.math});
|
|
87
90
|
} else {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {getMarkdown} from "../markdown/getMarkdown";
|
|
2
|
+
import {renderImageCaptions} from "../markdown/imageCaptionRender";
|
|
2
3
|
import {accessLocalStorage} from "../util/compatibility";
|
|
3
4
|
|
|
4
5
|
export const afterRenderEvent = (vditor: IVditor, options = {
|
|
@@ -6,6 +7,7 @@ export const afterRenderEvent = (vditor: IVditor, options = {
|
|
|
6
7
|
enableHint: false,
|
|
7
8
|
enableInput: true,
|
|
8
9
|
}) => {
|
|
10
|
+
renderImageCaptions(vditor.wysiwyg.element, "wysiwyg", vditor.options.preview.markdown.imageCaption);
|
|
9
11
|
if (options.enableHint) {
|
|
10
12
|
vditor.hint.render(vditor);
|
|
11
13
|
}
|
|
@@ -33,6 +33,7 @@ import {afterRenderEvent} from "./afterRenderEvent";
|
|
|
33
33
|
import {removeBlockElement} from "./processKeydown";
|
|
34
34
|
import {renderToc} from "../util/toc";
|
|
35
35
|
import {getMarkdown} from "../markdown/getMarkdown";
|
|
36
|
+
import {renderImageCaptions} from "../markdown/imageCaptionRender";
|
|
36
37
|
|
|
37
38
|
export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
|
|
38
39
|
clearTimeout(vditor.wysiwyg.hlToolbarTimeoutId);
|
|
@@ -1079,6 +1080,7 @@ export const genImagePopover = (event: Event, vditor: IVditor) => {
|
|
|
1079
1080
|
imgElement.setAttribute("src", inputElement.value);
|
|
1080
1081
|
imgElement.setAttribute("alt", alt.value);
|
|
1081
1082
|
imgElement.setAttribute("title", title.value);
|
|
1083
|
+
renderImageCaptions(vditor.wysiwyg.element, "wysiwyg", vditor.options.preview.markdown.imageCaption);
|
|
1082
1084
|
if (typeof vditor.options.input === "function") {
|
|
1083
1085
|
vditor.options.input(getMarkdown(vditor));
|
|
1084
1086
|
}
|
|
@@ -1150,5 +1152,7 @@ const focusToElement = (event: KeyboardEvent, range: Range) => {
|
|
|
1150
1152
|
};
|
|
1151
1153
|
|
|
1152
1154
|
const customWysiwygToolbar = (vditor: IVditor, type: TWYSISYGToolbar) => {
|
|
1153
|
-
vditor.options.customWysiwygToolbar
|
|
1155
|
+
if (vditor.options.customWysiwygToolbar) {
|
|
1156
|
+
vditor.options.customWysiwygToolbar(type, vditor.wysiwyg.popover);
|
|
1157
|
+
}
|
|
1154
1158
|
};
|
package/src/ts/wysiwyg/input.ts
CHANGED
|
@@ -71,6 +71,7 @@ export const input = (vditor: IVditor, range: Range, event?: InputEvent) => {
|
|
|
71
71
|
|
|
72
72
|
const isWYSIWYGElement = blockElement.isEqualNode(vditor.wysiwyg.element);
|
|
73
73
|
const footnoteElement = hasClosestByAttribute(blockElement, "data-type", "footnotes-block");
|
|
74
|
+
const calloutElement = hasClosestByAttribute(range.startContainer, "data-type", "callout");
|
|
74
75
|
|
|
75
76
|
if (!isWYSIWYGElement) {
|
|
76
77
|
// 列表需要到最顶层
|
|
@@ -90,6 +91,10 @@ export const input = (vditor: IVditor, range: Range, event?: InputEvent) => {
|
|
|
90
91
|
blockElement = footnoteElement;
|
|
91
92
|
}
|
|
92
93
|
|
|
94
|
+
if (calloutElement) {
|
|
95
|
+
blockElement = calloutElement;
|
|
96
|
+
}
|
|
97
|
+
|
|
93
98
|
html = blockElement.outerHTML;
|
|
94
99
|
|
|
95
100
|
if (blockElement.tagName === "UL" || blockElement.tagName === "OL") {
|
|
@@ -1,7 +1,94 @@
|
|
|
1
|
-
import {hasClosestBlock} from "../util/hasClosest";
|
|
1
|
+
import {hasClosestBlock, hasClosestByMatchTag} from "../util/hasClosest";
|
|
2
2
|
import {getEditorRange, setRangeByWbr} from "../util/selection";
|
|
3
3
|
import {renderToc} from "../util/toc";
|
|
4
4
|
|
|
5
|
+
const createBlockElement = (element: HTMLElement, tagName: string) => {
|
|
6
|
+
const blockElement = element.ownerDocument.createElement(tagName);
|
|
7
|
+
blockElement.setAttribute("data-block", "0");
|
|
8
|
+
return blockElement;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const replaceBlockElement = (element: HTMLElement, tagName: string) => {
|
|
12
|
+
const blockElement = createBlockElement(element, tagName);
|
|
13
|
+
while (element.firstChild) {
|
|
14
|
+
blockElement.appendChild(element.firstChild);
|
|
15
|
+
}
|
|
16
|
+
element.replaceWith(blockElement);
|
|
17
|
+
return blockElement;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const isListItemBlock = (node: Node) => {
|
|
21
|
+
if (node.nodeType !== 1) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
const element = node as HTMLElement;
|
|
25
|
+
return element.getAttribute("data-block") === "0" || element.tagName === "INPUT";
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const getListItemInlineNodes = (itemElement: HTMLElement, wbrElement: HTMLElement) => {
|
|
29
|
+
let anchorNode: Node = wbrElement;
|
|
30
|
+
while (anchorNode.parentNode && !anchorNode.parentNode.isSameNode(itemElement)) {
|
|
31
|
+
anchorNode = anchorNode.parentNode;
|
|
32
|
+
}
|
|
33
|
+
if (!anchorNode.parentNode?.isSameNode(itemElement)) {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let firstNode = anchorNode;
|
|
38
|
+
let lastNode = anchorNode;
|
|
39
|
+
while (firstNode.previousSibling && !isListItemBlock(firstNode.previousSibling)) {
|
|
40
|
+
firstNode = firstNode.previousSibling;
|
|
41
|
+
}
|
|
42
|
+
while (lastNode.nextSibling && !isListItemBlock(lastNode.nextSibling)) {
|
|
43
|
+
lastNode = lastNode.nextSibling;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 任务列表的复选框和正文之间需要保留分隔空格。
|
|
47
|
+
if (firstNode.previousSibling instanceof HTMLInputElement && firstNode.nodeType === 3) {
|
|
48
|
+
const leadingWhitespace = firstNode.textContent.match(/^\s+/)?.[0];
|
|
49
|
+
if (leadingWhitespace) {
|
|
50
|
+
firstNode.textContent = firstNode.textContent.substring(leadingWhitespace.length);
|
|
51
|
+
itemElement.insertBefore(itemElement.ownerDocument.createTextNode(leadingWhitespace), firstNode);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const nodes: Node[] = [];
|
|
56
|
+
let node: Node = firstNode;
|
|
57
|
+
while (node) {
|
|
58
|
+
nodes.push(node);
|
|
59
|
+
if (node.isSameNode(lastNode)) {
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
node = node.nextSibling;
|
|
63
|
+
}
|
|
64
|
+
return nodes;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const setListItemHeading = (itemElement: HTMLElement, wbrElement: HTMLElement, tagName: string) => {
|
|
68
|
+
const inlineNodes = getListItemInlineNodes(itemElement, wbrElement);
|
|
69
|
+
if (inlineNodes.length === 0) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const headingElement = createBlockElement(itemElement, tagName);
|
|
74
|
+
itemElement.insertBefore(headingElement, inlineNodes[0]);
|
|
75
|
+
inlineNodes.forEach((node) => {
|
|
76
|
+
headingElement.appendChild(node);
|
|
77
|
+
});
|
|
78
|
+
if (headingElement.innerHTML.trim() === "<wbr>") {
|
|
79
|
+
headingElement.appendChild(itemElement.ownerDocument.createElement("br"));
|
|
80
|
+
}
|
|
81
|
+
return true;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const unwrapBlockElement = (element: HTMLElement) => {
|
|
85
|
+
const fragment = element.ownerDocument.createDocumentFragment();
|
|
86
|
+
while (element.firstChild) {
|
|
87
|
+
fragment.appendChild(element.firstChild);
|
|
88
|
+
}
|
|
89
|
+
element.replaceWith(fragment);
|
|
90
|
+
};
|
|
91
|
+
|
|
5
92
|
export const setHeading = (vditor: IVditor, tagName: string) => {
|
|
6
93
|
const range = getEditorRange(vditor);
|
|
7
94
|
let blockElement = hasClosestBlock(range.startContainer);
|
|
@@ -12,16 +99,27 @@ export const setHeading = (vditor: IVditor, tagName: string) => {
|
|
|
12
99
|
blockElement = vditor.wysiwyg.element;
|
|
13
100
|
}
|
|
14
101
|
if (blockElement && !blockElement.classList.contains("vditor-wysiwyg__block")) {
|
|
15
|
-
|
|
102
|
+
const wbrElement = document.createElement("wbr");
|
|
103
|
+
range.insertNode(wbrElement);
|
|
16
104
|
// Firefox 需要 trim https://github.com/Vanessa219/vditor/issues/207
|
|
17
105
|
if (blockElement.innerHTML.trim() === "<wbr>") {
|
|
18
106
|
// Firefox 光标对不齐 https://github.com/Vanessa219/vditor/issues/199 1
|
|
19
107
|
blockElement.innerHTML = "<wbr><br>";
|
|
20
108
|
}
|
|
21
|
-
|
|
22
|
-
|
|
109
|
+
const itemElement = hasClosestByMatchTag(wbrElement, "LI");
|
|
110
|
+
if (itemElement && blockElement.isSameNode(itemElement.parentElement)) {
|
|
111
|
+
if (!setListItemHeading(itemElement, wbrElement, tagName)) {
|
|
112
|
+
wbrElement.remove();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
} else if (blockElement.tagName === "BLOCKQUOTE" || blockElement.classList.contains("vditor-reset")) {
|
|
116
|
+
const headingElement = createBlockElement(blockElement, tagName);
|
|
117
|
+
while (blockElement.firstChild) {
|
|
118
|
+
headingElement.appendChild(blockElement.firstChild);
|
|
119
|
+
}
|
|
120
|
+
blockElement.appendChild(headingElement);
|
|
23
121
|
} else {
|
|
24
|
-
blockElement
|
|
122
|
+
replaceBlockElement(blockElement, tagName);
|
|
25
123
|
}
|
|
26
124
|
setRangeByWbr(vditor.wysiwyg.element, range);
|
|
27
125
|
renderToc(vditor);
|
|
@@ -36,8 +134,14 @@ export const removeHeading = (vditor: IVditor) => {
|
|
|
36
134
|
}
|
|
37
135
|
if (blockElement) {
|
|
38
136
|
range.insertNode(document.createElement("wbr"));
|
|
39
|
-
blockElement.
|
|
137
|
+
if (blockElement.parentElement?.tagName === "LI" &&
|
|
138
|
+
blockElement.parentElement.parentElement?.getAttribute("data-tight") === "true") {
|
|
139
|
+
unwrapBlockElement(blockElement);
|
|
140
|
+
} else {
|
|
141
|
+
replaceBlockElement(blockElement, "p");
|
|
142
|
+
}
|
|
40
143
|
setRangeByWbr(vditor.wysiwyg.element, range);
|
|
144
|
+
renderToc(vditor);
|
|
41
145
|
}
|
|
42
146
|
vditor.wysiwyg.popover.style.display = "none";
|
|
43
147
|
};
|