vditor 3.8.6 → 3.8.10

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.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Vditor v3.8.6 - A markdown editor written in TypeScript.
2
+ * Vditor v3.8.10 - A markdown editor written in TypeScript.
3
3
  *
4
4
  * MIT License
5
5
  *
@@ -45,7 +45,7 @@ return /******/ (() => { // webpackBootstrap
45
45
  /* harmony export */ "g": () => (/* binding */ Constants)
46
46
  /* harmony export */ });
47
47
  /* unused harmony export VDITOR_VERSION */
48
- var _VDITOR_VERSION = (/* unused pure expression or super */ null && ("3.8.6"));
48
+ var _VDITOR_VERSION = (/* unused pure expression or super */ null && ("3.8.10"));
49
49
 
50
50
  var Constants = /** @class */ (function () {
51
51
  function Constants() {
@@ -71,7 +71,7 @@ var Constants = /** @class */ (function () {
71
71
  "swift", "ini", "typescript", "vbnet", "yaml",
72
72
  "ada", "clojure", "dart", "erb", "fortran", "gradle", "haskell", "julia", "julia-repl", "lisp", "matlab",
73
73
  "pgsql", "powershell", "sql_more", "stata", "cmake", "mathematica"];
74
- Constants.CDN = "https://cdn.jsdelivr.net/npm/vditor@" + "3.8.6";
74
+ Constants.CDN = "https://cdn.jsdelivr.net/npm/vditor@" + "3.8.10";
75
75
  Constants.MARKDOWN_OPTIONS = {
76
76
  autoSpace: false,
77
77
  codeBlockPreview: true,
@@ -258,6 +258,7 @@ var chartRender = function (element, cdn, theme) {
258
258
 
259
259
  var codeRender = function (element) {
260
260
  element.querySelectorAll("pre > code").forEach(function (e, index) {
261
+ var _a, _b, _c;
261
262
  if (e.parentElement.classList.contains("vditor-wysiwyg__pre") ||
262
263
  e.parentElement.classList.contains("vditor-ir__marker--pre")) {
263
264
  return;
@@ -285,10 +286,13 @@ var codeRender = function (element) {
285
286
  });
286
287
  codeText = codeElement.innerText;
287
288
  }
289
+ var iconHTML = '<svg><use xlink:href="#vditor-icon-copy"></use></svg>';
290
+ if (!document.getElementById("vditorIconScript")) {
291
+ iconHTML = '<svg viewBox="0 0 32 32"><path d="M22.545-0h-17.455c-1.6 0-2.909 1.309-2.909 2.909v20.364h2.909v-20.364h17.455v-2.909zM26.909 5.818h-16c-1.6 0-2.909 1.309-2.909 2.909v20.364c0 1.6 1.309 2.909 2.909 2.909h16c1.6 0 2.909-1.309 2.909-2.909v-20.364c0-1.6-1.309-2.909-2.909-2.909zM26.909 29.091h-16v-20.364h16v20.364z"></path></svg>';
292
+ }
288
293
  var divElement = document.createElement("div");
289
294
  divElement.className = "vditor-copy";
290
- divElement.innerHTML = "<span aria-label=\"" + window.VditorI18n.copy + "\"\nonmouseover=\"this.setAttribute('aria-label', '" + window.VditorI18n.copy + "')\"\nclass=\"vditor-tooltipped vditor-tooltipped__w\"\nonclick=\"this.previousElementSibling.select();document.execCommand('copy');" +
291
- ("this.setAttribute('aria-label', '" + window.VditorI18n.copied + "')\"><svg><use xlink:href=\"#vditor-icon-copy\"></use></svg></span>");
295
+ divElement.innerHTML = "<span aria-label=\"" + (((_a = window.VditorI18n) === null || _a === void 0 ? void 0 : _a.copy) || "复制") + "\"\nonmouseover=\"this.setAttribute('aria-label', '" + (((_b = window.VditorI18n) === null || _b === void 0 ? void 0 : _b.copy) || "复制") + "')\"\nclass=\"vditor-tooltipped vditor-tooltipped__w\"\nonclick=\"this.previousElementSibling.select();document.execCommand('copy');this.setAttribute('aria-label', '" + (((_c = window.VditorI18n) === null || _c === void 0 ? void 0 : _c.copy) || "已复制") + "')\">" + iconHTML + "</span>";
292
296
  var textarea = document.createElement("textarea");
293
297
  textarea.value = (0,_util_code160to32__WEBPACK_IMPORTED_MODULE_0__/* .code160to32 */ .X)(codeText);
294
298
  divElement.insertAdjacentElement("afterbegin", textarea);
@@ -965,7 +969,11 @@ var outlineRender = function (contentElement, targetElement, vditor) {
965
969
  var headingsElement = tempElement.firstElementChild.querySelectorAll("li > span[data-target-id]");
966
970
  headingsElement.forEach(function (item, index) {
967
971
  if (item.nextElementSibling && item.nextElementSibling.tagName === "UL") {
968
- item.innerHTML = "<svg class='vditor-outline__action'><use xlink:href='#vditor-icon-down'></use></svg><span>" + item.innerHTML + "</span>";
972
+ var iconHTML = "<svg class='vditor-outline__action'><use xlink:href='#vditor-icon-down'></use></svg>";
973
+ if (!document.getElementById("vditorIconScript")) {
974
+ iconHTML = '<svg class="vditor-outline__action" viewBox="0 0 32 32"><path d="M3.76 6.12l12.24 12.213 12.24-12.213 3.76 3.76-16 16-16-16 3.76-3.76z"></path></svg>';
975
+ }
976
+ item.innerHTML = iconHTML + "<span>" + item.innerHTML + "</span>";
969
977
  }
970
978
  else {
971
979
  item.innerHTML = "<svg></svg><span>" + item.innerHTML + "</span>";
@@ -2003,6 +2011,10 @@ var speechRender = function (element, lang) {
2003
2011
  }
2004
2012
  var playSVG = '<svg><use xlink:href="#vditor-icon-play"></use></svg>';
2005
2013
  var pauseSVG = '<svg><use xlink:href="#vditor-icon-pause"></use></svg>';
2014
+ if (!document.getElementById("vditorIconScript")) {
2015
+ playSVG = '<svg viewBox="0 0 32 32"><path d="M3.436 0l25.128 16-25.128 16v-32z"></path></svg>';
2016
+ pauseSVG = '<svg viewBox="0 0 32 32"><path d="M20.617 0h9.128v32h-9.128v-32zM2.255 32v-32h9.128v32h-9.128z"></path></svg>';
2017
+ }
2006
2018
  var speechDom = document.querySelector(".vditor-speech");
2007
2019
  if (!speechDom) {
2008
2020
  speechDom = document.createElement("div");
@@ -2194,7 +2206,7 @@ var md2html = function (mdText, options) {
2194
2206
  });
2195
2207
  };
2196
2208
  var previewRender = function (previewElement, markdown, options) { return __awaiter(void 0, void 0, void 0, function () {
2197
- var mergedOptions, html;
2209
+ var mergedOptions, html, i18nScriptPrefix, i18nScriptID_1;
2198
2210
  return __generator(this, function (_a) {
2199
2211
  switch (_a.label) {
2200
2212
  case 0:
@@ -2207,17 +2219,32 @@ var previewRender = function (previewElement, markdown, options) { return __awai
2207
2219
  }
2208
2220
  previewElement.innerHTML = html;
2209
2221
  previewElement.classList.add("vditor-reset");
2210
- if (!mergedOptions.i18n) {
2211
- if (!["en_US", "ja_JP", "ko_KR", "ru_RU", "zh_CN", "zh_TW"].includes(mergedOptions.lang)) {
2212
- throw new Error("options.lang error, see https://ld246.com/article/1549638745630#options");
2213
- }
2214
- else {
2215
- (0,addScript/* addScriptSync */.J)(mergedOptions.cdn + "/dist/js/i18n/" + mergedOptions.lang + ".js", "vditorI18nScript");
2222
+ if (!!mergedOptions.i18n) return [3 /*break*/, 5];
2223
+ if (!!["en_US", "ja_JP", "ko_KR", "ru_RU", "zh_CN", "zh_TW"].includes(mergedOptions.lang)) return [3 /*break*/, 2];
2224
+ throw new Error("options.lang error, see https://ld246.com/article/1549638745630#options");
2225
+ case 2:
2226
+ i18nScriptPrefix = "vditorI18nScript";
2227
+ i18nScriptID_1 = i18nScriptPrefix + mergedOptions.lang;
2228
+ document.querySelectorAll("head script[id^=\"" + i18nScriptPrefix + "\"]").forEach(function (el) {
2229
+ if (el.id !== i18nScriptID_1) {
2230
+ document.head.removeChild(el);
2216
2231
  }
2217
- }
2218
- else {
2219
- window.VditorI18n = mergedOptions.i18n;
2220
- }
2232
+ });
2233
+ return [4 /*yield*/, (0,addScript/* addScript */.G)(mergedOptions.cdn + "/dist/js/i18n/" + mergedOptions.lang + ".js", i18nScriptID_1)];
2234
+ case 3:
2235
+ _a.sent();
2236
+ _a.label = 4;
2237
+ case 4: return [3 /*break*/, 6];
2238
+ case 5:
2239
+ window.VditorI18n = mergedOptions.i18n;
2240
+ _a.label = 6;
2241
+ case 6:
2242
+ if (!mergedOptions.icon) return [3 /*break*/, 8];
2243
+ return [4 /*yield*/, (0,addScript/* addScript */.G)(mergedOptions.cdn + "/dist/js/icons/" + mergedOptions.icon + ".js", "vditorIconScript")];
2244
+ case 7:
2245
+ _a.sent();
2246
+ _a.label = 8;
2247
+ case 8:
2221
2248
  (0,setContentTheme/* setContentTheme */.Z)(mergedOptions.theme.current, mergedOptions.theme.path);
2222
2249
  if (mergedOptions.anchor === 1) {
2223
2250
  previewElement.classList.add("vditor-reset--anchor");
@@ -2248,9 +2275,6 @@ var previewRender = function (previewElement, markdown, options) { return __awai
2248
2275
  if (mergedOptions.lazyLoadImage) {
2249
2276
  lazyLoadImageRender(previewElement);
2250
2277
  }
2251
- if (mergedOptions.icon) {
2252
- (0,addScript/* addScript */.G)(mergedOptions.cdn + "/dist/js/icons/" + mergedOptions.icon + ".js", "vditorIconScript");
2253
- }
2254
2278
  previewElement.addEventListener("click", function (event) {
2255
2279
  var spanElement = (0,hasClosest/* hasClosestByMatchTag */.lG)(event.target, "SPAN");
2256
2280
  if (spanElement && (0,hasClosest/* hasClosestByClassName */.fb)(spanElement, "vditor-toc")) {
@@ -2339,7 +2363,7 @@ var Vditor = /** @class */ (function () {
2339
2363
 
2340
2364
  })();
2341
2365
 
2342
- __webpack_exports__ = __webpack_exports__.default;
2366
+ __webpack_exports__ = __webpack_exports__["default"];
2343
2367
  /******/ return __webpack_exports__;
2344
2368
  /******/ })()
2345
2369
  ;
@@ -7,3 +7,4 @@ declare global {
7
7
  export declare const initUI: (vditor: IVditor) => void;
8
8
  export declare const setPadding: (vditor: IVditor) => void;
9
9
  export declare const setTypewriterPosition: (vditor: IVditor) => void;
10
+ export declare function UIUnbindListener(): void;
@@ -9,11 +9,13 @@ declare class WYSIWYG {
9
9
  preventInput: boolean;
10
10
  composingLock: boolean;
11
11
  commentIds: string[];
12
+ private scrollListener;
12
13
  constructor(vditor: IVditor);
13
14
  getComments(vditor: IVditor, getData?: boolean): ICommentsData[];
14
15
  triggerRemoveComment(vditor: IVditor): void;
15
16
  showComment(): void;
16
17
  hideComment(): void;
18
+ unbindListener(): void;
17
19
  private copy;
18
20
  private bindEvent;
19
21
  }
@@ -118,6 +118,8 @@ declare class Lute {
118
118
 
119
119
  public static NewNodeID(): string;
120
120
 
121
+ public static Sanitize(html: string): string;
122
+
121
123
  private constructor();
122
124
 
123
125
  public SetJSRenderers(options?: {
@@ -232,6 +234,7 @@ declare const webkitAudioContext: {
232
234
 
233
235
  interface ITips {
234
236
  [index: string]: string;
237
+
235
238
  alignCenter: string;
236
239
  alignLeft: string;
237
240
  alignRight: string;
@@ -369,7 +372,7 @@ interface IUpload {
369
372
  validate?(files: File[]): string | boolean;
370
373
 
371
374
  /** 自定义上传,当发生错误时返回错误信息 */
372
- handler?(files: File[]): string | null;
375
+ handler?(files: File[]): string | null | Promise<string> | Promise<null>;
373
376
 
374
377
  /** 对服务端返回的数据进行转换,以满足内置的数据结构 */
375
378
  format?(files: File[], responseText: string): string;
@@ -378,7 +381,7 @@ interface IUpload {
378
381
  linkToImgFormat?(responseText: string): string;
379
382
 
380
383
  /** 将上传的文件处理后再返回 */
381
- file?(files: File[]): File[];
384
+ file?(files: File[]): File[] | Promise<File[]>;
382
385
 
383
386
  /** 图片地址上传后的回调 */
384
387
  linkToImgCallback?(responseText: string): void;
@@ -534,7 +537,7 @@ interface IHintData {
534
537
  interface IHintExtend {
535
538
  key: string;
536
539
 
537
- hint?(value: string): IHintData[];
540
+ hint?(value: string): IHintData[] | Promise<IHintData[]>;
538
541
  }
539
542
 
540
543
  /** @link https://ld246.com/article/1549638745630#options-hint */
@@ -744,6 +747,7 @@ interface IVditor {
744
747
  triggerRemoveComment(vditor: IVditor): void,
745
748
  showComment(): void,
746
749
  hideComment(): void,
750
+ unbindListener(): void,
747
751
  };
748
752
  ir?: {
749
753
  range: Range,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vditor",
3
- "version": "3.8.6",
3
+ "version": "3.8.10",
4
4
  "description": "♏ 易于使用的 Markdown 编辑器,为适配不同的应用场景而生",
5
5
  "author": "Vanessa <v@b3log.org> (http://vanessa.b3log.org)",
6
6
  "homepage": "https://b3log.org/vditor",
@@ -34,10 +34,10 @@
34
34
  "identity-obj-proxy": "^3.0.0",
35
35
  "jest": "^26.6.3",
36
36
  "mini-css-extract-plugin": "^0.8.2",
37
- "node-sass": "^4.14.1",
37
+ "node-sass": "^7.0.0",
38
38
  "postcss-loader": "^5.2.0",
39
39
  "puppeteer": "^1.20.0",
40
- "sass-loader": "^10.2.0",
40
+ "sass-loader": "^12.4.0",
41
41
  "style-loader": "^1.3.0",
42
42
  "terser-webpack-plugin": "^5.1.2",
43
43
  "ts-jest": "^26.5.6",
@@ -47,7 +47,7 @@
47
47
  "webpack": "^5.37.0",
48
48
  "webpack-bundle-analyzer": "^3.9.0",
49
49
  "webpack-cli": "^4.7.0",
50
- "webpack-dev-server": "^3.11.2"
50
+ "webpack-dev-server": "^4.1.0"
51
51
  },
52
52
  "license": "MIT",
53
53
  "repository": "git://github.com/Vanessa219/vditor.git",
Binary file
package/src/index.ts CHANGED
@@ -19,7 +19,7 @@ import {Tip} from "./ts/tip/index";
19
19
  import {Toolbar} from "./ts/toolbar/index";
20
20
  import {disableToolbar, hidePanel} from "./ts/toolbar/setToolbar";
21
21
  import {enableToolbar} from "./ts/toolbar/setToolbar";
22
- import {initUI} from "./ts/ui/initUI";
22
+ import {initUI, UIUnbindListener} from "./ts/ui/initUI";
23
23
  import {setCodeTheme} from "./ts/ui/setCodeTheme";
24
24
  import {setContentTheme} from "./ts/ui/setContentTheme";
25
25
  import {setPreviewMode} from "./ts/ui/setPreviewMode";
@@ -73,7 +73,14 @@ class Vditor extends VditorMethod {
73
73
  "options.lang error, see https://ld246.com/article/1549638745630#options",
74
74
  );
75
75
  } else {
76
- addScript(`${mergedOptions.cdn}/dist/js/i18n/${mergedOptions.lang}.js`, "vditorI18nScript").then(() => {
76
+ const i18nScriptPrefix = "vditorI18nScript";
77
+ const i18nScriptID = i18nScriptPrefix + mergedOptions.lang;
78
+ document.querySelectorAll(`head script[id^="${i18nScriptPrefix}"]`).forEach((el) => {
79
+ if (el.id !== i18nScriptID) {
80
+ document.head.removeChild(el);
81
+ }
82
+ });
83
+ addScript(`${mergedOptions.cdn}/dist/js/i18n/${mergedOptions.lang}.js`, i18nScriptID).then(() => {
77
84
  this.init(id as HTMLElement, mergedOptions);
78
85
  });
79
86
  }
@@ -322,6 +329,9 @@ class Vditor extends VditorMethod {
322
329
  this.vditor.element.removeAttribute("style");
323
330
  document.getElementById("vditorIconScript").remove();
324
331
  this.clearCache();
332
+
333
+ UIUnbindListener();
334
+ this.vditor.wysiwyg.unbindListener();
325
335
  }
326
336
 
327
337
  /** 获取评论 ID */
package/src/ts/.DS_Store CHANGED
Binary file
@@ -59,8 +59,8 @@ export class Hint {
59
59
  vditor.options.hint.extend.forEach((item) => {
60
60
  if (item.key === this.splitChar) {
61
61
  clearTimeout(this.timeId);
62
- this.timeId = window.setTimeout(() => {
63
- this.genHTML(item.hint(key), key, vditor);
62
+ this.timeId = window.setTimeout(async () => {
63
+ this.genHTML(await item.hint(key), key, vditor);
64
64
  }, vditor.options.hint.delay);
65
65
  }
66
66
  });
@@ -148,15 +148,24 @@ ${i === 0 ? "class='vditor-hint--current'" : ""}> ${html}</button>`;
148
148
  return;
149
149
  }
150
150
  }
151
- if (vditor.currentMode === "wysiwyg" && range.startContainer.nodeType !== 3 &&
152
- (range.startContainer as HTMLElement).firstElementChild.classList.contains("vditor-input")) {
153
- const inputElement = (range.startContainer as HTMLElement).firstElementChild as HTMLInputElement;
154
- inputElement.value = value.trimRight();
155
- range.selectNodeContents(inputElement);
156
- range.collapse(false);
157
- inputElement.dispatchEvent(new CustomEvent("input"));
158
- this.recentLanguage = value.trimRight();
159
- return;
151
+ if (vditor.currentMode === "wysiwyg" && range.startContainer.nodeType !== 3 ) {
152
+ const startContainer = range.startContainer as HTMLElement;
153
+ let inputElement: HTMLInputElement;
154
+ if (startContainer.classList.contains("vditor-input")) {
155
+ inputElement = startContainer as HTMLInputElement;
156
+ } else {
157
+ inputElement = startContainer.firstElementChild as HTMLInputElement;
158
+ }
159
+ if (inputElement && inputElement.classList.contains("vditor-input")) {
160
+ inputElement.value = value.trimRight();
161
+ range.selectNodeContents(inputElement);
162
+ range.collapse(false);
163
+ // {detail: 1}用于标识这个自定义事件是在编程语言选择后触发的
164
+ // 用于在鼠标选择语言后,自动聚焦到代码输入框
165
+ inputElement.dispatchEvent(new CustomEvent("input", {detail: 1}));
166
+ this.recentLanguage = value.trimRight();
167
+ return;
168
+ }
160
169
  }
161
170
 
162
171
  range.setStart(range.startContainer, this.lastIndex);
@@ -33,13 +33,17 @@ export const codeRender = (element: HTMLElement) => {
33
33
  codeText = codeElement.innerText;
34
34
  }
35
35
 
36
+ let iconHTML = '<svg><use xlink:href="#vditor-icon-copy"></use></svg>';
37
+ if (!document.getElementById("vditorIconScript")) {
38
+ iconHTML = '<svg viewBox="0 0 32 32"><path d="M22.545-0h-17.455c-1.6 0-2.909 1.309-2.909 2.909v20.364h2.909v-20.364h17.455v-2.909zM26.909 5.818h-16c-1.6 0-2.909 1.309-2.909 2.909v20.364c0 1.6 1.309 2.909 2.909 2.909h16c1.6 0 2.909-1.309 2.909-2.909v-20.364c0-1.6-1.309-2.909-2.909-2.909zM26.909 29.091h-16v-20.364h16v20.364z"></path></svg>';
39
+ }
40
+
36
41
  const divElement = document.createElement("div");
37
42
  divElement.className = "vditor-copy";
38
- divElement.innerHTML = `<span aria-label="${window.VditorI18n.copy}"
39
- onmouseover="this.setAttribute('aria-label', '${window.VditorI18n.copy}')"
43
+ divElement.innerHTML = `<span aria-label="${window.VditorI18n?.copy || "复制"}"
44
+ onmouseover="this.setAttribute('aria-label', '${window.VditorI18n?.copy || "复制"}')"
40
45
  class="vditor-tooltipped vditor-tooltipped__w"
41
- onclick="this.previousElementSibling.select();document.execCommand('copy');` +
42
- `this.setAttribute('aria-label', '${window.VditorI18n.copied}')"><svg><use xlink:href="#vditor-icon-copy"></use></svg></span>`;
46
+ onclick="this.previousElementSibling.select();document.execCommand('copy');this.setAttribute('aria-label', '${window.VditorI18n?.copy || "已复制"}')">${iconHTML}</span>`;
43
47
  const textarea = document.createElement("textarea");
44
48
  textarea.value = code160to32(codeText);
45
49
  divElement.insertAdjacentElement("afterbegin", textarea);
@@ -38,7 +38,11 @@ export const outlineRender = (contentElement: HTMLElement, targetElement: Elemen
38
38
  const headingsElement = tempElement.firstElementChild.querySelectorAll("li > span[data-target-id]");
39
39
  headingsElement.forEach((item, index) => {
40
40
  if (item.nextElementSibling && item.nextElementSibling.tagName === "UL") {
41
- item.innerHTML = `<svg class='vditor-outline__action'><use xlink:href='#vditor-icon-down'></use></svg><span>${item.innerHTML}</span>`;
41
+ let iconHTML = "<svg class='vditor-outline__action'><use xlink:href='#vditor-icon-down'></use></svg>";
42
+ if (!document.getElementById("vditorIconScript")) {
43
+ iconHTML = '<svg class="vditor-outline__action" viewBox="0 0 32 32"><path d="M3.76 6.12l12.24 12.213 12.24-12.213 3.76 3.76-16 16-16-16 3.76-3.76z"></path></svg>';
44
+ }
45
+ item.innerHTML = `${iconHTML}<span>${item.innerHTML}</span>`;
42
46
  } else {
43
47
  item.innerHTML = `<svg></svg><span>${item.innerHTML}</span>`;
44
48
  }
@@ -90,12 +90,23 @@ export const previewRender = async (previewElement: HTMLDivElement, markdown: st
90
90
  "options.lang error, see https://ld246.com/article/1549638745630#options",
91
91
  );
92
92
  } else {
93
- addScriptSync(`${mergedOptions.cdn}/dist/js/i18n/${mergedOptions.lang}.js`, "vditorI18nScript");
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);
94
101
  }
95
102
  } else {
96
103
  window.VditorI18n = mergedOptions.i18n;
97
104
  }
98
105
 
106
+ if (mergedOptions.icon) {
107
+ await addScript(`${mergedOptions.cdn}/dist/js/icons/${mergedOptions.icon}.js`, "vditorIconScript");
108
+ }
109
+
99
110
  setContentTheme(mergedOptions.theme.current, mergedOptions.theme.path);
100
111
  if (mergedOptions.anchor === 1) {
101
112
  previewElement.classList.add("vditor-reset--anchor");
@@ -126,9 +137,6 @@ export const previewRender = async (previewElement: HTMLDivElement, markdown: st
126
137
  if (mergedOptions.lazyLoadImage) {
127
138
  lazyLoadImageRender(previewElement);
128
139
  }
129
- if (mergedOptions.icon) {
130
- addScript(`${mergedOptions.cdn}/dist/js/icons/${mergedOptions.icon}.js`, "vditorIconScript");
131
- }
132
140
  previewElement.addEventListener("click", (event: MouseEvent & { target: HTMLElement }) => {
133
141
  const spanElement = hasClosestByMatchTag(event.target, "SPAN");
134
142
  if (spanElement && hasClosestByClassName(spanElement, "vditor-toc")) {
@@ -9,8 +9,12 @@ export const speechRender = (element: HTMLElement, lang: keyof II18n = "zh_CN")
9
9
  if (typeof speechSynthesis === "undefined" || typeof SpeechSynthesisUtterance === "undefined") {
10
10
  return;
11
11
  }
12
- const playSVG = '<svg><use xlink:href="#vditor-icon-play"></use></svg>';
13
- const pauseSVG = '<svg><use xlink:href="#vditor-icon-pause"></use></svg>';
12
+ let playSVG = '<svg><use xlink:href="#vditor-icon-play"></use></svg>';
13
+ let pauseSVG = '<svg><use xlink:href="#vditor-icon-pause"></use></svg>';
14
+ if (!document.getElementById("vditorIconScript")) {
15
+ playSVG = '<svg viewBox="0 0 32 32"><path d="M3.436 0l25.128 16-25.128 16v-32z"></path></svg>';
16
+ pauseSVG = '<svg viewBox="0 0 32 32"><path d="M20.617 0h9.128v32h-9.128v-32zM2.255 32v-32h9.128v32h-9.128z"></path></svg>';
17
+ }
14
18
  let speechDom: HTMLDivElement = document.querySelector(".vditor-speech");
15
19
  if (!speechDom) {
16
20
  speechDom = document.createElement("div");
@@ -23,7 +23,6 @@ export class Preview {
23
23
  constructor(vditor: IVditor) {
24
24
  this.element = document.createElement("div");
25
25
  this.element.className = `vditor-preview`;
26
-
27
26
  const previewElement = document.createElement("div");
28
27
  previewElement.className = "vditor-reset";
29
28
  if (vditor.options.classes.preview) {
@@ -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,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
  });
@@ -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;
@@ -22,7 +22,7 @@ export const focusEvent = (vditor: IVditor, editorElement: HTMLElement) => {
22
22
  if (vditor.options.focus) {
23
23
  vditor.options.focus(getMarkdown(vditor));
24
24
  }
25
- hidePanel(vditor, ["subToolbar"]);
25
+ hidePanel(vditor, ["subToolbar", "hint"]);
26
26
  });
27
27
  };
28
28
 
@@ -62,7 +62,7 @@ export const dropEvent = (vditor: IVditor, editorElement: HTMLElement) => {
62
62
  if (event.dataTransfer.getData(Constants.DROP_EDITOR)) {
63
63
  // 编辑器内选中文字拖拽
64
64
  execAfterRender(vditor);
65
- } else if (event.dataTransfer.types[0] === "Files" || event.dataTransfer.types.includes("text/html")) {
65
+ } else if (event.dataTransfer.types.includes("Files") || event.dataTransfer.types.includes("text/html")) {
66
66
  // 外部文件拖入编辑器中或者编辑器内选中文字拖拽
67
67
  paste(vditor, event, {
68
68
  pasteCode: (code: string) => {
@@ -2,7 +2,7 @@ import {Constants} from "../constants";
2
2
  import {input as IRInput} from "../ir/input";
3
3
  import {processAfterRender} from "../ir/process";
4
4
  import {processAfterRender as processSVAfterRender, processPaste} from "../sv/process";
5
- import {uploadFiles} from "../upload";
5
+ import {uploadFiles} from "../upload/index";
6
6
  import {setHeaders} from "../upload/setHeaders";
7
7
  import {afterRenderEvent} from "../wysiwyg/afterRenderEvent";
8
8
  import {input} from "../wysiwyg/input";
@@ -228,9 +228,13 @@ export const listToggle = (vditor: IVditor, range: Range, type: string, cancel =
228
228
  let element;
229
229
  if (type === "list") {
230
230
  element = document.createElement("ul");
231
+ element.setAttribute("data-marker", "*");
231
232
  } else {
232
233
  element = document.createElement("ol");
234
+ element.setAttribute("data-marker", "1.");
233
235
  }
236
+ element.setAttribute("data-block", "0");
237
+ element.setAttribute("data-tight", itemElement.parentElement.getAttribute("data-tight"));
234
238
  element.innerHTML = itemElement.parentElement.innerHTML;
235
239
  itemElement.parentElement.parentNode.replaceChild(element, itemElement.parentElement);
236
240
  }
@@ -973,7 +977,7 @@ export const fixCodeBlock = (vditor: IVditor, event: KeyboardEvent, codeRenderEl
973
977
  if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey) {
974
978
  const codePosition = getSelectPosition(codeRenderElement, vditor[vditor.currentMode].element, range);
975
979
  if ((codePosition.start === 0 ||
976
- (codePosition.start === 1 && codeRenderElement.innerText === "\n")) // 空代码块,光标在 \n 后
980
+ (codePosition.start === 1 && codeRenderElement.innerText === "\n")) // 空代码块,光标在 \n 后
977
981
  && range.toString() === "") {
978
982
  codeRenderElement.parentElement.outerHTML =
979
983
  `<p data-block="0"><wbr>${codeRenderElement.firstElementChild.innerHTML}</p>`;
@@ -1089,7 +1093,7 @@ export const fixTask = (vditor: IVditor, range: Range, event: KeyboardEvent) =>
1089
1093
  if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey && range.toString() === ""
1090
1094
  && range.startOffset === 1
1091
1095
  && ((startContainer.nodeType === 3 && startContainer.previousSibling &&
1092
- (startContainer.previousSibling as HTMLElement).tagName === "INPUT")
1096
+ (startContainer.previousSibling as HTMLElement).tagName === "INPUT")
1093
1097
  || startContainer.nodeType !== 3)) {
1094
1098
  const previousElement = taskItemElement.previousElementSibling;
1095
1099
  taskItemElement.querySelector("input").remove();
@@ -1260,7 +1264,7 @@ export const paste = async (vditor: IVditor, event: (ClipboardEvent | DragEvent)
1260
1264
  } else {
1261
1265
  textHTML = event.dataTransfer.getData("text/html");
1262
1266
  textPlain = event.dataTransfer.getData("text/plain");
1263
- if (event.dataTransfer.types[0] === "Files") {
1267
+ if (event.dataTransfer.types.includes("Files")) {
1264
1268
  files = event.dataTransfer.items;
1265
1269
  }
1266
1270
  }
@@ -1351,7 +1355,7 @@ export const paste = async (vditor: IVditor, event: (ClipboardEvent | DragEvent)
1351
1355
  if (doc.body) {
1352
1356
  textHTML = doc.body.innerHTML;
1353
1357
  }
1354
-
1358
+ textHTML = Lute.Sanitize(textHTML);
1355
1359
  vditor.wysiwyg.getComments(vditor);
1356
1360
 
1357
1361
  // process code
@@ -1406,7 +1410,7 @@ export const paste = async (vditor: IVditor, event: (ClipboardEvent | DragEvent)
1406
1410
  processPaste(vditor, vditor.lute.HTML2Md(tempElement.innerHTML).trimRight());
1407
1411
  }
1408
1412
  vditor.outline.render(vditor);
1409
- } else if (files.length > 0 && vditor.options.upload.url) {
1413
+ } else if (files.length > 0 && (vditor.options.upload.url || vditor.options.upload.handler)) {
1410
1414
  await uploadFiles(vditor, files);
1411
1415
  } else if (textPlain.trim() !== "" && files.length === 0) {
1412
1416
  if (vditor.currentMode === "ir") {