vditor 3.8.14 → 3.8.17

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.
@@ -9,1454 +9,1479 @@ import {input} from "../wysiwyg/input";
9
9
  import {isCtrl, isFirefox} from "./compatibility";
10
10
  import {scrollCenter} from "./editorCommonEvent";
11
11
  import {
12
- getTopList,
13
- hasClosestBlock,
14
- hasClosestByAttribute,
15
- hasClosestByClassName,
16
- hasClosestByMatchTag,
12
+ getTopList,
13
+ hasClosestBlock,
14
+ hasClosestByAttribute,
15
+ hasClosestByClassName,
16
+ hasClosestByMatchTag,
17
17
  } from "./hasClosest";
18
18
  import {getLastNode} from "./hasClosest";
19
19
  import {highlightToolbar} from "./highlightToolbar";
20
20
  import {matchHotKey} from "./hotKey";
21
21
  import {processCodeRender, processPasteCode} from "./processCode";
22
22
  import {
23
- getEditorRange,
24
- getSelectPosition,
25
- insertHTML,
26
- setRangeByWbr,
27
- setSelectionByPosition, setSelectionFocus,
23
+ getEditorRange,
24
+ getSelectPosition,
25
+ insertHTML,
26
+ setRangeByWbr,
27
+ setSelectionByPosition, setSelectionFocus,
28
28
  } from "./selection";
29
29
 
30
30
  // https://github.com/Vanessa219/vditor/issues/508 软键盘无法删除空块
31
31
  export const fixGSKeyBackspace = (event: KeyboardEvent, vditor: IVditor, startContainer: Node) => {
32
- if (event.keyCode === 229 && event.code === "" && event.key === "Unidentified" && vditor.currentMode !== "sv") {
33
- const blockElement = hasClosestBlock(startContainer);
34
- // 移动端的标点符号都显示为 299,因此需限定为空删除的条件
35
- if (blockElement && blockElement.textContent.trim() === "") {
36
- vditor[vditor.currentMode].composingLock = true;
37
- return false;
32
+ if (event.keyCode === 229 && event.code === "" && event.key === "Unidentified" && vditor.currentMode !== "sv") {
33
+ const blockElement = hasClosestBlock(startContainer);
34
+ // 移动端的标点符号都显示为 299,因此需限定为空删除的条件
35
+ if (blockElement && blockElement.textContent.trim() === "") {
36
+ vditor[vditor.currentMode].composingLock = true;
37
+ return false;
38
+ }
38
39
  }
39
- }
40
- return true;
40
+ return true;
41
41
  };
42
42
 
43
43
  // https://github.com/Vanessa219/vditor/issues/361 代码块后输入中文
44
44
  export const fixCJKPosition = (range: Range, vditor: IVditor, event: KeyboardEvent) => {
45
- if (event.key === "Enter" || event.key === "Tab" || event.key === "Backspace" || event.key.indexOf("Arrow") > -1
46
- || isCtrl(event) || event.key === "Escape" || event.shiftKey || event.altKey) {
47
- return;
48
- }
49
- const pLiElement = hasClosestByMatchTag(range.startContainer, "P") ||
50
- hasClosestByMatchTag(range.startContainer, "LI");
51
- if (pLiElement && getSelectPosition(pLiElement, vditor[vditor.currentMode].element, range).start === 0) {
52
- const zwspNode = document.createTextNode(Constants.ZWSP);
53
- range.insertNode(zwspNode);
54
- range.setStartAfter(zwspNode);
55
- }
45
+ if (event.key === "Enter" || event.key === "Tab" || event.key === "Backspace" || event.key.indexOf("Arrow") > -1
46
+ || isCtrl(event) || event.key === "Escape" || event.shiftKey || event.altKey) {
47
+ return;
48
+ }
49
+ const pLiElement = hasClosestByMatchTag(range.startContainer, "P") ||
50
+ hasClosestByMatchTag(range.startContainer, "LI");
51
+ if (pLiElement && getSelectPosition(pLiElement, vditor[vditor.currentMode].element, range).start === 0) {
52
+ const zwspNode = document.createTextNode(Constants.ZWSP);
53
+ range.insertNode(zwspNode);
54
+ range.setStartAfter(zwspNode);
55
+ }
56
56
  };
57
57
 
58
58
  // https://github.com/Vanessa219/vditor/issues/381 光标在内联数学公式中无法向下移动
59
59
  export const fixCursorDownInlineMath = (range: Range, key: string) => {
60
- if (key === "ArrowDown" || key === "ArrowUp") {
61
- const inlineElement = hasClosestByAttribute(range.startContainer, "data-type", "math-inline") ||
62
- hasClosestByAttribute(range.startContainer, "data-type", "html-entity") ||
63
- hasClosestByAttribute(range.startContainer, "data-type", "html-inline");
64
- if (inlineElement) {
65
- if (key === "ArrowDown") {
66
- range.setStartAfter(inlineElement.parentElement);
67
- }
68
- if (key === "ArrowUp") {
69
- range.setStartBefore(inlineElement.parentElement);
70
- }
60
+ if (key === "ArrowDown" || key === "ArrowUp") {
61
+ const inlineElement = hasClosestByAttribute(range.startContainer, "data-type", "math-inline") ||
62
+ hasClosestByAttribute(range.startContainer, "data-type", "html-entity") ||
63
+ hasClosestByAttribute(range.startContainer, "data-type", "html-inline");
64
+ if (inlineElement) {
65
+ if (key === "ArrowDown") {
66
+ range.setStartAfter(inlineElement.parentElement);
67
+ }
68
+ if (key === "ArrowUp") {
69
+ range.setStartBefore(inlineElement.parentElement);
70
+ }
71
+ }
71
72
  }
72
- }
73
73
  };
74
74
 
75
75
  export const insertEmptyBlock = (vditor: IVditor, position: InsertPosition) => {
76
- const range = getEditorRange(vditor);
77
- const blockElement = hasClosestBlock(range.startContainer);
78
- if (blockElement) {
79
- blockElement.insertAdjacentHTML(position, `<p data-block="0">${Constants.ZWSP}<wbr>\n</p>`);
80
- setRangeByWbr(vditor[vditor.currentMode].element, range);
81
- highlightToolbar(vditor);
82
- execAfterRender(vditor);
83
- }
76
+ const range = getEditorRange(vditor);
77
+ const blockElement = hasClosestBlock(range.startContainer);
78
+ if (blockElement) {
79
+ blockElement.insertAdjacentHTML(position, `<p data-block="0">${Constants.ZWSP}<wbr>\n</p>`);
80
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
81
+ highlightToolbar(vditor);
82
+ execAfterRender(vditor);
83
+ }
84
84
  };
85
85
 
86
86
  export const isFirstCell = (cellElement: HTMLElement) => {
87
- const tableElement = hasClosestByMatchTag(cellElement, "TABLE") as HTMLTableElement;
88
- if (tableElement && tableElement.rows[0].cells[0].isSameNode(cellElement)) {
89
- return tableElement;
90
- }
91
- return false;
87
+ const tableElement = hasClosestByMatchTag(cellElement, "TABLE") as HTMLTableElement;
88
+ if (tableElement && tableElement.rows[0].cells[0].isSameNode(cellElement)) {
89
+ return tableElement;
90
+ }
91
+ return false;
92
92
  };
93
93
 
94
94
  export const isLastCell = (cellElement: HTMLElement) => {
95
- const tableElement = hasClosestByMatchTag(cellElement, "TABLE") as HTMLTableElement;
96
- if (tableElement && tableElement.lastElementChild.lastElementChild.lastElementChild.isSameNode(cellElement)) {
97
- return tableElement;
98
- }
99
- return false;
95
+ const tableElement = hasClosestByMatchTag(cellElement, "TABLE") as HTMLTableElement;
96
+ if (tableElement && tableElement.lastElementChild.lastElementChild.lastElementChild.isSameNode(cellElement)) {
97
+ return tableElement;
98
+ }
99
+ return false;
100
100
  };
101
101
 
102
102
  // 光标设置到前一个表格中
103
103
  const goPreviousCell = (cellElement: HTMLElement, range: Range, isSelected = true) => {
104
- let previousElement = cellElement.previousElementSibling;
105
- if (!previousElement) {
106
- if (cellElement.parentElement.previousElementSibling) {
107
- previousElement = cellElement.parentElement.previousElementSibling.lastElementChild;
108
- } else if (cellElement.parentElement.parentElement.tagName === "TBODY" &&
109
- cellElement.parentElement.parentElement.previousElementSibling) {
110
- previousElement = cellElement.parentElement
111
- .parentElement.previousElementSibling.lastElementChild.lastElementChild;
112
- } else {
113
- previousElement = null;
104
+ let previousElement = cellElement.previousElementSibling;
105
+ if (!previousElement) {
106
+ if (cellElement.parentElement.previousElementSibling) {
107
+ previousElement = cellElement.parentElement.previousElementSibling.lastElementChild;
108
+ } else if (cellElement.parentElement.parentElement.tagName === "TBODY" &&
109
+ cellElement.parentElement.parentElement.previousElementSibling) {
110
+ previousElement = cellElement.parentElement
111
+ .parentElement.previousElementSibling.lastElementChild.lastElementChild;
112
+ } else {
113
+ previousElement = null;
114
+ }
114
115
  }
115
- }
116
- if (previousElement) {
117
- range.selectNodeContents(previousElement);
118
- if (!isSelected) {
119
- range.collapse(false);
116
+ if (previousElement) {
117
+ range.selectNodeContents(previousElement);
118
+ if (!isSelected) {
119
+ range.collapse(false);
120
+ }
121
+ setSelectionFocus(range);
120
122
  }
121
- setSelectionFocus(range);
122
- }
123
- return previousElement;
123
+ return previousElement;
124
124
  };
125
125
 
126
126
  export const insertAfterBlock = (vditor: IVditor, event: KeyboardEvent, range: Range, element: HTMLElement,
127
127
  blockElement: HTMLElement) => {
128
- const position = getSelectPosition(element, vditor[vditor.currentMode].element, range);
129
- if ((event.key === "ArrowDown" && element.textContent.trimRight().substr(position.start).indexOf("\n") === -1) ||
130
- (event.key === "ArrowRight" && position.start >= element.textContent.trimRight().length)) {
131
- const nextElement = blockElement.nextElementSibling;
132
- if (!nextElement ||
133
- (nextElement && (nextElement.tagName === "TABLE" || nextElement.getAttribute("data-type")))) {
134
- blockElement.insertAdjacentHTML("afterend",
135
- `<p data-block="0">${Constants.ZWSP}<wbr></p>`);
136
- setRangeByWbr(vditor[vditor.currentMode].element, range);
137
- } else {
138
- range.selectNodeContents(nextElement);
139
- range.collapse(true);
140
- setSelectionFocus(range);
128
+ const position = getSelectPosition(element, vditor[vditor.currentMode].element, range);
129
+ if ((event.key === "ArrowDown" && element.textContent.trimRight().substr(position.start).indexOf("\n") === -1) ||
130
+ (event.key === "ArrowRight" && position.start >= element.textContent.trimRight().length)) {
131
+ const nextElement = blockElement.nextElementSibling;
132
+ if (!nextElement ||
133
+ (nextElement && (nextElement.tagName === "TABLE" || nextElement.getAttribute("data-type")))) {
134
+ blockElement.insertAdjacentHTML("afterend",
135
+ `<p data-block="0">${Constants.ZWSP}<wbr></p>`);
136
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
137
+ } else {
138
+ range.selectNodeContents(nextElement);
139
+ range.collapse(true);
140
+ setSelectionFocus(range);
141
+ }
142
+ event.preventDefault();
143
+ return true;
141
144
  }
142
- event.preventDefault();
143
- return true;
144
- }
145
- return false;
145
+ return false;
146
146
  };
147
147
 
148
148
  export const insertBeforeBlock = (vditor: IVditor, event: KeyboardEvent, range: Range, element: HTMLElement,
149
149
  blockElement: HTMLElement) => {
150
- const position = getSelectPosition(element, vditor[vditor.currentMode].element, range);
151
- if ((event.key === "ArrowUp" && element.textContent.substr(0, position.start).indexOf("\n") === -1) ||
152
- ((event.key === "ArrowLeft" || (event.key === "Backspace" && range.toString() === "")) &&
153
- position.start === 0)) {
154
- const previousElement = blockElement.previousElementSibling;
155
- // table || code
156
- if (!previousElement ||
157
- (previousElement && (previousElement.tagName === "TABLE" || previousElement.getAttribute("data-type")))) {
158
- blockElement.insertAdjacentHTML("beforebegin",
159
- `<p data-block="0">${Constants.ZWSP}<wbr></p>`);
160
- setRangeByWbr(vditor[vditor.currentMode].element, range);
161
- } else {
162
- range.selectNodeContents(previousElement);
163
- range.collapse(false);
164
- setSelectionFocus(range);
150
+ const position = getSelectPosition(element, vditor[vditor.currentMode].element, range);
151
+ if ((event.key === "ArrowUp" && element.textContent.substr(0, position.start).indexOf("\n") === -1) ||
152
+ ((event.key === "ArrowLeft" || (event.key === "Backspace" && range.toString() === "")) &&
153
+ position.start === 0)) {
154
+ const previousElement = blockElement.previousElementSibling;
155
+ // table || code
156
+ if (!previousElement ||
157
+ (previousElement && (previousElement.tagName === "TABLE" || previousElement.getAttribute("data-type")))) {
158
+ blockElement.insertAdjacentHTML("beforebegin",
159
+ `<p data-block="0">${Constants.ZWSP}<wbr></p>`);
160
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
161
+ } else {
162
+ range.selectNodeContents(previousElement);
163
+ range.collapse(false);
164
+ setSelectionFocus(range);
165
+ }
166
+ event.preventDefault();
167
+ return true;
165
168
  }
166
- event.preventDefault();
167
- return true;
168
- }
169
- return false;
169
+ return false;
170
170
  };
171
171
 
172
172
  export const listToggle = (vditor: IVditor, range: Range, type: string, cancel = true) => {
173
- const itemElement = hasClosestByMatchTag(range.startContainer, "LI");
174
- vditor[vditor.currentMode].element.querySelectorAll("wbr").forEach((wbr) => {
175
- wbr.remove();
176
- });
177
- range.insertNode(document.createElement("wbr"));
178
-
179
- if (cancel && itemElement) {
180
- // 取消
181
- let pHTML = "";
182
- for (let i = 0; i < itemElement.parentElement.childElementCount; i++) {
183
- const inputElement = itemElement.parentElement.children[i].querySelector("input");
184
- if (inputElement) {
185
- inputElement.remove();
186
- }
187
- pHTML += `<p data-block="0">${itemElement.parentElement.children[i].innerHTML.trimLeft()}</p>`;
188
- }
189
- itemElement.parentElement.insertAdjacentHTML("beforebegin", pHTML);
190
- itemElement.parentElement.remove();
191
- } else {
192
- if (!itemElement) {
193
- // 添加
194
- let blockElement = hasClosestByAttribute(range.startContainer, "data-block", "0");
195
- if (!blockElement) {
196
- vditor[vditor.currentMode].element.querySelector("wbr").remove();
197
- blockElement = vditor[vditor.currentMode].element.querySelector("p");
198
- blockElement.innerHTML = "<wbr>";
199
- }
200
- if (type === "check") {
201
- blockElement.insertAdjacentHTML("beforebegin",
202
- `<ul data-block="0"><li class="vditor-task"><input type="checkbox" /> ${blockElement.innerHTML}</li></ul>`);
203
- blockElement.remove();
204
- } else if (type === "list") {
205
- blockElement.insertAdjacentHTML("beforebegin",
206
- `<ul data-block="0"><li>${blockElement.innerHTML}</li></ul>`);
207
- blockElement.remove();
208
- } else if (type === "ordered-list") {
209
- blockElement.insertAdjacentHTML("beforebegin",
210
- `<ol data-block="0"><li>${blockElement.innerHTML}</li></ol>`);
211
- blockElement.remove();
212
- }
173
+ const itemElement = hasClosestByMatchTag(range.startContainer, "LI");
174
+ vditor[vditor.currentMode].element.querySelectorAll("wbr").forEach((wbr) => {
175
+ wbr.remove();
176
+ });
177
+ range.insertNode(document.createElement("wbr"));
178
+
179
+ if (cancel && itemElement) {
180
+ // 取消
181
+ let pHTML = "";
182
+ for (let i = 0; i < itemElement.parentElement.childElementCount; i++) {
183
+ const inputElement = itemElement.parentElement.children[i].querySelector("input");
184
+ if (inputElement) {
185
+ inputElement.remove();
186
+ }
187
+ pHTML += `<p data-block="0">${itemElement.parentElement.children[i].innerHTML.trimLeft()}</p>`;
188
+ }
189
+ itemElement.parentElement.insertAdjacentHTML("beforebegin", pHTML);
190
+ itemElement.parentElement.remove();
213
191
  } else {
214
- // 切换
215
- if (type === "check") {
216
- itemElement.parentElement.querySelectorAll("li").forEach((item) => {
217
- item.insertAdjacentHTML("afterbegin",
218
- `<input type="checkbox" />${item.textContent.indexOf(" ") === 0 ? "" : " "}`);
219
- item.classList.add("vditor-task");
220
- });
221
- } else {
222
- if (itemElement.querySelector("input")) {
223
- itemElement.parentElement.querySelectorAll("li").forEach((item) => {
224
- item.querySelector("input").remove();
225
- item.classList.remove("vditor-task");
226
- });
227
- }
228
- let element;
229
- if (type === "list") {
230
- element = document.createElement("ul");
231
- element.setAttribute("data-marker", "*");
192
+ if (!itemElement) {
193
+ // 添加
194
+ let blockElement = hasClosestByAttribute(range.startContainer, "data-block", "0");
195
+ if (!blockElement) {
196
+ vditor[vditor.currentMode].element.querySelector("wbr").remove();
197
+ blockElement = vditor[vditor.currentMode].element.querySelector("p");
198
+ blockElement.innerHTML = "<wbr>";
199
+ }
200
+ if (type === "check") {
201
+ blockElement.insertAdjacentHTML("beforebegin",
202
+ `<ul data-block="0"><li class="vditor-task"><input type="checkbox" /> ${blockElement.innerHTML}</li></ul>`);
203
+ blockElement.remove();
204
+ } else if (type === "list") {
205
+ blockElement.insertAdjacentHTML("beforebegin",
206
+ `<ul data-block="0"><li>${blockElement.innerHTML}</li></ul>`);
207
+ blockElement.remove();
208
+ } else if (type === "ordered-list") {
209
+ blockElement.insertAdjacentHTML("beforebegin",
210
+ `<ol data-block="0"><li>${blockElement.innerHTML}</li></ol>`);
211
+ blockElement.remove();
212
+ }
232
213
  } else {
233
- element = document.createElement("ol");
234
- element.setAttribute("data-marker", "1.");
235
- }
236
- element.setAttribute("data-block", "0");
237
- element.setAttribute("data-tight", itemElement.parentElement.getAttribute("data-tight"));
238
- element.innerHTML = itemElement.parentElement.innerHTML;
239
- itemElement.parentElement.parentNode.replaceChild(element, itemElement.parentElement);
240
- }
214
+ // 切换
215
+ if (type === "check") {
216
+ itemElement.parentElement.querySelectorAll("li").forEach((item) => {
217
+ item.insertAdjacentHTML("afterbegin",
218
+ `<input type="checkbox" />${item.textContent.indexOf(" ") === 0 ? "" : " "}`);
219
+ item.classList.add("vditor-task");
220
+ });
221
+ } else {
222
+ if (itemElement.querySelector("input")) {
223
+ itemElement.parentElement.querySelectorAll("li").forEach((item) => {
224
+ item.querySelector("input").remove();
225
+ item.classList.remove("vditor-task");
226
+ });
227
+ }
228
+ let element;
229
+ if (type === "list") {
230
+ element = document.createElement("ul");
231
+ element.setAttribute("data-marker", "*");
232
+ } else {
233
+ element = document.createElement("ol");
234
+ element.setAttribute("data-marker", "1.");
235
+ }
236
+ element.setAttribute("data-block", "0");
237
+ element.setAttribute("data-tight", itemElement.parentElement.getAttribute("data-tight"));
238
+ element.innerHTML = itemElement.parentElement.innerHTML;
239
+ itemElement.parentElement.parentNode.replaceChild(element, itemElement.parentElement);
240
+ }
241
+ }
241
242
  }
242
- }
243
243
  };
244
244
 
245
245
  export const listIndent = (vditor: IVditor, liElement: HTMLElement, range: Range) => {
246
- const previousElement = liElement.previousElementSibling;
247
- if (liElement && previousElement) {
248
- const liElements: HTMLElement[] = [liElement];
249
- Array.from(range.cloneContents().children).forEach((item, index) => {
250
- if (item.nodeType !== 3 && liElement && item.textContent.trim() !== ""
251
- && liElement.getAttribute("data-node-id") === item.getAttribute("data-node-id")) {
252
- if (index !== 0) {
253
- liElements.push(liElement);
254
- }
255
- liElement = liElement.nextElementSibling as HTMLElement;
256
- }
257
- });
246
+ const previousElement = liElement.previousElementSibling;
247
+ if (liElement && previousElement) {
248
+ const liElements: HTMLElement[] = [liElement];
249
+ Array.from(range.cloneContents().children).forEach((item, index) => {
250
+ if (item.nodeType !== 3 && liElement && item.textContent.trim() !== ""
251
+ && liElement.getAttribute("data-node-id") === item.getAttribute("data-node-id")) {
252
+ if (index !== 0) {
253
+ liElements.push(liElement);
254
+ }
255
+ liElement = liElement.nextElementSibling as HTMLElement;
256
+ }
257
+ });
258
258
 
259
- vditor[vditor.currentMode].element.querySelectorAll("wbr").forEach((wbr) => {
260
- wbr.remove();
261
- });
262
- range.insertNode(document.createElement("wbr"));
263
- const liParentElement = previousElement.parentElement;
264
-
265
- let liHTML = "";
266
- liElements.forEach((item: HTMLElement) => {
267
- let marker = item.getAttribute("data-marker");
268
- if (marker.length !== 1) {
269
- marker = `1${marker.slice(-1)}`;
270
- }
271
- liHTML += `<li data-node-id="${item.getAttribute("data-node-id")}" data-marker="${marker}">${item.innerHTML}</li>`;
272
- item.remove();
273
- });
274
- previousElement.insertAdjacentHTML("beforeend",
275
- `<${liParentElement.tagName} data-block="0">${liHTML}</${liParentElement.tagName}>`);
259
+ vditor[vditor.currentMode].element.querySelectorAll("wbr").forEach((wbr) => {
260
+ wbr.remove();
261
+ });
262
+ range.insertNode(document.createElement("wbr"));
263
+ const liParentElement = previousElement.parentElement;
264
+
265
+ let liHTML = "";
266
+ liElements.forEach((item: HTMLElement) => {
267
+ let marker = item.getAttribute("data-marker");
268
+ if (marker.length !== 1) {
269
+ marker = `1${marker.slice(-1)}`;
270
+ }
271
+ liHTML += `<li data-node-id="${item.getAttribute("data-node-id")}" data-marker="${marker}">${item.innerHTML}</li>`;
272
+ item.remove();
273
+ });
274
+ previousElement.insertAdjacentHTML("beforeend",
275
+ `<${liParentElement.tagName} data-block="0">${liHTML}</${liParentElement.tagName}>`);
276
276
 
277
- if (vditor.currentMode === "wysiwyg") {
278
- liParentElement.outerHTML = vditor.lute.SpinVditorDOM(liParentElement.outerHTML);
279
- } else {
280
- liParentElement.outerHTML = vditor.lute.SpinVditorIRDOM(liParentElement.outerHTML);
281
- }
277
+ if (vditor.currentMode === "wysiwyg") {
278
+ liParentElement.outerHTML = vditor.lute.SpinVditorDOM(liParentElement.outerHTML);
279
+ } else {
280
+ liParentElement.outerHTML = vditor.lute.SpinVditorIRDOM(liParentElement.outerHTML);
281
+ }
282
282
 
283
- setRangeByWbr(vditor[vditor.currentMode].element, range);
284
- const tempTopListElement = getTopList(range.startContainer);
285
- if (tempTopListElement) {
286
- tempTopListElement.querySelectorAll(`.vditor-${vditor.currentMode}__preview[data-render='2']`)
287
- .forEach((item: HTMLElement) => {
288
- processCodeRender(item, vditor);
289
- if (vditor.currentMode === "wysiwyg") {
290
- item.previousElementSibling.setAttribute("style", "display:none");
291
- }
292
- });
283
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
284
+ const tempTopListElement = getTopList(range.startContainer);
285
+ if (tempTopListElement) {
286
+ tempTopListElement.querySelectorAll(`.vditor-${vditor.currentMode}__preview[data-render='2']`)
287
+ .forEach((item: HTMLElement) => {
288
+ processCodeRender(item, vditor);
289
+ if (vditor.currentMode === "wysiwyg") {
290
+ item.previousElementSibling.setAttribute("style", "display:none");
291
+ }
292
+ });
293
+ }
294
+ execAfterRender(vditor);
295
+ highlightToolbar(vditor);
296
+ } else {
297
+ vditor[vditor.currentMode].element.focus();
293
298
  }
294
- execAfterRender(vditor);
295
- highlightToolbar(vditor);
296
- } else {
297
- vditor[vditor.currentMode].element.focus();
298
- }
299
299
  };
300
300
 
301
301
  export const listOutdent = (vditor: IVditor, liElement: HTMLElement, range: Range, topListElement: HTMLElement) => {
302
- const liParentLiElement = hasClosestByMatchTag(liElement.parentElement, "LI");
303
- if (liParentLiElement) {
304
- vditor[vditor.currentMode].element.querySelectorAll("wbr").forEach((wbr) => {
305
- wbr.remove();
306
- });
307
- range.insertNode(document.createElement("wbr"));
302
+ const liParentLiElement = hasClosestByMatchTag(liElement.parentElement, "LI");
303
+ if (liParentLiElement) {
304
+ vditor[vditor.currentMode].element.querySelectorAll("wbr").forEach((wbr) => {
305
+ wbr.remove();
306
+ });
307
+ range.insertNode(document.createElement("wbr"));
308
+
309
+ const liParentElement = liElement.parentElement;
310
+ const liParentAfterElement = liParentElement.cloneNode() as HTMLElement;
311
+ const liElements: HTMLElement[] = [liElement];
312
+ Array.from(range.cloneContents().children).forEach((item, index) => {
313
+ if (item.nodeType !== 3 && liElement && item.textContent.trim() !== "" &&
314
+ liElement.getAttribute("data-node-id") === item.getAttribute("data-node-id")) {
315
+ if (index !== 0) {
316
+ liElements.push(liElement);
317
+ }
318
+ liElement = liElement.nextElementSibling as HTMLElement;
319
+ }
320
+ });
321
+ let isMatch = false;
322
+ let afterHTML = "";
323
+ liParentElement.querySelectorAll("li").forEach((item) => {
324
+ if (isMatch) {
325
+ afterHTML += item.outerHTML;
326
+ if (!item.nextElementSibling && !item.previousElementSibling) {
327
+ item.parentElement.remove();
328
+ } else {
329
+ item.remove();
330
+ }
331
+ }
332
+ if (item.isSameNode(liElements[liElements.length - 1])) {
333
+ isMatch = true;
334
+ }
335
+ });
308
336
 
309
- const liParentElement = liElement.parentElement;
310
- const liParentAfterElement = liParentElement.cloneNode() as HTMLElement;
311
- const liElements: HTMLElement[] = [liElement];
312
- Array.from(range.cloneContents().children).forEach((item, index) => {
313
- if (item.nodeType !== 3 && liElement && item.textContent.trim() !== "" &&
314
- liElement.getAttribute("data-node-id") === item.getAttribute("data-node-id")) {
315
- if (index !== 0) {
316
- liElements.push(liElement);
317
- }
318
- liElement = liElement.nextElementSibling as HTMLElement;
319
- }
320
- });
321
- let isMatch = false;
322
- let afterHTML = "";
323
- liParentElement.querySelectorAll("li").forEach((item) => {
324
- if (isMatch) {
325
- afterHTML += item.outerHTML;
326
- if (!item.nextElementSibling && !item.previousElementSibling) {
327
- item.parentElement.remove();
328
- } else {
329
- item.remove();
330
- }
331
- }
332
- if (item.isSameNode(liElements[liElements.length - 1])) {
333
- isMatch = true;
334
- }
335
- });
337
+ liElements.reverse().forEach((item) => {
338
+ liParentLiElement.insertAdjacentElement("afterend", item);
339
+ });
336
340
 
337
- liElements.reverse().forEach((item) => {
338
- liParentLiElement.insertAdjacentElement("afterend", item);
339
- });
341
+ if (afterHTML) {
342
+ liParentAfterElement.innerHTML = afterHTML;
343
+ liElements[0].insertAdjacentElement("beforeend", liParentAfterElement);
344
+ }
340
345
 
341
- if (afterHTML) {
342
- liParentAfterElement.innerHTML = afterHTML;
343
- liElements[0].insertAdjacentElement("beforeend", liParentAfterElement);
344
- }
346
+ if (vditor.currentMode === "wysiwyg") {
347
+ topListElement.outerHTML = vditor.lute.SpinVditorDOM(topListElement.outerHTML);
348
+ } else {
349
+ topListElement.outerHTML = vditor.lute.SpinVditorIRDOM(topListElement.outerHTML);
350
+ }
345
351
 
346
- if (vditor.currentMode === "wysiwyg") {
347
- topListElement.outerHTML = vditor.lute.SpinVditorDOM(topListElement.outerHTML);
352
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
353
+ const tempTopListElement = getTopList(range.startContainer);
354
+ if (tempTopListElement) {
355
+ tempTopListElement.querySelectorAll(`.vditor-${vditor.currentMode}__preview[data-render='2']`)
356
+ .forEach((item: HTMLElement) => {
357
+ processCodeRender(item, vditor);
358
+ if (vditor.currentMode === "wysiwyg") {
359
+ item.previousElementSibling.setAttribute("style", "display:none");
360
+ }
361
+ });
362
+ }
363
+ execAfterRender(vditor);
364
+ highlightToolbar(vditor);
348
365
  } else {
349
- topListElement.outerHTML = vditor.lute.SpinVditorIRDOM(topListElement.outerHTML);
366
+ vditor[vditor.currentMode].element.focus();
350
367
  }
351
-
352
- setRangeByWbr(vditor[vditor.currentMode].element, range);
353
- const tempTopListElement = getTopList(range.startContainer);
354
- if (tempTopListElement) {
355
- tempTopListElement.querySelectorAll(`.vditor-${vditor.currentMode}__preview[data-render='2']`)
356
- .forEach((item: HTMLElement) => {
357
- processCodeRender(item, vditor);
358
- if (vditor.currentMode === "wysiwyg") {
359
- item.previousElementSibling.setAttribute("style", "display:none");
360
- }
361
- });
362
- }
363
- execAfterRender(vditor);
364
- highlightToolbar(vditor);
365
- } else {
366
- vditor[vditor.currentMode].element.focus();
367
- }
368
368
  };
369
369
 
370
370
  export const setTableAlign = (tableElement: HTMLTableElement, type: string) => {
371
- const cell = getSelection().getRangeAt(0).startContainer.parentElement;
372
-
373
- const columnCnt = tableElement.rows[0].cells.length;
374
- const rowCnt = tableElement.rows.length;
375
- let currentColumn = 0;
376
-
377
- for (let i = 0; i < rowCnt; i++) {
378
- for (let j = 0; j < columnCnt; j++) {
379
- if (tableElement.rows[i].cells[j].isSameNode(cell)) {
380
- currentColumn = j;
381
- break;
382
- }
371
+ const cell = getSelection().getRangeAt(0).startContainer.parentElement;
372
+
373
+ const columnCnt = tableElement.rows[0].cells.length;
374
+ const rowCnt = tableElement.rows.length;
375
+ let currentColumn = 0;
376
+
377
+ for (let i = 0; i < rowCnt; i++) {
378
+ for (let j = 0; j < columnCnt; j++) {
379
+ if (tableElement.rows[i].cells[j].isSameNode(cell)) {
380
+ currentColumn = j;
381
+ break;
382
+ }
383
+ }
384
+ }
385
+ for (let k = 0; k < rowCnt; k++) {
386
+ tableElement.rows[k].cells[currentColumn].setAttribute("align", type);
383
387
  }
384
- }
385
- for (let k = 0; k < rowCnt; k++) {
386
- tableElement.rows[k].cells[currentColumn].setAttribute("align", type);
387
- }
388
388
  };
389
389
 
390
390
  export const isHrMD = (text: string) => {
391
- // - _ *
392
- const marker = text.trimRight().split("\n").pop();
393
- if (marker === "") {
394
- return false;
395
- }
396
- if (marker.replace(/ |-/g, "") === ""
397
- || marker.replace(/ |_/g, "") === ""
398
- || marker.replace(/ |\*/g, "") === "") {
399
- if (marker.replace(/ /g, "").length > 2) {
400
- if (marker.indexOf("-") > -1 && marker.trimLeft().indexOf(" ") === -1
401
- && text.trimRight().split("\n").length > 1) {
402
- // 满足 heading
391
+ // - _ *
392
+ const marker = text.trimRight().split("\n").pop();
393
+ if (marker === "") {
403
394
  return false;
404
- }
405
- if (marker.indexOf(" ") === 0 || marker.indexOf("\t") === 0) {
406
- // 代码块
395
+ }
396
+ if (marker.replace(/ |-/g, "") === ""
397
+ || marker.replace(/ |_/g, "") === ""
398
+ || marker.replace(/ |\*/g, "") === "") {
399
+ if (marker.replace(/ /g, "").length > 2) {
400
+ if (marker.indexOf("-") > -1 && marker.trimLeft().indexOf(" ") === -1
401
+ && text.trimRight().split("\n").length > 1) {
402
+ // 满足 heading
403
+ return false;
404
+ }
405
+ if (marker.indexOf(" ") === 0 || marker.indexOf("\t") === 0) {
406
+ // 代码块
407
+ return false;
408
+ }
409
+ return true;
410
+ }
407
411
  return false;
408
- }
409
- return true;
410
412
  }
411
413
  return false;
412
- }
413
- return false;
414
414
  };
415
415
 
416
416
  export const isHeadingMD = (text: string) => {
417
- // - =
418
- const textArray = text.trimRight().split("\n");
419
- text = textArray.pop();
417
+ // - =
418
+ const textArray = text.trimRight().split("\n");
419
+ text = textArray.pop();
420
420
 
421
- if (text.indexOf(" ") === 0 || text.indexOf("\t") === 0) {
422
- return false;
423
- }
421
+ if (text.indexOf(" ") === 0 || text.indexOf("\t") === 0) {
422
+ return false;
423
+ }
424
424
 
425
- text = text.trimLeft();
426
- if (text === "" || textArray.length === 0) {
425
+ text = text.trimLeft();
426
+ if (text === "" || textArray.length === 0) {
427
+ return false;
428
+ }
429
+ if (text.replace(/-/g, "") === ""
430
+ || text.replace(/=/g, "") === "") {
431
+ return true;
432
+ }
427
433
  return false;
428
- }
429
- if (text.replace(/-/g, "") === ""
430
- || text.replace(/=/g, "") === "") {
431
- return true;
432
- }
433
- return false;
434
434
  };
435
435
 
436
436
  export const execAfterRender = (vditor: IVditor, options = {
437
- enableAddUndoStack: true,
438
- enableHint: false,
439
- enableInput: true,
437
+ enableAddUndoStack: true,
438
+ enableHint: false,
439
+ enableInput: true,
440
440
  }) => {
441
- if (vditor.currentMode === "wysiwyg") {
442
- afterRenderEvent(vditor, options);
443
- } else if (vditor.currentMode === "ir") {
444
- processAfterRender(vditor, options);
445
- } else if (vditor.currentMode === "sv") {
446
- processSVAfterRender(vditor, options);
447
- }
441
+ if (vditor.currentMode === "wysiwyg") {
442
+ afterRenderEvent(vditor, options);
443
+ } else if (vditor.currentMode === "ir") {
444
+ processAfterRender(vditor, options);
445
+ } else if (vditor.currentMode === "sv") {
446
+ processSVAfterRender(vditor, options);
447
+ }
448
448
  };
449
449
 
450
450
  export const fixList = (range: Range, vditor: IVditor, pElement: HTMLElement | false, event: KeyboardEvent) => {
451
- const startContainer = range.startContainer;
452
- const liElement = hasClosestByMatchTag(startContainer, "LI");
453
- if (liElement) {
454
- if (!isCtrl(event) && !event.altKey && event.key === "Enter" &&
455
- // fix li 中有多个 P 时,在第一个 P 中换行会在下方生成新的 li
456
- (!event.shiftKey && pElement && liElement.contains(pElement) && pElement.nextElementSibling)) {
457
- if (liElement && !liElement.textContent.endsWith("\n")) {
458
- // li 结尾需 \n
459
- liElement.insertAdjacentText("beforeend", "\n");
460
- }
461
- range.insertNode(document.createTextNode("\n\n"));
462
- range.collapse(false);
463
- execAfterRender(vditor);
464
- event.preventDefault();
465
- return true;
466
- }
451
+ const startContainer = range.startContainer;
452
+ const liElement = hasClosestByMatchTag(startContainer, "LI");
453
+ if (liElement) {
454
+ if (!isCtrl(event) && !event.altKey && event.key === "Enter" &&
455
+ // fix li 中有多个 P 时,在第一个 P 中换行会在下方生成新的 li
456
+ (!event.shiftKey && pElement && liElement.contains(pElement) && pElement.nextElementSibling)) {
457
+ if (liElement && !liElement.textContent.endsWith("\n")) {
458
+ // li 结尾需 \n
459
+ liElement.insertAdjacentText("beforeend", "\n");
460
+ }
461
+ range.insertNode(document.createTextNode("\n\n"));
462
+ range.collapse(false);
463
+ execAfterRender(vditor);
464
+ event.preventDefault();
465
+ return true;
466
+ }
467
467
 
468
- if (!isCtrl(event) && !event.shiftKey && !event.altKey && event.key === "Backspace" &&
469
- !liElement.previousElementSibling && range.toString() === "" &&
470
- getSelectPosition(liElement, vditor[vditor.currentMode].element, range).start === 0) {
471
- // 光标位于点和第一个字符中间时,无法删除 li 元素
472
- if (liElement.nextElementSibling) {
473
- liElement.parentElement.insertAdjacentHTML("beforebegin",
474
- `<p data-block="0"><wbr>${liElement.innerHTML}</p>`);
475
- liElement.remove();
476
- } else {
477
- liElement.parentElement.outerHTML = `<p data-block="0"><wbr>${liElement.innerHTML}</p>`;
478
- }
479
- setRangeByWbr(vditor[vditor.currentMode].element, range);
480
- execAfterRender(vditor);
481
- event.preventDefault();
482
- return true;
483
- }
468
+ if (!isCtrl(event) && !event.shiftKey && !event.altKey && event.key === "Backspace" &&
469
+ !liElement.previousElementSibling && range.toString() === "" &&
470
+ getSelectPosition(liElement, vditor[vditor.currentMode].element, range).start === 0) {
471
+ // 光标位于点和第一个字符中间时,无法删除 li 元素
472
+ if (liElement.nextElementSibling) {
473
+ liElement.parentElement.insertAdjacentHTML("beforebegin",
474
+ `<p data-block="0"><wbr>${liElement.innerHTML}</p>`);
475
+ liElement.remove();
476
+ } else {
477
+ liElement.parentElement.outerHTML = `<p data-block="0"><wbr>${liElement.innerHTML}</p>`;
478
+ }
479
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
480
+ execAfterRender(vditor);
481
+ event.preventDefault();
482
+ return true;
483
+ }
484
484
 
485
- // 空列表删除后与上一级段落对齐
486
- if (!isCtrl(event) && !event.shiftKey && !event.altKey && event.key === "Backspace" &&
487
- liElement.textContent.trim().replace(Constants.ZWSP, "") === "" &&
488
- range.toString() === "" && liElement.previousElementSibling?.tagName === "LI") {
489
- liElement.previousElementSibling.insertAdjacentText("beforeend", "\n\n");
490
- range.selectNodeContents(liElement.previousElementSibling);
491
- range.collapse(false);
492
- liElement.remove();
493
- setRangeByWbr(vditor[vditor.currentMode].element, range);
494
- execAfterRender(vditor);
495
- event.preventDefault();
496
- return true;
497
- }
485
+ // 空列表删除后与上一级段落对齐
486
+ if (!isCtrl(event) && !event.shiftKey && !event.altKey && event.key === "Backspace" &&
487
+ liElement.textContent.trim().replace(Constants.ZWSP, "") === "" &&
488
+ range.toString() === "" && liElement.previousElementSibling?.tagName === "LI") {
489
+ liElement.previousElementSibling.insertAdjacentText("beforeend", "\n\n");
490
+ range.selectNodeContents(liElement.previousElementSibling);
491
+ range.collapse(false);
492
+ liElement.remove();
493
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
494
+ execAfterRender(vditor);
495
+ event.preventDefault();
496
+ return true;
497
+ }
498
498
 
499
- if (!isCtrl(event) && !event.altKey && event.key === "Tab") {
500
- // 光标位于第一/零字符时,tab 用于列表的缩进
501
- let isFirst = false;
502
- if (range.startOffset === 0
503
- && ((startContainer.nodeType === 3 && !startContainer.previousSibling)
504
- || (startContainer.nodeType !== 3 && startContainer.nodeName === "LI"))) {
505
- // 有序/无序列表
506
- isFirst = true;
507
- } else if (liElement.classList.contains("vditor-task") && range.startOffset === 1
508
- && startContainer.previousSibling.nodeType !== 3
509
- && (startContainer.previousSibling as HTMLElement).tagName === "INPUT") {
510
- // 任务列表
511
- isFirst = true;
512
- }
513
-
514
- if (isFirst || range.toString() !== "") {
515
- if (event.shiftKey) {
516
- listOutdent(vditor, liElement, range, liElement.parentElement);
517
- } else {
518
- listIndent(vditor, liElement, range);
499
+ if (!isCtrl(event) && !event.altKey && event.key === "Tab") {
500
+ // 光标位于第一/零字符时,tab 用于列表的缩进
501
+ let isFirst = false;
502
+ if (range.startOffset === 0
503
+ && ((startContainer.nodeType === 3 && !startContainer.previousSibling)
504
+ || (startContainer.nodeType !== 3 && startContainer.nodeName === "LI"))) {
505
+ // 有序/无序列表
506
+ isFirst = true;
507
+ } else if (liElement.classList.contains("vditor-task") && range.startOffset === 1
508
+ && startContainer.previousSibling.nodeType !== 3
509
+ && (startContainer.previousSibling as HTMLElement).tagName === "INPUT") {
510
+ // 任务列表
511
+ isFirst = true;
512
+ }
513
+
514
+ if (isFirst || range.toString() !== "") {
515
+ if (event.shiftKey) {
516
+ listOutdent(vditor, liElement, range, liElement.parentElement);
517
+ } else {
518
+ listIndent(vditor, liElement, range);
519
+ }
520
+ event.preventDefault();
521
+ return true;
522
+ }
519
523
  }
520
- event.preventDefault();
521
- return true;
522
- }
523
524
  }
524
- }
525
- return false;
525
+ return false;
526
526
  };
527
527
 
528
528
  // tab 处理: block code render, table, 列表第一个字符中的 tab 处理单独写在上面
529
529
  export const fixTab = (vditor: IVditor, range: Range, event: KeyboardEvent) => {
530
- if (vditor.options.tab && event.key === "Tab") {
531
- if (event.shiftKey) {
532
- // TODO shift+tab
533
- } else {
534
- if (range.toString() === "") {
535
- range.insertNode(document.createTextNode(vditor.options.tab));
536
- range.collapse(false);
537
- } else {
538
- range.extractContents();
539
- range.insertNode(document.createTextNode(vditor.options.tab));
540
- range.collapse(false);
541
- }
530
+ if (vditor.options.tab && event.key === "Tab") {
531
+ if (event.shiftKey) {
532
+ // TODO shift+tab
533
+ } else {
534
+ if (range.toString() === "") {
535
+ range.insertNode(document.createTextNode(vditor.options.tab));
536
+ range.collapse(false);
537
+ } else {
538
+ range.extractContents();
539
+ range.insertNode(document.createTextNode(vditor.options.tab));
540
+ range.collapse(false);
541
+ }
542
+ }
543
+ setSelectionFocus(range);
544
+ execAfterRender(vditor);
545
+ event.preventDefault();
546
+ return true;
542
547
  }
543
- setSelectionFocus(range);
544
- execAfterRender(vditor);
545
- event.preventDefault();
546
- return true;
547
- }
548
548
  };
549
549
 
550
550
  export const fixMarkdown = (event: KeyboardEvent, vditor: IVditor, pElement: HTMLElement | false, range: Range) => {
551
- if (!pElement) {
552
- return;
553
- }
554
- if (!isCtrl(event) && !event.altKey && event.key === "Enter") {
555
- const pText = String.raw`${pElement.textContent}`.replace(/\\\|/g, "").trim();
556
- const pTextList = pText.split("|");
557
- if (pText.startsWith("|") && pText.endsWith("|") && pTextList.length > 3) {
558
- // table 自动完成
559
- let tableHeaderMD = pTextList.map(() => "---").join("|");
560
- tableHeaderMD =
561
- pElement.textContent + "\n" + tableHeaderMD.substring(3, tableHeaderMD.length - 3) + "\n|<wbr>";
562
- pElement.outerHTML = vditor.lute.SpinVditorDOM(tableHeaderMD);
563
- setRangeByWbr(vditor[vditor.currentMode].element, range);
564
- execAfterRender(vditor);
565
- scrollCenter(vditor);
566
- event.preventDefault();
567
- return true;
551
+ if (!pElement) {
552
+ return;
568
553
  }
554
+ if (!isCtrl(event) && !event.altKey && event.key === "Enter") {
555
+ const pText = String.raw`${pElement.textContent}`.replace(/\\\|/g, "").trim();
556
+ const pTextList = pText.split("|");
557
+ if (pText.startsWith("|") && pText.endsWith("|") && pTextList.length > 3) {
558
+ // table 自动完成
559
+ let tableHeaderMD = pTextList.map(() => "---").join("|");
560
+ tableHeaderMD =
561
+ pElement.textContent + "\n" + tableHeaderMD.substring(3, tableHeaderMD.length - 3) + "\n|<wbr>";
562
+ pElement.outerHTML = vditor.lute.SpinVditorDOM(tableHeaderMD);
563
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
564
+ execAfterRender(vditor);
565
+ scrollCenter(vditor);
566
+ event.preventDefault();
567
+ return true;
568
+ }
569
569
 
570
- // hr 渲染
571
- if (isHrMD(pElement.innerHTML) && pElement.previousElementSibling) {
572
- // 软换行后 hr 前有内容
573
- let pInnerHTML = "";
574
- const innerHTMLList = pElement.innerHTML.trimRight().split("\n");
575
- if (innerHTMLList.length > 1) {
576
- innerHTMLList.pop();
577
- pInnerHTML = `<p data-block="0">${innerHTMLList.join("\n")}</p>`;
578
- }
579
-
580
- pElement.insertAdjacentHTML("afterend",
581
- `${pInnerHTML}<hr data-block="0"><p data-block="0"><wbr>\n</p>`);
582
- pElement.remove();
583
- setRangeByWbr(vditor[vditor.currentMode].element, range);
584
- execAfterRender(vditor);
585
- scrollCenter(vditor);
586
- event.preventDefault();
587
- return true;
588
- }
570
+ // hr 渲染
571
+ if (isHrMD(pElement.innerHTML) && pElement.previousElementSibling) {
572
+ // 软换行后 hr 前有内容
573
+ let pInnerHTML = "";
574
+ const innerHTMLList = pElement.innerHTML.trimRight().split("\n");
575
+ if (innerHTMLList.length > 1) {
576
+ innerHTMLList.pop();
577
+ pInnerHTML = `<p data-block="0">${innerHTMLList.join("\n")}</p>`;
578
+ }
589
579
 
590
- if (isHeadingMD(pElement.innerHTML)) {
591
- // heading 渲染
592
- if (vditor.currentMode === "wysiwyg") {
593
- pElement.outerHTML = vditor.lute.SpinVditorDOM(pElement.innerHTML + '<p data-block="0"><wbr>\n</p>');
594
- } else {
595
- pElement.outerHTML = vditor.lute.SpinVditorIRDOM(pElement.innerHTML + '<p data-block="0"><wbr>\n</p>');
596
- }
597
- setRangeByWbr(vditor[vditor.currentMode].element, range);
598
- execAfterRender(vditor);
599
- scrollCenter(vditor);
600
- event.preventDefault();
601
- return true;
580
+ pElement.insertAdjacentHTML("afterend",
581
+ `${pInnerHTML}<hr data-block="0"><p data-block="0"><wbr>\n</p>`);
582
+ pElement.remove();
583
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
584
+ execAfterRender(vditor);
585
+ scrollCenter(vditor);
586
+ event.preventDefault();
587
+ return true;
588
+ }
589
+
590
+ if (isHeadingMD(pElement.innerHTML)) {
591
+ // heading 渲染
592
+ if (vditor.currentMode === "wysiwyg") {
593
+ pElement.outerHTML = vditor.lute.SpinVditorDOM(pElement.innerHTML + '<p data-block="0"><wbr>\n</p>');
594
+ } else {
595
+ pElement.outerHTML = vditor.lute.SpinVditorIRDOM(pElement.innerHTML + '<p data-block="0"><wbr>\n</p>');
596
+ }
597
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
598
+ execAfterRender(vditor);
599
+ scrollCenter(vditor);
600
+ event.preventDefault();
601
+ return true;
602
+ }
602
603
  }
603
- }
604
-
605
- // 软换行会被切割 https://github.com/Vanessa219/vditor/issues/220
606
- if (range.collapsed && pElement.previousElementSibling && event.key === "Backspace" &&
607
- !isCtrl(event) && !event.altKey && !event.shiftKey &&
608
- pElement.textContent.trimRight().split("\n").length > 1 &&
609
- getSelectPosition(pElement, vditor[vditor.currentMode].element, range).start === 0) {
610
- const lastElement = getLastNode(pElement.previousElementSibling) as HTMLElement;
611
- if (!lastElement.textContent.endsWith("\n")) {
612
- lastElement.textContent = lastElement.textContent + "\n";
604
+
605
+ // 软换行会被切割 https://github.com/Vanessa219/vditor/issues/220
606
+ if (range.collapsed && pElement.previousElementSibling && event.key === "Backspace" &&
607
+ !isCtrl(event) && !event.altKey && !event.shiftKey &&
608
+ pElement.textContent.trimRight().split("\n").length > 1 &&
609
+ getSelectPosition(pElement, vditor[vditor.currentMode].element, range).start === 0) {
610
+ const lastElement = getLastNode(pElement.previousElementSibling) as HTMLElement;
611
+ if (!lastElement.textContent.endsWith("\n")) {
612
+ lastElement.textContent = lastElement.textContent + "\n";
613
+ }
614
+ lastElement.parentElement.insertAdjacentHTML("beforeend", `<wbr>${pElement.innerHTML}`);
615
+ pElement.remove();
616
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
617
+ return false;
613
618
  }
614
- lastElement.parentElement.insertAdjacentHTML("beforeend", `<wbr>${pElement.innerHTML}`);
615
- pElement.remove();
616
- setRangeByWbr(vditor[vditor.currentMode].element, range);
617
619
  return false;
618
- }
619
- return false;
620
620
  };
621
621
 
622
622
  export const insertRow = (vditor: IVditor, range: Range, cellElement: HTMLElement) => {
623
- let rowHTML = "";
624
- for (let m = 0; m < cellElement.parentElement.childElementCount; m++) {
625
- rowHTML += `<td align="${cellElement.parentElement.children[m].getAttribute("align")}"> </td>`;
626
- }
627
- if (cellElement.tagName === "TH") {
628
- cellElement.parentElement.parentElement.insertAdjacentHTML("afterend",
629
- `<tbody><tr>${rowHTML}</tr></tbody>`);
630
- } else {
631
- cellElement.parentElement.insertAdjacentHTML("afterend", `<tr>${rowHTML}</tr>`);
632
- }
633
- execAfterRender(vditor);
623
+ let rowHTML = "";
624
+ for (let m = 0; m < cellElement.parentElement.childElementCount; m++) {
625
+ rowHTML += `<td align="${cellElement.parentElement.children[m].getAttribute("align")}"> </td>`;
626
+ }
627
+ if (cellElement.tagName === "TH") {
628
+ cellElement.parentElement.parentElement.insertAdjacentHTML("afterend",
629
+ `<tbody><tr>${rowHTML}</tr></tbody>`);
630
+ } else {
631
+ cellElement.parentElement.insertAdjacentHTML("afterend", `<tr>${rowHTML}</tr>`);
632
+ }
633
+ execAfterRender(vditor);
634
634
  };
635
635
 
636
636
  export const insertRowAbove = (vditor: IVditor, range: Range, cellElement: HTMLElement) => {
637
- let rowHTML = "";
638
- for (let m = 0; m < cellElement.parentElement.childElementCount; m++) {
637
+ let rowHTML = "";
638
+ for (let m = 0; m < cellElement.parentElement.childElementCount; m++) {
639
+ if (cellElement.tagName === "TH") {
640
+ rowHTML += `<th align="${cellElement.parentElement.children[m].getAttribute("align")}"> </th>`;
641
+ } else {
642
+ rowHTML += `<td align="${cellElement.parentElement.children[m].getAttribute("align")}"> </td>`;
643
+ }
644
+ }
639
645
  if (cellElement.tagName === "TH") {
640
- rowHTML += `<th align="${cellElement.parentElement.children[m].getAttribute("align")}"> </th>`;
646
+ cellElement.parentElement.parentElement.insertAdjacentHTML("beforebegin", `<thead><tr>${rowHTML}</tr></thead>`);
647
+
648
+ range.insertNode(document.createElement("wbr"));
649
+ const theadHTML = cellElement.parentElement.innerHTML.replace(/<th>/g, "<td>").replace(/<\/th>/g, "</td>");
650
+ cellElement.parentElement.parentElement.nextElementSibling.insertAdjacentHTML("afterbegin", theadHTML);
651
+
652
+ cellElement.parentElement.parentElement.remove();
653
+ setRangeByWbr(vditor.ir.element, range);
641
654
  } else {
642
- rowHTML += `<td align="${cellElement.parentElement.children[m].getAttribute("align")}"> </td>`;
655
+ cellElement.parentElement.insertAdjacentHTML("beforebegin", `<tr>${rowHTML}</tr>`);
643
656
  }
644
- }
645
- if (cellElement.tagName === "TH") {
646
- cellElement.parentElement.parentElement.insertAdjacentHTML("beforebegin", `<thead><tr>${rowHTML}</tr></thead>`);
647
-
648
- range.insertNode(document.createElement("wbr"));
649
- const theadHTML = cellElement.parentElement.innerHTML.replace(/<th>/g, "<td>").replace(/<\/th>/g, "</td>");
650
- cellElement.parentElement.parentElement.nextElementSibling.insertAdjacentHTML("afterbegin", theadHTML);
651
-
652
- cellElement.parentElement.parentElement.remove();
653
- setRangeByWbr(vditor.ir.element, range);
654
- } else {
655
- cellElement.parentElement.insertAdjacentHTML("beforebegin", `<tr>${rowHTML}</tr>`);
656
- }
657
- execAfterRender(vditor);
657
+ execAfterRender(vditor);
658
658
  };
659
659
 
660
660
  export const insertColumn =
661
- (vditor: IVditor, tableElement: HTMLTableElement, cellElement: HTMLElement, type: InsertPosition = "afterend") => {
662
- let index = 0;
663
- let previousElement = cellElement.previousElementSibling;
664
- while (previousElement) {
665
- index++;
666
- previousElement = previousElement.previousElementSibling;
667
- }
668
- for (let i = 0; i < tableElement.rows.length; i++) {
669
- if (i === 0) {
670
- tableElement.rows[i].cells[index].insertAdjacentHTML(type, "<th> </th>");
671
- } else {
672
- tableElement.rows[i].cells[index].insertAdjacentHTML(type, "<td> </td>");
673
- }
674
- }
675
- execAfterRender(vditor);
676
- };
661
+ (vditor: IVditor, tableElement: HTMLTableElement, cellElement: HTMLElement, type: InsertPosition = "afterend") => {
662
+ let index = 0;
663
+ let previousElement = cellElement.previousElementSibling;
664
+ while (previousElement) {
665
+ index++;
666
+ previousElement = previousElement.previousElementSibling;
667
+ }
668
+ for (let i = 0; i < tableElement.rows.length; i++) {
669
+ if (i === 0) {
670
+ tableElement.rows[i].cells[index].insertAdjacentHTML(type, "<th> </th>");
671
+ } else {
672
+ tableElement.rows[i].cells[index].insertAdjacentHTML(type, "<td> </td>");
673
+ }
674
+ }
675
+ execAfterRender(vditor);
676
+ };
677
677
  export const deleteRow = (vditor: IVditor, range: Range, cellElement: HTMLElement) => {
678
- if (cellElement.tagName === "TD") {
679
- const tbodyElement = cellElement.parentElement.parentElement;
680
- if (cellElement.parentElement.previousElementSibling) {
681
- range.selectNodeContents(cellElement.parentElement.previousElementSibling.lastElementChild);
682
- } else {
683
- range.selectNodeContents(tbodyElement.previousElementSibling.lastElementChild.lastElementChild);
684
- }
678
+ if (cellElement.tagName === "TD") {
679
+ const tbodyElement = cellElement.parentElement.parentElement;
680
+ if (cellElement.parentElement.previousElementSibling) {
681
+ range.selectNodeContents(cellElement.parentElement.previousElementSibling.lastElementChild);
682
+ } else {
683
+ range.selectNodeContents(tbodyElement.previousElementSibling.lastElementChild.lastElementChild);
684
+ }
685
685
 
686
- if (tbodyElement.childElementCount === 1) {
687
- tbodyElement.remove();
688
- } else {
689
- cellElement.parentElement.remove();
690
- }
686
+ if (tbodyElement.childElementCount === 1) {
687
+ tbodyElement.remove();
688
+ } else {
689
+ cellElement.parentElement.remove();
690
+ }
691
691
 
692
- range.collapse(false);
693
- setSelectionFocus(range);
694
- execAfterRender(vditor);
695
- }
692
+ range.collapse(false);
693
+ setSelectionFocus(range);
694
+ execAfterRender(vditor);
695
+ }
696
696
  };
697
697
 
698
698
  export const deleteColumn =
699
- (vditor: IVditor, range: Range, tableElement: HTMLTableElement, cellElement: HTMLElement) => {
700
- let index = 0;
701
- let previousElement = cellElement.previousElementSibling;
702
- while (previousElement) {
703
- index++;
704
- previousElement = previousElement.previousElementSibling;
705
- }
706
- if (cellElement.previousElementSibling || cellElement.nextElementSibling) {
707
- range.selectNodeContents(cellElement.previousElementSibling || cellElement.nextElementSibling);
708
- range.collapse(true);
709
- }
710
- for (let i = 0; i < tableElement.rows.length; i++) {
711
- const cells = tableElement.rows[i].cells;
712
- if (cells.length === 1) {
713
- tableElement.remove();
714
- highlightToolbar(vditor);
715
- break;
716
- }
717
- cells[index].remove();
718
- }
719
- setSelectionFocus(range);
720
- execAfterRender(vditor);
721
- };
699
+ (vditor: IVditor, range: Range, tableElement: HTMLTableElement, cellElement: HTMLElement) => {
700
+ let index = 0;
701
+ let previousElement = cellElement.previousElementSibling;
702
+ while (previousElement) {
703
+ index++;
704
+ previousElement = previousElement.previousElementSibling;
705
+ }
706
+ if (cellElement.previousElementSibling || cellElement.nextElementSibling) {
707
+ range.selectNodeContents(cellElement.previousElementSibling || cellElement.nextElementSibling);
708
+ range.collapse(true);
709
+ }
710
+ for (let i = 0; i < tableElement.rows.length; i++) {
711
+ const cells = tableElement.rows[i].cells;
712
+ if (cells.length === 1) {
713
+ tableElement.remove();
714
+ highlightToolbar(vditor);
715
+ break;
716
+ }
717
+ cells[index].remove();
718
+ }
719
+ setSelectionFocus(range);
720
+ execAfterRender(vditor);
721
+ };
722
722
 
723
723
  export const fixTable = (vditor: IVditor, event: KeyboardEvent, range: Range) => {
724
- const startContainer = range.startContainer;
725
- const cellElement = hasClosestByMatchTag(startContainer, "TD") ||
726
- hasClosestByMatchTag(startContainer, "TH");
727
- if (cellElement) {
728
- // 换行或软换行:在 cell 中添加 br
729
- if (!isCtrl(event) && !event.altKey && event.key === "Enter") {
730
- if (!cellElement.lastElementChild ||
731
- (cellElement.lastElementChild && (!cellElement.lastElementChild.isSameNode(cellElement.lastChild) ||
732
- cellElement.lastElementChild.tagName !== "BR"))) {
733
- cellElement.insertAdjacentHTML("beforeend", "<br>");
734
- }
735
- const brElement = document.createElement("br");
736
- range.insertNode(brElement);
737
- range.setStartAfter(brElement);
738
- execAfterRender(vditor);
739
- scrollCenter(vditor);
740
- event.preventDefault();
741
- return true;
742
- }
724
+ const startContainer = range.startContainer;
725
+ const cellElement = hasClosestByMatchTag(startContainer, "TD") ||
726
+ hasClosestByMatchTag(startContainer, "TH");
727
+ if (cellElement) {
728
+ // 换行或软换行:在 cell 中添加 br
729
+ if (!isCtrl(event) && !event.altKey && event.key === "Enter") {
730
+ if (!cellElement.lastElementChild ||
731
+ (cellElement.lastElementChild && (!cellElement.lastElementChild.isSameNode(cellElement.lastChild) ||
732
+ cellElement.lastElementChild.tagName !== "BR"))) {
733
+ cellElement.insertAdjacentHTML("beforeend", "<br>");
734
+ }
735
+ const brElement = document.createElement("br");
736
+ range.insertNode(brElement);
737
+ range.setStartAfter(brElement);
738
+ execAfterRender(vditor);
739
+ scrollCenter(vditor);
740
+ event.preventDefault();
741
+ return true;
742
+ }
743
743
 
744
- // tab:光标移向下一个 cell
745
- if (event.key === "Tab") {
746
- if (event.shiftKey) {
747
- // shift + tab 光标移动到前一个 cell
748
- goPreviousCell(cellElement, range);
749
- event.preventDefault();
750
- return true;
751
- }
752
-
753
- let nextElement = cellElement.nextElementSibling;
754
- if (!nextElement) {
755
- if (cellElement.parentElement.nextElementSibling) {
756
- nextElement = cellElement.parentElement.nextElementSibling.firstElementChild;
757
- } else if (cellElement.parentElement.parentElement.tagName === "THEAD" &&
758
- cellElement.parentElement.parentElement.nextElementSibling) {
759
- nextElement =
760
- cellElement.parentElement.parentElement.nextElementSibling.firstElementChild.firstElementChild;
761
- } else {
762
- nextElement = null;
744
+ // tab:光标移向下一个 cell
745
+ if (event.key === "Tab") {
746
+ if (event.shiftKey) {
747
+ // shift + tab 光标移动到前一个 cell
748
+ goPreviousCell(cellElement, range);
749
+ event.preventDefault();
750
+ return true;
751
+ }
752
+
753
+ let nextElement = cellElement.nextElementSibling;
754
+ if (!nextElement) {
755
+ if (cellElement.parentElement.nextElementSibling) {
756
+ nextElement = cellElement.parentElement.nextElementSibling.firstElementChild;
757
+ } else if (cellElement.parentElement.parentElement.tagName === "THEAD" &&
758
+ cellElement.parentElement.parentElement.nextElementSibling) {
759
+ nextElement =
760
+ cellElement.parentElement.parentElement.nextElementSibling.firstElementChild.firstElementChild;
761
+ } else {
762
+ nextElement = null;
763
+ }
764
+ }
765
+ if (nextElement) {
766
+ range.selectNodeContents(nextElement);
767
+ setSelectionFocus(range);
768
+ }
769
+ event.preventDefault();
770
+ return true;
763
771
  }
764
- }
765
- if (nextElement) {
766
- range.selectNodeContents(nextElement);
767
- setSelectionFocus(range);
768
- }
769
- event.preventDefault();
770
- return true;
771
- }
772
772
 
773
- const tableElement = cellElement.parentElement.parentElement.parentElement as HTMLTableElement;
774
- if (event.key === "ArrowUp") {
775
- event.preventDefault();
776
- if (cellElement.tagName === "TH") {
777
- if (tableElement.previousElementSibling) {
778
- range.selectNodeContents(tableElement.previousElementSibling);
779
- range.collapse(false);
780
- setSelectionFocus(range);
781
- } else {
782
- insertEmptyBlock(vditor, "beforebegin");
773
+ const tableElement = cellElement.parentElement.parentElement.parentElement as HTMLTableElement;
774
+ if (event.key === "ArrowUp") {
775
+ event.preventDefault();
776
+ if (cellElement.tagName === "TH") {
777
+ if (tableElement.previousElementSibling) {
778
+ range.selectNodeContents(tableElement.previousElementSibling);
779
+ range.collapse(false);
780
+ setSelectionFocus(range);
781
+ } else {
782
+ insertEmptyBlock(vditor, "beforebegin");
783
+ }
784
+ return true;
785
+ }
786
+
787
+ let m = 0;
788
+ const trElement = cellElement.parentElement as HTMLTableRowElement;
789
+ for (; m < trElement.cells.length; m++) {
790
+ if (trElement.cells[m].isSameNode(cellElement)) {
791
+ break;
792
+ }
793
+ }
794
+
795
+ let previousElement = trElement.previousElementSibling as HTMLTableRowElement;
796
+ if (!previousElement) {
797
+ previousElement = trElement.parentElement.previousElementSibling.firstChild as HTMLTableRowElement;
798
+ }
799
+ range.selectNodeContents(previousElement.cells[m]);
800
+ range.collapse(false);
801
+ setSelectionFocus(range);
802
+ return true;
783
803
  }
784
- return true;
785
- }
786
-
787
- let m = 0;
788
- const trElement = cellElement.parentElement as HTMLTableRowElement;
789
- for (; m < trElement.cells.length; m++) {
790
- if (trElement.cells[m].isSameNode(cellElement)) {
791
- break;
792
- }
793
- }
794
-
795
- let previousElement = trElement.previousElementSibling as HTMLTableRowElement;
796
- if (!previousElement) {
797
- previousElement = trElement.parentElement.previousElementSibling.firstChild as HTMLTableRowElement;
798
- }
799
- range.selectNodeContents(previousElement.cells[m]);
800
- range.collapse(false);
801
- setSelectionFocus(range);
802
- return true;
803
- }
804
804
 
805
- if (event.key === "ArrowDown") {
806
- event.preventDefault();
807
- const trElement = cellElement.parentElement as HTMLTableRowElement;
808
- if (!trElement.nextElementSibling && cellElement.tagName === "TD") {
809
- if (tableElement.nextElementSibling) {
810
- range.selectNodeContents(tableElement.nextElementSibling);
811
- range.collapse(true);
812
- setSelectionFocus(range);
813
- } else {
814
- insertEmptyBlock(vditor, "afterend");
805
+ if (event.key === "ArrowDown") {
806
+ event.preventDefault();
807
+ const trElement = cellElement.parentElement as HTMLTableRowElement;
808
+ if (!trElement.nextElementSibling && cellElement.tagName === "TD") {
809
+ if (tableElement.nextElementSibling) {
810
+ range.selectNodeContents(tableElement.nextElementSibling);
811
+ range.collapse(true);
812
+ setSelectionFocus(range);
813
+ } else {
814
+ insertEmptyBlock(vditor, "afterend");
815
+ }
816
+ return true;
817
+ }
818
+
819
+ let m = 0;
820
+ for (; m < trElement.cells.length; m++) {
821
+ if (trElement.cells[m].isSameNode(cellElement)) {
822
+ break;
823
+ }
824
+ }
825
+
826
+ let nextElement = trElement.nextElementSibling as HTMLTableRowElement;
827
+ if (!nextElement) {
828
+ nextElement = trElement.parentElement.nextElementSibling.firstChild as HTMLTableRowElement;
829
+ }
830
+ range.selectNodeContents(nextElement.cells[m]);
831
+ range.collapse(true);
832
+ setSelectionFocus(range);
833
+ return true;
815
834
  }
816
- return true;
817
- }
818
-
819
- let m = 0;
820
- for (; m < trElement.cells.length; m++) {
821
- if (trElement.cells[m].isSameNode(cellElement)) {
822
- break;
823
- }
824
- }
825
-
826
- let nextElement = trElement.nextElementSibling as HTMLTableRowElement;
827
- if (!nextElement) {
828
- nextElement = trElement.parentElement.nextElementSibling.firstChild as HTMLTableRowElement;
829
- }
830
- range.selectNodeContents(nextElement.cells[m]);
831
- range.collapse(true);
832
- setSelectionFocus(range);
833
- return true;
834
- }
835
835
 
836
- // focus row input, only wysiwyg
837
- if (vditor.currentMode === "wysiwyg" &&
838
- !isCtrl(event) && event.key === "Enter" && !event.shiftKey && event.altKey) {
839
- const inputElement = (vditor.wysiwyg.popover.querySelector(".vditor-input") as HTMLInputElement);
840
- inputElement.focus();
841
- inputElement.select();
842
- event.preventDefault();
843
- return true;
844
- }
836
+ // focus row input, only wysiwyg
837
+ if (vditor.currentMode === "wysiwyg" &&
838
+ !isCtrl(event) && event.key === "Enter" && !event.shiftKey && event.altKey) {
839
+ const inputElement = (vditor.wysiwyg.popover.querySelector(".vditor-input") as HTMLInputElement);
840
+ inputElement.focus();
841
+ inputElement.select();
842
+ event.preventDefault();
843
+ return true;
844
+ }
845
845
 
846
- // Backspace:光标移动到前一个 cell
847
- if (!isCtrl(event) && !event.shiftKey && !event.altKey && event.key === "Backspace"
848
- && range.startOffset === 0 && range.toString() === "") {
849
- const previousCellElement = goPreviousCell(cellElement, range, false);
850
- if (!previousCellElement && tableElement) {
851
- if (tableElement.textContent.trim() === "") {
852
- tableElement.outerHTML = `<p data-block="0"><wbr>\n</p>`;
853
- setRangeByWbr(vditor[vditor.currentMode].element, range);
854
- } else {
855
- range.setStartBefore(tableElement);
856
- range.collapse(true);
846
+ // Backspace:光标移动到前一个 cell
847
+ if (!isCtrl(event) && !event.shiftKey && !event.altKey && event.key === "Backspace"
848
+ && range.startOffset === 0 && range.toString() === "") {
849
+ const previousCellElement = goPreviousCell(cellElement, range, false);
850
+ if (!previousCellElement && tableElement) {
851
+ if (tableElement.textContent.trim() === "") {
852
+ tableElement.outerHTML = `<p data-block="0"><wbr>\n</p>`;
853
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
854
+ } else {
855
+ range.setStartBefore(tableElement);
856
+ range.collapse(true);
857
+ }
858
+ execAfterRender(vditor);
859
+ }
860
+ event.preventDefault();
861
+ return true;
862
+ }
863
+ // 上方新添加一行
864
+ if (matchHotKey("⇧⌘F", event)) {
865
+ insertRowAbove(vditor, range, cellElement);
866
+ event.preventDefault();
867
+ return true;
857
868
  }
858
- execAfterRender(vditor);
859
- }
860
- event.preventDefault();
861
- return true;
862
- }
863
- // 上方新添加一行
864
- if (matchHotKey("⇧⌘F", event)) {
865
- insertRowAbove(vditor, range, cellElement);
866
- event.preventDefault();
867
- return true;
868
- }
869
869
 
870
- // 下方新添加一行 https://github.com/Vanessa219/vditor/issues/46
871
- if (matchHotKey("⌘=", event)) {
872
- insertRow(vditor, range, cellElement);
873
- event.preventDefault();
874
- return true;
875
- }
870
+ // 下方新添加一行 https://github.com/Vanessa219/vditor/issues/46
871
+ if (matchHotKey("⌘=", event)) {
872
+ insertRow(vditor, range, cellElement);
873
+ event.preventDefault();
874
+ return true;
875
+ }
876
876
 
877
- // 左方新添加一列
878
- if (matchHotKey("⇧⌘G", event)) {
879
- insertColumn(vditor, tableElement, cellElement, "beforebegin");
880
- event.preventDefault();
881
- return true;
882
- }
877
+ // 左方新添加一列
878
+ if (matchHotKey("⇧⌘G", event)) {
879
+ insertColumn(vditor, tableElement, cellElement, "beforebegin");
880
+ event.preventDefault();
881
+ return true;
882
+ }
883
883
 
884
- // 后方新添加一列
885
- if (matchHotKey("⇧⌘=", event)) {
886
- insertColumn(vditor, tableElement, cellElement);
887
- event.preventDefault();
888
- return true;
889
- }
884
+ // 后方新添加一列
885
+ if (matchHotKey("⇧⌘=", event)) {
886
+ insertColumn(vditor, tableElement, cellElement);
887
+ event.preventDefault();
888
+ return true;
889
+ }
890
890
 
891
- // 删除当前行
892
- if (matchHotKey("⌘-", event)) {
893
- deleteRow(vditor, range, cellElement);
894
- event.preventDefault();
895
- return true;
896
- }
891
+ // 删除当前行
892
+ if (matchHotKey("⌘-", event)) {
893
+ deleteRow(vditor, range, cellElement);
894
+ event.preventDefault();
895
+ return true;
896
+ }
897
897
 
898
- // 删除当前列
899
- if (matchHotKey("⇧⌘-", event)) {
900
- deleteColumn(vditor, range, tableElement, cellElement);
901
- event.preventDefault();
902
- return true;
903
- }
898
+ // 删除当前列
899
+ if (matchHotKey("⇧⌘-", event)) {
900
+ deleteColumn(vditor, range, tableElement, cellElement);
901
+ event.preventDefault();
902
+ return true;
903
+ }
904
904
 
905
- // 剧左
906
- if (matchHotKey("⇧⌘L", event)) {
907
- if (vditor.currentMode === "ir") {
908
- setTableAlign(tableElement, "left");
909
- execAfterRender(vditor);
910
- event.preventDefault();
911
- return true;
912
- } else {
913
- const itemElement: HTMLElement = vditor.wysiwyg.popover.querySelector('[data-type="left"]');
914
- if (itemElement) {
915
- itemElement.click();
916
- event.preventDefault();
917
- return true;
918
- }
919
- }
905
+ // 剧左
906
+ if (matchHotKey("⇧⌘L", event)) {
907
+ if (vditor.currentMode === "ir") {
908
+ setTableAlign(tableElement, "left");
909
+ execAfterRender(vditor);
910
+ event.preventDefault();
911
+ return true;
912
+ } else {
913
+ const itemElement: HTMLElement = vditor.wysiwyg.popover.querySelector('[data-type="left"]');
914
+ if (itemElement) {
915
+ itemElement.click();
916
+ event.preventDefault();
917
+ return true;
918
+ }
919
+ }
920
+ }
921
+
922
+ // 剧中
923
+ if (matchHotKey("⇧⌘C", event)) {
924
+ if (vditor.currentMode === "ir") {
925
+ setTableAlign(tableElement, "center");
926
+ execAfterRender(vditor);
927
+ event.preventDefault();
928
+ return true;
929
+ } else {
930
+ const itemElement: HTMLElement = vditor.wysiwyg.popover.querySelector('[data-type="center"]');
931
+ if (itemElement) {
932
+ itemElement.click();
933
+ event.preventDefault();
934
+ return true;
935
+ }
936
+ }
937
+ }
938
+ // 剧右
939
+ if (matchHotKey("⇧⌘R", event)) {
940
+ if (vditor.currentMode === "ir") {
941
+ setTableAlign(tableElement, "right");
942
+ execAfterRender(vditor);
943
+ event.preventDefault();
944
+ return true;
945
+ } else {
946
+ const itemElement: HTMLElement = vditor.wysiwyg.popover.querySelector('[data-type="right"]');
947
+ if (itemElement) {
948
+ itemElement.click();
949
+ event.preventDefault();
950
+ return true;
951
+ }
952
+ }
953
+ }
920
954
  }
955
+ return false;
956
+ };
921
957
 
922
- // 剧中
923
- if (matchHotKey("⇧⌘C", event)) {
924
- if (vditor.currentMode === "ir") {
925
- setTableAlign(tableElement, "center");
926
- execAfterRender(vditor);
958
+ export const fixCodeBlock = (vditor: IVditor, event: KeyboardEvent, codeRenderElement: HTMLElement, range: Range) => {
959
+ // 行级代码块中 command + a,近对当前代码块进行全选
960
+ if (codeRenderElement.tagName === "PRE" && matchHotKey("⌘A", event)) {
961
+ range.selectNodeContents(codeRenderElement.firstElementChild);
927
962
  event.preventDefault();
928
963
  return true;
929
- } else {
930
- const itemElement: HTMLElement = vditor.wysiwyg.popover.querySelector('[data-type="center"]');
931
- if (itemElement) {
932
- itemElement.click();
933
- event.preventDefault();
934
- return true;
935
- }
936
- }
937
964
  }
938
- // 剧右
939
- if (matchHotKey("⇧⌘R", event)) {
940
- if (vditor.currentMode === "ir") {
941
- setTableAlign(tableElement, "right");
965
+
966
+ // tab
967
+ // TODO shift + tab, shift and 选中文字
968
+ if (vditor.options.tab && event.key === "Tab" && !event.shiftKey && range.toString() === "") {
969
+ range.insertNode(document.createTextNode(vditor.options.tab));
970
+ range.collapse(false);
942
971
  execAfterRender(vditor);
943
972
  event.preventDefault();
944
973
  return true;
945
- } else {
946
- const itemElement: HTMLElement = vditor.wysiwyg.popover.querySelector('[data-type="right"]');
947
- if (itemElement) {
948
- itemElement.click();
949
- event.preventDefault();
950
- return true;
951
- }
952
- }
953
974
  }
954
- }
955
- return false;
956
- };
957
-
958
- export const fixCodeBlock = (vditor: IVditor, event: KeyboardEvent, codeRenderElement: HTMLElement, range: Range) => {
959
- // 行级代码块中 command + a,近对当前代码块进行全选
960
- if (codeRenderElement.tagName === "PRE" && matchHotKey("⌘A", event)) {
961
- range.selectNodeContents(codeRenderElement.firstElementChild);
962
- event.preventDefault();
963
- return true;
964
- }
965
975
 
966
- // tab
967
- // TODO shift + tab, shift and 选中文字
968
- if (vditor.options.tab && event.key === "Tab" && !event.shiftKey && range.toString() === "") {
969
- range.insertNode(document.createTextNode(vditor.options.tab));
970
- range.collapse(false);
971
- execAfterRender(vditor);
972
- event.preventDefault();
973
- return true;
974
- }
975
-
976
- // Backspace: 光标位于第零个字符,仅删除代码块标签
977
- if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey) {
978
- const codePosition = getSelectPosition(codeRenderElement, vditor[vditor.currentMode].element, range);
979
- if ((codePosition.start === 0 ||
980
- (codePosition.start === 1 && codeRenderElement.innerText === "\n")) // 空代码块,光标在 \n 后
981
- && range.toString() === "") {
982
- codeRenderElement.parentElement.outerHTML =
983
- `<p data-block="0"><wbr>${codeRenderElement.firstElementChild.innerHTML}</p>`;
984
- setRangeByWbr(vditor[vditor.currentMode].element, range);
985
- execAfterRender(vditor);
986
- event.preventDefault();
987
- return true;
976
+ // Backspace: 光标位于第零个字符,仅删除代码块标签
977
+ if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey) {
978
+ const codePosition = getSelectPosition(codeRenderElement, vditor[vditor.currentMode].element, range);
979
+ if ((codePosition.start === 0 ||
980
+ (codePosition.start === 1 && codeRenderElement.innerText === "\n")) // 空代码块,光标在 \n 后
981
+ && range.toString() === "") {
982
+ codeRenderElement.parentElement.outerHTML =
983
+ `<p data-block="0"><wbr>${codeRenderElement.firstElementChild.innerHTML}</p>`;
984
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
985
+ execAfterRender(vditor);
986
+ event.preventDefault();
987
+ return true;
988
+ }
988
989
  }
989
- }
990
990
 
991
- // 换行
992
- if (!isCtrl(event) && !event.altKey && event.key === "Enter") {
993
- if (!codeRenderElement.firstElementChild.textContent.endsWith("\n")) {
994
- codeRenderElement.firstElementChild.insertAdjacentText("beforeend", "\n");
995
- }
996
- range.extractContents();
997
- range.insertNode(document.createTextNode("\n"));
998
- range.collapse(false);
999
- setSelectionFocus(range);
1000
- if (!isFirefox()) {
1001
- if (vditor.currentMode === "wysiwyg") {
1002
- input(vditor, range);
1003
- } else {
1004
- IRInput(vditor, range);
1005
- }
991
+ // 换行
992
+ if (!isCtrl(event) && !event.altKey && event.key === "Enter") {
993
+ if (!codeRenderElement.firstElementChild.textContent.endsWith("\n")) {
994
+ codeRenderElement.firstElementChild.insertAdjacentText("beforeend", "\n");
995
+ }
996
+ range.extractContents();
997
+ range.insertNode(document.createTextNode("\n"));
998
+ range.collapse(false);
999
+ setSelectionFocus(range);
1000
+ if (!isFirefox()) {
1001
+ if (vditor.currentMode === "wysiwyg") {
1002
+ input(vditor, range);
1003
+ } else {
1004
+ IRInput(vditor, range);
1005
+ }
1006
+ }
1007
+ scrollCenter(vditor);
1008
+ event.preventDefault();
1009
+ return true;
1006
1010
  }
1007
- scrollCenter(vditor);
1008
- event.preventDefault();
1009
- return true;
1010
- }
1011
- return false;
1011
+ return false;
1012
1012
  };
1013
1013
 
1014
1014
  export const fixBlockquote = (vditor: IVditor, range: Range, event: KeyboardEvent, pElement: HTMLElement | false) => {
1015
- const startContainer = range.startContainer;
1016
- const blockquoteElement = hasClosestByMatchTag(startContainer, "BLOCKQUOTE");
1017
- if (blockquoteElement && range.toString() === "") {
1018
- if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey &&
1019
- getSelectPosition(blockquoteElement, vditor[vditor.currentMode].element, range).start === 0) {
1020
- // Backspace: 光标位于引用中的第零个字符,仅删除引用标签
1021
- range.insertNode(document.createElement("wbr"));
1022
- blockquoteElement.outerHTML = blockquoteElement.innerHTML;
1023
- setRangeByWbr(vditor[vditor.currentMode].element, range);
1024
- execAfterRender(vditor);
1025
- event.preventDefault();
1026
- return true;
1027
- }
1015
+ const startContainer = range.startContainer;
1016
+ const blockquoteElement = hasClosestByMatchTag(startContainer, "BLOCKQUOTE");
1017
+ if (blockquoteElement && range.toString() === "") {
1018
+ if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey &&
1019
+ getSelectPosition(blockquoteElement, vditor[vditor.currentMode].element, range).start === 0) {
1020
+ // Backspace: 光标位于引用中的第零个字符,仅删除引用标签
1021
+ range.insertNode(document.createElement("wbr"));
1022
+ blockquoteElement.outerHTML = blockquoteElement.innerHTML;
1023
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
1024
+ execAfterRender(vditor);
1025
+ event.preventDefault();
1026
+ return true;
1027
+ }
1028
1028
 
1029
- if (pElement && event.key === "Enter" && !isCtrl(event) && !event.shiftKey && !event.altKey
1030
- && pElement.parentElement.tagName === "BLOCKQUOTE") {
1031
- // Enter: 空行回车应逐层跳出
1032
- let isEmpty = false;
1033
- if (pElement.innerHTML.replace(Constants.ZWSP, "") === "\n" ||
1034
- pElement.innerHTML.replace(Constants.ZWSP, "") === "") {
1035
- // 空 P
1036
- isEmpty = true;
1037
- pElement.remove();
1038
- } else if (pElement.innerHTML.endsWith("\n\n") &&
1039
- getSelectPosition(pElement, vditor[vditor.currentMode].element, range).start ===
1040
- pElement.textContent.length - 1) {
1041
- // 软换行
1042
- pElement.innerHTML = pElement.innerHTML.substr(0, pElement.innerHTML.length - 2);
1043
- isEmpty = true;
1044
- }
1045
- if (isEmpty) {
1046
- // 需添加零宽字符,否则的话无法记录 undo
1047
- blockquoteElement.insertAdjacentHTML("afterend", `<p data-block="0">${Constants.ZWSP}<wbr>\n</p>`);
1048
- setRangeByWbr(vditor[vditor.currentMode].element, range);
1049
- execAfterRender(vditor);
1050
- event.preventDefault();
1051
- return true;
1052
- }
1053
- }
1054
- const blockElement = hasClosestBlock(startContainer);
1055
- if (vditor.currentMode === "wysiwyg" && blockElement && matchHotKey("⇧⌘;", event)) {
1056
- // 插入 blockquote
1057
- range.insertNode(document.createElement("wbr"));
1058
- blockElement.outerHTML = `<blockquote data-block="0">${blockElement.outerHTML}</blockquote>`;
1059
- setRangeByWbr(vditor.wysiwyg.element, range);
1060
- afterRenderEvent(vditor);
1061
- event.preventDefault();
1062
- return true;
1063
- }
1029
+ if (pElement && event.key === "Enter" && !isCtrl(event) && !event.shiftKey && !event.altKey
1030
+ && pElement.parentElement.tagName === "BLOCKQUOTE") {
1031
+ // Enter: 空行回车应逐层跳出
1032
+ let isEmpty = false;
1033
+ if (pElement.innerHTML.replace(Constants.ZWSP, "") === "\n" ||
1034
+ pElement.innerHTML.replace(Constants.ZWSP, "") === "") {
1035
+ // 空 P
1036
+ isEmpty = true;
1037
+ pElement.remove();
1038
+ } else if (pElement.innerHTML.endsWith("\n\n") &&
1039
+ getSelectPosition(pElement, vditor[vditor.currentMode].element, range).start ===
1040
+ pElement.textContent.length - 1) {
1041
+ // 软换行
1042
+ pElement.innerHTML = pElement.innerHTML.substr(0, pElement.innerHTML.length - 2);
1043
+ isEmpty = true;
1044
+ }
1045
+ if (isEmpty) {
1046
+ // 需添加零宽字符,否则的话无法记录 undo
1047
+ blockquoteElement.insertAdjacentHTML("afterend", `<p data-block="0">${Constants.ZWSP}<wbr>\n</p>`);
1048
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
1049
+ execAfterRender(vditor);
1050
+ event.preventDefault();
1051
+ return true;
1052
+ }
1053
+ }
1054
+ const blockElement = hasClosestBlock(startContainer);
1055
+ if (vditor.currentMode === "wysiwyg" && blockElement && matchHotKey("⇧⌘;", event)) {
1056
+ // 插入 blockquote
1057
+ range.insertNode(document.createElement("wbr"));
1058
+ blockElement.outerHTML = `<blockquote data-block="0">${blockElement.outerHTML}</blockquote>`;
1059
+ setRangeByWbr(vditor.wysiwyg.element, range);
1060
+ afterRenderEvent(vditor);
1061
+ event.preventDefault();
1062
+ return true;
1063
+ }
1064
1064
 
1065
- if (insertAfterBlock(vditor, event, range, blockquoteElement, blockquoteElement)) {
1066
- return true;
1067
- }
1068
- if (insertBeforeBlock(vditor, event, range, blockquoteElement, blockquoteElement)) {
1069
- return true;
1065
+ if (insertAfterBlock(vditor, event, range, blockquoteElement, blockquoteElement)) {
1066
+ return true;
1067
+ }
1068
+ if (insertBeforeBlock(vditor, event, range, blockquoteElement, blockquoteElement)) {
1069
+ return true;
1070
+ }
1070
1071
  }
1071
- }
1072
- return false;
1072
+ return false;
1073
1073
  };
1074
1074
 
1075
1075
  export const fixTask = (vditor: IVditor, range: Range, event: KeyboardEvent) => {
1076
- const startContainer = range.startContainer;
1077
- const taskItemElement = hasClosestByClassName(startContainer, "vditor-task");
1078
- if (taskItemElement) {
1079
- if (matchHotKey("⇧⌘J", event)) {
1080
- // ctrl + shift: toggle checked
1081
- const inputElement = taskItemElement.firstElementChild as HTMLInputElement;
1082
- if (inputElement.checked) {
1083
- inputElement.removeAttribute("checked");
1084
- } else {
1085
- inputElement.setAttribute("checked", "checked");
1086
- }
1087
- execAfterRender(vditor);
1088
- event.preventDefault();
1089
- return true;
1090
- }
1091
-
1092
- // Backspace: 在选择框前进行删除
1093
- if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey && range.toString() === ""
1094
- && range.startOffset === 1
1095
- && ((startContainer.nodeType === 3 && startContainer.previousSibling &&
1096
- (startContainer.previousSibling as HTMLElement).tagName === "INPUT")
1097
- || startContainer.nodeType !== 3)) {
1098
- const previousElement = taskItemElement.previousElementSibling;
1099
- taskItemElement.querySelector("input").remove();
1100
- if (previousElement) {
1101
- const lastNode = getLastNode(previousElement);
1102
- lastNode.parentElement.insertAdjacentHTML("beforeend", "<wbr>" + taskItemElement.innerHTML.trim());
1103
- taskItemElement.remove();
1104
- } else {
1105
- taskItemElement.parentElement.insertAdjacentHTML("beforebegin",
1106
- `<p data-block="0"><wbr>${taskItemElement.innerHTML.trim() || "\n"}</p>`);
1107
- if (taskItemElement.nextElementSibling) {
1108
- taskItemElement.remove();
1109
- } else {
1110
- taskItemElement.parentElement.remove();
1076
+ const startContainer = range.startContainer;
1077
+ const taskItemElement = hasClosestByClassName(startContainer, "vditor-task");
1078
+ if (taskItemElement) {
1079
+ if (matchHotKey("⇧⌘J", event)) {
1080
+ // ctrl + shift: toggle checked
1081
+ const inputElement = taskItemElement.firstElementChild as HTMLInputElement;
1082
+ if (inputElement.checked) {
1083
+ inputElement.removeAttribute("checked");
1084
+ } else {
1085
+ inputElement.setAttribute("checked", "checked");
1086
+ }
1087
+ execAfterRender(vditor);
1088
+ event.preventDefault();
1089
+ return true;
1111
1090
  }
1112
- }
1113
- setRangeByWbr(vditor[vditor.currentMode].element, range);
1114
- execAfterRender(vditor);
1115
- event.preventDefault();
1116
- return true;
1117
- }
1118
1091
 
1119
- if (event.key === "Enter" && !isCtrl(event) && !event.shiftKey && !event.altKey) {
1120
- if (taskItemElement.textContent.trim() === "") {
1121
- // 当前任务列表无文字
1122
- if (hasClosestByClassName(taskItemElement.parentElement, "vditor-task")) {
1123
- // 为子元素时,需进行反向缩进
1124
- const topListElement = getTopList(startContainer);
1125
- if (topListElement) {
1126
- listOutdent(vditor, taskItemElement, range, topListElement);
1127
- }
1128
- } else {
1129
- // 仅有一级任务列表
1130
- if (taskItemElement.nextElementSibling) {
1131
- // 任务列表下方还有元素,需要使用用段落隔断
1132
- let afterHTML = "";
1133
- let beforeHTML = "";
1134
- let isAfter = false;
1135
- Array.from(taskItemElement.parentElement.children).forEach((taskItem) => {
1136
- if (taskItemElement.isSameNode(taskItem)) {
1137
- isAfter = true;
1138
- } else {
1139
- if (isAfter) {
1140
- afterHTML += taskItem.outerHTML;
1092
+ // Backspace: 在选择框前进行删除
1093
+ if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey && range.toString() === ""
1094
+ && range.startOffset === 1
1095
+ && ((startContainer.nodeType === 3 && startContainer.previousSibling &&
1096
+ (startContainer.previousSibling as HTMLElement).tagName === "INPUT")
1097
+ || startContainer.nodeType !== 3)) {
1098
+ const previousElement = taskItemElement.previousElementSibling;
1099
+ taskItemElement.querySelector("input").remove();
1100
+ if (previousElement) {
1101
+ const lastNode = getLastNode(previousElement);
1102
+ lastNode.parentElement.insertAdjacentHTML("beforeend", "<wbr>" + taskItemElement.innerHTML.trim());
1103
+ taskItemElement.remove();
1104
+ } else {
1105
+ taskItemElement.parentElement.insertAdjacentHTML("beforebegin",
1106
+ `<p data-block="0"><wbr>${taskItemElement.innerHTML.trim() || "\n"}</p>`);
1107
+ if (taskItemElement.nextElementSibling) {
1108
+ taskItemElement.remove();
1141
1109
  } else {
1142
- beforeHTML += taskItem.outerHTML;
1110
+ taskItemElement.parentElement.remove();
1143
1111
  }
1144
- }
1145
- });
1146
- const parentTagName = taskItemElement.parentElement.tagName;
1147
- const dataMarker = taskItemElement.parentElement.tagName === "OL" ? "" : ` data-marker="${taskItemElement.parentElement.getAttribute("data-marker")}"`;
1148
- let startAttribute = "";
1149
- if (beforeHTML) {
1150
- startAttribute = taskItemElement.parentElement.tagName === "UL" ? "" : ` start="1"`;
1151
- beforeHTML = `<${parentTagName} data-tight="true"${dataMarker} data-block="0">${beforeHTML}</${parentTagName}>`;
1152
1112
  }
1153
- // <p data-block="0">\n<wbr></p> => <p data-block="0"><wbr>\n</p>
1154
- // https://github.com/Vanessa219/vditor/issues/430
1155
- taskItemElement.parentElement.outerHTML = `${beforeHTML}<p data-block="0"><wbr>\n</p><${parentTagName}
1113
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
1114
+ execAfterRender(vditor);
1115
+ event.preventDefault();
1116
+ return true;
1117
+ }
1118
+
1119
+ if (event.key === "Enter" && !isCtrl(event) && !event.shiftKey && !event.altKey) {
1120
+ if (taskItemElement.textContent.trim() === "") {
1121
+ // 当前任务列表无文字
1122
+ if (hasClosestByClassName(taskItemElement.parentElement, "vditor-task")) {
1123
+ // 为子元素时,需进行反向缩进
1124
+ const topListElement = getTopList(startContainer);
1125
+ if (topListElement) {
1126
+ listOutdent(vditor, taskItemElement, range, topListElement);
1127
+ }
1128
+ } else {
1129
+ // 仅有一级任务列表
1130
+ if (taskItemElement.nextElementSibling) {
1131
+ // 任务列表下方还有元素,需要使用用段落隔断
1132
+ let afterHTML = "";
1133
+ let beforeHTML = "";
1134
+ let isAfter = false;
1135
+ Array.from(taskItemElement.parentElement.children).forEach((taskItem) => {
1136
+ if (taskItemElement.isSameNode(taskItem)) {
1137
+ isAfter = true;
1138
+ } else {
1139
+ if (isAfter) {
1140
+ afterHTML += taskItem.outerHTML;
1141
+ } else {
1142
+ beforeHTML += taskItem.outerHTML;
1143
+ }
1144
+ }
1145
+ });
1146
+ const parentTagName = taskItemElement.parentElement.tagName;
1147
+ const dataMarker = taskItemElement.parentElement.tagName === "OL" ? "" : ` data-marker="${taskItemElement.parentElement.getAttribute("data-marker")}"`;
1148
+ let startAttribute = "";
1149
+ if (beforeHTML) {
1150
+ startAttribute = taskItemElement.parentElement.tagName === "UL" ? "" : ` start="1"`;
1151
+ beforeHTML = `<${parentTagName} data-tight="true"${dataMarker} data-block="0">${beforeHTML}</${parentTagName}>`;
1152
+ }
1153
+ // <p data-block="0">\n<wbr></p> => <p data-block="0"><wbr>\n</p>
1154
+ // https://github.com/Vanessa219/vditor/issues/430
1155
+ taskItemElement.parentElement.outerHTML = `${beforeHTML}<p data-block="0"><wbr>\n</p><${parentTagName}
1156
1156
  data-tight="true"${dataMarker} data-block="0"${startAttribute}>${afterHTML}</${parentTagName}>`;
1157
- } else {
1158
- // 任务列表下方无任务列表元素
1159
- taskItemElement.parentElement.insertAdjacentHTML("afterend", `<p data-block="0"><wbr>\n</p>`);
1160
- if (taskItemElement.parentElement.querySelectorAll("li").length === 1) {
1161
- // 任务列表仅有一项时,使用 p 元素替换
1162
- taskItemElement.parentElement.remove();
1157
+ } else {
1158
+ // 任务列表下方无任务列表元素
1159
+ taskItemElement.parentElement.insertAdjacentHTML("afterend", `<p data-block="0"><wbr>\n</p>`);
1160
+ if (taskItemElement.parentElement.querySelectorAll("li").length === 1) {
1161
+ // 任务列表仅有一项时,使用 p 元素替换
1162
+ taskItemElement.parentElement.remove();
1163
+ } else {
1164
+ // 任务列表有多项时,当前任务列表位于最后一项,移除该任务列表
1165
+ taskItemElement.remove();
1166
+ }
1167
+ }
1168
+ }
1169
+ } else if (startContainer.nodeType !== 3 && range.startOffset === 0 &&
1170
+ (startContainer.firstChild as HTMLElement).tagName === "INPUT") {
1171
+ // 光标位于 input 之前
1172
+ range.setStart(startContainer.childNodes[1], 1);
1163
1173
  } else {
1164
- // 任务列表有多项时,当前任务列表位于最后一项,移除该任务列表
1165
- taskItemElement.remove();
1174
+ // 当前任务列表有文字,光标后的文字需添加到新任务列表中
1175
+ range.setEndAfter(taskItemElement.lastChild);
1176
+ taskItemElement.insertAdjacentHTML("afterend", `<li class="vditor-task" data-marker="${taskItemElement.getAttribute("data-marker")}"><input type="checkbox"> <wbr></li>`);
1177
+ document.querySelector("wbr").after(range.extractContents());
1166
1178
  }
1167
- }
1168
- }
1169
- } else if (startContainer.nodeType !== 3 && range.startOffset === 0 &&
1170
- (startContainer.firstChild as HTMLElement).tagName === "INPUT") {
1171
- // 光标位于 input 之前
1172
- range.setStart(startContainer.childNodes[1], 1);
1173
- } else {
1174
- // 当前任务列表有文字,光标后的文字需添加到新任务列表中
1175
- range.setEndAfter(taskItemElement.lastChild);
1176
- taskItemElement.insertAdjacentHTML("afterend", `<li class="vditor-task" data-marker="${taskItemElement.getAttribute("data-marker")}"><input type="checkbox"> <wbr></li>`);
1177
- document.querySelector("wbr").after(range.extractContents());
1178
- }
1179
- setRangeByWbr(vditor[vditor.currentMode].element, range);
1180
- execAfterRender(vditor);
1181
- scrollCenter(vditor);
1182
- event.preventDefault();
1183
- return true;
1179
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
1180
+ execAfterRender(vditor);
1181
+ scrollCenter(vditor);
1182
+ event.preventDefault();
1183
+ return true;
1184
+ }
1184
1185
  }
1185
- }
1186
- return false;
1186
+ return false;
1187
1187
  };
1188
1188
 
1189
1189
  export const fixDelete = (vditor: IVditor, range: Range, event: KeyboardEvent, pElement: HTMLElement | false) => {
1190
- if (range.startContainer.nodeType !== 3) {
1191
- // 光标位于 hr 前,hr 前有内容
1192
- const rangeElement = (range.startContainer as HTMLElement).children[range.startOffset];
1193
- if (rangeElement && rangeElement.tagName === "HR") {
1194
- range.selectNodeContents(rangeElement.previousElementSibling);
1195
- range.collapse(false);
1196
- event.preventDefault();
1197
- return true;
1190
+ if (range.startContainer.nodeType !== 3) {
1191
+ // 光标位于 hr 前,hr 前有内容
1192
+ const rangeElement = (range.startContainer as HTMLElement).children[range.startOffset];
1193
+ if (rangeElement && rangeElement.tagName === "HR") {
1194
+ range.selectNodeContents(rangeElement.previousElementSibling);
1195
+ range.collapse(false);
1196
+ event.preventDefault();
1197
+ return true;
1198
+ }
1198
1199
  }
1199
- }
1200
-
1201
- if (pElement) {
1202
- const previousElement = pElement.previousElementSibling;
1203
- if (previousElement && getSelectPosition(pElement, vditor[vditor.currentMode].element, range).start === 0 &&
1204
- ((isFirefox() && previousElement.tagName === "HR") || previousElement.tagName === "TABLE")) {
1205
- if (previousElement.tagName === "TABLE") {
1206
- // table 后删除 https://github.com/Vanessa219/vditor/issues/243
1207
- const lastCellElement = previousElement.lastElementChild.lastElementChild.lastElementChild;
1208
- lastCellElement.innerHTML =
1209
- lastCellElement.innerHTML.trimLeft() + "<wbr>" + pElement.textContent.trim();
1210
- pElement.remove();
1211
- } else {
1212
- // 光标位于 hr 后进行删除
1213
- previousElement.remove();
1214
- }
1215
- setRangeByWbr(vditor[vditor.currentMode].element, range);
1216
- execAfterRender(vditor);
1217
- event.preventDefault();
1218
- return true;
1200
+
1201
+ if (pElement) {
1202
+ const previousElement = pElement.previousElementSibling;
1203
+ if (previousElement && getSelectPosition(pElement, vditor[vditor.currentMode].element, range).start === 0 &&
1204
+ ((isFirefox() && previousElement.tagName === "HR") || previousElement.tagName === "TABLE")) {
1205
+ if (previousElement.tagName === "TABLE") {
1206
+ // table 后删除 https://github.com/Vanessa219/vditor/issues/243
1207
+ const lastCellElement = previousElement.lastElementChild.lastElementChild.lastElementChild;
1208
+ lastCellElement.innerHTML =
1209
+ lastCellElement.innerHTML.trimLeft() + "<wbr>" + pElement.textContent.trim();
1210
+ pElement.remove();
1211
+ } else {
1212
+ // 光标位于 hr 后进行删除
1213
+ previousElement.remove();
1214
+ }
1215
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
1216
+ execAfterRender(vditor);
1217
+ event.preventDefault();
1218
+ return true;
1219
+ }
1219
1220
  }
1220
- }
1221
- return false;
1221
+ return false;
1222
1222
  };
1223
1223
 
1224
1224
  export const fixHR = (range: Range) => {
1225
- if (isFirefox() && range.startContainer.nodeType !== 3 &&
1226
- (range.startContainer as HTMLElement).tagName === "HR") {
1227
- range.setStartBefore(range.startContainer);
1228
- }
1225
+ if (isFirefox() && range.startContainer.nodeType !== 3 &&
1226
+ (range.startContainer as HTMLElement).tagName === "HR") {
1227
+ range.setStartBefore(range.startContainer);
1228
+ }
1229
1229
  };
1230
1230
 
1231
1231
  // firefox https://github.com/Vanessa219/vditor/issues/407
1232
1232
  export const fixFirefoxArrowUpTable = (event: KeyboardEvent, blockElement: false | HTMLElement, range: Range) => {
1233
- if (!isFirefox()) {
1233
+ if (!isFirefox()) {
1234
+ return false;
1235
+ }
1236
+ if (event.key === "ArrowUp" && blockElement && blockElement.previousElementSibling?.tagName === "TABLE") {
1237
+ const tableElement = blockElement.previousElementSibling as HTMLTableElement;
1238
+ range.selectNodeContents(tableElement.rows[tableElement.rows.length - 1].lastElementChild);
1239
+ range.collapse(false);
1240
+ event.preventDefault();
1241
+ return true;
1242
+ }
1243
+ if (event.key === "ArrowDown" && blockElement && blockElement.nextElementSibling?.tagName === "TABLE") {
1244
+ range.selectNodeContents((blockElement.nextElementSibling as HTMLTableElement).rows[0].cells[0]);
1245
+ range.collapse(true);
1246
+ event.preventDefault();
1247
+ return true;
1248
+ }
1234
1249
  return false;
1235
- }
1236
- if (event.key === "ArrowUp" && blockElement && blockElement.previousElementSibling?.tagName === "TABLE") {
1237
- const tableElement = blockElement.previousElementSibling as HTMLTableElement;
1238
- range.selectNodeContents(tableElement.rows[tableElement.rows.length - 1].lastElementChild);
1239
- range.collapse(false);
1240
- event.preventDefault();
1241
- return true;
1242
- }
1243
- if (event.key === "ArrowDown" && blockElement && blockElement.nextElementSibling?.tagName === "TABLE") {
1244
- range.selectNodeContents((blockElement.nextElementSibling as HTMLTableElement).rows[0].cells[0]);
1245
- range.collapse(true);
1246
- event.preventDefault();
1247
- return true;
1248
- }
1249
- return false;
1250
1250
  };
1251
1251
 
1252
1252
  export const paste = async (vditor: IVditor, event: (ClipboardEvent | DragEvent) & { target: HTMLElement }, callback: {
1253
- pasteCode(code: string): void,
1253
+ pasteCode(code: string): void,
1254
1254
  }) => {
1255
- if (vditor[vditor.currentMode].element.getAttribute("contenteditable") !== "true") {
1256
- return;
1257
- }
1258
- event.stopPropagation();
1259
- event.preventDefault();
1260
- let textHTML;
1261
- let textPlain;
1262
- let files;
1263
- if ("clipboardData" in event) {
1264
- textHTML = event.clipboardData.getData("text/html");
1265
- textPlain = event.clipboardData.getData("text/plain");
1266
- files = event.clipboardData.files;
1267
- } else {
1268
- textHTML = event.dataTransfer.getData("text/html");
1269
- textPlain = event.dataTransfer.getData("text/plain");
1270
- if (event.dataTransfer.types.includes("Files")) {
1271
- files = event.dataTransfer.items;
1255
+ if (vditor[vditor.currentMode].element.getAttribute("contenteditable") !== "true") {
1256
+ return;
1272
1257
  }
1273
- }
1274
- const renderers: {
1275
- HTML2VditorDOM?: ILuteRender,
1276
- HTML2VditorIRDOM?: ILuteRender,
1277
- Md2VditorDOM?: ILuteRender,
1278
- Md2VditorIRDOM?: ILuteRender,
1279
- Md2VditorSVDOM?: ILuteRender,
1280
- } = {};
1281
- const renderLinkDest: ILuteRenderCallback = (node, entering) => {
1282
- if (!entering) {
1283
- return ["", Lute.WalkContinue];
1258
+ event.stopPropagation();
1259
+ event.preventDefault();
1260
+ let textHTML;
1261
+ let textPlain;
1262
+ let files;
1263
+
1264
+ if ("clipboardData" in event) {
1265
+ textHTML = event.clipboardData.getData("text/html");
1266
+ textPlain = event.clipboardData.getData("text/plain");
1267
+ files = event.clipboardData.files;
1268
+ } else {
1269
+ textHTML = event.dataTransfer.getData("text/html");
1270
+ textPlain = event.dataTransfer.getData("text/plain");
1271
+ if (event.dataTransfer.types.includes("Files")) {
1272
+ files = event.dataTransfer.items;
1273
+ }
1284
1274
  }
1275
+ const renderers: {
1276
+ HTML2VditorDOM?: ILuteRender,
1277
+ HTML2VditorIRDOM?: ILuteRender,
1278
+ Md2VditorDOM?: ILuteRender,
1279
+ Md2VditorIRDOM?: ILuteRender,
1280
+ Md2VditorSVDOM?: ILuteRender,
1281
+ } = {};
1282
+ const renderLinkDest: ILuteRenderCallback = (node, entering) => {
1283
+ if (!entering) {
1284
+ return ["", Lute.WalkContinue];
1285
+ }
1285
1286
 
1286
- const src = node.TokensStr();
1287
- if (node.__internal_object__.Parent.Type === 34 && src && src.indexOf("file://") === -1 &&
1288
- vditor.options.upload.linkToImgUrl) {
1289
- const xhr = new XMLHttpRequest();
1290
- xhr.open("POST", vditor.options.upload.linkToImgUrl);
1291
- if (vditor.options.upload.token) {
1292
- xhr.setRequestHeader("X-Upload-Token", vditor.options.upload.token);
1293
- }
1294
- if (vditor.options.upload.withCredentials) {
1295
- xhr.withCredentials = true;
1296
- }
1297
- setHeaders(vditor, xhr);
1298
- xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
1299
- xhr.onreadystatechange = () => {
1300
- if (xhr.readyState === XMLHttpRequest.DONE) {
1301
- if (xhr.status === 200) {
1302
- let responseText = xhr.responseText;
1303
- if (vditor.options.upload.linkToImgFormat) {
1304
- responseText = vditor.options.upload.linkToImgFormat(xhr.responseText);
1287
+ const src = node.TokensStr();
1288
+ if (node.__internal_object__.Parent.Type === 34 && src && src.indexOf("file://") === -1 &&
1289
+ vditor.options.upload.linkToImgUrl) {
1290
+ const xhr = new XMLHttpRequest();
1291
+ xhr.open("POST", vditor.options.upload.linkToImgUrl);
1292
+ if (vditor.options.upload.token) {
1293
+ xhr.setRequestHeader("X-Upload-Token", vditor.options.upload.token);
1305
1294
  }
1306
- const responseJSON = JSON.parse(responseText);
1307
- if (responseJSON.code !== 0) {
1308
- vditor.tip.show(responseJSON.msg);
1309
- return;
1295
+ if (vditor.options.upload.withCredentials) {
1296
+ xhr.withCredentials = true;
1310
1297
  }
1311
- const original = responseJSON.data.originalURL;
1312
- if (vditor.currentMode === "sv") {
1313
- vditor.sv.element.querySelectorAll(".vditor-sv__marker--link")
1314
- .forEach((item: HTMLElement) => {
1315
- if (item.textContent === original) {
1316
- item.textContent = responseJSON.data.url;
1317
- }
1318
- });
1319
- } else {
1320
- const imgElement: HTMLImageElement =
1321
- vditor[vditor.currentMode].element.querySelector(`img[src="${original}"]`);
1322
- imgElement.src = responseJSON.data.url;
1323
- if (vditor.currentMode === "ir") {
1324
- imgElement.previousElementSibling.previousElementSibling.innerHTML =
1325
- responseJSON.data.url;
1326
- }
1298
+ setHeaders(vditor, xhr);
1299
+ xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
1300
+ xhr.onreadystatechange = () => {
1301
+ if (xhr.readyState === XMLHttpRequest.DONE) {
1302
+ if (xhr.status === 200) {
1303
+ let responseText = xhr.responseText;
1304
+ if (vditor.options.upload.linkToImgFormat) {
1305
+ responseText = vditor.options.upload.linkToImgFormat(xhr.responseText);
1306
+ }
1307
+ const responseJSON = JSON.parse(responseText);
1308
+ if (responseJSON.code !== 0) {
1309
+ vditor.tip.show(responseJSON.msg);
1310
+ return;
1311
+ }
1312
+ const original = responseJSON.data.originalURL;
1313
+ if (vditor.currentMode === "sv") {
1314
+ vditor.sv.element.querySelectorAll(".vditor-sv__marker--link")
1315
+ .forEach((item: HTMLElement) => {
1316
+ if (item.textContent === original) {
1317
+ item.textContent = responseJSON.data.url;
1318
+ }
1319
+ });
1320
+ } else {
1321
+ const imgElement: HTMLImageElement =
1322
+ vditor[vditor.currentMode].element.querySelector(`img[src="${original}"]`);
1323
+ imgElement.src = responseJSON.data.url;
1324
+ if (vditor.currentMode === "ir") {
1325
+ imgElement.previousElementSibling.previousElementSibling.innerHTML =
1326
+ responseJSON.data.url;
1327
+ }
1328
+ }
1329
+ execAfterRender(vditor);
1330
+ } else {
1331
+ vditor.tip.show(xhr.responseText);
1332
+ }
1333
+ if (vditor.options.upload.linkToImgCallback) {
1334
+ vditor.options.upload.linkToImgCallback(xhr.responseText);
1335
+ }
1336
+ }
1337
+ };
1338
+ xhr.send(JSON.stringify({url: src}));
1339
+ }
1340
+ if (vditor.currentMode === "ir") {
1341
+ return [`<span class="vditor-ir__marker vditor-ir__marker--link">${Lute.EscapeHTMLStr(src)}</span>`, Lute.WalkContinue];
1342
+ } else if (vditor.currentMode === "wysiwyg") {
1343
+ return ["", Lute.WalkContinue];
1344
+ } else {
1345
+ return [`<span class="vditor-sv__marker--link">${Lute.EscapeHTMLStr(src)}</span>`, Lute.WalkContinue];
1346
+ }
1347
+ };
1348
+
1349
+ // 浏览器地址栏拷贝处理
1350
+ if (textHTML.replace(/&amp;/g, "&").replace(/<(|\/)(html|body|meta)[^>]*?>/ig, "").trim() ===
1351
+ `<a href="${textPlain}">${textPlain}</a>` ||
1352
+ textHTML.replace(/&amp;/g, "&").replace(/<(|\/)(html|body|meta)[^>]*?>/ig, "").trim() ===
1353
+ `<!--StartFragment--><a href="${textPlain}">${textPlain}</a><!--EndFragment-->`) {
1354
+ textHTML = "";
1355
+ }
1356
+
1357
+ // process word
1358
+ const doc = new DOMParser().parseFromString(textHTML, "text/html");
1359
+ if (doc.body) {
1360
+ textHTML = doc.body.innerHTML;
1361
+ }
1362
+ textHTML = Lute.Sanitize(textHTML);
1363
+ vditor.wysiwyg.getComments(vditor);
1364
+
1365
+ // process code
1366
+ const height = vditor[vditor.currentMode].element.scrollHeight;
1367
+ const code = processPasteCode(textHTML, textPlain, vditor.currentMode);
1368
+ const codeElement = vditor.currentMode === "sv" ?
1369
+ hasClosestByAttribute(event.target, "data-type", "code-block") :
1370
+ hasClosestByMatchTag(event.target, "CODE");
1371
+ if (codeElement) {
1372
+ // 粘贴在代码位置
1373
+ if (vditor.currentMode === "sv") {
1374
+ document.execCommand("insertHTML", false, textPlain.replace(/&/g, "&amp;").replace(/</g, "&lt;"));
1375
+ } else {
1376
+ const position = getSelectPosition(event.target, vditor[vditor.currentMode].element);
1377
+ if (codeElement.parentElement.tagName !== "PRE") {
1378
+ // https://github.com/Vanessa219/vditor/issues/463
1379
+ textPlain += Constants.ZWSP;
1327
1380
  }
1328
- execAfterRender(vditor);
1329
- } else {
1330
- vditor.tip.show(xhr.responseText);
1331
- }
1332
- if (vditor.options.upload.linkToImgCallback) {
1333
- vditor.options.upload.linkToImgCallback(xhr.responseText);
1334
- }
1335
- }
1336
- };
1337
- xhr.send(JSON.stringify({url: src}));
1338
- }
1339
- if (vditor.currentMode === "ir") {
1340
- return [`<span class="vditor-ir__marker vditor-ir__marker--link">${src}</span>`, Lute.WalkContinue];
1341
- } else if (vditor.currentMode === "wysiwyg") {
1342
- return ["", Lute.WalkContinue];
1343
- } else {
1344
- return [`<span class="vditor-sv__marker--link">${src}</span>`, Lute.WalkContinue];
1345
- }
1346
- };
1347
-
1348
- // 浏览器地址栏拷贝处理
1349
- if (textHTML.replace(/&amp;/g, "&").replace(/<(|\/)(html|body|meta)[^>]*?>/ig, "").trim() ===
1350
- `<a href="${textPlain}">${textPlain}</a>` ||
1351
- textHTML.replace(/&amp;/g, "&").replace(/<(|\/)(html|body|meta)[^>]*?>/ig, "").trim() ===
1352
- `<!--StartFragment--><a href="${textPlain}">${textPlain}</a><!--EndFragment-->`) {
1353
- textHTML = "";
1354
- }
1355
-
1356
- // process word
1357
- const doc = new DOMParser().parseFromString(textHTML, "text/html");
1358
- if (doc.body) {
1359
- textHTML = doc.body.innerHTML;
1360
- }
1361
- textHTML = Lute.Sanitize(textHTML);
1362
- vditor.wysiwyg.getComments(vditor);
1363
-
1364
- // process code
1365
- const height = vditor[vditor.currentMode].element.scrollHeight;
1366
- const code = processPasteCode(textHTML, textPlain, vditor.currentMode);
1367
- const codeElement = vditor.currentMode === "sv" ?
1368
- hasClosestByAttribute(event.target, "data-type", "code-block") :
1369
- hasClosestByMatchTag(event.target, "CODE");
1370
- if (codeElement) {
1371
- // 粘贴在代码位置
1372
- if (vditor.currentMode === "sv") {
1373
- document.execCommand("insertHTML", false, textPlain.replace(/&/g, "&amp;").replace(/</g, "&lt;"));
1381
+ codeElement.textContent = codeElement.textContent.substring(0, position.start)
1382
+ + textPlain + codeElement.textContent.substring(position.end);
1383
+ setSelectionByPosition(position.start + textPlain.length, position.start + textPlain.length,
1384
+ codeElement.parentElement);
1385
+ if (codeElement.parentElement?.nextElementSibling.classList
1386
+ .contains(`vditor-${vditor.currentMode}__preview`)) {
1387
+ codeElement.parentElement.nextElementSibling.innerHTML = codeElement.outerHTML;
1388
+ processCodeRender(codeElement.parentElement.nextElementSibling as HTMLElement, vditor);
1389
+ }
1390
+ }
1391
+ } else if (code) {
1392
+ callback.pasteCode(code);
1374
1393
  } else {
1375
- const position = getSelectPosition(event.target, vditor[vditor.currentMode].element);
1376
- if (codeElement.parentElement.tagName !== "PRE") {
1377
- // https://github.com/Vanessa219/vditor/issues/463
1378
- textPlain += Constants.ZWSP;
1379
- }
1380
- codeElement.textContent = codeElement.textContent.substring(0, position.start)
1381
- + textPlain + codeElement.textContent.substring(position.end);
1382
- setSelectionByPosition(position.start + textPlain.length, position.start + textPlain.length,
1383
- codeElement.parentElement);
1384
- if (codeElement.parentElement?.nextElementSibling.classList
1385
- .contains(`vditor-${vditor.currentMode}__preview`)) {
1386
- codeElement.parentElement.nextElementSibling.innerHTML = codeElement.outerHTML;
1387
- processCodeRender(codeElement.parentElement.nextElementSibling as HTMLElement, vditor);
1388
- }
1394
+ if (textHTML.trim() !== "") {
1395
+ const tempElement = document.createElement("div");
1396
+ tempElement.innerHTML = textHTML;
1397
+ tempElement.querySelectorAll("[style]").forEach((e) => {
1398
+ e.removeAttribute("style");
1399
+ });
1400
+ tempElement.querySelectorAll(".vditor-copy").forEach((e) => {
1401
+ e.remove();
1402
+ });
1403
+ if (vditor.currentMode === "ir") {
1404
+ renderers.HTML2VditorIRDOM = {renderLinkDest};
1405
+ vditor.lute.SetJSRenderers({renderers});
1406
+ insertHTML(vditor.lute.HTML2VditorIRDOM(tempElement.innerHTML), vditor);
1407
+ } else if (vditor.currentMode === "wysiwyg") {
1408
+ renderers.HTML2VditorDOM = {renderLinkDest};
1409
+ vditor.lute.SetJSRenderers({renderers});
1410
+ insertHTML(vditor.lute.HTML2VditorDOM(tempElement.innerHTML), vditor);
1411
+ } else {
1412
+ renderers.Md2VditorSVDOM = {renderLinkDest};
1413
+ vditor.lute.SetJSRenderers({renderers});
1414
+ processPaste(vditor, vditor.lute.HTML2Md(tempElement.innerHTML).trimRight());
1415
+ }
1416
+ vditor.outline.render(vditor);
1417
+ } else if (files.length > 0) {
1418
+ if (vditor.options.upload.url || vditor.options.upload.handler) {
1419
+ await uploadFiles(vditor, files);
1420
+ } else {
1421
+ const fileReader = new FileReader();
1422
+ let file: File;
1423
+ if ("clipboardData" in event) {
1424
+ files = event.clipboardData.files;
1425
+ file = files[0];
1426
+ } else if (event.dataTransfer.types.includes("Files")) {
1427
+ files = event.dataTransfer.items;
1428
+ file = files[0].getAsFile();
1429
+ }
1430
+ if (file && file.type.startsWith("image")) {
1431
+ fileReader.readAsDataURL(file);
1432
+ fileReader.onload = () => {
1433
+ let imgHTML = ''
1434
+ if (vditor.currentMode === "wysiwyg") {
1435
+ imgHTML += `<img alt="${file.name}" src="${fileReader.result.toString()}">\n`;
1436
+ } else {
1437
+ imgHTML += `![${file.name}](${fileReader.result.toString()})\n`;
1438
+ }
1439
+ document.execCommand("insertHTML", false, imgHTML);
1440
+ }
1441
+ }
1442
+ }
1443
+ } else if (textPlain.trim() !== "" && files.length === 0) {
1444
+ if (vditor.currentMode === "ir") {
1445
+ renderers.Md2VditorIRDOM = {renderLinkDest};
1446
+ vditor.lute.SetJSRenderers({renderers});
1447
+ insertHTML(vditor.lute.Md2VditorIRDOM(textPlain), vditor);
1448
+ } else if (vditor.currentMode === "wysiwyg") {
1449
+ renderers.Md2VditorDOM = {renderLinkDest};
1450
+ vditor.lute.SetJSRenderers({renderers});
1451
+ insertHTML(vditor.lute.Md2VditorDOM(textPlain), vditor);
1452
+ } else {
1453
+ renderers.Md2VditorSVDOM = {renderLinkDest};
1454
+ vditor.lute.SetJSRenderers({renderers});
1455
+ processPaste(vditor, textPlain);
1456
+ }
1457
+ vditor.outline.render(vditor);
1458
+ }
1389
1459
  }
1390
- } else if (code) {
1391
- callback.pasteCode(code);
1392
- } else {
1393
- if (textHTML.trim() !== "") {
1394
- const tempElement = document.createElement("div");
1395
- tempElement.innerHTML = textHTML;
1396
- tempElement.querySelectorAll("[style]").forEach((e) => {
1397
- e.removeAttribute("style");
1398
- });
1399
- tempElement.querySelectorAll(".vditor-copy").forEach((e) => {
1400
- e.remove();
1401
- });
1402
- if (vditor.currentMode === "ir") {
1403
- renderers.HTML2VditorIRDOM = {renderLinkDest};
1404
- vditor.lute.SetJSRenderers({renderers});
1405
- insertHTML(vditor.lute.HTML2VditorIRDOM(tempElement.innerHTML), vditor);
1406
- } else if (vditor.currentMode === "wysiwyg") {
1407
- renderers.HTML2VditorDOM = {renderLinkDest};
1408
- vditor.lute.SetJSRenderers({renderers});
1409
- insertHTML(vditor.lute.HTML2VditorDOM(tempElement.innerHTML), vditor);
1410
- } else {
1411
- renderers.Md2VditorSVDOM = {renderLinkDest};
1412
- vditor.lute.SetJSRenderers({renderers});
1413
- processPaste(vditor, vditor.lute.HTML2Md(tempElement.innerHTML).trimRight());
1414
- }
1415
- vditor.outline.render(vditor);
1416
- } else if (files.length > 0 && (vditor.options.upload.url || vditor.options.upload.handler)) {
1417
- await uploadFiles(vditor, files);
1418
- } else if (textPlain.trim() !== "" && files.length === 0) {
1419
- if (vditor.currentMode === "ir") {
1420
- renderers.Md2VditorIRDOM = {renderLinkDest};
1421
- vditor.lute.SetJSRenderers({renderers});
1422
- insertHTML(vditor.lute.Md2VditorIRDOM(textPlain), vditor);
1423
- } else if (vditor.currentMode === "wysiwyg") {
1424
- renderers.Md2VditorDOM = {renderLinkDest};
1425
- vditor.lute.SetJSRenderers({renderers});
1426
- insertHTML(vditor.lute.Md2VditorDOM(textPlain), vditor);
1427
- } else {
1428
- renderers.Md2VditorSVDOM = {renderLinkDest};
1429
- vditor.lute.SetJSRenderers({renderers});
1430
- processPaste(vditor, textPlain);
1431
- }
1432
- vditor.outline.render(vditor);
1460
+ if (vditor.currentMode !== "sv") {
1461
+ const blockElement = hasClosestBlock(getEditorRange(vditor).startContainer);
1462
+ if (blockElement) {
1463
+ // https://github.com/Vanessa219/vditor/issues/591
1464
+ const range = getEditorRange(vditor);
1465
+ vditor[vditor.currentMode].element.querySelectorAll("wbr").forEach((wbr) => {
1466
+ wbr.remove();
1467
+ });
1468
+ range.insertNode(document.createElement("wbr"));
1469
+ if (vditor.currentMode === "wysiwyg") {
1470
+ blockElement.outerHTML = vditor.lute.SpinVditorDOM(blockElement.outerHTML);
1471
+ } else {
1472
+ blockElement.outerHTML = vditor.lute.SpinVditorIRDOM(blockElement.outerHTML);
1473
+ }
1474
+ setRangeByWbr(vditor[vditor.currentMode].element, range);
1475
+ }
1476
+ vditor[vditor.currentMode].element.querySelectorAll(`.vditor-${vditor.currentMode}__preview[data-render='2']`)
1477
+ .forEach((item: HTMLElement) => {
1478
+ processCodeRender(item, vditor);
1479
+ });
1433
1480
  }
1434
- }
1435
- if (vditor.currentMode !== "sv") {
1436
- const blockElement = hasClosestBlock(getEditorRange(vditor).startContainer);
1437
- if (blockElement) {
1438
- // https://github.com/Vanessa219/vditor/issues/591
1439
- const range = getEditorRange(vditor);
1440
- vditor[vditor.currentMode].element.querySelectorAll("wbr").forEach((wbr) => {
1441
- wbr.remove();
1442
- });
1443
- range.insertNode(document.createElement("wbr"));
1444
- if (vditor.currentMode === "wysiwyg") {
1445
- blockElement.outerHTML = vditor.lute.SpinVditorDOM(blockElement.outerHTML);
1446
- } else {
1447
- blockElement.outerHTML = vditor.lute.SpinVditorIRDOM(blockElement.outerHTML);
1448
- }
1449
- setRangeByWbr(vditor[vditor.currentMode].element, range);
1481
+ vditor.wysiwyg.triggerRemoveComment(vditor);
1482
+ execAfterRender(vditor);
1483
+ if (vditor[vditor.currentMode].element.scrollHeight - height >
1484
+ Math.min(vditor[vditor.currentMode].element.clientHeight, window.innerHeight) / 2) {
1485
+ scrollCenter(vditor);
1450
1486
  }
1451
- vditor[vditor.currentMode].element.querySelectorAll(`.vditor-${vditor.currentMode}__preview[data-render='2']`)
1452
- .forEach((item: HTMLElement) => {
1453
- processCodeRender(item, vditor);
1454
- });
1455
- }
1456
- vditor.wysiwyg.triggerRemoveComment(vditor);
1457
- execAfterRender(vditor);
1458
- if (vditor[vditor.currentMode].element.scrollHeight - height >
1459
- Math.min(vditor[vditor.currentMode].element.clientHeight, window.innerHeight) / 2) {
1460
- scrollCenter(vditor);
1461
- }
1462
1487
  };