vditor 3.11.0 → 3.11.2
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/LICENSE +1 -1
- package/README.md +3 -1
- package/dist/index.css +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +140 -26
- package/dist/index.min.js +1 -1
- package/dist/js/i18n/de_DE.js +86 -0
- package/dist/js/i18n/en_US.js +2 -2
- package/dist/js/i18n/es_ES.js +86 -0
- package/dist/js/i18n/vi_VN.js +86 -0
- package/dist/js/icons/ant.js +1 -1
- package/dist/js/icons/material.js +1 -1
- package/dist/js/lute/lute.min.js +72 -71
- package/dist/method.js +11 -5
- package/dist/method.min.js +1 -1
- package/dist/types/index.d.ts +34 -3
- package/package.json +1 -1
- package/src/index.ts +9 -4
- package/src/ts/markdown/previewRender.ts +1 -1
- package/src/ts/upload/index.ts +6 -4
- package/src/ts/util/fixBrowserBehavior.ts +75 -7
- package/src/ts/util/selection.ts +7 -2
- package/src/ts/wysiwyg/highlightToolbarWYSIWYG.ts +19 -4
|
@@ -52,7 +52,7 @@ export const fixCJKPosition = (range: Range, vditor: IVditor, event: KeyboardEve
|
|
|
52
52
|
|
|
53
53
|
// https://github.com/Vanessa219/vditor/issues/1289 WKWebView切换输入法产生六分之一空格,造成光标错位
|
|
54
54
|
if (pLiElement.nodeValue) {
|
|
55
|
-
pLiElement.nodeValue = pLiElement.nodeValue.replace(/\u2006/g,
|
|
55
|
+
pLiElement.nodeValue = pLiElement.nodeValue.replace(/\u2006/g, "");
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
const zwspNode = document.createTextNode(Constants.ZWSP);
|
|
@@ -1080,7 +1080,7 @@ export const fixBlockquote = (vditor: IVditor, range: Range, event: KeyboardEven
|
|
|
1080
1080
|
|
|
1081
1081
|
export const fixTask = (vditor: IVditor, range: Range, event: KeyboardEvent) => {
|
|
1082
1082
|
const startContainer = range.startContainer;
|
|
1083
|
-
const taskItemElement = hasClosestByMatchTag(startContainer, "
|
|
1083
|
+
const taskItemElement = hasClosestByMatchTag(startContainer, "LI");
|
|
1084
1084
|
if (taskItemElement && taskItemElement.classList.contains("vditor-task")) {
|
|
1085
1085
|
if (matchHotKey("⇧⌘J", event)) {
|
|
1086
1086
|
// ctrl + shift: toggle checked
|
|
@@ -1255,7 +1255,7 @@ export const fixFirefoxArrowUpTable = (event: KeyboardEvent, blockElement: false
|
|
|
1255
1255
|
return false;
|
|
1256
1256
|
};
|
|
1257
1257
|
|
|
1258
|
-
export const paste = async (vditor: IVditor, event: (ClipboardEvent | DragEvent) & {
|
|
1258
|
+
export const paste = async (vditor: IVditor, event: (ClipboardEvent | DragEvent) & {target: HTMLElement}, callback: {
|
|
1259
1259
|
pasteCode(code: string): void,
|
|
1260
1260
|
}) => {
|
|
1261
1261
|
if (vditor[vditor.currentMode].element.getAttribute("contenteditable") !== "true") {
|
|
@@ -1404,6 +1404,11 @@ export const paste = async (vditor: IVditor, event: (ClipboardEvent | DragEvent)
|
|
|
1404
1404
|
if (textHTML.trim() !== "") {
|
|
1405
1405
|
const tempElement = document.createElement("div");
|
|
1406
1406
|
tempElement.innerHTML = textHTML;
|
|
1407
|
+
if (!vditor.options.upload.base64ToLink) {
|
|
1408
|
+
// word 复制的图文混合,替换为 link: <v:imagedata src="file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image001.png" o:title="">
|
|
1409
|
+
await processVMLImage(vditor, tempElement, ("clipboardData" in event ? event.clipboardData : event.dataTransfer).getData("text/rtf"));
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1407
1412
|
tempElement.querySelectorAll("[style]").forEach((e) => {
|
|
1408
1413
|
e.removeAttribute("style");
|
|
1409
1414
|
});
|
|
@@ -1440,14 +1445,14 @@ export const paste = async (vditor: IVditor, event: (ClipboardEvent | DragEvent)
|
|
|
1440
1445
|
if (file && file.type.startsWith("image")) {
|
|
1441
1446
|
fileReader.readAsDataURL(file);
|
|
1442
1447
|
fileReader.onload = () => {
|
|
1443
|
-
let imgHTML =
|
|
1448
|
+
let imgHTML = "";
|
|
1444
1449
|
if (vditor.currentMode === "wysiwyg") {
|
|
1445
1450
|
imgHTML += `<img alt="${file.name}" src="${fileReader.result.toString()}">\n`;
|
|
1446
1451
|
} else {
|
|
1447
1452
|
imgHTML += `})\n`;
|
|
1448
1453
|
}
|
|
1449
1454
|
document.execCommand("insertHTML", false, imgHTML);
|
|
1450
|
-
}
|
|
1455
|
+
};
|
|
1451
1456
|
}
|
|
1452
1457
|
}
|
|
1453
1458
|
} else if (textPlain.trim() !== "" && files.length === 0) {
|
|
@@ -1458,11 +1463,11 @@ export const paste = async (vditor: IVditor, event: (ClipboardEvent | DragEvent)
|
|
|
1458
1463
|
if (vditor.currentMode === "ir") {
|
|
1459
1464
|
renderers.Md2VditorIRDOM = {renderLinkDest};
|
|
1460
1465
|
vditor.lute.SetJSRenderers({renderers});
|
|
1461
|
-
insertHTML(vditor.lute.Md2VditorIRDOM(textPlain), vditor);
|
|
1466
|
+
insertHTML(Lute.Sanitize(vditor.lute.Md2VditorIRDOM(textPlain)), vditor);
|
|
1462
1467
|
} else if (vditor.currentMode === "wysiwyg") {
|
|
1463
1468
|
renderers.Md2VditorDOM = {renderLinkDest};
|
|
1464
1469
|
vditor.lute.SetJSRenderers({renderers});
|
|
1465
|
-
insertHTML(vditor.lute.Md2VditorDOM(textPlain), vditor);
|
|
1470
|
+
insertHTML(Lute.Sanitize(vditor.lute.Md2VditorDOM(textPlain)), vditor);
|
|
1466
1471
|
} else {
|
|
1467
1472
|
renderers.Md2VditorSVDOM = {renderLinkDest};
|
|
1468
1473
|
vditor.lute.SetJSRenderers({renderers});
|
|
@@ -1499,3 +1504,66 @@ export const paste = async (vditor: IVditor, event: (ClipboardEvent | DragEvent)
|
|
|
1499
1504
|
scrollCenter(vditor);
|
|
1500
1505
|
}
|
|
1501
1506
|
};
|
|
1507
|
+
|
|
1508
|
+
const processVMLImage = async (vditor: IVditor, root: Element, rtfData: string) => {
|
|
1509
|
+
if (!rtfData) {
|
|
1510
|
+
return;
|
|
1511
|
+
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
const regexPictureHeader = /{\\pict[\s\S]+?\\bliptag-?\d+(\\blipupi-?\d+)?({\\\*\\blipuid\s?[\da-fA-F]+)?[\s}]*?/;
|
|
1515
|
+
const regexPicture = new RegExp("(?:(" + regexPictureHeader.source + "))([\\da-fA-F\\s]+)\\}", "g");
|
|
1516
|
+
const regImages = rtfData.match(regexPicture);
|
|
1517
|
+
const images = [];
|
|
1518
|
+
if (regImages) {
|
|
1519
|
+
for (const image of regImages) {
|
|
1520
|
+
let imageType;
|
|
1521
|
+
|
|
1522
|
+
if (image.includes("\\pngblip")) {
|
|
1523
|
+
imageType = "image/png";
|
|
1524
|
+
} else if (image.includes("\\jpegblip")) {
|
|
1525
|
+
imageType = "image/jpeg";
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
if (imageType) {
|
|
1529
|
+
images.push({
|
|
1530
|
+
hex: image.replace(regexPictureHeader, "").replace(/[^\da-fA-F]/g, ""),
|
|
1531
|
+
type: imageType,
|
|
1532
|
+
});
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
const shapes: Array<{shape: Element, img: Element}> = [];
|
|
1538
|
+
walk(root, (child: Element) => {
|
|
1539
|
+
if (child.tagName === "V:SHAPE") {
|
|
1540
|
+
walk(child, (sub) => {
|
|
1541
|
+
if (sub.tagName === "V:IMAGEDATA") shapes.push({shape: child, img: sub});
|
|
1542
|
+
});
|
|
1543
|
+
return false;
|
|
1544
|
+
}
|
|
1545
|
+
});
|
|
1546
|
+
for (let i = 0; i < shapes.length; i++) {
|
|
1547
|
+
const img = document.createElement("img");
|
|
1548
|
+
const newSrc = "data:" + images[i].type + ";base64," + btoa((images[i].hex.match(/\w{2}/g) || []).map(char => {
|
|
1549
|
+
return String.fromCharCode(parseInt(char, 16));
|
|
1550
|
+
}).join(""));
|
|
1551
|
+
img.src = newSrc;
|
|
1552
|
+
img.title = shapes[i].img.getAttribute("title");
|
|
1553
|
+
shapes[i].shape.parentNode.replaceChild(img, shapes[i].shape);
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
const imgs = root.querySelectorAll("img");
|
|
1557
|
+
for (let i = 0; i < imgs.length; i++) {
|
|
1558
|
+
const src = imgs[i].src || "";
|
|
1559
|
+
if (src) imgs[i].src = await vditor.options.upload.base64ToLink(src);
|
|
1560
|
+
}
|
|
1561
|
+
};
|
|
1562
|
+
|
|
1563
|
+
const walk = (el: Element, fn: (el: Element) => boolean | void) => {
|
|
1564
|
+
const goNext = fn(el);
|
|
1565
|
+
if (goNext !== false)
|
|
1566
|
+
for (let i = 0; i < el.children.length; i++) {
|
|
1567
|
+
walk(el.children[i], fn);
|
|
1568
|
+
}
|
|
1569
|
+
};
|
package/src/ts/util/selection.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {Constants} from "../constants";
|
|
2
2
|
import {isChrome} from "./compatibility";
|
|
3
|
-
import {hasClosestBlock, hasClosestByClassName} from "./hasClosest";
|
|
3
|
+
import {hasClosestBlock, hasClosestByClassName, hasClosestByMatchTag} from "./hasClosest";
|
|
4
4
|
|
|
5
5
|
export const getEditorRange = (vditor: IVditor) => {
|
|
6
6
|
let range: Range;
|
|
@@ -262,7 +262,12 @@ export const insertHTML = (html: string, vditor: IVditor) => {
|
|
|
262
262
|
if (!blockElement) {
|
|
263
263
|
vditor[vditor.currentMode].element.insertAdjacentHTML("beforeend", pasteElement.innerHTML);
|
|
264
264
|
} else {
|
|
265
|
-
|
|
265
|
+
const liElement = hasClosestByMatchTag(range.startContainer, "LI");
|
|
266
|
+
if (liElement && pasteElement.firstElementChild.tagName === "UL") {
|
|
267
|
+
liElement.insertAdjacentHTML("afterend", pasteElement.firstElementChild.innerHTML);
|
|
268
|
+
} else {
|
|
269
|
+
blockElement.insertAdjacentHTML("afterend", pasteElement.innerHTML);
|
|
270
|
+
}
|
|
266
271
|
}
|
|
267
272
|
setRangeByWbr(vditor[vditor.currentMode].element, range);
|
|
268
273
|
} else {
|
|
@@ -65,6 +65,7 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
|
|
|
65
65
|
if (footnotesElement) {
|
|
66
66
|
vditor.wysiwyg.popover.innerHTML = "";
|
|
67
67
|
genClose(footnotesElement, vditor);
|
|
68
|
+
customWysiwygToolbar(vditor, "footnotes-block")
|
|
68
69
|
setPopoverPosition(vditor, footnotesElement);
|
|
69
70
|
return;
|
|
70
71
|
}
|
|
@@ -195,6 +196,7 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
|
|
|
195
196
|
if (tocElement) {
|
|
196
197
|
vditor.wysiwyg.popover.innerHTML = "";
|
|
197
198
|
genClose(tocElement, vditor);
|
|
199
|
+
customWysiwygToolbar(vditor, "vditor-toc")
|
|
198
200
|
setPopoverPosition(vditor, tocElement);
|
|
199
201
|
return;
|
|
200
202
|
}
|
|
@@ -206,6 +208,7 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
|
|
|
206
208
|
genUp(range, blockquoteElement, vditor);
|
|
207
209
|
genDown(range, blockquoteElement, vditor);
|
|
208
210
|
genClose(blockquoteElement, vditor);
|
|
211
|
+
customWysiwygToolbar(vditor, "blockquote")
|
|
209
212
|
setPopoverPosition(vditor, blockquoteElement);
|
|
210
213
|
}
|
|
211
214
|
|
|
@@ -216,7 +219,7 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
|
|
|
216
219
|
genUp(range, liElement, vditor);
|
|
217
220
|
genDown(range, liElement, vditor);
|
|
218
221
|
genClose(liElement, vditor);
|
|
219
|
-
|
|
222
|
+
customWysiwygToolbar(vditor, "li")
|
|
220
223
|
setPopoverPosition(vditor, liElement);
|
|
221
224
|
}
|
|
222
225
|
|
|
@@ -549,6 +552,7 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
|
|
|
549
552
|
vditor.wysiwyg.popover.insertAdjacentElement("beforeend", inputWrap);
|
|
550
553
|
vditor.wysiwyg.popover.insertAdjacentHTML("beforeend", " x ");
|
|
551
554
|
vditor.wysiwyg.popover.insertAdjacentElement("beforeend", input2Wrap);
|
|
555
|
+
customWysiwygToolbar(vditor, "table")
|
|
552
556
|
setPopoverPosition(vditor, tableElement);
|
|
553
557
|
}
|
|
554
558
|
|
|
@@ -596,6 +600,7 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
|
|
|
596
600
|
|
|
597
601
|
genClose(footnotesRefElement, vditor);
|
|
598
602
|
vditor.wysiwyg.popover.insertAdjacentElement("beforeend", inputWrap);
|
|
603
|
+
customWysiwygToolbar(vditor, "footnotes-ref")
|
|
599
604
|
setPopoverPosition(vditor, footnotesRefElement);
|
|
600
605
|
}
|
|
601
606
|
|
|
@@ -684,7 +689,7 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
|
|
|
684
689
|
}
|
|
685
690
|
const matchLangData: IHintData[] = [];
|
|
686
691
|
const key = language.value.substring(0, language.selectionStart);
|
|
687
|
-
(vditor.options.preview.hljs.langs ||
|
|
692
|
+
(vditor.options.preview.hljs.langs || Constants.ALIAS_CODE_LANGUAGES.concat((window.hljs?.listLanguages() ?? []).sort())).forEach((keyName) => {
|
|
688
693
|
if (keyName.indexOf(key.toLowerCase()) > -1) {
|
|
689
694
|
matchLangData.push({
|
|
690
695
|
html: keyName,
|
|
@@ -696,6 +701,9 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
|
|
|
696
701
|
event.preventDefault();
|
|
697
702
|
};
|
|
698
703
|
vditor.wysiwyg.popover.insertAdjacentElement("beforeend", languageWrap);
|
|
704
|
+
customWysiwygToolbar(vditor, "code-block")
|
|
705
|
+
} else {
|
|
706
|
+
customWysiwygToolbar(vditor, "block")
|
|
699
707
|
}
|
|
700
708
|
setPopoverPosition(vditor, blockRenderElement);
|
|
701
709
|
} else {
|
|
@@ -735,6 +743,7 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
|
|
|
735
743
|
genDown(range, headingElement, vditor);
|
|
736
744
|
genClose(headingElement, vditor);
|
|
737
745
|
vditor.wysiwyg.popover.insertAdjacentElement("beforeend", inputWrap);
|
|
746
|
+
customWysiwygToolbar(vditor, "heading")
|
|
738
747
|
setPopoverPosition(vditor, headingElement);
|
|
739
748
|
}
|
|
740
749
|
|
|
@@ -763,7 +772,7 @@ export const highlightToolbarWYSIWYG = (vditor: IVditor) => {
|
|
|
763
772
|
genUp(range, blockElement, vditor);
|
|
764
773
|
genDown(range, blockElement, vditor);
|
|
765
774
|
genClose(blockElement, vditor);
|
|
766
|
-
|
|
775
|
+
customWysiwygToolbar(vditor, "block")
|
|
767
776
|
setPopoverPosition(vditor, blockElement);
|
|
768
777
|
} else {
|
|
769
778
|
vditor.wysiwyg.popover.style.display = "none";
|
|
@@ -864,6 +873,7 @@ export const genLinkRefPopover = (vditor: IVditor, linkRefElement: HTMLElement,
|
|
|
864
873
|
genClose(linkRefElement, vditor);
|
|
865
874
|
vditor.wysiwyg.popover.insertAdjacentElement("beforeend", inputWrap);
|
|
866
875
|
vditor.wysiwyg.popover.insertAdjacentElement("beforeend", input1Wrap);
|
|
876
|
+
customWysiwygToolbar(vditor, "link-ref")
|
|
867
877
|
setPopoverPosition(vditor, linkRefElement);
|
|
868
878
|
};
|
|
869
879
|
|
|
@@ -1058,6 +1068,7 @@ export const genAPopover = (vditor: IVditor, aElement: HTMLElement, range: Range
|
|
|
1058
1068
|
vditor.wysiwyg.popover.insertAdjacentElement("beforeend", inputWrap);
|
|
1059
1069
|
vditor.wysiwyg.popover.insertAdjacentElement("beforeend", input1Wrap);
|
|
1060
1070
|
vditor.wysiwyg.popover.insertAdjacentElement("beforeend", input2Wrap);
|
|
1071
|
+
customWysiwygToolbar(vditor, "a")
|
|
1061
1072
|
setPopoverPosition(vditor, aElement);
|
|
1062
1073
|
};
|
|
1063
1074
|
|
|
@@ -1122,7 +1133,7 @@ export const genImagePopover = (event: Event, vditor: IVditor) => {
|
|
|
1122
1133
|
vditor.wysiwyg.popover.insertAdjacentElement("beforeend", inputWrap);
|
|
1123
1134
|
vditor.wysiwyg.popover.insertAdjacentElement("beforeend", altWrap);
|
|
1124
1135
|
vditor.wysiwyg.popover.insertAdjacentElement("beforeend", titleWrap);
|
|
1125
|
-
|
|
1136
|
+
customWysiwygToolbar(vditor, "image")
|
|
1126
1137
|
setPopoverPosition(vditor, imgElement);
|
|
1127
1138
|
};
|
|
1128
1139
|
|
|
@@ -1137,3 +1148,7 @@ const focusToElement = (event: KeyboardEvent, range: Range) => {
|
|
|
1137
1148
|
return true;
|
|
1138
1149
|
}
|
|
1139
1150
|
};
|
|
1151
|
+
|
|
1152
|
+
const customWysiwygToolbar = (vditor: IVditor, type: TWYSISYGToolbar) => {
|
|
1153
|
+
vditor.options.customWysiwygToolbar(type, vditor.wysiwyg.popover);
|
|
1154
|
+
};
|