@8btc/mditor 0.0.3 → 0.0.4

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.
@@ -3,7 +3,9 @@ import { hidePanel } from "../toolbar/setToolbar";
3
3
  import { isCtrl, isFirefox } from "../util/compatibility";
4
4
  import {
5
5
  blurEvent,
6
- copyEvent, cutEvent, dblclickEvent,
6
+ copyEvent,
7
+ cutEvent,
8
+ dblclickEvent,
7
9
  dropEvent,
8
10
  focusEvent,
9
11
  hotkeyEvent,
@@ -12,19 +14,26 @@ import {
12
14
  } from "../util/editorCommonEvent";
13
15
  import { isHeadingMD, isHrMD, paste } from "../util/fixBrowserBehavior";
14
16
  import {
15
- hasClosestBlock, hasClosestByAttribute,
16
- hasClosestByClassName, hasClosestByMatchTag,
17
+ hasClosestBlock,
18
+ hasClosestByAttribute,
19
+ hasClosestByClassName,
20
+ hasClosestByMatchTag,
17
21
  } from "../util/hasClosest";
18
22
  import { hasClosestByHeadings } from "../util/hasClosestByHeadings";
19
23
  import {
20
24
  getCursorPosition,
21
25
  getEditorRange,
22
26
  getSelectPosition,
23
- setRangeByWbr, setSelectionFocus,
24
- } from "../util/selection"
27
+ setRangeByWbr,
28
+ setSelectionFocus,
29
+ } from "../util/selection";
25
30
  import { clickToc, renderToc } from "../util/toc";
26
31
  import { afterRenderEvent } from "./afterRenderEvent";
27
- import { genImagePopover, genLinkRefPopover, highlightToolbarWYSIWYG } from "./highlightToolbarWYSIWYG";
32
+ import {
33
+ genImagePopover,
34
+ genLinkRefPopover,
35
+ highlightToolbarWYSIWYG,
36
+ } from "./highlightToolbarWYSIWYG";
28
37
  import { getRenderElementNextNode, modifyPre } from "./inlineTag";
29
38
  import { input } from "./input";
30
39
  import { showCode } from "./showCode";
@@ -60,7 +69,8 @@ class WYSIWYG {
60
69
  </div>`;
61
70
 
62
71
  this.element = divElement.firstElementChild as HTMLPreElement;
63
- this.popover = divElement.firstElementChild.nextElementSibling as HTMLDivElement;
72
+ this.popover = divElement.firstElementChild
73
+ .nextElementSibling as HTMLDivElement;
64
74
  this.selectPopover = divElement.lastElementChild as HTMLDivElement;
65
75
 
66
76
  this.bindEvent(vditor);
@@ -84,64 +94,104 @@ class WYSIWYG {
84
94
  let blockEndElement: HTMLElement;
85
95
  let removeStart = false;
86
96
  let removeEnd = false;
87
- contents.childNodes.forEach((item: HTMLElement, index: number) => {
88
- let wrap = false;
89
- if (item.nodeType === 3) {
90
- wrap = true;
91
- } else if (!item.classList.contains("vditor-comment")) {
92
- wrap = true;
93
- } else if (item.classList.contains("vditor-comment")) {
94
- item.setAttribute("data-cmtids", item.getAttribute("data-cmtids") + " " + id);
95
- }
96
- if (wrap) {
97
- if (item.nodeType !== 3 && item.getAttribute("data-block") === "0"
98
- && index === 0 && rangeClone.startOffset > 0) {
99
- item.innerHTML =
100
- `<span class="vditor-comment" data-cmtids="${id}">${item.innerHTML}</span>`;
101
- blockStartElement = item;
102
- } else if (item.nodeType !== 3 && item.getAttribute("data-block") === "0"
103
- && index === contents.childNodes.length - 1
104
- && rangeClone.endOffset < rangeClone.endContainer.textContent.length) {
105
- item.innerHTML =
106
- `<span class="vditor-comment" data-cmtids="${id}">${item.innerHTML}</span>`;
107
- blockEndElement = item;
108
- } else if (item.nodeType !== 3 && item.getAttribute("data-block") === "0") {
109
- if (index === 0) {
110
- removeStart = true;
111
- } else if (index === contents.childNodes.length - 1) {
112
- removeEnd = true;
97
+ contents.childNodes.forEach(
98
+ (item: HTMLElement, index: number) => {
99
+ let wrap = false;
100
+ if (item.nodeType === 3) {
101
+ wrap = true;
102
+ } else if (!item.classList.contains("vditor-comment")) {
103
+ wrap = true;
104
+ } else if (item.classList.contains("vditor-comment")) {
105
+ item.setAttribute(
106
+ "data-cmtids",
107
+ item.getAttribute("data-cmtids") + " " + id
108
+ );
109
+ }
110
+ if (wrap) {
111
+ if (
112
+ item.nodeType !== 3 &&
113
+ item.getAttribute("data-block") === "0" &&
114
+ index === 0 &&
115
+ rangeClone.startOffset > 0
116
+ ) {
117
+ item.innerHTML = `<span class="vditor-comment" data-cmtids="${id}">${item.innerHTML}</span>`;
118
+ blockStartElement = item;
119
+ } else if (
120
+ item.nodeType !== 3 &&
121
+ item.getAttribute("data-block") === "0" &&
122
+ index === contents.childNodes.length - 1 &&
123
+ rangeClone.endOffset <
124
+ rangeClone.endContainer.textContent.length
125
+ ) {
126
+ item.innerHTML = `<span class="vditor-comment" data-cmtids="${id}">${item.innerHTML}</span>`;
127
+ blockEndElement = item;
128
+ } else if (
129
+ item.nodeType !== 3 &&
130
+ item.getAttribute("data-block") === "0"
131
+ ) {
132
+ if (index === 0) {
133
+ removeStart = true;
134
+ } else if (
135
+ index ===
136
+ contents.childNodes.length - 1
137
+ ) {
138
+ removeEnd = true;
139
+ }
140
+ item.innerHTML = `<span class="vditor-comment" data-cmtids="${id}">${item.innerHTML}</span>`;
141
+ } else {
142
+ const commentElement =
143
+ document.createElement("span");
144
+ commentElement.classList.add("vditor-comment");
145
+ commentElement.setAttribute("data-cmtids", id);
146
+ item.parentNode.insertBefore(
147
+ commentElement,
148
+ item
149
+ );
150
+ commentElement.appendChild(item);
113
151
  }
114
- item.innerHTML =
115
- `<span class="vditor-comment" data-cmtids="${id}">${item.innerHTML}</span>`;
116
- } else {
117
- const commentElement = document.createElement("span");
118
- commentElement.classList.add("vditor-comment");
119
- commentElement.setAttribute("data-cmtids", id);
120
- item.parentNode.insertBefore(commentElement, item);
121
- commentElement.appendChild(item);
122
152
  }
123
153
  }
124
- });
154
+ );
125
155
  const startElement = hasClosestBlock(rangeClone.startContainer);
126
156
  if (startElement) {
127
157
  if (blockStartElement) {
128
- startElement.insertAdjacentHTML("beforeend", blockStartElement.innerHTML);
158
+ startElement.insertAdjacentHTML(
159
+ "beforeend",
160
+ blockStartElement.innerHTML
161
+ );
129
162
  blockStartElement.remove();
130
- } else if (startElement.textContent.trim().replace(Constants.ZWSP, "") === "" && removeStart) {
163
+ } else if (
164
+ startElement.textContent
165
+ .trim()
166
+ .replace(Constants.ZWSP, "") === "" &&
167
+ removeStart
168
+ ) {
131
169
  startElement.remove();
132
170
  }
133
171
  }
134
172
  const endElement = hasClosestBlock(rangeClone.endContainer);
135
173
  if (endElement) {
136
174
  if (blockEndElement) {
137
- endElement.insertAdjacentHTML("afterbegin", blockEndElement.innerHTML);
175
+ endElement.insertAdjacentHTML(
176
+ "afterbegin",
177
+ blockEndElement.innerHTML
178
+ );
138
179
  blockEndElement.remove();
139
- } else if (endElement.textContent.trim().replace(Constants.ZWSP, "") === "" && removeEnd) {
180
+ } else if (
181
+ endElement.textContent
182
+ .trim()
183
+ .replace(Constants.ZWSP, "") === "" &&
184
+ removeEnd
185
+ ) {
140
186
  endElement.remove();
141
187
  }
142
188
  }
143
189
  range.insertNode(contents);
144
- vditor.options.comment.add(id, range.toString(), this.getComments(vditor, true));
190
+ vditor.options.comment.add(
191
+ id,
192
+ range.toString(),
193
+ this.getComments(vditor, true)
194
+ );
145
195
  afterRenderEvent(vditor, {
146
196
  enableAddUndoStack: true,
147
197
  enableHint: false,
@@ -156,8 +206,9 @@ class WYSIWYG {
156
206
  if (vditor.currentMode === "wysiwyg" && vditor.options.comment.enable) {
157
207
  this.commentIds = [];
158
208
  this.element.querySelectorAll(".vditor-comment").forEach((item) => {
159
- this.commentIds =
160
- this.commentIds.concat(item.getAttribute("data-cmtids").split(" "));
209
+ this.commentIds = this.commentIds.concat(
210
+ item.getAttribute("data-cmtids").split(" ")
211
+ );
161
212
  });
162
213
  this.commentIds = Array.from(new Set(this.commentIds));
163
214
 
@@ -166,8 +217,11 @@ class WYSIWYG {
166
217
  this.commentIds.forEach((id) => {
167
218
  comments.push({
168
219
  id,
169
- top:
170
- (this.element.querySelector(`.vditor-comment[data-cmtids="${id}"]`) as HTMLElement).offsetTop,
220
+ top: (
221
+ this.element.querySelector(
222
+ `.vditor-comment[data-cmtids="${id}"]`
223
+ ) as HTMLElement
224
+ ).offsetTop,
171
225
  });
172
226
  });
173
227
  return comments;
@@ -182,7 +236,11 @@ class WYSIWYG {
182
236
  const s = new Set(b);
183
237
  return a.filter((x) => !s.has(x));
184
238
  };
185
- if (vditor.currentMode === "wysiwyg" && vditor.options.comment.enable && vditor.wysiwyg.commentIds.length > 0) {
239
+ if (
240
+ vditor.currentMode === "wysiwyg" &&
241
+ vditor.options.comment.enable &&
242
+ vditor.wysiwyg.commentIds.length > 0
243
+ ) {
186
244
  const oldIds = JSON.parse(JSON.stringify(this.commentIds));
187
245
  this.getComments(vditor);
188
246
  const removedIds = difference(oldIds, this.commentIds);
@@ -194,7 +252,10 @@ class WYSIWYG {
194
252
 
195
253
  public showComment() {
196
254
  const position = getCursorPosition(this.element);
197
- this.selectPopover.setAttribute("style", `left:${position.left}px;display:block;top:${Math.max(-8, position.top - 21)}px`);
255
+ this.selectPopover.setAttribute(
256
+ "style",
257
+ `left:${position.left}px;display:block;top:${Math.max(-8, position.top - 21)}px`
258
+ );
198
259
  }
199
260
 
200
261
  public hideComment() {
@@ -221,7 +282,11 @@ class WYSIWYG {
221
282
 
222
283
  const codeElement = hasClosestByMatchTag(range.startContainer, "CODE");
223
284
  const codeEndElement = hasClosestByMatchTag(range.endContainer, "CODE");
224
- if (codeElement && codeEndElement && codeEndElement.isSameNode(codeElement)) {
285
+ if (
286
+ codeElement &&
287
+ codeEndElement &&
288
+ codeEndElement.isSameNode(codeElement)
289
+ ) {
225
290
  let codeText = "";
226
291
  if (codeElement.parentElement.tagName === "PRE") {
227
292
  codeText = range.toString();
@@ -240,20 +305,33 @@ class WYSIWYG {
240
305
  if (aTitle) {
241
306
  aTitle = ` "${aTitle}"`;
242
307
  }
243
- event.clipboardData.setData("text/plain",
244
- `[${range.toString()}](${aElement.getAttribute("href")}${aTitle})`);
308
+ event.clipboardData.setData(
309
+ "text/plain",
310
+ `[${range.toString()}](${aElement.getAttribute("href")}${aTitle})`
311
+ );
245
312
  event.clipboardData.setData("text/html", "");
246
313
  return;
247
314
  }
248
315
 
249
316
  // 数学公式选区:仅复制可见文本
250
- const startPreview = hasClosestByClassName(range.startContainer, "vditor-wysiwyg__preview") as HTMLElement;
251
- const endPreview = hasClosestByClassName(range.endContainer, "vditor-wysiwyg__preview") as HTMLElement;
317
+ const startPreview = hasClosestByClassName(
318
+ range.startContainer,
319
+ "vditor-wysiwyg__preview"
320
+ ) as HTMLElement;
321
+ const endPreview = hasClosestByClassName(
322
+ range.endContainer,
323
+ "vditor-wysiwyg__preview"
324
+ ) as HTMLElement;
252
325
  const isMathPreview = (el: HTMLElement) => {
253
326
  const first = el.firstElementChild as HTMLElement | null;
254
327
  return !!first && first.classList.contains("language-math");
255
328
  };
256
- if (startPreview && endPreview && startPreview.isSameNode(endPreview) && isMathPreview(startPreview)) {
329
+ if (
330
+ startPreview &&
331
+ endPreview &&
332
+ startPreview.isSameNode(endPreview) &&
333
+ isMathPreview(startPreview)
334
+ ) {
257
335
  event.clipboardData.setData("text/plain", range.toString());
258
336
  event.clipboardData.setData("text/html", "");
259
337
  return;
@@ -262,77 +340,122 @@ class WYSIWYG {
262
340
  // 默认:转换为 Markdown 文本
263
341
  const tempElement = document.createElement("div");
264
342
  tempElement.appendChild(range.cloneContents());
265
- event.clipboardData.setData("text/plain", vditor.lute.VditorDOM2Md(tempElement.innerHTML).trim());
343
+ event.clipboardData.setData(
344
+ "text/plain",
345
+ vditor.lute.VditorDOM2Md(tempElement.innerHTML).trim()
346
+ );
266
347
  event.clipboardData.setData("text/html", "");
267
348
  }
268
349
 
269
350
  private bindEvent(vditor: IVditor) {
270
351
  this.unbindListener();
271
- window.addEventListener("scroll", this.scrollListener = () => {
272
- hidePanel(vditor, ["hint"]);
273
- if (this.popover.style.display !== "block" || this.selectPopover.style.display !== "block") {
274
- return;
275
- }
276
- const top = parseInt(this.popover.getAttribute("data-top"), 10);
277
- if (vditor.options.height !== "auto") {
278
- if (vditor.options.toolbarConfig.pin && vditor.toolbar.element.getBoundingClientRect().top === 0) {
279
- const popoverTop = Math.max(window.scrollY - vditor.element.offsetTop - 8,
280
- Math.min(top - vditor.wysiwyg.element.scrollTop, this.element.clientHeight - 21)) + "px";
281
- if (this.popover.style.display === "block") {
282
- this.popover.style.top = popoverTop;
283
- }
284
- if (this.selectPopover.style.display === "block") {
285
- this.selectPopover.style.top = popoverTop;
352
+ window.addEventListener(
353
+ "scroll",
354
+ (this.scrollListener = () => {
355
+ hidePanel(vditor, ["hint"]);
356
+ if (
357
+ this.popover.style.display !== "block" ||
358
+ this.selectPopover.style.display !== "block"
359
+ ) {
360
+ return;
361
+ }
362
+ const top = parseInt(this.popover.getAttribute("data-top"), 10);
363
+ if (vditor.options.height !== "auto") {
364
+ if (
365
+ vditor.options.toolbarConfig.pin &&
366
+ vditor.toolbar.element.getBoundingClientRect().top === 0
367
+ ) {
368
+ const popoverTop =
369
+ Math.max(
370
+ window.scrollY - vditor.element.offsetTop - 8,
371
+ Math.min(
372
+ top - vditor.wysiwyg.element.scrollTop,
373
+ this.element.clientHeight - 21
374
+ )
375
+ ) + "px";
376
+ if (this.popover.style.display === "block") {
377
+ this.popover.style.top = popoverTop;
378
+ }
379
+ if (this.selectPopover.style.display === "block") {
380
+ this.selectPopover.style.top = popoverTop;
381
+ }
286
382
  }
383
+ return;
384
+ } else if (!vditor.options.toolbarConfig.pin) {
385
+ return;
287
386
  }
288
- return;
289
- } else if (!vditor.options.toolbarConfig.pin) {
290
- return;
291
- }
292
- const popoverTop1 = Math.max(top, (window.scrollY - vditor.element.offsetTop - 8)) + "px";
293
- if (this.popover.style.display === "block") {
294
- this.popover.style.top = popoverTop1;
295
- }
296
- if (this.selectPopover.style.display === "block") {
297
- this.selectPopover.style.top = popoverTop1;
298
- }
299
- });
387
+ const popoverTop1 =
388
+ Math.max(
389
+ top,
390
+ window.scrollY - vditor.element.offsetTop - 8
391
+ ) + "px";
392
+ if (this.popover.style.display === "block") {
393
+ this.popover.style.top = popoverTop1;
394
+ }
395
+ if (this.selectPopover.style.display === "block") {
396
+ this.selectPopover.style.top = popoverTop1;
397
+ }
398
+ })
399
+ );
300
400
 
301
401
  this.element.addEventListener("scroll", () => {
302
402
  hidePanel(vditor, ["hint"]);
303
- if (vditor.options.comment && vditor.options.comment.enable && vditor.options.comment.scroll) {
403
+ if (
404
+ vditor.options.comment &&
405
+ vditor.options.comment.enable &&
406
+ vditor.options.comment.scroll
407
+ ) {
304
408
  vditor.options.comment.scroll(vditor.wysiwyg.element.scrollTop);
305
409
  }
306
410
  if (this.popover.style.display !== "block") {
307
411
  return;
308
412
  }
309
- const top = parseInt(this.popover.getAttribute("data-top"), 10) - vditor.wysiwyg.element.scrollTop;
413
+ const top =
414
+ parseInt(this.popover.getAttribute("data-top"), 10) -
415
+ vditor.wysiwyg.element.scrollTop;
310
416
  let max = -8;
311
- if (vditor.options.toolbarConfig.pin && vditor.toolbar.element.getBoundingClientRect().top === 0) {
417
+ if (
418
+ vditor.options.toolbarConfig.pin &&
419
+ vditor.toolbar.element.getBoundingClientRect().top === 0
420
+ ) {
312
421
  max = window.scrollY - vditor.element.offsetTop + max;
313
422
  }
314
- const topPx = Math.max(max, Math.min(top, this.element.clientHeight - 21)) + "px";
423
+ const topPx =
424
+ Math.max(max, Math.min(top, this.element.clientHeight - 21)) +
425
+ "px";
315
426
  this.popover.style.top = topPx;
316
427
  this.selectPopover.style.top = topPx;
317
428
  });
318
429
 
319
- this.element.addEventListener("paste", (event: ClipboardEvent & { target: HTMLElement }) => {
320
- paste(vditor, event, {
321
- pasteCode: (code: string) => {
322
- const range = getEditorRange(vditor);
323
- const node = document.createElement("template");
324
- node.innerHTML = code;
325
- range.insertNode(node.content.cloneNode(true));
326
- const blockElement = hasClosestByAttribute(range.startContainer, "data-block", "0");
327
- if (blockElement) {
328
- blockElement.outerHTML = vditor.lute.SpinVditorDOM(blockElement.outerHTML);
329
- } else {
330
- vditor.wysiwyg.element.innerHTML = vditor.lute.SpinVditorDOM(vditor.wysiwyg.element.innerHTML);
331
- }
332
- setRangeByWbr(vditor.wysiwyg.element, range);
333
- },
334
- });
335
- });
430
+ this.element.addEventListener(
431
+ "paste",
432
+ (event: ClipboardEvent & { target: HTMLElement }) => {
433
+ paste(vditor, event, {
434
+ pasteCode: (code: string) => {
435
+ const range = getEditorRange(vditor);
436
+ const node = document.createElement("template");
437
+ node.innerHTML = code;
438
+ range.insertNode(node.content.cloneNode(true));
439
+ const blockElement = hasClosestByAttribute(
440
+ range.startContainer,
441
+ "data-block",
442
+ "0"
443
+ );
444
+ if (blockElement) {
445
+ blockElement.outerHTML = vditor.lute.SpinVditorDOM(
446
+ blockElement.outerHTML
447
+ );
448
+ } else {
449
+ vditor.wysiwyg.element.innerHTML =
450
+ vditor.lute.SpinVditorDOM(
451
+ vditor.wysiwyg.element.innerHTML
452
+ );
453
+ }
454
+ setRangeByWbr(vditor.wysiwyg.element, range);
455
+ },
456
+ });
457
+ }
458
+ );
336
459
 
337
460
  // 中文处理
338
461
  this.element.addEventListener("compositionstart", () => {
@@ -340,7 +463,9 @@ class WYSIWYG {
340
463
  });
341
464
 
342
465
  this.element.addEventListener("compositionend", (event: InputEvent) => {
343
- const headingElement = hasClosestByHeadings(getSelection().getRangeAt(0).startContainer);
466
+ const headingElement = hasClosestByHeadings(
467
+ getSelection().getRangeAt(0).startContainer
468
+ );
344
469
  if (headingElement && headingElement.textContent === "") {
345
470
  // heading 为空删除 https://github.com/Vanessa219/vditor/issues/150
346
471
  renderToc(vditor);
@@ -353,7 +478,10 @@ class WYSIWYG {
353
478
  });
354
479
 
355
480
  this.element.addEventListener("input", (event: InputEvent) => {
356
- if (event.inputType === "deleteByDrag" || event.inputType === "insertFromDrop") {
481
+ if (
482
+ event.inputType === "deleteByDrag" ||
483
+ event.inputType === "insertFromDrop"
484
+ ) {
357
485
  // https://github.com/Vanessa219/vditor/issues/801 编辑器内容拖拽问题
358
486
  return;
359
487
  }
@@ -362,7 +490,12 @@ class WYSIWYG {
362
490
  afterRenderEvent(vditor);
363
491
  return;
364
492
  }
365
- if (this.composingLock || event.data === "‘" || event.data === "“" || event.data === "《") {
493
+ if (
494
+ this.composingLock ||
495
+ event.data === "‘" ||
496
+ event.data === "“" ||
497
+ event.data === "《"
498
+ ) {
366
499
  afterRenderEvent(vditor);
367
500
  return;
368
501
  }
@@ -378,14 +511,27 @@ class WYSIWYG {
378
511
  }
379
512
 
380
513
  // 前后空格处理
381
- const startOffset = getSelectPosition(blockElement, vditor.wysiwyg.element, range).start;
514
+ const startOffset = getSelectPosition(
515
+ blockElement,
516
+ vditor.wysiwyg.element,
517
+ range
518
+ ).start;
382
519
 
383
520
  // 开始可以输入空格
384
521
  let startSpace = true;
385
- for (let i = startOffset - 1; i > blockElement.textContent.substr(0, startOffset).lastIndexOf("\n"); i--) {
386
- if (blockElement.textContent.charAt(i) !== " " &&
522
+ for (
523
+ let i = startOffset - 1;
524
+ i >
525
+ blockElement.textContent
526
+ .substr(0, startOffset)
527
+ .lastIndexOf("\n");
528
+ i--
529
+ ) {
530
+ if (
531
+ blockElement.textContent.charAt(i) !== " " &&
387
532
  // 多个 tab 前删除不形成代码块 https://github.com/Vanessa219/vditor/issues/162 1
388
- blockElement.textContent.charAt(i) !== "\t") {
533
+ blockElement.textContent.charAt(i) !== "\t"
534
+ ) {
389
535
  startSpace = false;
390
536
  break;
391
537
  }
@@ -396,8 +542,15 @@ class WYSIWYG {
396
542
 
397
543
  // 结尾可以输入空格
398
544
  let endSpace = true;
399
- for (let i = startOffset - 1; i < blockElement.textContent.length; i++) {
400
- if (blockElement.textContent.charAt(i) !== " " && blockElement.textContent.charAt(i) !== "\n") {
545
+ for (
546
+ let i = startOffset - 1;
547
+ i < blockElement.textContent.length;
548
+ i++
549
+ ) {
550
+ if (
551
+ blockElement.textContent.charAt(i) !== " " &&
552
+ blockElement.textContent.charAt(i) !== "\n"
553
+ ) {
401
554
  endSpace = false;
402
555
  break;
403
556
  }
@@ -408,196 +561,275 @@ class WYSIWYG {
408
561
  endSpace = false;
409
562
  }
410
563
 
411
- const headingElement = hasClosestByHeadings(getSelection().getRangeAt(0).startContainer);
564
+ const headingElement = hasClosestByHeadings(
565
+ getSelection().getRangeAt(0).startContainer
566
+ );
412
567
  if (headingElement && headingElement.textContent === "") {
413
568
  // heading 为空删除 https://github.com/Vanessa219/vditor/issues/150
414
569
  renderToc(vditor);
415
570
  headingElement.remove();
416
571
  }
417
572
 
418
- if ((startSpace && blockElement.getAttribute("data-type") !== "code-block")
419
- || endSpace || isHeadingMD(blockElement.innerHTML) ||
420
- (isHrMD(blockElement.innerHTML) && blockElement.previousElementSibling)) {
573
+ if (
574
+ (startSpace &&
575
+ blockElement.getAttribute("data-type") !== "code-block") ||
576
+ endSpace ||
577
+ isHeadingMD(blockElement.innerHTML) ||
578
+ (isHrMD(blockElement.innerHTML) &&
579
+ blockElement.previousElementSibling)
580
+ ) {
421
581
  if (typeof vditor.options.input === "function") {
422
582
  vditor.options.input(getMarkdown(vditor));
423
583
  }
424
584
  return;
425
585
  }
426
586
  // https://github.com/Vanessa219/vditor/issues/1565
427
- if (event.inputType === "insertParagraph" && this.element.innerHTML === '<p><br></p><p><br></p>') {
587
+ if (
588
+ event.inputType === "insertParagraph" &&
589
+ this.element.innerHTML === "<p><br></p><p><br></p>"
590
+ ) {
428
591
  blockElement.previousElementSibling.remove();
429
592
  }
430
593
 
431
594
  input(vditor, range, event);
432
595
  });
433
596
 
434
- this.element.addEventListener("click", (event: MouseEvent & { target: HTMLElement }) => {
435
- if (event.target.tagName === "INPUT") {
436
- const checkElement = event.target as HTMLInputElement;
437
- if (checkElement.checked) {
438
- checkElement.setAttribute("checked", "checked");
439
- } else {
440
- checkElement.removeAttribute("checked");
441
- }
442
- this.preventInput = true;
443
- if (getSelection().rangeCount > 0) {
444
- setSelectionFocus(getSelection().getRangeAt(0));
597
+ this.element.addEventListener(
598
+ "click",
599
+ (event: MouseEvent & { target: HTMLElement }) => {
600
+ if (event.target.tagName === "INPUT") {
601
+ const checkElement = event.target as HTMLInputElement;
602
+ if (checkElement.checked) {
603
+ checkElement.setAttribute("checked", "checked");
604
+ } else {
605
+ checkElement.removeAttribute("checked");
606
+ }
607
+ this.preventInput = true;
608
+ if (getSelection().rangeCount > 0) {
609
+ setSelectionFocus(getSelection().getRangeAt(0));
610
+ }
611
+ afterRenderEvent(vditor);
612
+ return;
445
613
  }
446
- afterRenderEvent(vditor);
447
- return;
448
- }
449
614
 
450
- if (event.target.tagName === "IMG" &&
451
- // plantuml 图片渲染不进行提示
452
- !event.target.parentElement.classList.contains("vditor-wysiwyg__preview")) {
453
- if (event.target.getAttribute("data-type") === "link-ref") {
454
- genLinkRefPopover(vditor, event.target);
455
- } else {
456
- genImagePopover(event, vditor);
615
+ if (
616
+ event.target.tagName === "IMG" &&
617
+ // plantuml 图片渲染不进行提示
618
+ !event.target.parentElement.classList.contains(
619
+ "vditor-wysiwyg__preview"
620
+ )
621
+ ) {
622
+ if (event.target.getAttribute("data-type") === "link-ref") {
623
+ genLinkRefPopover(vditor, event.target);
624
+ } else {
625
+ genImagePopover(event, vditor);
626
+ }
627
+ return;
457
628
  }
458
- return;
459
- }
460
629
 
461
- // 打开链接
462
- const a = hasClosestByMatchTag(event.target, "A");
463
- if (a) {
464
- if (vditor.options.link.click) {
465
- vditor.options.link.click(a);
466
- } else if (vditor.options.link.isOpen) {
467
- window.open(a.getAttribute("href"));
630
+ // 打开链接
631
+ const a = hasClosestByMatchTag(event.target, "A");
632
+ if (a) {
633
+ if (vditor.options.link.click) {
634
+ vditor.options.link.click(a);
635
+ } else if (vditor.options.link.isOpen) {
636
+ window.open(a.getAttribute("href"));
637
+ }
638
+ event.preventDefault();
639
+ return;
468
640
  }
469
- event.preventDefault();
470
- return;
471
- }
472
641
 
473
- const range = getEditorRange(vditor);
474
- if (event.target.isEqualNode(this.element) && this.element.lastElementChild && range.collapsed) {
475
- const lastRect = this.element.lastElementChild.getBoundingClientRect();
476
- if (event.y > lastRect.top + lastRect.height) {
477
- if (this.element.lastElementChild.tagName === "P" &&
478
- this.element.lastElementChild.textContent.trim().replace(Constants.ZWSP, "") === "") {
479
- range.selectNodeContents(this.element.lastElementChild);
480
- range.collapse(false);
481
- } else {
482
- this.element.insertAdjacentHTML("beforeend",
483
- `<p data-block="0">${Constants.ZWSP}<wbr></p>`);
484
- setRangeByWbr(this.element, range);
642
+ const range = getEditorRange(vditor);
643
+ if (
644
+ event.target.isEqualNode(this.element) &&
645
+ this.element.lastElementChild &&
646
+ range.collapsed
647
+ ) {
648
+ const lastRect =
649
+ this.element.lastElementChild.getBoundingClientRect();
650
+ if (event.y > lastRect.top + lastRect.height) {
651
+ if (
652
+ this.element.lastElementChild.tagName === "P" &&
653
+ this.element.lastElementChild.textContent
654
+ .trim()
655
+ .replace(Constants.ZWSP, "") === ""
656
+ ) {
657
+ range.selectNodeContents(
658
+ this.element.lastElementChild
659
+ );
660
+ range.collapse(false);
661
+ } else {
662
+ this.element.insertAdjacentHTML(
663
+ "beforeend",
664
+ `<p data-block="0">${Constants.ZWSP}<wbr></p>`
665
+ );
666
+ setRangeByWbr(this.element, range);
667
+ }
485
668
  }
486
669
  }
487
- }
488
-
489
- highlightToolbarWYSIWYG(vditor);
490
670
 
491
- // 点击后光标落于预览区,需展开代码块(无选区时)
492
- let previewElement = hasClosestByClassName(event.target, "vditor-wysiwyg__preview");
493
- if (!previewElement) {
494
- previewElement =
495
- hasClosestByClassName(getEditorRange(vditor).startContainer, "vditor-wysiwyg__preview");
496
- }
497
- if (previewElement) {
498
- const hasSelection = getSelectText(vditor.wysiwyg.element).trim().length > 0;
499
- if (!hasSelection) {
500
- showCode(previewElement, vditor);
671
+ highlightToolbarWYSIWYG(vditor);
672
+
673
+ // 点击后光标落于预览区,需展开代码块(无选区时)
674
+ let previewElement = hasClosestByClassName(
675
+ event.target,
676
+ "vditor-wysiwyg__preview"
677
+ );
678
+ if (!previewElement) {
679
+ previewElement = hasClosestByClassName(
680
+ getEditorRange(vditor).startContainer,
681
+ "vditor-wysiwyg__preview"
682
+ );
683
+ }
684
+ if (previewElement) {
685
+ const hasSelection =
686
+ getSelectText(vditor.wysiwyg.element).trim().length > 0;
687
+ if (!hasSelection) {
688
+ showCode(previewElement, vditor);
689
+ }
501
690
  }
502
- }
503
-
504
- clickToc(event, vditor);
505
- });
506
691
 
507
- this.element.addEventListener("keyup", (event: KeyboardEvent & { target: HTMLElement }) => {
508
- if (event.isComposing || isCtrl(event)) {
509
- return;
510
- }
511
- // 除 md 处理、cell 内换行、table 添加新行/列、代码块语言切换、block render 换行、跳出/逐层跳出 blockquote、h6 换行、
512
- // 任务列表换行、软换行外需在换行时调整文档位置
513
- if (event.key === "Enter") {
514
- scrollCenter(vditor);
515
- }
516
- if ((event.key === "Backspace" || event.key === "Delete") &&
517
- vditor.wysiwyg.element.innerHTML !== "" && vditor.wysiwyg.element.childNodes.length === 1 &&
518
- vditor.wysiwyg.element.firstElementChild && vditor.wysiwyg.element.firstElementChild.tagName === "P"
519
- && vditor.wysiwyg.element.firstElementChild.childElementCount === 0
520
- && (vditor.wysiwyg.element.textContent === "" || vditor.wysiwyg.element.textContent === "\n")) {
521
- // 为空时显示 placeholder
522
- vditor.wysiwyg.element.innerHTML = "";
692
+ clickToc(event, vditor);
523
693
  }
524
- const range = getEditorRange(vditor);
525
- if (event.key === "Backspace") {
526
- // firefox headings https://github.com/Vanessa219/vditor/issues/211
527
- if (isFirefox() && range.startContainer.textContent === "\n" && range.startOffset === 1) {
528
- range.startContainer.textContent = "";
694
+ );
695
+
696
+ this.element.addEventListener(
697
+ "keyup",
698
+ (event: KeyboardEvent & { target: HTMLElement }) => {
699
+ if (event.isComposing || isCtrl(event)) {
700
+ return;
701
+ }
702
+ // 除 md 处理、cell 内换行、table 添加新行/列、代码块语言切换、block render 换行、跳出/逐层跳出 blockquote、h6 换行、
703
+ // 任务列表换行、软换行外需在换行时调整文档位置
704
+ if (event.key === "Enter") {
705
+ scrollCenter(vditor);
706
+ }
707
+ if (
708
+ (event.key === "Backspace" || event.key === "Delete") &&
709
+ vditor.wysiwyg.element.innerHTML !== "" &&
710
+ vditor.wysiwyg.element.childNodes.length === 1 &&
711
+ vditor.wysiwyg.element.firstElementChild &&
712
+ vditor.wysiwyg.element.firstElementChild.tagName === "P" &&
713
+ vditor.wysiwyg.element.firstElementChild
714
+ .childElementCount === 0 &&
715
+ (vditor.wysiwyg.element.textContent === "" ||
716
+ vditor.wysiwyg.element.textContent === "\n")
717
+ ) {
718
+ // 为空时显示 placeholder
719
+ vditor.wysiwyg.element.innerHTML = "";
720
+ }
721
+ const range = getEditorRange(vditor);
722
+ if (event.key === "Backspace") {
723
+ // firefox headings https://github.com/Vanessa219/vditor/issues/211
724
+ if (
725
+ isFirefox() &&
726
+ range.startContainer.textContent === "\n" &&
727
+ range.startOffset === 1
728
+ ) {
729
+ range.startContainer.textContent = "";
730
+ }
529
731
  }
530
- }
531
732
 
532
- // 没有被块元素包裹
533
- modifyPre(vditor, range);
733
+ // 没有被块元素包裹
734
+ modifyPre(vditor, range);
534
735
 
535
- highlightToolbarWYSIWYG(vditor);
736
+ highlightToolbarWYSIWYG(vditor);
536
737
 
537
- if (event.key !== "ArrowDown" && event.key !== "ArrowRight" && event.key !== "Backspace"
538
- && event.key !== "ArrowLeft" && event.key !== "ArrowUp") {
539
- return;
540
- }
738
+ if (
739
+ event.key !== "ArrowDown" &&
740
+ event.key !== "ArrowRight" &&
741
+ event.key !== "Backspace" &&
742
+ event.key !== "ArrowLeft" &&
743
+ event.key !== "ArrowUp"
744
+ ) {
745
+ return;
746
+ }
541
747
 
542
- if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
543
- vditor.hint.render(vditor);
544
- }
748
+ if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
749
+ vditor.hint.render(vditor);
750
+ }
545
751
 
546
- // 上下左右,删除遇到块预览的处理
547
- let previewElement = hasClosestByClassName(range.startContainer, "vditor-wysiwyg__preview");
548
- if (!previewElement && range.startContainer.nodeType !== 3 && range.startOffset > 0) {
549
- // table 前删除遇到代码块
550
- const blockRenderElement = range.startContainer as HTMLElement;
551
- if (blockRenderElement.classList.contains("vditor-wysiwyg__block")) {
552
- previewElement = blockRenderElement.lastElementChild as HTMLElement;
752
+ // 上下左右,删除遇到块预览的处理
753
+ let previewElement = hasClosestByClassName(
754
+ range.startContainer,
755
+ "vditor-wysiwyg__preview"
756
+ );
757
+ if (
758
+ !previewElement &&
759
+ range.startContainer.nodeType !== 3 &&
760
+ range.startOffset > 0
761
+ ) {
762
+ // table 前删除遇到代码块
763
+ const blockRenderElement =
764
+ range.startContainer as HTMLElement;
765
+ if (
766
+ blockRenderElement.classList.contains(
767
+ "vditor-wysiwyg__block"
768
+ )
769
+ ) {
770
+ previewElement =
771
+ blockRenderElement.lastElementChild as HTMLElement;
772
+ }
553
773
  }
554
- }
555
- if (!previewElement) {
556
- return;
557
- }
558
- const previousElement = previewElement.previousElementSibling as HTMLElement;
559
- if (previousElement.style.display === "none") {
560
- if (event.key === "ArrowDown" || event.key === "ArrowRight") {
561
- showCode(previewElement, vditor);
562
- } else {
563
- showCode(previewElement, vditor, false);
774
+ if (!previewElement) {
775
+ return;
776
+ }
777
+ const previousElement =
778
+ previewElement.previousElementSibling as HTMLElement;
779
+ if (previousElement.style.display === "none") {
780
+ if (
781
+ event.key === "ArrowDown" ||
782
+ event.key === "ArrowRight"
783
+ ) {
784
+ showCode(previewElement, vditor);
785
+ } else {
786
+ showCode(previewElement, vditor, false);
787
+ }
788
+ return;
564
789
  }
565
- return;
566
- }
567
790
 
568
- let codeElement = previewElement.previousElementSibling as HTMLElement;
569
- if (codeElement.tagName === "PRE") {
570
- codeElement = codeElement.firstElementChild as HTMLElement;
571
- }
791
+ let codeElement =
792
+ previewElement.previousElementSibling as HTMLElement;
793
+ if (codeElement.tagName === "PRE") {
794
+ codeElement = codeElement.firstElementChild as HTMLElement;
795
+ }
572
796
 
573
- if (event.key === "ArrowDown" || event.key === "ArrowRight") {
574
- const blockRenderElement = previewElement.parentElement;
575
- let nextNode = getRenderElementNextNode(blockRenderElement) as HTMLElement;
576
- if (nextNode && nextNode.nodeType !== 3) {
577
- // 下一节点依旧为代码渲染块
578
- const nextRenderElement = nextNode.querySelector(".vditor-wysiwyg__preview") as HTMLElement;
579
- if (nextRenderElement) {
580
- showCode(nextRenderElement, vditor);
581
- return;
797
+ if (event.key === "ArrowDown" || event.key === "ArrowRight") {
798
+ const blockRenderElement = previewElement.parentElement;
799
+ let nextNode = getRenderElementNextNode(
800
+ blockRenderElement
801
+ ) as HTMLElement;
802
+ if (nextNode && nextNode.nodeType !== 3) {
803
+ // 下一节点依旧为代码渲染块
804
+ const nextRenderElement = nextNode.querySelector(
805
+ ".vditor-wysiwyg__preview"
806
+ ) as HTMLElement;
807
+ if (nextRenderElement) {
808
+ showCode(nextRenderElement, vditor);
809
+ return;
810
+ }
582
811
  }
583
- }
584
- // 跳过渲染块,光标移动到下一个节点
585
- if (nextNode.nodeType === 3) {
586
- // inline
587
- while (nextNode.textContent.length === 0 && nextNode.nextSibling) {
588
- // https://github.com/Vanessa219/vditor/issues/100 2
589
- nextNode = nextNode.nextSibling as HTMLElement;
812
+ // 跳过渲染块,光标移动到下一个节点
813
+ if (nextNode.nodeType === 3) {
814
+ // inline
815
+ while (
816
+ nextNode.textContent.length === 0 &&
817
+ nextNode.nextSibling
818
+ ) {
819
+ // https://github.com/Vanessa219/vditor/issues/100 2
820
+ nextNode = nextNode.nextSibling as HTMLElement;
821
+ }
822
+ range.setStart(nextNode, 1);
823
+ } else {
824
+ // block
825
+ range.setStart(nextNode.firstChild, 0);
590
826
  }
591
- range.setStart(nextNode, 1);
592
827
  } else {
593
- // block
594
- range.setStart(nextNode.firstChild, 0);
828
+ range.selectNodeContents(codeElement);
829
+ range.collapse(false);
595
830
  }
596
- } else {
597
- range.selectNodeContents(codeElement);
598
- range.collapse(false);
599
831
  }
600
- });
832
+ );
601
833
  }
602
834
  }
603
835