vditor 3.8.7 → 3.8.11
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.
- package/README.md +13 -13
- package/dist/index.css +2 -2
- package/dist/index.min.js +1 -15353
- package/dist/js/highlight.js/styles/abap.css +7 -96
- package/dist/js/highlight.js/styles/algol.css +7 -104
- package/dist/js/highlight.js/styles/algol_nu.css +7 -52
- package/dist/js/highlight.js/styles/arduino.css +7 -95
- package/dist/js/highlight.js/styles/autumn.css +7 -76
- package/dist/js/highlight.js/styles/borland.css +7 -94
- package/dist/js/highlight.js/styles/bw.css +7 -108
- package/dist/js/highlight.js/styles/colorful.css +7 -90
- package/dist/js/highlight.js/styles/dracula.css +9 -86
- package/dist/js/highlight.js/styles/emacs.css +7 -103
- package/dist/js/highlight.js/styles/friendly.css +7 -119
- package/dist/js/highlight.js/styles/fruity.css +7 -76
- package/dist/js/highlight.js/styles/github.css +7 -106
- package/dist/js/highlight.js/styles/igor.css +7 -90
- package/dist/js/highlight.js/styles/lovelace.css +7 -77
- package/dist/js/highlight.js/styles/manni.css +7 -75
- package/dist/js/highlight.js/styles/monokai.css +7 -77
- package/dist/js/highlight.js/styles/monokailight.css +7 -114
- package/dist/js/highlight.js/styles/murphy.css +7 -78
- package/dist/js/highlight.js/styles/native.css +7 -103
- package/dist/js/highlight.js/styles/paraiso-dark.css +7 -79
- package/dist/js/highlight.js/styles/paraiso-light.css +7 -78
- package/dist/js/highlight.js/styles/pastie.css +7 -115
- package/dist/js/highlight.js/styles/perldoc.css +7 -80
- package/dist/js/highlight.js/styles/pygments.css +7 -95
- package/dist/js/highlight.js/styles/rainbow_dash.css +7 -103
- package/dist/js/highlight.js/styles/rrt.css +7 -119
- package/dist/js/highlight.js/styles/solarized-dark.css +7 -91
- package/dist/js/highlight.js/styles/solarized-dark256.css +7 -90
- package/dist/js/highlight.js/styles/solarized-light.css +7 -90
- package/dist/js/highlight.js/styles/swapoff.css +7 -99
- package/dist/js/highlight.js/styles/tango.css +7 -106
- package/dist/js/highlight.js/styles/trac.css +7 -105
- package/dist/js/highlight.js/styles/vim.css +7 -89
- package/dist/js/highlight.js/styles/vs.css +7 -75
- package/dist/js/highlight.js/styles/xcode.css +7 -111
- package/dist/js/i18n/zh_CN.js +1 -1
- package/dist/js/katex/mhchem.min.js +1 -0
- package/dist/js/lute/lute.min.js +9 -8
- package/dist/method.min.js +1 -2346
- package/dist/ts/ui/initUI.d.ts +1 -0
- package/dist/ts/wysiwyg/index.d.ts +2 -0
- package/dist/types/index.d.ts +4 -3
- package/package.json +7 -7
- package/src/index.ts +12 -2
- package/src/ts/.DS_Store +0 -0
- package/src/ts/hint/index.ts +20 -11
- package/src/ts/markdown/codeRender.ts +8 -4
- package/src/ts/markdown/mathRender.ts +29 -27
- package/src/ts/markdown/outlineRender.ts +5 -1
- package/src/ts/markdown/previewRender.ts +12 -4
- package/src/ts/markdown/speechRender.ts +6 -2
- package/src/ts/preview/index.ts +0 -1
- package/src/ts/toolbar/Info.ts +1 -1
- package/src/ts/ui/initUI.ts +19 -5
- package/src/ts/upload/index.ts +4 -4
- package/src/ts/util/editorCommonEvent.ts +2 -2
- package/src/ts/util/fixBrowserBehavior.ts +4 -4
- package/src/ts/wysiwyg/highlightToolbarWYSIWYG.ts +12 -5
- package/src/ts/wysiwyg/index.ts +8 -2
- package/CHANGELOG.md +0 -1072
- package/dist/images/.DS_Store +0 -0
- package/dist/js/.DS_Store +0 -0
- package/dist/js/lute/.DS_Store +0 -0
- package/dist/js/mathjax/.DS_Store +0 -0
package/dist/ts/ui/initUI.d.ts
CHANGED
|
@@ -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
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -372,7 +372,7 @@ interface IUpload {
|
|
|
372
372
|
validate?(files: File[]): string | boolean;
|
|
373
373
|
|
|
374
374
|
/** 自定义上传,当发生错误时返回错误信息 */
|
|
375
|
-
handler?(files: File[]): string | null
|
|
375
|
+
handler?(files: File[]): string | null | Promise<string> | Promise<null>;
|
|
376
376
|
|
|
377
377
|
/** 对服务端返回的数据进行转换,以满足内置的数据结构 */
|
|
378
378
|
format?(files: File[], responseText: string): string;
|
|
@@ -381,7 +381,7 @@ interface IUpload {
|
|
|
381
381
|
linkToImgFormat?(responseText: string): string;
|
|
382
382
|
|
|
383
383
|
/** 将上传的文件处理后再返回 */
|
|
384
|
-
file?(files: File[]): File[]
|
|
384
|
+
file?(files: File[]): File[] | Promise<File[]>;
|
|
385
385
|
|
|
386
386
|
/** 图片地址上传后的回调 */
|
|
387
387
|
linkToImgCallback?(responseText: string): void;
|
|
@@ -537,7 +537,7 @@ interface IHintData {
|
|
|
537
537
|
interface IHintExtend {
|
|
538
538
|
key: string;
|
|
539
539
|
|
|
540
|
-
hint?(value: string): IHintData[]
|
|
540
|
+
hint?(value: string): IHintData[] | Promise<IHintData[]>;
|
|
541
541
|
}
|
|
542
542
|
|
|
543
543
|
/** @link https://ld246.com/article/1549638745630#options-hint */
|
|
@@ -747,6 +747,7 @@ interface IVditor {
|
|
|
747
747
|
triggerRemoveComment(vditor: IVditor): void,
|
|
748
748
|
showComment(): void,
|
|
749
749
|
hideComment(): void,
|
|
750
|
+
unbindListener(): void,
|
|
750
751
|
};
|
|
751
752
|
ir?: {
|
|
752
753
|
range: Range,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vditor",
|
|
3
|
-
"version": "3.8.
|
|
3
|
+
"version": "3.8.11",
|
|
4
4
|
"description": "♏ 易于使用的 Markdown 编辑器,为适配不同的应用场景而生",
|
|
5
5
|
"author": "Vanessa <v@b3log.org> (http://vanessa.b3log.org)",
|
|
6
6
|
"homepage": "https://b3log.org/vditor",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@types/diff-match-patch": "^1.0.32",
|
|
25
25
|
"@types/jest": "^26.0.23",
|
|
26
26
|
"@types/puppeteer": "^2.1.5",
|
|
27
|
-
"autoprefixer": "^
|
|
27
|
+
"autoprefixer": "^10.4.2",
|
|
28
28
|
"babel-loader": "^8.2.2",
|
|
29
29
|
"clean-webpack-plugin": "^4.0.0-alpha.0",
|
|
30
30
|
"copy-webpack-plugin": "^6.4.1",
|
|
@@ -34,19 +34,19 @@
|
|
|
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": "^
|
|
37
|
+
"node-sass": "^7.0.0",
|
|
38
38
|
"postcss-loader": "^5.2.0",
|
|
39
39
|
"puppeteer": "^1.20.0",
|
|
40
|
-
"sass-loader": "^
|
|
40
|
+
"sass-loader": "^12.4.0",
|
|
41
41
|
"style-loader": "^1.3.0",
|
|
42
|
-
"terser-webpack-plugin": "^5.
|
|
42
|
+
"terser-webpack-plugin": "^5.3.0",
|
|
43
43
|
"ts-jest": "^26.5.6",
|
|
44
44
|
"ts-loader": "^6.2.2",
|
|
45
45
|
"tslint": "^5.20.1",
|
|
46
46
|
"typescript": "^3.9.9",
|
|
47
|
-
"webpack": "^5.
|
|
47
|
+
"webpack": "^5.66.0",
|
|
48
48
|
"webpack-bundle-analyzer": "^3.9.0",
|
|
49
|
-
"webpack-cli": "^4.
|
|
49
|
+
"webpack-cli": "^4.9.1",
|
|
50
50
|
"webpack-dev-server": "^4.1.0"
|
|
51
51
|
},
|
|
52
52
|
"license": "MIT",
|
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
|
-
|
|
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
|
package/src/ts/hint/index.ts
CHANGED
|
@@ -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
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
|
39
|
-
onmouseover="this.setAttribute('aria-label', '${window.VditorI18n
|
|
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);
|
|
@@ -42,33 +42,35 @@ export const mathRender = (element: HTMLElement, options?: { cdn?: string, math?
|
|
|
42
42
|
if (options.math.engine === "KaTeX") {
|
|
43
43
|
addStyle(`${options.cdn}/dist/js/katex/katex.min.css`, "vditorKatexStyle");
|
|
44
44
|
addScript(`${options.cdn}/dist/js/katex/katex.min.js`, "vditorKatexScript").then(() => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
mathElement.parentElement.classList.contains("vditor-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
45
|
+
addScript(`${options.cdn}/dist/js/katex/mhchem.min.js`, "vditorKatexChemScript").then(() => {
|
|
46
|
+
mathElements.forEach((mathElement) => {
|
|
47
|
+
if (mathElement.parentElement.classList.contains("vditor-wysiwyg__pre") ||
|
|
48
|
+
mathElement.parentElement.classList.contains("vditor-ir__marker--pre")) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (mathElement.getAttribute("data-math")) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const math = code160to32(mathRenderAdapter.getCode(mathElement));
|
|
55
|
+
mathElement.setAttribute("data-math", math);
|
|
56
|
+
try {
|
|
57
|
+
mathElement.innerHTML = katex.renderToString(math, {
|
|
58
|
+
displayMode: mathElement.tagName === "DIV",
|
|
59
|
+
output: "html",
|
|
60
|
+
});
|
|
61
|
+
} catch (e) {
|
|
62
|
+
mathElement.innerHTML = e.message;
|
|
63
|
+
mathElement.className = "language-math vditor-reset--error";
|
|
64
|
+
}
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
mathElement.addEventListener("copy", (event: ClipboardEvent) => {
|
|
67
|
+
event.stopPropagation();
|
|
68
|
+
event.preventDefault();
|
|
69
|
+
const vditorMathElement = (event.currentTarget as HTMLElement).closest(".language-math");
|
|
70
|
+
event.clipboardData.setData("text/html", vditorMathElement.innerHTML);
|
|
71
|
+
event.clipboardData.setData("text/plain",
|
|
72
|
+
vditorMathElement.getAttribute("data-math"));
|
|
73
|
+
});
|
|
72
74
|
});
|
|
73
75
|
});
|
|
74
76
|
});
|
|
@@ -88,7 +90,7 @@ export const mathRender = (element: HTMLElement, options?: { cdn?: string, math?
|
|
|
88
90
|
if (!window.MathJax) {
|
|
89
91
|
window.MathJax = {
|
|
90
92
|
loader: {
|
|
91
|
-
paths: {
|
|
93
|
+
paths: {mathjax: `${options.cdn}/dist/js/mathjax`},
|
|
92
94
|
},
|
|
93
95
|
startup: {
|
|
94
96
|
typeset: false,
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
13
|
-
|
|
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");
|
package/src/ts/preview/index.ts
CHANGED
|
@@ -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) {
|
package/src/ts/toolbar/Info.ts
CHANGED
|
@@ -16,7 +16,7 @@ export class Info extends MenuItem {
|
|
|
16
16
|
<div> </div>
|
|
17
17
|
<div style="flex: 1;min-width: 250px">
|
|
18
18
|
Vditor 是一款浏览器端的 Markdown 编辑器,支持所见即所得、即时渲染(类似 Typora)和分屏预览模式。
|
|
19
|
-
它使用 TypeScript 实现,支持原生 JavaScript
|
|
19
|
+
它使用 TypeScript 实现,支持原生 JavaScript 以及 Vue、React、Angular 和 Svelte 等框架。
|
|
20
20
|
</div>
|
|
21
21
|
</div>
|
|
22
22
|
<div style="display: flex;flex-wrap: wrap;">
|
package/src/ts/ui/initUI.ts
CHANGED
|
@@ -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
|
|
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"
|
|
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
|
-
|
|
145
|
-
|
|
152
|
+
let resizeCb: () => void;
|
|
153
|
+
|
|
154
|
+
export function UIUnbindListener() {
|
|
155
|
+
window.removeEventListener("resize", resizeCb);
|
|
156
|
+
}
|
|
146
157
|
|
|
147
|
-
|
|
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
|
});
|
package/src/ts/upload/index.ts
CHANGED
|
@@ -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><audio controls="controls" src="${path}"></audio></code></pre
|
|
111
|
+
data-block="0"><pre><code><audio controls="controls" src="${path}"></audio></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 += `\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
|
|
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) => {
|
|
@@ -977,7 +977,7 @@ export const fixCodeBlock = (vditor: IVditor, event: KeyboardEvent, codeRenderEl
|
|
|
977
977
|
if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey) {
|
|
978
978
|
const codePosition = getSelectPosition(codeRenderElement, vditor[vditor.currentMode].element, range);
|
|
979
979
|
if ((codePosition.start === 0 ||
|
|
980
|
-
|
|
980
|
+
(codePosition.start === 1 && codeRenderElement.innerText === "\n")) // 空代码块,光标在 \n 后
|
|
981
981
|
&& range.toString() === "") {
|
|
982
982
|
codeRenderElement.parentElement.outerHTML =
|
|
983
983
|
`<p data-block="0"><wbr>${codeRenderElement.firstElementChild.innerHTML}</p>`;
|
|
@@ -1093,7 +1093,7 @@ export const fixTask = (vditor: IVditor, range: Range, event: KeyboardEvent) =>
|
|
|
1093
1093
|
if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey && range.toString() === ""
|
|
1094
1094
|
&& range.startOffset === 1
|
|
1095
1095
|
&& ((startContainer.nodeType === 3 && startContainer.previousSibling &&
|
|
1096
|
-
|
|
1096
|
+
(startContainer.previousSibling as HTMLElement).tagName === "INPUT")
|
|
1097
1097
|
|| startContainer.nodeType !== 3)) {
|
|
1098
1098
|
const previousElement = taskItemElement.previousElementSibling;
|
|
1099
1099
|
taskItemElement.querySelector("input").remove();
|
|
@@ -1264,7 +1264,7 @@ export const paste = async (vditor: IVditor, event: (ClipboardEvent | DragEvent)
|
|
|
1264
1264
|
} else {
|
|
1265
1265
|
textHTML = event.dataTransfer.getData("text/html");
|
|
1266
1266
|
textPlain = event.dataTransfer.getData("text/plain");
|
|
1267
|
-
if (event.dataTransfer.types
|
|
1267
|
+
if (event.dataTransfer.types.includes("Files")) {
|
|
1268
1268
|
files = event.dataTransfer.items;
|
|
1269
1269
|
}
|
|
1270
1270
|
}
|
|
@@ -1410,7 +1410,7 @@ export const paste = async (vditor: IVditor, event: (ClipboardEvent | DragEvent)
|
|
|
1410
1410
|
processPaste(vditor, vditor.lute.HTML2Md(tempElement.innerHTML).trimRight());
|
|
1411
1411
|
}
|
|
1412
1412
|
vditor.outline.render(vditor);
|
|
1413
|
-
} else if (files.length > 0 && vditor.options.upload.url) {
|
|
1413
|
+
} else if (files.length > 0 && (vditor.options.upload.url || vditor.options.upload.handler)) {
|
|
1414
1414
|
await uploadFiles(vditor, files);
|
|
1415
1415
|
} else if (textPlain.trim() !== "" && files.length === 0) {
|
|
1416
1416
|
if (vditor.currentMode === "ir") {
|
|
@@ -618,7 +618,7 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
|
|
|
618
618
|
codeElement.className.indexOf("language-") > -1
|
|
619
619
|
? codeElement.className.split("-")[1].split(" ")[0]
|
|
620
620
|
: "";
|
|
621
|
-
language.oninput = () => {
|
|
621
|
+
language.oninput = (e: InputEvent) => {
|
|
622
622
|
if (language.value.trim() !== "") {
|
|
623
623
|
codeElement.className = `language-${language.value}`;
|
|
624
624
|
} else {
|
|
@@ -631,6 +631,13 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
|
|
|
631
631
|
processCodeRender(blockRenderElement.lastElementChild as HTMLElement, vditor);
|
|
632
632
|
}
|
|
633
633
|
afterRenderEvent(vditor);
|
|
634
|
+
// 当鼠标点选语言时,触发自定义input事件
|
|
635
|
+
if (e.detail === 1) {
|
|
636
|
+
// 选择语言后,输入焦点切换到代码输入框
|
|
637
|
+
range.setStart(codeElement.firstChild, 0);
|
|
638
|
+
range.collapse(true);
|
|
639
|
+
setSelectionFocus(range);
|
|
640
|
+
}
|
|
634
641
|
};
|
|
635
642
|
language.onkeydown = (event: KeyboardEvent) => {
|
|
636
643
|
if (event.isComposing) {
|
|
@@ -647,17 +654,18 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
|
|
|
647
654
|
event.preventDefault();
|
|
648
655
|
return;
|
|
649
656
|
}
|
|
657
|
+
vditor.hint.select(event, vditor);
|
|
650
658
|
if (
|
|
651
659
|
!isCtrl(event) &&
|
|
652
660
|
!event.shiftKey &&
|
|
653
|
-
event.altKey &&
|
|
654
661
|
event.key === "Enter"
|
|
655
662
|
) {
|
|
656
663
|
range.setStart(codeElement.firstChild, 0);
|
|
657
664
|
range.collapse(true);
|
|
658
665
|
setSelectionFocus(range);
|
|
666
|
+
event.preventDefault();
|
|
667
|
+
event.stopPropagation();
|
|
659
668
|
}
|
|
660
|
-
vditor.hint.select(event, vditor);
|
|
661
669
|
};
|
|
662
670
|
language.onkeyup = (event: KeyboardEvent) => {
|
|
663
671
|
if (
|
|
@@ -964,8 +972,6 @@ const linkHotkey = (
|
|
|
964
972
|
};
|
|
965
973
|
|
|
966
974
|
export const genAPopover = (vditor: IVditor, aElement: HTMLElement) => {
|
|
967
|
-
const lang: keyof II18n | "" = vditor.options.lang;
|
|
968
|
-
const options: IOptions = vditor.options;
|
|
969
975
|
vditor.wysiwyg.popover.innerHTML = "";
|
|
970
976
|
|
|
971
977
|
const updateA = () => {
|
|
@@ -974,6 +980,7 @@ export const genAPopover = (vditor: IVditor, aElement: HTMLElement) => {
|
|
|
974
980
|
}
|
|
975
981
|
aElement.setAttribute("href", input1.value);
|
|
976
982
|
aElement.setAttribute("title", input2.value);
|
|
983
|
+
afterRenderEvent(vditor);
|
|
977
984
|
};
|
|
978
985
|
|
|
979
986
|
aElement.querySelectorAll("[data-marker]").forEach((item: HTMLElement) => {
|
package/src/ts/wysiwyg/index.ts
CHANGED
|
@@ -39,6 +39,7 @@ class WYSIWYG {
|
|
|
39
39
|
public preventInput: boolean;
|
|
40
40
|
public composingLock = false;
|
|
41
41
|
public commentIds: string[] = [];
|
|
42
|
+
private scrollListener: () => void;
|
|
42
43
|
|
|
43
44
|
constructor(vditor: IVditor) {
|
|
44
45
|
const divElement = document.createElement("div");
|
|
@@ -195,6 +196,10 @@ class WYSIWYG {
|
|
|
195
196
|
this.selectPopover.setAttribute("style", "display:none");
|
|
196
197
|
}
|
|
197
198
|
|
|
199
|
+
public unbindListener() {
|
|
200
|
+
window.removeEventListener("scroll", this.scrollListener);
|
|
201
|
+
}
|
|
202
|
+
|
|
198
203
|
private copy(event: ClipboardEvent, vditor: IVditor) {
|
|
199
204
|
const range = getSelection().getRangeAt(0);
|
|
200
205
|
if (range.toString() === "") {
|
|
@@ -238,7 +243,8 @@ class WYSIWYG {
|
|
|
238
243
|
}
|
|
239
244
|
|
|
240
245
|
private bindEvent(vditor: IVditor) {
|
|
241
|
-
|
|
246
|
+
this.unbindListener();
|
|
247
|
+
window.addEventListener("scroll", this.scrollListener = () => {
|
|
242
248
|
hidePanel(vditor, ["hint"]);
|
|
243
249
|
if (this.popover.style.display !== "block" || this.selectPopover.style.display !== "block") {
|
|
244
250
|
return;
|
|
@@ -331,7 +337,7 @@ class WYSIWYG {
|
|
|
331
337
|
this.preventInput = false;
|
|
332
338
|
return;
|
|
333
339
|
}
|
|
334
|
-
if (this.composingLock ||
|
|
340
|
+
if (this.composingLock || event.data === "‘" || event.data === "“" || event.data === "《") {
|
|
335
341
|
return;
|
|
336
342
|
}
|
|
337
343
|
const range = getSelection().getRangeAt(0);
|