vditor 3.8.5 → 3.8.9

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 (60) hide show
  1. package/README.md +48 -45
  2. package/dist/index.css +2 -2
  3. package/dist/index.d.ts +4 -1
  4. package/dist/index.min.js +722 -858
  5. package/dist/js/i18n/en_US.js +85 -0
  6. package/dist/js/i18n/ja_JP.js +85 -0
  7. package/dist/js/i18n/ko_KR.js +85 -0
  8. package/dist/js/i18n/ru_RU.js +85 -0
  9. package/dist/js/i18n/zh_CN.js +85 -0
  10. package/dist/js/i18n/zh_TW.js +85 -0
  11. package/dist/js/lute/lute.min.js +31 -28
  12. package/dist/method.d.ts +4 -1
  13. package/dist/method.min.js +157 -543
  14. package/dist/ts/markdown/adapterRender.d.ts +33 -0
  15. package/dist/ts/markdown/codeRender.d.ts +1 -2
  16. package/dist/ts/ui/initUI.d.ts +1 -0
  17. package/dist/ts/wysiwyg/index.d.ts +2 -0
  18. package/dist/types/index.d.ts +773 -0
  19. package/package.json +4 -4
  20. package/src/assets/.DS_Store +0 -0
  21. package/src/assets/scss/_content.scss +4 -0
  22. package/src/assets/scss/_reset.scss +11 -0
  23. package/src/index.ts +156 -97
  24. package/src/method.ts +6 -2
  25. package/src/ts/.DS_Store +0 -0
  26. package/src/ts/export/index.ts +7 -5
  27. package/src/ts/hint/index.ts +20 -11
  28. package/src/ts/markdown/abcRender.ts +3 -2
  29. package/src/ts/markdown/adapterRender.ts +33 -0
  30. package/src/ts/markdown/chartRender.ts +3 -2
  31. package/src/ts/markdown/codeRender.ts +5 -6
  32. package/src/ts/markdown/flowchartRender.ts +3 -2
  33. package/src/ts/markdown/graphvizRender.ts +13 -11
  34. package/src/ts/markdown/mathRender.ts +5 -4
  35. package/src/ts/markdown/mermaidRender.ts +4 -2
  36. package/src/ts/markdown/mindmapRender.ts +3 -2
  37. package/src/ts/markdown/plantumlRender.ts +3 -2
  38. package/src/ts/markdown/previewRender.ts +26 -4
  39. package/src/ts/preview/image.ts +2 -4
  40. package/src/ts/preview/index.ts +2 -5
  41. package/src/ts/toolbar/EditMode.ts +3 -4
  42. package/src/ts/toolbar/Headings.ts +6 -6
  43. package/src/ts/toolbar/Info.ts +1 -1
  44. package/src/ts/toolbar/MenuItem.ts +1 -3
  45. package/src/ts/toolbar/Record.ts +3 -4
  46. package/src/ts/ui/initUI.ts +19 -5
  47. package/src/ts/upload/index.ts +11 -11
  48. package/src/ts/util/Options.ts +255 -196
  49. package/src/ts/util/editorCommonEvent.ts +2 -2
  50. package/src/ts/util/fixBrowserBehavior.ts +10 -6
  51. package/src/ts/util/processCode.ts +1 -1
  52. package/src/ts/wysiwyg/highlightToolbarWYSIWYG.ts +298 -138
  53. package/src/ts/wysiwyg/index.ts +9 -4
  54. package/CHANGELOG.md +0 -1053
  55. package/dist/images/.DS_Store +0 -0
  56. package/dist/js/.DS_Store +0 -0
  57. package/dist/js/lute/.DS_Store +0 -0
  58. package/dist/js/mathjax/.DS_Store +0 -0
  59. package/dist/ts/i18n/index.d.ts +0 -2
  60. package/src/ts/i18n/index.ts +0 -476
@@ -1,7 +1,6 @@
1
- import {i18n} from "../i18n/index";
2
1
  import {code160to32} from "../util/code160to32";
3
2
 
4
- export const codeRender = (element: HTMLElement, lang: keyof II18n = "zh_CN") => {
3
+ export const codeRender = (element: HTMLElement) => {
5
4
  element.querySelectorAll("pre > code").forEach((e: HTMLElement, index: number) => {
6
5
  if (e.parentElement.classList.contains("vditor-wysiwyg__pre") ||
7
6
  e.parentElement.classList.contains("vditor-ir__marker--pre")) {
@@ -11,7 +10,7 @@ export const codeRender = (element: HTMLElement, lang: keyof II18n = "zh_CN") =>
11
10
  e.classList.contains("language-echarts") || e.classList.contains("language-mindmap") ||
12
11
  e.classList.contains("language-plantuml") ||
13
12
  e.classList.contains("language-abc") || e.classList.contains("language-graphviz") ||
14
- e.classList.contains("language-math") ) {
13
+ e.classList.contains("language-math")) {
15
14
  return;
16
15
  }
17
16
 
@@ -36,11 +35,11 @@ export const codeRender = (element: HTMLElement, lang: keyof II18n = "zh_CN") =>
36
35
 
37
36
  const divElement = document.createElement("div");
38
37
  divElement.className = "vditor-copy";
39
- divElement.innerHTML = `<span aria-label="${i18n[lang].copy}"
40
- onmouseover="this.setAttribute('aria-label', '${i18n[lang].copy}')"
38
+ divElement.innerHTML = `<span aria-label="${window.VditorI18n.copy}"
39
+ onmouseover="this.setAttribute('aria-label', '${window.VditorI18n.copy}')"
41
40
  class="vditor-tooltipped vditor-tooltipped__w"
42
41
  onclick="this.previousElementSibling.select();document.execCommand('copy');` +
43
- `this.setAttribute('aria-label', '${i18n[lang].copied}')"><svg><use xlink:href="#vditor-icon-copy"></use></svg></span>`;
42
+ `this.setAttribute('aria-label', '${window.VditorI18n.copied}')"><svg><use xlink:href="#vditor-icon-copy"></use></svg></span>`;
44
43
  const textarea = document.createElement("textarea");
45
44
  textarea.value = code160to32(codeText);
46
45
  divElement.insertAdjacentElement("afterbegin", textarea);
@@ -1,12 +1,13 @@
1
1
  import {Constants} from "../constants";
2
2
  import {addScript} from "../util/addScript";
3
+ import {flowchartRenderAdapter} from "./adapterRender";
3
4
 
4
5
  declare const flowchart: {
5
6
  parse(text: string): { drawSVG: (type: HTMLElement) => void };
6
7
  };
7
8
 
8
9
  export const flowchartRender = (element: HTMLElement, cdn = Constants.CDN) => {
9
- const flowchartElements = element.querySelectorAll(".language-flowchart");
10
+ const flowchartElements = flowchartRenderAdapter.getElements(element);
10
11
  if (flowchartElements.length === 0) {
11
12
  return;
12
13
  }
@@ -15,7 +16,7 @@ export const flowchartRender = (element: HTMLElement, cdn = Constants.CDN) => {
15
16
  if (item.getAttribute("data-processed") === "true") {
16
17
  return;
17
18
  }
18
- const flowchartObj = flowchart.parse(item.textContent);
19
+ const flowchartObj = flowchart.parse(flowchartRenderAdapter.getCode(item));
19
20
  item.innerHTML = "";
20
21
  flowchartObj.drawSVG(item);
21
22
  item.setAttribute("data-processed", "true");
@@ -1,42 +1,44 @@
1
1
  import {Constants} from "../constants";
2
2
  import {addScript} from "../util/addScript";
3
+ import {graphvizRenderAdapter} from "./adapterRender";
3
4
 
4
5
  declare class Viz {
5
6
  public renderSVGElement: (code: string) => Promise<any>;
6
7
 
7
- constructor({}: { worker: Worker });
8
+ constructor({ }: { worker: Worker });
8
9
  }
9
10
 
10
11
  export const graphvizRender = (element: HTMLElement, cdn = Constants.CDN) => {
11
- const graphvizElements = element.querySelectorAll(".language-graphviz");
12
+ const graphvizElements = graphvizRenderAdapter.getElements(element);
12
13
 
13
14
  if (graphvizElements.length === 0) {
14
15
  return;
15
16
  }
16
17
  addScript(`${cdn}/dist/js/graphviz/viz.js`, "vditorGraphVizScript").then(() => {
17
18
  graphvizElements.forEach((e: HTMLDivElement) => {
19
+ const code = graphvizRenderAdapter.getCode(e);
18
20
  if (e.parentElement.classList.contains("vditor-wysiwyg__pre") ||
19
21
  e.parentElement.classList.contains("vditor-ir__marker--pre")) {
20
22
  return;
21
23
  }
22
24
 
23
- if (e.getAttribute("data-processed") === "true" || e.textContent.trim() === "") {
25
+ if (e.getAttribute("data-processed") === "true" || code.trim() === "") {
24
26
  return;
25
27
  }
26
28
 
27
29
  try {
28
30
  const blob = new Blob([`importScripts('${(document.getElementById("vditorGraphVizScript") as HTMLScriptElement).src.replace("viz.js", "full.render.js")}');`],
29
- {type: "application/javascript"});
31
+ { type: "application/javascript" });
30
32
  const url = window.URL || window.webkitURL;
31
33
  const blobUrl = url.createObjectURL(blob);
32
34
  const worker = new Worker(blobUrl);
33
- new Viz({worker})
34
- .renderSVGElement(e.textContent).then((result: HTMLElement) => {
35
- e.innerHTML = result.outerHTML;
36
- }).catch((error) => {
37
- e.innerHTML = `graphviz render error: <br>${error}`;
38
- e.className = "vditor-reset--error";
39
- });
35
+ new Viz({ worker })
36
+ .renderSVGElement(code).then((result: HTMLElement) => {
37
+ e.innerHTML = result.outerHTML;
38
+ }).catch((error) => {
39
+ e.innerHTML = `graphviz render error: <br>${error}`;
40
+ e.className = "vditor-reset--error";
41
+ });
40
42
  } catch (e) {
41
43
  console.error("graphviz error", e);
42
44
  }
@@ -2,6 +2,7 @@ import {Constants} from "../constants";
2
2
  import {addScript, addScriptSync} from "../util/addScript";
3
3
  import {addStyle} from "../util/addStyle";
4
4
  import {code160to32} from "../util/code160to32";
5
+ import {mathRenderAdapter} from "./adapterRender";
5
6
 
6
7
  declare const katex: {
7
8
  renderToString(math: string, option: {
@@ -17,7 +18,7 @@ declare global {
17
18
  }
18
19
 
19
20
  export const mathRender = (element: HTMLElement, options?: { cdn?: string, math?: IMath }) => {
20
- const mathElements = element.querySelectorAll(".language-math");
21
+ const mathElements = mathRenderAdapter.getElements(element);
21
22
 
22
23
  if (mathElements.length === 0) {
23
24
  return;
@@ -49,7 +50,7 @@ export const mathRender = (element: HTMLElement, options?: { cdn?: string, math?
49
50
  if (mathElement.getAttribute("data-math")) {
50
51
  return;
51
52
  }
52
- const math = code160to32(mathElement.textContent);
53
+ const math = code160to32(mathRenderAdapter.getCode(mathElement));
53
54
  mathElement.setAttribute("data-math", math);
54
55
  try {
55
56
  mathElement.innerHTML = katex.renderToString(math, {
@@ -87,7 +88,7 @@ export const mathRender = (element: HTMLElement, options?: { cdn?: string, math?
87
88
  if (!window.MathJax) {
88
89
  window.MathJax = {
89
90
  loader: {
90
- paths: {mathjax: `${options.cdn}/dist/js/mathjax`},
91
+ paths: { mathjax: `${options.cdn}/dist/js/mathjax` },
91
92
  },
92
93
  startup: {
93
94
  typeset: false,
@@ -120,7 +121,7 @@ export const mathRender = (element: HTMLElement, options?: { cdn?: string, math?
120
121
  });
121
122
  };
122
123
  window.MathJax.startup.promise.then(() => {
123
- const chains: any [] = [];
124
+ const chains: any[] = [];
124
125
  for (let i = 0; i < mathElements.length; i++) {
125
126
  const mathElement = mathElements[i];
126
127
  if (!mathElement.parentElement.classList.contains("vditor-wysiwyg__pre") &&
@@ -1,5 +1,6 @@
1
1
  import {Constants} from "../constants";
2
2
  import {addScript} from "../util/addScript";
3
+ import {mermaidRenderAdapter} from "./adapterRender";
3
4
 
4
5
  declare const mermaid: {
5
6
  initialize(options: any): void,
@@ -7,7 +8,7 @@ declare const mermaid: {
7
8
  };
8
9
 
9
10
  export const mermaidRender = (element: HTMLElement, cdn = Constants.CDN, theme: string) => {
10
- const mermaidElements = element.querySelectorAll(".language-mermaid");
11
+ const mermaidElements = mermaidRenderAdapter.getElements(element);
11
12
  if (mermaidElements.length === 0) {
12
13
  return;
13
14
  }
@@ -115,7 +116,8 @@ export const mermaidRender = (element: HTMLElement, cdn = Constants.CDN, theme:
115
116
  }
116
117
  mermaid.initialize(config);
117
118
  mermaidElements.forEach((item) => {
118
- if (item.getAttribute("data-processed") === "true" || item.textContent.trim() === "") {
119
+ const code = mermaidRenderAdapter.getCode(item);
120
+ if (item.getAttribute("data-processed") === "true" || code.trim() === "") {
119
121
  return;
120
122
  }
121
123
  mermaid.init(undefined, item);
@@ -1,12 +1,13 @@
1
1
  import {Constants} from "../constants";
2
2
  import {addScript} from "../util/addScript";
3
+ import {mindmapRenderAdapter} from "./adapterRender";
3
4
 
4
5
  declare const echarts: {
5
6
  init(element: HTMLElement, theme?: string): IEChart;
6
7
  };
7
8
 
8
9
  export const mindmapRender = (element: (HTMLElement | Document) = document, cdn = Constants.CDN, theme: string) => {
9
- const mindmapElements = element.querySelectorAll(".language-mindmap");
10
+ const mindmapElements = mindmapRenderAdapter.getElements(element);
10
11
  if (mindmapElements.length > 0) {
11
12
  addScript(`${cdn}/dist/js/echarts/echarts.min.js`, "vditorEchartsScript").then(() => {
12
13
  mindmapElements.forEach((e: HTMLDivElement) => {
@@ -14,7 +15,7 @@ export const mindmapRender = (element: (HTMLElement | Document) = document, cdn
14
15
  e.parentElement.classList.contains("vditor-ir__marker--pre")) {
15
16
  return;
16
17
  }
17
- const text = e.getAttribute("data-code");
18
+ const text = mindmapRenderAdapter.getCode(e);
18
19
  if (!text) {
19
20
  return;
20
21
  }
@@ -1,12 +1,13 @@
1
1
  import {Constants} from "../constants";
2
2
  import {addScript} from "../util/addScript";
3
+ import {plantumlRenderAdapter} from "./adapterRender";
3
4
 
4
5
  declare const plantumlEncoder: {
5
6
  encode(options: string): string,
6
7
  };
7
8
 
8
9
  export const plantumlRender = (element: (HTMLElement | Document) = document, cdn = Constants.CDN) => {
9
- const plantumlElements = element.querySelectorAll(".language-plantuml");
10
+ const plantumlElements = plantumlRenderAdapter.getElements(element);
10
11
  if (plantumlElements.length === 0) {
11
12
  return;
12
13
  }
@@ -16,7 +17,7 @@ export const plantumlRender = (element: (HTMLElement | Document) = document, cdn
16
17
  e.parentElement.classList.contains("vditor-ir__marker--pre")) {
17
18
  return;
18
19
  }
19
- const text = e.textContent.trim();
20
+ const text = plantumlRenderAdapter.getCode(e).trim();
20
21
  if (!text) {
21
22
  return;
22
23
  }
@@ -1,6 +1,6 @@
1
1
  import {Constants} from "../constants";
2
2
  import {setContentTheme} from "../ui/setContentTheme";
3
- import {addScript} from "../util/addScript";
3
+ import {addScript, addScriptSync} from "../util/addScript";
4
4
  import {hasClosestByClassName, hasClosestByMatchTag} from "../util/hasClosest";
5
5
  import {merge} from "../util/merge";
6
6
  import {abcRender} from "./abcRender";
@@ -24,7 +24,9 @@ const mergeOptions = (options?: IPreviewOptions) => {
24
24
  anchor: 0,
25
25
  cdn: Constants.CDN,
26
26
  customEmoji: {},
27
- emojiPath: `${(options && options.emojiPath) || Constants.CDN}/dist/images/emoji`,
27
+ emojiPath: `${
28
+ (options && options.emojiPath) || Constants.CDN
29
+ }/dist/images/emoji`,
28
30
  hljs: Constants.HLJS_OPTIONS,
29
31
  icon: "ant",
30
32
  lang: "zh_CN",
@@ -81,11 +83,31 @@ export const previewRender = async (previewElement: HTMLDivElement, markdown: st
81
83
  }
82
84
  previewElement.innerHTML = html;
83
85
  previewElement.classList.add("vditor-reset");
86
+
87
+ if (!mergedOptions.i18n) {
88
+ if (!["en_US", "ja_JP", "ko_KR", "ru_RU", "zh_CN", "zh_TW"].includes(mergedOptions.lang)) {
89
+ throw new Error(
90
+ "options.lang error, see https://ld246.com/article/1549638745630#options",
91
+ );
92
+ } else {
93
+ const i18nScriptPrefix = "vditorI18nScript";
94
+ const i18nScriptID = i18nScriptPrefix + mergedOptions.lang;
95
+ document.querySelectorAll(`head script[id^="${i18nScriptPrefix}"]`).forEach((el) => {
96
+ if (el.id !== i18nScriptID) {
97
+ document.head.removeChild(el);
98
+ }
99
+ });
100
+ await addScript(`${mergedOptions.cdn}/dist/js/i18n/${mergedOptions.lang}.js`, i18nScriptID);
101
+ }
102
+ } else {
103
+ window.VditorI18n = mergedOptions.i18n;
104
+ }
105
+
84
106
  setContentTheme(mergedOptions.theme.current, mergedOptions.theme.path);
85
107
  if (mergedOptions.anchor === 1) {
86
108
  previewElement.classList.add("vditor-reset--anchor");
87
109
  }
88
- codeRender(previewElement, mergedOptions.lang);
110
+ codeRender(previewElement);
89
111
  highlightRender(mergedOptions.hljs, previewElement, mergedOptions.cdn);
90
112
  mathRender(previewElement, {
91
113
  cdn: mergedOptions.cdn,
@@ -100,7 +122,7 @@ export const previewRender = async (previewElement: HTMLDivElement, markdown: st
100
122
  abcRender(previewElement, mergedOptions.cdn);
101
123
  mediaRender(previewElement);
102
124
  if (mergedOptions.speech.enable) {
103
- speechRender(previewElement, mergedOptions.lang);
125
+ speechRender(previewElement);
104
126
  }
105
127
  if (mergedOptions.anchor !== 0) {
106
128
  anchorRender(mergedOptions.anchor);
@@ -1,5 +1,3 @@
1
- import {i18n} from "../i18n";
2
-
3
1
  export const previewImage = (oldImgElement: HTMLImageElement, lang: keyof II18n = "zh_CN", theme = "classic") => {
4
2
  const oldImgRect = oldImgElement.getBoundingClientRect();
5
3
  const height = 36;
@@ -7,10 +5,10 @@ export const previewImage = (oldImgElement: HTMLImageElement, lang: keyof II18n
7
5
  <div class="vditor-img__bar">
8
6
  <span class="vditor-img__btn" data-deg="0">
9
7
  <svg><use xlink:href="#vditor-icon-redo"></use></svg>
10
- ${i18n[lang].spin}
8
+ ${window.VditorI18n.spin}
11
9
  </span>
12
10
  <span class="vditor-img__btn" onclick="this.parentElement.parentElement.outerHTML = '';document.body.style.overflow = ''">
13
- X &nbsp;${i18n[lang].close}
11
+ X &nbsp;${window.VditorI18n.close}
14
12
  </span>
15
13
  </div>
16
14
  <div class="vditor-img__img" onclick="this.parentElement.outerHTML = '';document.body.style.overflow = ''">
@@ -1,4 +1,3 @@
1
- import {i18n} from "../i18n/index";
2
1
  import {abcRender} from "../markdown/abcRender";
3
2
  import {chartRender} from "../markdown/chartRender";
4
3
  import {codeRender} from "../markdown/codeRender";
@@ -24,7 +23,6 @@ export class Preview {
24
23
  constructor(vditor: IVditor) {
25
24
  this.element = document.createElement("div");
26
25
  this.element.className = `vditor-preview`;
27
-
28
26
  const previewElement = document.createElement("div");
29
27
  previewElement.className = "vditor-reset";
30
28
  if (vditor.options.classes.preview) {
@@ -199,8 +197,7 @@ export class Preview {
199
197
  const time = (new Date().getTime() - startTime);
200
198
  if ((new Date().getTime() - startTime) > 2600) {
201
199
  // https://github.com/b3log/vditor/issues/67
202
- vditor.tip.show(i18n[vditor.options.lang].performanceTip.replace("${x}",
203
- time.toString()));
200
+ vditor.tip.show(window.VditorI18n.performanceTip.replace("${x}", time.toString()));
204
201
  vditor.preview.element.setAttribute("data-type", "renderPerformance");
205
202
  } else if (vditor.preview.element.getAttribute("data-type") === "renderPerformance") {
206
203
  vditor.tip.hide();
@@ -210,7 +207,7 @@ export class Preview {
210
207
  if (cmtFocusElement) {
211
208
  cmtFocusElement.classList.remove("vditor-comment--focus");
212
209
  }
213
- codeRender(vditor.preview.element.lastElementChild as HTMLElement, vditor.options.lang);
210
+ codeRender(vditor.preview.element.lastElementChild as HTMLElement);
214
211
  highlightRender(vditor.options.preview.hljs, vditor.preview.element.lastElementChild as HTMLElement,
215
212
  vditor.options.cdn);
216
213
  mermaidRender(vditor.preview.element.lastElementChild as HTMLElement, vditor.options.cdn, vditor.options.theme);
@@ -1,5 +1,4 @@
1
1
  import {Constants} from "../constants";
2
- import {i18n} from "../i18n";
3
2
  import {processAfterRender} from "../ir/process";
4
3
  import {getMarkdown} from "../markdown/getMarkdown";
5
4
  import {mathRender} from "../markdown/mathRender";
@@ -157,9 +156,9 @@ export class EditMode extends MenuItem {
157
156
 
158
157
  const panelElement = document.createElement("div");
159
158
  panelElement.className = `vditor-hint${menuItem.level === 2 ? "" : " vditor-panel--arrow"}`;
160
- panelElement.innerHTML = `<button data-mode="wysiwyg">${i18n[vditor.options.lang].wysiwyg} &lt;${updateHotkeyTip("⌥⌘7")}></button>
161
- <button data-mode="ir">${i18n[vditor.options.lang].instantRendering} &lt;${updateHotkeyTip("⌥⌘8")}></button>
162
- <button data-mode="sv">${i18n[vditor.options.lang].splitView} &lt;${updateHotkeyTip("⌥⌘9")}></button>`;
159
+ panelElement.innerHTML = `<button data-mode="wysiwyg">${window.VditorI18n.wysiwyg} &lt;${updateHotkeyTip("⌥⌘7")}></button>
160
+ <button data-mode="ir">${window.VditorI18n.instantRendering} &lt;${updateHotkeyTip("⌥⌘8")}></button>
161
+ <button data-mode="sv">${window.VditorI18n.splitView} &lt;${updateHotkeyTip("⌥⌘9")}></button>`;
163
162
 
164
163
  this.element.appendChild(panelElement);
165
164
 
@@ -15,12 +15,12 @@ export class Headings extends MenuItem {
15
15
 
16
16
  const panelElement = document.createElement("div");
17
17
  panelElement.className = "vditor-hint vditor-panel--arrow";
18
- panelElement.innerHTML = `<button data-tag="h1" data-value="# ">Heading 1 ${updateHotkeyTip("&lt;⌥⌘1>")}</button>
19
- <button data-tag="h2" data-value="## ">Heading 2 &lt;${updateHotkeyTip("⌥⌘2")}></button>
20
- <button data-tag="h3" data-value="### ">Heading 3 &lt;${updateHotkeyTip("⌥⌘3")}></button>
21
- <button data-tag="h4" data-value="#### ">Heading 4 &lt;${updateHotkeyTip("⌥⌘4")}></button>
22
- <button data-tag="h5" data-value="##### ">Heading 5 &lt;${updateHotkeyTip("⌥⌘5")}></button>
23
- <button data-tag="h6" data-value="###### ">Heading 6 &lt;${updateHotkeyTip("⌥⌘6")}></button>`;
18
+ panelElement.innerHTML = `<button data-tag="h1" data-value="# ">${window.VditorI18n.heading1} ${updateHotkeyTip("&lt;⌥⌘1>")}</button>
19
+ <button data-tag="h2" data-value="## ">${window.VditorI18n.heading2} &lt;${updateHotkeyTip("⌥⌘2")}></button>
20
+ <button data-tag="h3" data-value="### ">${window.VditorI18n.heading3} &lt;${updateHotkeyTip("⌥⌘3")}></button>
21
+ <button data-tag="h4" data-value="#### ">${window.VditorI18n.heading4} &lt;${updateHotkeyTip("⌥⌘4")}></button>
22
+ <button data-tag="h5" data-value="##### ">${window.VditorI18n.heading5} &lt;${updateHotkeyTip("⌥⌘5")}></button>
23
+ <button data-tag="h6" data-value="###### ">${window.VditorI18n.heading6} &lt;${updateHotkeyTip("⌥⌘6")}></button>`;
24
24
 
25
25
  this.element.appendChild(panelElement);
26
26
 
@@ -16,7 +16,7 @@ export class Info extends MenuItem {
16
16
  <div>&nbsp;&nbsp;</div>
17
17
  <div style="flex: 1;min-width: 250px">
18
18
  Vditor 是一款浏览器端的 Markdown 编辑器,支持所见即所得、即时渲染(类似 Typora)和分屏预览模式。
19
- 它使用 TypeScript 实现,支持原生 JavaScript、Vue、React、Angular,提供<a target="_blank" href="https://b3log.org/siyuan">桌面版</a>。
19
+ 它使用 TypeScript 实现,支持原生 JavaScript 以及 Vue、React、Angular 和 Svelte 等框架。
20
20
  </div>
21
21
  </div>
22
22
  <div style="display: flex;flex-wrap: wrap;">
@@ -1,5 +1,4 @@
1
1
  import {Constants} from "../constants";
2
- import {i18n} from "../i18n/index";
3
2
  import {processToolbar} from "../ir/process";
4
3
  import {processToolbar as processToolbarSV} from "../sv/process";
5
4
  import {getEventName} from "../util/compatibility";
@@ -19,8 +18,7 @@ export class MenuItem {
19
18
  if (menuItem.level === 2) {
20
19
  hotkey = menuItem.hotkey ? ` &lt;${updateHotkeyTip(menuItem.hotkey)}&gt;` : "";
21
20
  }
22
- const tip = menuItem.tip ?
23
- menuItem.tip + hotkey : i18n[vditor.options.lang][menuItem.name] + hotkey;
21
+ const tip = menuItem.tip ? menuItem.tip + hotkey : `${window.VditorI18n[menuItem.name]}${hotkey}`;
24
22
  const tagName = menuItem.name === "upload" ? "div" : "button";
25
23
  if (menuItem.level === 2) {
26
24
  this.element.innerHTML = `<${tagName} data-type="${menuItem.name}">${tip}</${tagName}>`;
@@ -1,5 +1,4 @@
1
1
  import {Constants} from "../constants";
2
- import {i18n} from "../i18n/index";
3
2
  import {uploadFiles} from "../upload/index";
4
3
  import {getEventName} from "../util/compatibility";
5
4
  import {RecordMedia} from "../util/RecordMedia";
@@ -34,11 +33,11 @@ export class Record extends MenuItem {
34
33
  mediaRecorder.cloneChannelData(left, right);
35
34
  };
36
35
  mediaRecorder.startRecordingNewWavFile();
37
- vditor.tip.show(i18n[vditor.options.lang].recording);
36
+ vditor.tip.show(window.VditorI18n.recording);
38
37
  editorElement.setAttribute("contenteditable", "false");
39
38
  this.element.children[0].classList.add("vditor-menu--current");
40
39
  }).catch(() => {
41
- vditor.tip.show(i18n[vditor.options.lang]["record-tip"]);
40
+ vditor.tip.show(window.VditorI18n["record-tip"]);
42
41
  });
43
42
  return;
44
43
  }
@@ -51,7 +50,7 @@ export class Record extends MenuItem {
51
50
  uploadFiles(vditor, [file]);
52
51
  this.element.children[0].classList.remove("vditor-menu--current");
53
52
  } else {
54
- vditor.tip.show(i18n[vditor.options.lang].recording);
53
+ vditor.tip.show(window.VditorI18n.recording);
55
54
  editorElement.setAttribute("contenteditable", "false");
56
55
  mediaRecorder.startRecordingNewWavFile();
57
56
  this.element.children[0].classList.add("vditor-menu--current");
@@ -1,5 +1,6 @@
1
1
  import {Constants} from "../constants";
2
2
  import {setEditMode} from "../toolbar/EditMode";
3
+ import {hidePanel} from "../toolbar/setToolbar";
3
4
  import {accessLocalStorage} from "../util/compatibility";
4
5
  import {setContentTheme} from "./setContentTheme";
5
6
  import {setTheme} from "./setTheme";
@@ -67,13 +68,17 @@ export const initUI = (vditor: IVditor) => {
67
68
 
68
69
  vditor.element.appendChild(contentElement);
69
70
 
71
+ contentElement.addEventListener("click", () => {
72
+ hidePanel(vditor, ["subToolbar"]);
73
+ });
74
+
70
75
  if (vditor.toolbar.elements.export) {
71
76
  // for export pdf
72
77
  vditor.element.insertAdjacentHTML("beforeend",
73
78
  '<iframe style="width: 100%;height: 0;border: 0"></iframe>');
74
79
  }
75
80
 
76
- setEditMode(vditor, vditor.options.mode, afterRender(vditor, contentElement));
81
+ setEditMode(vditor, vditor.options.mode, afterRender(vditor));
77
82
 
78
83
  document.execCommand("DefaultParagraphSeparator", false, "p");
79
84
 
@@ -114,10 +119,13 @@ export const setPadding = (vditor: IVditor) => {
114
119
  vditor.ir.element.style.padding = `10px ${Math.max(minPadding, padding)}px`;
115
120
  }
116
121
 
117
- if (vditor.preview.element.style.display !== "block" || vditor.currentMode === "sv") {
122
+ if (vditor.preview.element.style.display !== "block") {
118
123
  vditor.toolbar.element.style.paddingLeft = Math.max(5,
119
124
  parseInt(vditor[vditor.currentMode].element.style.paddingLeft || "0", 10) +
120
125
  (vditor.options.outline.position === "left" ? vditor.outline.element.offsetWidth : 0)) + "px";
126
+ } else {
127
+ vditor.toolbar.element.style.paddingLeft = (5 +
128
+ (vditor.options.outline.position === "left" ? vditor.outline.element.offsetWidth : 0)) + "px";
121
129
  }
122
130
  };
123
131
 
@@ -141,10 +149,16 @@ export const setTypewriterPosition = (vditor: IVditor) => {
141
149
  ((height - vditor.toolbar.element.offsetHeight) / 2) + "px");
142
150
  };
143
151
 
144
- const afterRender = (vditor: IVditor, contentElement: HTMLElement) => {
145
- setTypewriterPosition(vditor);
152
+ let resizeCb: () => void;
153
+
154
+ export function UIUnbindListener() {
155
+ window.removeEventListener("resize", resizeCb);
156
+ }
146
157
 
147
- window.addEventListener("resize", () => {
158
+ const afterRender = (vditor: IVditor) => {
159
+ setTypewriterPosition(vditor);
160
+ UIUnbindListener();
161
+ window.addEventListener("resize", resizeCb = () => {
148
162
  setPadding(vditor);
149
163
  setTypewriterPosition(vditor);
150
164
  });
@@ -1,4 +1,3 @@
1
- import {i18n} from "../i18n/index";
2
1
  import {getEditorRange, setSelectionFocus} from "../util/selection";
3
2
  import {getElement} from "./getElement";
4
3
  import {setHeaders} from "./setHeaders";
@@ -20,19 +19,20 @@ const validateFile = (vditor: IVditor, files: File[]) => {
20
19
  const uploadFileList = [];
21
20
  let errorTip = "";
22
21
  let uploadingStr = "";
23
- const lang: keyof II18n = vditor.options.lang;
22
+ const lang: keyof II18n | "" = vditor.options.lang;
23
+ const options: IOptions = vditor.options;
24
24
 
25
25
  for (let iMax = files.length, i = 0; i < iMax; i++) {
26
26
  const file = files[i];
27
27
  let validate = true;
28
28
 
29
29
  if (!file.name) {
30
- errorTip += `<li>${i18n[lang].nameEmpty}</li>`;
30
+ errorTip += `<li>${window.VditorI18n.nameEmpty}</li>`;
31
31
  validate = false;
32
32
  }
33
33
 
34
34
  if (file.size > vditor.options.upload.max) {
35
- errorTip += `<li>${file.name} ${i18n[lang].over} ${vditor.options.upload.max / 1024 / 1024}M</li>`;
35
+ errorTip += `<li>${file.name} ${window.VditorI18n.over} ${vditor.options.upload.max / 1024 / 1024}M</li>`;
36
36
  validate = false;
37
37
  }
38
38
 
@@ -56,14 +56,14 @@ const validateFile = (vditor: IVditor, files: File[]) => {
56
56
  });
57
57
 
58
58
  if (!isAccept) {
59
- errorTip += `<li>${file.name} ${i18n[lang].fileTypeError}</li>`;
59
+ errorTip += `<li>${file.name} ${window.VditorI18n.fileTypeError}</li>`;
60
60
  validate = false;
61
61
  }
62
62
  }
63
63
 
64
64
  if (validate) {
65
65
  uploadFileList.push(file);
66
- uploadingStr += `<li>${filename} ${i18n[lang].uploading}</li>`;
66
+ uploadingStr += `<li>${filename} ${window.VditorI18n.uploading}</li>`;
67
67
  }
68
68
  }
69
69
 
@@ -87,7 +87,7 @@ const genUploadedLabel = (responseText: string, vditor: IVditor) => {
87
87
  response.data.errFiles.forEach((data: string) => {
88
88
  const lastIndex = data.lastIndexOf(".");
89
89
  const filename = vditor.options.upload.filename(data.substr(0, lastIndex)) + data.substr(lastIndex);
90
- errorTip += `<li>${filename} ${i18n[vditor.options.lang].uploadError}</li>`;
90
+ errorTip += `<li>${filename} ${window.VditorI18n.uploadError}</li>`;
91
91
  });
92
92
  errorTip += "</ul>";
93
93
  }
@@ -108,7 +108,7 @@ const genUploadedLabel = (responseText: string, vditor: IVditor) => {
108
108
  if (type.indexOf(".wav") === 0 || type.indexOf(".mp3") === 0 || type.indexOf(".ogg") === 0) {
109
109
  if (vditor.currentMode === "wysiwyg") {
110
110
  succFileText += `<div class="vditor-wysiwyg__block" data-type="html-block"
111
- data-block="0"><pre><code>&lt;audio controls="controls" src="${path}"&gt;&lt;/audio&gt;</code></pre>`;
111
+ data-block="0"><pre><code>&lt;audio controls="controls" src="${path}"&gt;&lt;/audio&gt;</code></pre>\n`;
112
112
  } else if (vditor.currentMode === "ir") {
113
113
  succFileText += `<audio controls="controls" src="${path}"></audio>\n`;
114
114
  } else {
@@ -123,13 +123,13 @@ const genUploadedLabel = (responseText: string, vditor: IVditor) => {
123
123
  || type.indexOf(".svg") === 0
124
124
  || type.indexOf(".webp") === 0) {
125
125
  if (vditor.currentMode === "wysiwyg") {
126
- succFileText += `<img alt="${filename}" src="${path}">`;
126
+ succFileText += `<img alt="${filename}" src="${path}">\n`;
127
127
  } else {
128
128
  succFileText += `![${filename}](${path})\n`;
129
129
  }
130
130
  } else {
131
131
  if (vditor.currentMode === "wysiwyg") {
132
- succFileText += `<a href="${path}">${filename}</a>`;
132
+ succFileText += `<a href="${path}">${filename}</a>\n`;
133
133
  } else {
134
134
  succFileText += `[${filename}](${path})\n`;
135
135
  }
@@ -154,7 +154,7 @@ const uploadFiles =
154
154
  }
155
155
 
156
156
  if (vditor.options.upload.handler) {
157
- const isValidate = vditor.options.upload.handler(fileList);
157
+ const isValidate = await vditor.options.upload.handler(fileList);
158
158
  if (typeof isValidate === "string") {
159
159
  vditor.tip.show(isValidate);
160
160
  return;