vditor 3.11.2 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +12 -1
  2. package/dist/css/content-theme/ant-design.css +10 -0
  3. package/dist/css/content-theme/dark.css +10 -0
  4. package/dist/css/content-theme/light.css +13 -0
  5. package/dist/css/content-theme/wechat.css +10 -0
  6. package/dist/index.css +163 -81
  7. package/dist/index.js +3035 -2715
  8. package/dist/index.min.js +1 -1
  9. package/dist/js/i18n/ja_JP.js +2 -2
  10. package/dist/js/i18n/zh_TW.js +8 -8
  11. package/dist/js/lute/lute.min.js +75 -60
  12. package/dist/js/mermaid/mermaid.min.js +2027 -1047
  13. package/dist/js/wavedrom/LICENSE.WaveDrom +21 -0
  14. package/dist/js/wavedrom/wavedrom.min.js +9 -0
  15. package/dist/method.d.ts +2 -0
  16. package/dist/method.js +323 -9
  17. package/dist/method.min.js +1 -1
  18. package/dist/ts/constants.d.ts +4 -0
  19. package/dist/ts/markdown/adapterRender.d.ts +4 -0
  20. package/dist/ts/markdown/imageCaptionRender.d.ts +2 -0
  21. package/dist/ts/markdown/wavedromRender.d.ts +1 -0
  22. package/dist/ts/sv/index.d.ts +1 -5
  23. package/dist/ts/sv/process.d.ts +1 -3
  24. package/dist/ts/upload/getElement.d.ts +1 -1
  25. package/dist/ts/upload/index.d.ts +2 -0
  26. package/dist/ts/util/editorCommonEvent.d.ts +1 -1
  27. package/dist/ts/util/fixBrowserBehavior.d.ts +1 -0
  28. package/dist/types/index.d.ts +22 -5
  29. package/package.json +7 -4
  30. package/src/assets/less/_reset.less +103 -2
  31. package/src/assets/less/_sv.less +2 -98
  32. package/src/assets/less/_wysiwyg.less +30 -0
  33. package/src/assets/less/index.less +20 -0
  34. package/src/index.ts +48 -14
  35. package/src/method.ts +3 -0
  36. package/src/ts/constants.ts +5 -1
  37. package/src/ts/export/index.ts +2 -0
  38. package/src/ts/hint/index.ts +9 -4
  39. package/src/ts/ir/highlightToolbarIR.ts +4 -4
  40. package/src/ts/ir/index.ts +26 -0
  41. package/src/ts/ir/process.ts +24 -1
  42. package/src/ts/markdown/adapterRender.ts +4 -0
  43. package/src/ts/markdown/getHTML.ts +6 -3
  44. package/src/ts/markdown/getMarkdown.ts +3 -3
  45. package/src/ts/markdown/imageCaptionRender.ts +175 -0
  46. package/src/ts/markdown/mermaidRender.ts +1 -1
  47. package/src/ts/markdown/previewRender.ts +7 -1
  48. package/src/ts/markdown/setLute.ts +3 -0
  49. package/src/ts/markdown/wavedromRender.ts +54 -0
  50. package/src/ts/preview/index.ts +5 -0
  51. package/src/ts/sv/index.ts +37 -76
  52. package/src/ts/sv/process.ts +48 -164
  53. package/src/ts/sv/processKeydown.ts +19 -186
  54. package/src/ts/toolbar/EditMode.ts +3 -10
  55. package/src/ts/toolbar/Emoji.ts +8 -1
  56. package/src/ts/toolbar/Record.ts +10 -2
  57. package/src/ts/toolbar/index.ts +3 -0
  58. package/src/ts/ui/initUI.ts +7 -3
  59. package/src/ts/undo/index.ts +32 -17
  60. package/src/ts/upload/index.ts +42 -10
  61. package/src/ts/util/Options.ts +1 -1
  62. package/src/ts/util/editorCommonEvent.ts +18 -9
  63. package/src/ts/util/fixBrowserBehavior.ts +197 -51
  64. package/src/ts/util/processCode.ts +3 -0
  65. package/src/ts/util/selection.ts +11 -3
  66. package/src/ts/wysiwyg/afterRenderEvent.ts +2 -0
  67. package/src/ts/wysiwyg/highlightToolbarWYSIWYG.ts +58 -2
  68. package/src/ts/wysiwyg/input.ts +5 -0
  69. package/src/ts/wysiwyg/processKeydown.ts +47 -0
  70. package/src/ts/wysiwyg/setHeading.ts +110 -6
  71. package/dist/ts/sv/combineFootnote.d.ts +0 -6
  72. package/dist/ts/sv/inputEvent.d.ts +0 -1
  73. package/src/ts/sv/combineFootnote.ts +0 -27
  74. package/src/ts/sv/inputEvent.ts +0 -188
@@ -1,5 +1,6 @@
1
1
  import {Constants} from "../constants";
2
2
  import {getMarkdown} from "../markdown/getMarkdown";
3
+ import {renderImageCaptions} from "../markdown/imageCaptionRender";
3
4
  import {removeCurrentToolbar} from "../toolbar/setToolbar";
4
5
  import {accessLocalStorage} from "../util/compatibility";
5
6
  import {listToggle} from "../util/fixBrowserBehavior";
@@ -41,6 +42,7 @@ export const processAfterRender = (vditor: IVditor, options = {
41
42
  enableHint: false,
42
43
  enableInput: true,
43
44
  }) => {
45
+ renderImageCaptions(vditor.ir.element, "ir", vditor.options.preview.markdown.imageCaption);
44
46
  if (options.enableHint) {
45
47
  processHint(vditor);
46
48
  }
@@ -96,12 +98,25 @@ export const processHeading = (vditor: IVditor, value: string) => {
96
98
  const removeInline = (range: Range, vditor: IVditor, type: string) => {
97
99
  const inlineElement = hasClosestByAttribute(range.startContainer, "data-type", type) as HTMLElement;
98
100
  if (inlineElement) {
101
+ const keepSelection = !range.collapsed;
99
102
  inlineElement.firstElementChild.remove();
100
103
  inlineElement.lastElementChild.remove();
104
+ if (keepSelection) {
105
+ const endRange = range.cloneRange();
106
+ endRange.collapse(false);
107
+ endRange.insertNode(document.createElement("wbr"));
108
+ }
101
109
  range.insertNode(document.createElement("wbr"));
102
110
  const tempElement = document.createElement("div");
103
111
  tempElement.innerHTML = vditor.lute.SpinVditorIRDOM(inlineElement.outerHTML);
104
112
  inlineElement.outerHTML = tempElement.firstElementChild.innerHTML.trim();
113
+ if (keepSelection) {
114
+ setRangeByWbr(vditor.ir.element, range);
115
+ const endWbrElement = vditor.ir.element.querySelector("wbr");
116
+ range.setEndBefore(endWbrElement);
117
+ endWbrElement.remove();
118
+ setSelectionFocus(range);
119
+ }
105
120
  }
106
121
  };
107
122
 
@@ -182,6 +197,7 @@ export const processToolbar = (vditor: IVditor, actionBtn: Element, prefix: stri
182
197
  } else if (commandName === "italic" || commandName === "bold" || commandName === "strike"
183
198
  || commandName === "inline-code" || commandName === "code" || commandName === "table") {
184
199
  let html;
200
+ let keepSelection = false;
185
201
  if (range.toString() === "") {
186
202
  html = `${prefix}<wbr>${suffix}`;
187
203
  } else {
@@ -190,7 +206,8 @@ export const processToolbar = (vditor: IVditor, actionBtn: Element, prefix: stri
190
206
  } else if (commandName === "table") {
191
207
  html = `${prefix}${range.toString()}<wbr>${suffix}`;
192
208
  } else {
193
- html = `${prefix}${range.toString()}${suffix}<wbr>`;
209
+ html = `${prefix}<wbr>${range.toString()}<wbr>${suffix}`;
210
+ keepSelection = true;
194
211
  }
195
212
  range.deleteContents();
196
213
  }
@@ -202,6 +219,12 @@ export const processToolbar = (vditor: IVditor, actionBtn: Element, prefix: stri
202
219
  spanElement.innerHTML = html;
203
220
  range.insertNode(spanElement);
204
221
  input(vditor, range);
222
+ if (keepSelection) {
223
+ const endWbrElement = vditor.ir.element.querySelector("wbr");
224
+ range.setEndBefore(endWbrElement);
225
+ endWbrElement.remove();
226
+ setSelectionFocus(range);
227
+ }
205
228
 
206
229
  if (commandName === "table") {
207
230
  range.selectNodeContents(getSelection().getRangeAt(0).startContainer.parentElement);
@@ -31,6 +31,10 @@ export const graphvizRenderAdapter = {
31
31
  getCode: (el: Element) => el.textContent,
32
32
  getElements: (el: HTMLElement | Document) => el.querySelectorAll(".language-graphviz"),
33
33
  };
34
+ export const wavedromRenderAdapter = {
35
+ getCode: (el: Element) => el.textContent,
36
+ getElements: (el: HTMLElement | Document) => el.querySelectorAll(".language-wavedrom"),
37
+ };
34
38
  export const flowchartRenderAdapter = {
35
39
  getCode: (el: Element) => el.textContent,
36
40
  getElements: (el: HTMLElement | Document) => el.querySelectorAll(".language-flowchart"),
@@ -1,11 +1,14 @@
1
1
  import {getMarkdown} from "./getMarkdown";
2
+ import {renderImageCaptionHTML} from "./imageCaptionRender";
2
3
 
3
4
  export const getHTML = (vditor: IVditor) => {
5
+ let html = "";
4
6
  if (vditor.currentMode === "sv") {
5
- return vditor.lute.Md2HTML(getMarkdown(vditor));
7
+ html = vditor.lute.Md2HTML(getMarkdown(vditor));
6
8
  } else if (vditor.currentMode === "wysiwyg") {
7
- return vditor.lute.VditorDOM2HTML(vditor.wysiwyg.element.innerHTML);
9
+ html = vditor.lute.VditorDOM2HTML(vditor.wysiwyg.element.innerHTML);
8
10
  } else if (vditor.currentMode === "ir") {
9
- return vditor.lute.VditorIRDOM2HTML(vditor.ir.element.innerHTML);
11
+ html = vditor.lute.VditorIRDOM2HTML(vditor.ir.element.innerHTML);
10
12
  }
13
+ return renderImageCaptionHTML(html, vditor.options.preview.markdown.imageCaption);
11
14
  };
@@ -2,11 +2,11 @@ import {code160to32} from "../util/code160to32";
2
2
 
3
3
  export const getMarkdown = (vditor: IVditor) => {
4
4
  if (vditor.currentMode === "sv") {
5
- return code160to32(`${vditor.sv.element.textContent}\n`.replace(/\n\n$/, "\n"));
5
+ return code160to32(`${vditor.sv.element.value}\n`.replace(/\n\n$/, "\n"));
6
6
  } else if (vditor.currentMode === "wysiwyg") {
7
- return vditor.lute.VditorDOM2Md(vditor.wysiwyg.element.innerHTML);
7
+ return code160to32(vditor.lute.VditorDOM2Md(vditor.wysiwyg.element.innerHTML));
8
8
  } else if (vditor.currentMode === "ir") {
9
- return vditor.lute.VditorIRDOM2Md(vditor.ir.element.innerHTML);
9
+ return code160to32(vditor.lute.VditorIRDOM2Md(vditor.ir.element.innerHTML));
10
10
  }
11
11
  return "";
12
12
  };
@@ -0,0 +1,175 @@
1
+ const getContentNodes = (element: Element, ignoreIRMarkers = false) => {
2
+ return Array.from(element.childNodes).filter((node) => {
3
+ if (node.nodeType === Node.COMMENT_NODE) {
4
+ return false;
5
+ }
6
+ if (node.nodeType === Node.TEXT_NODE) {
7
+ return node.textContent.replace(/\u200b/g, "").trim() !== "";
8
+ }
9
+ if (!(node instanceof HTMLElement)) {
10
+ return true;
11
+ }
12
+ if (node.tagName === "WBR") {
13
+ return false;
14
+ }
15
+ return !ignoreIRMarkers || !node.classList.contains("vditor-ir__marker");
16
+ });
17
+ };
18
+
19
+ const getWYSIWYGImage = (paragraph: HTMLParagraphElement) => {
20
+ const nodes = getContentNodes(paragraph);
21
+ if (nodes.length !== 1 || !(nodes[0] instanceof HTMLElement)) {
22
+ return undefined;
23
+ }
24
+
25
+ const container = nodes[0];
26
+ if (container instanceof HTMLImageElement) {
27
+ return {
28
+ container,
29
+ image: container,
30
+ };
31
+ }
32
+ if (container instanceof HTMLAnchorElement) {
33
+ const linkNodes = getContentNodes(container);
34
+ if (linkNodes.length === 1 && linkNodes[0] instanceof HTMLImageElement) {
35
+ return {
36
+ container,
37
+ image: linkNodes[0],
38
+ };
39
+ }
40
+ }
41
+ return undefined;
42
+ };
43
+
44
+ const getIRImage = (paragraph: HTMLParagraphElement) => {
45
+ const nodes = getContentNodes(paragraph);
46
+ if (nodes.length !== 1 || !(nodes[0] instanceof HTMLElement)) {
47
+ return undefined;
48
+ }
49
+
50
+ let imageNode = nodes[0];
51
+ if (imageNode.getAttribute("data-type") === "a") {
52
+ const linkNodes = getContentNodes(imageNode, true);
53
+ if (linkNodes.length !== 1 || !(linkNodes[0] instanceof HTMLElement)) {
54
+ return undefined;
55
+ }
56
+ imageNode = linkNodes[0];
57
+ }
58
+ if (imageNode.getAttribute("data-type") !== "img") {
59
+ return undefined;
60
+ }
61
+
62
+ const image = imageNode.querySelector(":scope > img");
63
+ const titleMarker = imageNode.querySelector<HTMLElement>(":scope > .vditor-ir__marker--title");
64
+ if (!(image instanceof HTMLImageElement) || !titleMarker) {
65
+ return undefined;
66
+ }
67
+
68
+ const markerText = titleMarker.textContent.trim();
69
+ const closeMarker = markerText[0] === "(" ? ")" : markerText[0];
70
+ if (markerText.length < 2 || !["\"", "'", "("].includes(markerText[0]) ||
71
+ markerText[markerText.length - 1] !== closeMarker) {
72
+ return undefined;
73
+ }
74
+ return {
75
+ caption: markerText.slice(1, -1).trim(),
76
+ container: imageNode,
77
+ image,
78
+ };
79
+ };
80
+
81
+ const unwrapWYSIWYGCaptions = (element: HTMLElement) => {
82
+ element.querySelectorAll("span.vditor-image[data-image-caption]").forEach((wrapper) => {
83
+ while (wrapper.firstChild) {
84
+ wrapper.parentNode.insertBefore(wrapper.firstChild, wrapper);
85
+ }
86
+ wrapper.remove();
87
+ });
88
+ };
89
+
90
+ const resetIRCaptions = (element: HTMLElement) => {
91
+ element.querySelectorAll(".vditor-image[data-image-caption]").forEach((imageNode) => {
92
+ imageNode.classList.remove("vditor-image");
93
+ imageNode.removeAttribute("data-image-caption");
94
+ });
95
+ };
96
+
97
+ const renderPreviewCaptions = (element: HTMLElement) => {
98
+ element.querySelectorAll("p").forEach((paragraph: HTMLParagraphElement) => {
99
+ const imageData = getWYSIWYGImage(paragraph);
100
+ const caption = imageData?.image.getAttribute("title")?.trim();
101
+ if (!imageData || !caption) {
102
+ return;
103
+ }
104
+
105
+ const figure = document.createElement("figure");
106
+ Array.from(paragraph.attributes).forEach((attribute) => {
107
+ figure.setAttribute(attribute.name, attribute.value);
108
+ });
109
+ figure.classList.add("vditor-image");
110
+ const figcaption = document.createElement("figcaption");
111
+ figcaption.textContent = caption;
112
+ figure.append(imageData.container, figcaption);
113
+ paragraph.replaceWith(figure);
114
+ });
115
+ };
116
+
117
+ const renderWYSIWYGCaptions = (element: HTMLElement) => {
118
+ element.querySelectorAll("p").forEach((paragraph: HTMLParagraphElement) => {
119
+ const imageData = getWYSIWYGImage(paragraph);
120
+ const caption = imageData?.image.getAttribute("title")?.trim();
121
+ if (!imageData || !caption) {
122
+ return;
123
+ }
124
+
125
+ const wrapper = document.createElement("span");
126
+ wrapper.className = "vditor-image";
127
+ wrapper.setAttribute("data-image-caption", caption);
128
+ imageData.container.replaceWith(wrapper);
129
+ wrapper.append(imageData.container);
130
+ });
131
+ };
132
+
133
+ const renderIRCaptions = (element: HTMLElement) => {
134
+ element.querySelectorAll("p").forEach((paragraph: HTMLParagraphElement) => {
135
+ const imageData = getIRImage(paragraph);
136
+ if (!imageData?.caption) {
137
+ return;
138
+ }
139
+ imageData.container.classList.add("vditor-image");
140
+ imageData.container.setAttribute("data-image-caption", imageData.caption);
141
+ });
142
+ };
143
+
144
+ export const renderImageCaptions = (
145
+ element: HTMLElement,
146
+ mode: "preview" | "wysiwyg" | "ir",
147
+ enable: boolean,
148
+ ) => {
149
+ if (mode === "wysiwyg") {
150
+ unwrapWYSIWYGCaptions(element);
151
+ } else if (mode === "ir") {
152
+ resetIRCaptions(element);
153
+ }
154
+ if (!enable) {
155
+ return;
156
+ }
157
+
158
+ if (mode === "preview") {
159
+ renderPreviewCaptions(element);
160
+ } else if (mode === "wysiwyg") {
161
+ renderWYSIWYGCaptions(element);
162
+ } else {
163
+ renderIRCaptions(element);
164
+ }
165
+ };
166
+
167
+ export const renderImageCaptionHTML = (html: string, enable: boolean) => {
168
+ if (!enable) {
169
+ return html;
170
+ }
171
+ const container = document.createElement("div");
172
+ container.innerHTML = html;
173
+ renderImageCaptions(container, "preview", true);
174
+ return container.innerHTML;
175
+ };
@@ -13,7 +13,7 @@ export const mermaidRender = (element: (HTMLElement | Document) = document, cdn
13
13
  if (mermaidElements.length === 0) {
14
14
  return;
15
15
  }
16
- addScript(`${cdn}/dist/js/mermaid/mermaid.min.js?v=11.6.0`, "vditorMermaidScript").then(() => {
16
+ addScript(`${cdn}/dist/js/mermaid/mermaid.min.js?v=11.16.1`, "vditorMermaidScript").then(() => {
17
17
  const config: any = {
18
18
  securityLevel: "loose", // 升级后无 https://github.com/siyuan-note/siyuan/issues/3587,可使用该选项
19
19
  altFontFamily: "sans-serif",
@@ -10,6 +10,7 @@ import {codeRender} from "./codeRender";
10
10
  import {flowchartRender} from "./flowchartRender";
11
11
  import {graphvizRender} from "./graphvizRender";
12
12
  import {highlightRender} from "./highlightRender";
13
+ import {renderImageCaptionHTML} from "./imageCaptionRender";
13
14
  import {lazyLoadImageRender} from "./lazyLoadImageRender";
14
15
  import {mathRender} from "./mathRender";
15
16
  import {mediaRender} from "./mediaRender";
@@ -20,6 +21,7 @@ import {mindmapRender} from "./mindmapRender";
20
21
  import {plantumlRender} from "./plantumlRender";
21
22
  import {setLute} from "./setLute";
22
23
  import {speechRender} from "./speechRender";
24
+ import {wavedromRender} from "./wavedromRender";
23
25
 
24
26
  const mergeOptions = (options?: IPreviewOptions) => {
25
27
  const defaultOption: IPreviewOptions = {
@@ -59,6 +61,7 @@ export const md2html = (mdText: string, options?: IPreviewOptions) => {
59
61
  return addScript(`${mergedOptions.cdn}/dist/js/lute/lute.min.js`, "vditorLuteScript").then(() => {
60
62
  const lute = setLute({
61
63
  autoSpace: mergedOptions.markdown.autoSpace,
64
+ callout: mergedOptions.markdown.callout,
62
65
  gfmAutoLink: mergedOptions.markdown.gfmAutoLink,
63
66
  codeBlockPreview: mergedOptions.markdown.codeBlockPreview,
64
67
  emojiSite: mergedOptions.emojiPath,
@@ -75,6 +78,8 @@ export const md2html = (mdText: string, options?: IPreviewOptions) => {
75
78
  mathBlockPreview: mergedOptions.markdown.mathBlockPreview,
76
79
  paragraphBeginningSpace: mergedOptions.markdown.paragraphBeginningSpace,
77
80
  sanitize: mergedOptions.markdown.sanitize,
81
+ sub: mergedOptions.markdown.sub,
82
+ sup: mergedOptions.markdown.sup,
78
83
  toc: mergedOptions.markdown.toc,
79
84
  });
80
85
  if (options?.renderers) {
@@ -85,7 +90,7 @@ export const md2html = (mdText: string, options?: IPreviewOptions) => {
85
90
  });
86
91
  }
87
92
  lute.SetHeadingID(true);
88
- return lute.Md2HTML(mdText);
93
+ return renderImageCaptionHTML(lute.Md2HTML(mdText), mergedOptions.markdown.imageCaption);
89
94
  });
90
95
  };
91
96
 
@@ -136,6 +141,7 @@ export const previewRender = async (previewElement: HTMLDivElement, markdown: st
136
141
  markmapRender(previewElement, mergedOptions.cdn);
137
142
  flowchartRender(previewElement, mergedOptions.cdn);
138
143
  graphvizRender(previewElement, mergedOptions.cdn);
144
+ wavedromRender(previewElement, mergedOptions.cdn);
139
145
  chartRender(previewElement, mergedOptions.cdn, mergedOptions.mode);
140
146
  mindmapRender(previewElement, mergedOptions.cdn, mergedOptions.mode);
141
147
  plantumlRender(previewElement, mergedOptions.cdn);
@@ -5,6 +5,7 @@ export const setLute = (options: ILuteOptions) => {
5
5
  lute.SetHeadingAnchor(options.headingAnchor);
6
6
  lute.SetInlineMathAllowDigitAfterOpenMarker(options.inlineMathDigit);
7
7
  lute.SetAutoSpace(options.autoSpace);
8
+ lute.SetCallout(options.callout);
8
9
  lute.SetToC(options.toc);
9
10
  lute.SetFootnotes(options.footnotes);
10
11
  lute.SetFixTermTypo(options.fixTermTypo);
@@ -20,5 +21,7 @@ export const setLute = (options: ILuteOptions) => {
20
21
  if (options.lazyLoadImage) {
21
22
  lute.SetImageLazyLoading(options.lazyLoadImage);
22
23
  }
24
+ lute.SetSup(options.sup);
25
+ lute.SetSub(options.sub);
23
26
  return lute;
24
27
  };
@@ -0,0 +1,54 @@
1
+ import {Constants} from "../constants";
2
+ import {addScript} from "../util/addScript";
3
+ import {looseJsonParse} from "../util/function";
4
+ import {wavedromRenderAdapter} from "./adapterRender";
5
+
6
+ declare const wavedrom: {
7
+ renderWaveElement(index: number, source: object, element: HTMLElement, skin: object, notFirstSignal: boolean): void;
8
+ waveSkin: object;
9
+ };
10
+
11
+ let wavedromIndex = 0;
12
+
13
+ export const wavedromRender = (element: (HTMLElement | Document) = document, cdn = Constants.CDN) => {
14
+ const wavedromElements = wavedromRenderAdapter.getElements(element);
15
+ if (wavedromElements.length === 0) {
16
+ return;
17
+ }
18
+
19
+ addScript(`${cdn}/dist/js/wavedrom/wavedrom.min.js?v=3.6.2`, "vditorWavedromScript").then(() => {
20
+ wavedromElements.forEach(async (item: HTMLElement) => {
21
+ if (item.parentElement.classList.contains("vditor-wysiwyg__pre") ||
22
+ item.parentElement.classList.contains("vditor-ir__marker--pre")) {
23
+ return;
24
+ }
25
+
26
+ const code = wavedromRenderAdapter.getCode(item);
27
+ if (item.getAttribute("data-processed") === "true" || code.trim() === "") {
28
+ return;
29
+ }
30
+
31
+ let renderElement = item;
32
+ if (item.tagName === "CODE") {
33
+ renderElement = document.createElement("div");
34
+ Array.from(item.attributes).forEach((attribute) => {
35
+ renderElement.setAttribute(attribute.name, attribute.value);
36
+ });
37
+ item.replaceWith(renderElement);
38
+ }
39
+
40
+ try {
41
+ const source = await looseJsonParse(code);
42
+ wavedrom.renderWaveElement(wavedromIndex, source, renderElement, wavedrom.waveSkin, false);
43
+ wavedromIndex++;
44
+ } catch (error) {
45
+ const message = error instanceof Error ? error.message : String(error);
46
+ const lineBreak = document.createElement("br");
47
+ renderElement.replaceChildren(document.createTextNode("wavedrom render error:"), lineBreak,
48
+ document.createTextNode(message));
49
+ renderElement.classList.add("vditor-reset--error");
50
+ }
51
+ renderElement.setAttribute("data-processed", "true");
52
+ });
53
+ });
54
+ };
@@ -5,6 +5,7 @@ import {flowchartRender} from "../markdown/flowchartRender";
5
5
  import {getMarkdown} from "../markdown/getMarkdown";
6
6
  import {graphvizRender} from "../markdown/graphvizRender";
7
7
  import {highlightRender} from "../markdown/highlightRender";
8
+ import {renderImageCaptions} from "../markdown/imageCaptionRender";
8
9
  import {mathRender} from "../markdown/mathRender";
9
10
  import {mediaRender} from "../markdown/mediaRender";
10
11
  import {mermaidRender} from "../markdown/mermaidRender";
@@ -12,6 +13,7 @@ import {SMILESRender} from "../markdown/SMILESRender";
12
13
  import {markmapRender} from "../markdown/markmapRender";
13
14
  import {mindmapRender} from "../markdown/mindmapRender";
14
15
  import {plantumlRender} from "../markdown/plantumlRender";
16
+ import {wavedromRender} from "../markdown/wavedromRender";
15
17
  import {getEventName} from "../util/compatibility";
16
18
  import {hasClosestByClassName, hasClosestByMatchTag} from "../util/hasClosest";
17
19
  import {hasClosestByTag} from "../util/hasClosestByHeadings";
@@ -152,6 +154,7 @@ export class Preview {
152
154
 
153
155
  if (value) {
154
156
  this.previewElement.innerHTML = value;
157
+ renderImageCaptions(this.previewElement, "preview", vditor.options.preview.markdown.imageCaption);
155
158
  return;
156
159
  }
157
160
 
@@ -205,6 +208,7 @@ export class Preview {
205
208
  }
206
209
 
207
210
  private afterRender(vditor: IVditor, startTime: number) {
211
+ renderImageCaptions(this.previewElement, "preview", vditor.options.preview.markdown.imageCaption);
208
212
  if (vditor.options.preview.parse) {
209
213
  vditor.options.preview.parse(this.element);
210
214
  }
@@ -229,6 +233,7 @@ export class Preview {
229
233
  SMILESRender(vditor.preview.previewElement, vditor.options.cdn, vditor.options.theme);
230
234
  flowchartRender(vditor.preview.previewElement, vditor.options.cdn);
231
235
  graphvizRender(vditor.preview.previewElement, vditor.options.cdn);
236
+ wavedromRender(vditor.preview.previewElement, vditor.options.cdn);
232
237
  chartRender(vditor.preview.previewElement, vditor.options.cdn, vditor.options.theme);
233
238
  mindmapRender(vditor.preview.previewElement, vditor.options.cdn, vditor.options.theme);
234
239
  plantumlRender(vditor.preview.previewElement, vditor.options.cdn);
@@ -1,55 +1,39 @@
1
- import {isCtrl, isFirefox} from "../util/compatibility";
2
- import {
3
- blurEvent,
4
- copyEvent, cutEvent,
5
- dropEvent,
6
- focusEvent,
7
- hotkeyEvent,
8
- scrollCenter,
9
- selectEvent,
10
- } from "../util/editorCommonEvent";
1
+ import {getMarkdown} from "../markdown/getMarkdown";
2
+ import {isFirefox} from "../util/compatibility";
3
+ import {dropEvent, focusEvent, hotkeyEvent} from "../util/editorCommonEvent";
11
4
  import {paste} from "../util/fixBrowserBehavior";
12
- import {getSelectText} from "../util/getSelectText";
13
- import {inputEvent} from "./inputEvent";
14
- import {processAfterRender} from "./process";
5
+ import {processAfterRender, processPaste} from "./process";
15
6
 
16
7
  class Editor {
17
- public range: Range;
18
- public element: HTMLPreElement;
8
+ public element: HTMLTextAreaElement;
19
9
  public composingLock: boolean = false;
20
10
  public processTimeoutId: number;
21
- public hlToolbarTimeoutId: number;
22
- public preventInput: boolean;
23
11
 
24
12
  constructor(vditor: IVditor) {
25
- this.element = document.createElement("pre");
13
+ this.element = document.createElement("textarea");
26
14
  this.element.className = "vditor-sv vditor-reset";
27
- this.element.setAttribute("placeholder", vditor.options.placeholder);
28
- this.element.setAttribute("contenteditable", "true");
29
- this.element.setAttribute("spellcheck", "false");
15
+ this.element.placeholder = vditor.options.placeholder;
16
+ this.element.spellcheck = false;
30
17
 
31
18
  this.bindEvent(vditor);
32
-
33
19
  focusEvent(vditor, this.element);
34
- blurEvent(vditor, this.element);
35
20
  hotkeyEvent(vditor, this.element);
36
- selectEvent(vditor, this.element);
37
- dropEvent(vditor, this.element);
38
- copyEvent(vditor, this.element, this.copy);
39
- cutEvent(vditor, this.element, this.copy);
40
- }
41
-
42
- private copy(event: ClipboardEvent, vditor: IVditor) {
43
- event.stopPropagation();
44
- event.preventDefault();
45
- event.clipboardData.setData("text/plain", getSelectText(vditor[vditor.currentMode].element));
21
+ dropEvent(vditor, this.element, (code: string) => {
22
+ processPaste(vditor, code.replace(/&lt;/g, "<").replace(/&amp;/g, "&"));
23
+ });
46
24
  }
47
25
 
48
26
  private bindEvent(vditor: IVditor) {
49
- this.element.addEventListener("paste", (event: ClipboardEvent & { target: HTMLElement }) => {
27
+ this.element.addEventListener("blur", () => {
28
+ if (vditor.options.blur) {
29
+ vditor.options.blur(getMarkdown(vditor));
30
+ }
31
+ });
32
+
33
+ this.element.addEventListener("paste", (event: ClipboardEvent & {target: HTMLElement}) => {
50
34
  paste(vditor, event, {
51
35
  pasteCode: (code: string) => {
52
- document.execCommand("insertHTML", false, code);
36
+ processPaste(vditor, code.replace(/&lt;/g, "<").replace(/&amp;/g, "&"));
53
37
  },
54
38
  });
55
39
  });
@@ -62,61 +46,38 @@ class Editor {
62
46
  const textHeight = this.element.clientHeight;
63
47
  const textScrollHeight = this.element.scrollHeight - parseFloat(this.element.style.paddingBottom || "0");
64
48
  const preview = vditor.preview.element;
65
- if ((textScrollTop / textHeight > 0.5)) {
66
- preview.scrollTop = (textScrollTop + textHeight) *
67
- preview.scrollHeight / textScrollHeight - textHeight;
49
+ if (textScrollTop / textHeight > 0.5) {
50
+ preview.scrollTop = (textScrollTop + textHeight) * preview.scrollHeight / textScrollHeight - textHeight;
68
51
  } else {
69
- preview.scrollTop = textScrollTop *
70
- preview.scrollHeight / textScrollHeight;
52
+ preview.scrollTop = textScrollTop * preview.scrollHeight / textScrollHeight;
71
53
  }
72
54
  });
73
55
 
74
- this.element.addEventListener("compositionstart", (event: InputEvent) => {
56
+ this.element.addEventListener("compositionstart", () => {
75
57
  this.composingLock = true;
76
58
  });
77
59
 
78
- this.element.addEventListener("compositionend", (event: InputEvent) => {
60
+ this.element.addEventListener("compositionend", () => {
61
+ this.composingLock = false;
79
62
  if (!isFirefox()) {
80
- inputEvent(vditor, event);
63
+ processAfterRender(vditor);
81
64
  }
82
- this.composingLock = false;
83
65
  });
84
66
 
85
- this.element.addEventListener("input", (event: InputEvent) => {
86
- if (event.inputType === "deleteByDrag" || event.inputType === "insertFromDrop") {
87
- // https://github.com/Vanessa219/vditor/issues/801 编辑器内容拖拽问题
88
- return;
89
- }
90
- if (this.composingLock || event.data === "‘" || event.data === "“" || event.data === "《") {
91
- return;
92
- }
93
- if (this.preventInput) {
94
- this.preventInput = false;
95
- processAfterRender(vditor, {
96
- enableAddUndoStack: true,
97
- enableHint: true,
98
- enableInput: true,
99
- });
100
- return;
67
+ this.element.addEventListener("input", () => {
68
+ if (!this.composingLock) {
69
+ processAfterRender(vditor);
101
70
  }
102
- inputEvent(vditor, event);
103
71
  });
104
72
 
105
- this.element.addEventListener("keyup", (event) => {
106
- if (event.isComposing || isCtrl(event)) {
107
- return;
108
- }
109
- if ((event.key === "Backspace" || event.key === "Delete") &&
110
- vditor.sv.element.innerHTML !== "" && vditor.sv.element.childNodes.length === 1 &&
111
- vditor.sv.element.firstElementChild && vditor.sv.element.firstElementChild.tagName === "DIV"
112
- && vditor.sv.element.firstElementChild.childElementCount === 2
113
- && (vditor.sv.element.firstElementChild.textContent === "" || vditor.sv.element.textContent === "\n")) {
114
- // 为空时显示 placeholder
115
- vditor.sv.element.innerHTML = "";
116
- return;
117
- }
118
- if (event.key === "Enter") {
119
- scrollCenter(vditor);
73
+ this.element.addEventListener("select", () => {
74
+ const selectedText = this.element.value.substring(this.element.selectionStart, this.element.selectionEnd);
75
+ if (selectedText.trim()) {
76
+ if (vditor.options.select) {
77
+ vditor.options.select(selectedText);
78
+ }
79
+ } else if (vditor.options.unSelect) {
80
+ vditor.options.unSelect();
120
81
  }
121
82
  });
122
83
  }