Browse Source

:sparkles: toolbar

Van 6 years ago
parent
commit
a9d2519d82

+ 1 - 1
demo/index.js

@@ -16,7 +16,7 @@ window.vditor = new Vditor('vditor', {
   },
   tab: '\t',
   upload: {
-    accept: 'image/*,.mp3',
+    accept: 'image/*,.mp3, .wav, .rar',
     token: 'test',
     url: '/api/upload/editor',
     linkToImgUrl: '/api/upload/fetch',

+ 2 - 1
src/assets/scss/_wysiwyg.scss

@@ -17,7 +17,8 @@
       background-color: $textareaFocusBg;
     }
 
-    blockquote:empty::before {
+    blockquote:empty::before,
+    pre > code:empty::before{
       content: ' ';
     }
 

+ 14 - 10
src/ts/toolbar/Headings.ts

@@ -1,6 +1,7 @@
 import headingsSVG from "../../assets/icons/headings.svg";
 import {insertText} from "../editor/insertText";
 import {getEventName} from "../util/getEventName";
+import {highlightToolbar} from "../wysiwyg/highlightToolbar";
 import {MenuItem} from "./MenuItem";
 
 export class Headings extends MenuItem {
@@ -28,18 +29,20 @@ export class Headings extends MenuItem {
         this.element.children[0].addEventListener(getEventName(), (event) => {
             const actionBtn = this.element.children[0];
             if (vditor.currentMode === "wysiwyg" && actionBtn.classList.contains("vditor-menu--current")) {
+                if (vditor.wysiwyg.element.querySelector("wbr")) {
+                    vditor.wysiwyg.element.querySelector("wbr").remove();
+                }
                 document.execCommand("formatBlock", false, "p");
-                actionBtn.classList.remove("vditor-menu--current");
-                return;
-            }
-
-            if (headingsPanelElement.style.display === "block") {
-                headingsPanelElement.style.display = "none";
+                highlightToolbar(vditor);
             } else {
-                headingsPanelElement.style.display = "block";
-                if (vditor.toolbar.elements.emoji) {
-                    const panel = vditor.toolbar.elements.emoji.children[1] as HTMLElement;
-                    panel.style.display = "none";
+                if (headingsPanelElement.style.display === "block") {
+                    headingsPanelElement.style.display = "none";
+                } else {
+                    headingsPanelElement.style.display = "block";
+                    if (vditor.toolbar.elements.emoji) {
+                        const panel = vditor.toolbar.elements.emoji.children[1] as HTMLElement;
+                        panel.style.display = "none";
+                    }
                 }
             }
             if (vditor.hint) {
@@ -52,6 +55,7 @@ export class Headings extends MenuItem {
             headingsPanelElement.children.item(i).addEventListener(getEventName(), (event: Event) => {
                 if (vditor.currentMode === "wysiwyg") {
                     document.execCommand("formatblock", false, (event.target as HTMLElement).tagName.toLowerCase());
+                    highlightToolbar(vditor);
                 } else {
                     insertText(vditor, (event.target as HTMLElement).getAttribute("data-value"), "",
                         false, true);

+ 60 - 35
src/ts/toolbar/MenuItem.ts

@@ -2,7 +2,8 @@ import {insertText} from "../editor/insertText";
 import {setSelectionFocus} from "../editor/setSelection";
 import {i18n} from "../i18n/index";
 import {getEventName} from "../util/getEventName";
-import {removeCurrentToolbar} from "./removeCurrentToolbar";
+import {hasClosestByMatchTag} from "../util/hasClosest";
+import {highlightToolbar} from "../wysiwyg/highlightToolbar";
 
 export class MenuItem {
     public element: HTMLElement;
@@ -29,65 +30,84 @@ export class MenuItem {
     public bindEvent(vditor: IVditor, replace: boolean = false) {
         this.element.children[0].addEventListener(getEventName(), (event) => {
             if (vditor.currentMode === "wysiwyg") {
+                let useHighlight = true;
                 const actionBtn = this.element.children[0];
                 if (actionBtn.classList.contains("vditor-menu--disabled")) {
                     return;
                 }
+                if (vditor.wysiwyg.element.querySelector("wbr")) {
+                    vditor.wysiwyg.element.querySelector("wbr").remove();
+                }
                 const range = getSelection().getRangeAt(0);
                 let commandName = actionBtn.getAttribute("data-type");
                 if (actionBtn.classList.contains("vditor-menu--current")) {
-                    if (commandName === "link") {
-                        commandName = "unlink";
-                    } else if (commandName === "strike") {
+                    if (commandName === "bold" || commandName === "italic" || commandName === "strike") {
+                        useHighlight = false;
+                        actionBtn.classList.remove("vditor-menu--current");
+                    }
+                    if (commandName === "strike") {
                         commandName = "strikeThrough";
-                    } else if (commandName === "list") {
+                    } else if (commandName === "list" || commandName === "check") {
                         commandName = "insertUnorderedList";
                     } else if (commandName === "ordered-list") {
                         commandName = "insertOrderedList";
                     }
                     if (commandName === "quote") {
-                        // const quoteElement = hasClosestByTag(range.commonAncestorContainer.nodeType === 3 ? range.commonAncestorContainer.parentElement : range.commonAncestorContainer as HTMLElement, 'BLOCKQUOTE')
-                        // const origalRange = range.cloneRange()
-                        // range.selectNode(quoteElement)
-                        document.execCommand("formatBlock", false, "P");
-                        // setSelectionFocus(origalRange)
+                        const quoteElement = hasClosestByMatchTag(range.startContainer.nodeType === 3 ?
+                            range.startContainer.parentNode as HTMLElement : range.startContainer as HTMLElement, "BLOCKQUOTE");
+                        const tempELement = document.createElement('div')
+                        tempELement.innerHTML = quoteElement.innerHTML
+                        quoteElement.parentNode.replaceChild(tempELement, quoteElement);
                     } else if (commandName === "inline-code") {
-                        range.selectNode(range.startContainer.nodeType === 3 ?
-                            range.startContainer.parentElement : range.startContainer.childNodes[range.startOffset]);
-                        document.execCommand("removeFormat", false, "");
+                        if (!range.collapsed) {
+                            document.execCommand("removeFormat", false, "");
+                        } else {
+                            range.selectNode(range.startContainer.parentElement);
+                            document.execCommand("removeFormat", false, "");
+                        }
+                    } else if (commandName === "link") {
+                        if (!range.collapsed) {
+                            document.execCommand("unlink", false, "");
+                        } else {
+                            range.selectNode(range.startContainer.parentElement);
+                            document.execCommand("unlink", false, "");
+                        }
                     } else {
+                        // bold, italic, check
                         document.execCommand(commandName, false, "");
                     }
                     vditor.wysiwyg.element.focus();
-                    actionBtn.classList.remove("vditor-menu--current");
                 } else {
+                    if (commandName === "bold" || commandName === "italic" || commandName === "strike") {
+                        useHighlight = false;
+                        actionBtn.classList.add("vditor-menu--current");
+                    }
+
                     if (commandName === "line") {
                         commandName = "insertHorizontalRule";
                     } else if (commandName === "strike") {
                         commandName = "strikeThrough";
                     } else if (commandName === "list") {
                         commandName = "insertUnorderedList";
-                        removeCurrentToolbar(vditor.toolbar.elements, ["ordered-list"]);
                     } else if (commandName === "ordered-list") {
                         commandName = "insertOrderedList";
-                        removeCurrentToolbar(vditor.toolbar.elements, ["list"]);
                     }
 
                     if (commandName === "quote") {
                         document.execCommand("formatBlock", false, "BLOCKQUOTE");
                     } else if (commandName === "check") {
-                        if (range.collapsed) {
+                        const liElement = hasClosestByMatchTag(range.startContainer.nodeType === 3 ?
+                            range.startContainer.parentNode as HTMLElement : range.startContainer as HTMLElement, "LI");
+                        if (liElement) {
+                            range.setStartAfter(liElement);
+                            range.collapse(true);
                             document.execCommand("insertHTML", false,
-                                '<ul><li class="vditor-task"><input type="checkbox" /> </li></ul>');
+                                '<li class="vditor-task"><input type="checkbox" /> </li>');
                         } else {
-                            const node = document.createElement("ul");
-                            node.innerHTML =
-                                `<li class="vditor-task"><input type="checkbox" /> ${range.toString()}</li>`;
-                            range.deleteContents();
-                            range.insertNode(node);
-                            range.selectNodeContents(node);
-                            setSelectionFocus(range);
+                            document.execCommand("insertHTML", false,
+                                '<ul><li class="vditor-task"><input type="checkbox" /> </li></ul>');
                         }
+
                     } else if (commandName === "inline-code") {
                         if (range.collapsed) {
                             const node = document.createTextNode("``");
@@ -98,19 +118,25 @@ export class MenuItem {
                             const node = document.createElement("code");
                             range.surroundContents(node);
                             range.insertNode(node);
-                            actionBtn.classList.add("vditor-menu--current");
                         }
                         setSelectionFocus(range);
                     } else if (commandName === "code") {
                         if (range.collapsed) {
-                            document.execCommand("insertHTML", false,
-                                "<div class='vditor-wysiwyg__block' data-type='code-block'><pre><code>\n</code></pre></div>");
+                            const node = document.createElement("div");
+                            node.className = "vditor-wysiwyg__block";
+                            node.setAttribute("data-type", "code-block");
+                            node.innerHTML = `<pre><code></code></pre>`;
+                            range.insertNode(node);
+                            range.selectNodeContents(node.firstChild.firstChild);
+                            setSelectionFocus(range);
                         } else {
                             const node = document.createElement("div");
+                            node.className = "vditor-wysiwyg__block";
+                            node.setAttribute("data-type", "code-block");
                             node.innerHTML = `<pre><code>${range.toString()}</code></pre>`;
                             range.deleteContents();
                             range.insertNode(node);
-                            range.selectNodeContents(node);
+                            range.selectNodeContents(node.firstChild.firstChild);
                             setSelectionFocus(range);
                         }
                     } else if (commandName === "link") {
@@ -119,13 +145,14 @@ export class MenuItem {
                             range.insertNode(textNode);
                             range.setStart(textNode, 1);
                             range.collapse(true);
-                            setSelectionFocus(range);
                         } else {
                             const node = document.createElement("a");
+                            node.setAttribute("href", "");
                             node.innerHTML = range.toString();
                             range.surroundContents(node);
                             range.insertNode(node);
                         }
+                        setSelectionFocus(range);
                     } else if (commandName === "table") {
                         document.execCommand("insertHTML", false,
                             "<table><thead><tr><th>col1</th><th>col2</th><th>col3</th></tr></thead>"
@@ -135,12 +162,10 @@ export class MenuItem {
                         document.execCommand(commandName, false, "");
                         vditor.wysiwyg.element.focus();
                     }
+                }
 
-                    if (commandName !== "insertHorizontalRule" && commandName !== "link"
-                        && commandName !== "inline-code"
-                        && commandName !== "check" && commandName !== "code" && commandName !== "table") {
-                        actionBtn.classList.add("vditor-menu--current");
-                    }
+                if (useHighlight) {
+                    highlightToolbar(vditor);
                 }
             } else {
                 insertText(vditor, this.menuItem.prefix || "", this.menuItem.suffix || "",

+ 23 - 25
src/ts/util/Options.ts

@@ -71,16 +71,10 @@ export class Options {
             suffix: "~~",
             tipPosition: "ne",
         }, {
-            name: "|",
-        }, {
-            hotkey: "⌘-⇧-d",
-            name: "line",
-            prefix: "---",
-            tipPosition: "n",
-        }, {
-            hotkey: "⌘-.",
-            name: "quote",
-            prefix: "> ",
+            hotkey: "⌘-k",
+            name: "link",
+            prefix: "[",
+            suffix: "](https://)",
             tipPosition: "n",
         }, {
             name: "|",
@@ -101,6 +95,16 @@ export class Options {
             tipPosition: "n",
         }, {
             name: "|",
+        }, {
+            hotkey: "⌘-.",
+            name: "quote",
+            prefix: "> ",
+            tipPosition: "n",
+        }, {
+            hotkey: "⌘-⇧-d",
+            name: "line",
+            prefix: "---",
+            tipPosition: "n",
         }, {
             hotkey: "⌘-u",
             name: "code",
@@ -115,24 +119,11 @@ export class Options {
             tipPosition: "n",
         }, {
             name: "|",
-        }, {
-            hotkey: "⌘-z",
-            name: "undo",
-            tipPosition: "n",
-        }, {
-            hotkey: "⌘-y",
-            name: "redo",
-            tipPosition: "n",
-        }, {
-            name: "|",
         }, {
             name: "upload",
             tipPosition: "n",
         }, {
-            hotkey: "⌘-k",
-            name: "link",
-            prefix: "[",
-            suffix: "](https://)",
+            name: "record",
             tipPosition: "n",
         }, {
             hotkey: "⌘-m",
@@ -141,7 +132,14 @@ export class Options {
             suffix: " | col2 | col3 |\n| --- | --- | --- |\n|  |  |  |\n|  |  |  |",
             tipPosition: "n",
         }, {
-            name: "record",
+            name: "|",
+        }, {
+            hotkey: "⌘-z",
+            name: "undo",
+            tipPosition: "n",
+        }, {
+            hotkey: "⌘-y",
+            name: "redo",
             tipPosition: "n",
         }, {
             name: "|",

+ 13 - 0
src/ts/util/hasClosest.ts

@@ -11,6 +11,19 @@ export const hasClosestByTag = (element: HTMLElement, nodeName: string) => {
     return isClosest && e;
 };
 
+export const hasClosestByMatchTag = (element: HTMLElement, nodeName: string) => {
+    let e = element;
+    let isClosest = false;
+    while (e && !isClosest && !e.classList.contains("vditor-wysiwyg")) {
+        if (e.nodeName === nodeName) {
+            isClosest = true;
+        } else {
+            e = e.parentElement;
+        }
+    }
+    return isClosest && e;
+};
+
 export const hasClosestByClassName = (element: HTMLElement, className: string) => {
     let e = element.nodeType === 3 ? element.parentElement : element;
     let isClosest = false;

+ 69 - 76
src/ts/wysiwyg/highlightToolbar.ts

@@ -17,60 +17,79 @@ import {disableToolbar} from "../toolbar/disableToolbar";
 import {enableToolbar} from "../toolbar/enableToolbar";
 import {removeCurrentToolbar} from "../toolbar/removeCurrentToolbar";
 import {setCurrentToolbar} from "../toolbar/setCurrentToolbar";
-import {hasClosestByClassName, hasClosestByTag, hasTopClosestByTag} from "../util/hasClosest";
+import {hasClosestByClassName, hasClosestByMatchTag, hasClosestByTag, hasTopClosestByTag} from "../util/hasClosest";
 
 export const highlightToolbar = (vditor: IVditor) => {
     if (getSelection().rangeCount === 0) {
         return;
     }
+
+    const allToolbar = ["headings", "bold", "italic", "strike", "line", "quote",
+        "list", "ordered-list", "check", "code", "inline-code", "upload", "link", "table", "record"];
+    removeCurrentToolbar(vditor.toolbar.elements, allToolbar);
+    enableToolbar(vditor.toolbar.elements, allToolbar);
+
     const range = getSelection().getRangeAt(0);
     let typeElement = range.startContainer as HTMLElement;
     if (range.startContainer.nodeType === 3) {
         typeElement = range.startContainer.parentElement;
     }
 
-    let toolbarName = typeElement.nodeName;
-    if (toolbarName === "B") {
-        toolbarName = "STRONG";
+    // 工具栏高亮和禁用
+    if (hasClosestByMatchTag(typeElement, "OL")) {
+        setCurrentToolbar(vditor.toolbar.elements, ["ordered-list"]);
     }
-    if (toolbarName === "I") {
-        toolbarName = "EM";
+
+    if (hasClosestByMatchTag(typeElement, "BLOCKQUOTE")) {
+        setCurrentToolbar(vditor.toolbar.elements, ["quote"]);
     }
-    if (toolbarName === "S") {
-        toolbarName = "STRIKE";
+
+    if (hasClosestByMatchTag(typeElement, "B") || hasClosestByMatchTag(typeElement, "STRONG")) {
+        setCurrentToolbar(vditor.toolbar.elements, ["bold"]);
     }
 
-    const tagToolbar: { [key: string]: string } = {
-        CODE: "inline-code",
-        EM: "italic",
-        STRIKE: "strike",
-        STRONG: "bold",
-    };
+    if (hasClosestByMatchTag(typeElement, "EM") || hasClosestByMatchTag(typeElement, "I")) {
+        setCurrentToolbar(vditor.toolbar.elements, ["italic"]);
+    }
+
+    if (hasClosestByMatchTag(typeElement, "STRIKE") || hasClosestByMatchTag(typeElement, "S")) {
+        setCurrentToolbar(vditor.toolbar.elements, ["strike"]);
+    }
 
-    // 工具栏高亮
-    Object.keys(tagToolbar).forEach((key) => {
-        const value = tagToolbar[key];
-        if (toolbarName === key) {
-            setCurrentToolbar(vditor.toolbar.elements, [value]);
+    if (hasClosestByMatchTag(typeElement, "A")) {
+        setCurrentToolbar(vditor.toolbar.elements, ["link"]);
+    }
+    const ulElement = hasClosestByMatchTag(typeElement, "UL");
+    if (hasClosestByMatchTag(typeElement, "CODE")) {
+        if (hasClosestByMatchTag(typeElement, "PRE")) {
+            disableToolbar(vditor.toolbar.elements, ["headings", "bold", "italic", "strike", "line", "quote",
+                "list", "ordered-list", "check", "code", "inline-code", "upload", "link", "table", "record"]);
+            setCurrentToolbar(vditor.toolbar.elements, ["code"]);
         } else {
-            removeCurrentToolbar(vditor.toolbar.elements, [value]);
+            disableToolbar(vditor.toolbar.elements, ["headings", "bold", "italic", "strike", "line", "quote",
+                "list", "ordered-list", "check", "code", "upload", "link", "table", "record"]);
+            setCurrentToolbar(vditor.toolbar.elements, ["inline-code"]);
         }
-    });
-
-    if (hasClosestByTag(typeElement, "UL")) {
+    } else if (hasClosestByTag(typeElement, "H")) {
+        disableToolbar(vditor.toolbar.elements, ["bold"]);
+        setCurrentToolbar(vditor.toolbar.elements, ["headings"]);
+    } else if (ulElement && !ulElement.querySelector("input")) {
         setCurrentToolbar(vditor.toolbar.elements, ["list"]);
-    } else {
-        removeCurrentToolbar(vditor.toolbar.elements, ["list"]);
-    }
-    if (hasClosestByTag(typeElement, "OL")) {
+    } else if (hasClosestByMatchTag(typeElement, "OL")) {
         setCurrentToolbar(vditor.toolbar.elements, ["ordered-list"]);
-    } else {
-        removeCurrentToolbar(vditor.toolbar.elements, ["ordered-list"]);
     }
 
-    // ul popover
-    const topUlElement = hasTopClosestByTag(typeElement, "UL") as HTMLElement;
-    if (topUlElement) {
+    // list popover
+    const topUlElement = hasTopClosestByTag(typeElement, "UL");
+    const topOlElement = hasTopClosestByTag(typeElement, "OL");
+    let topListElement = topUlElement;
+    if (topOlElement && (!topUlElement || (topUlElement && topOlElement.contains(topUlElement)))) {
+        topListElement = topOlElement;
+    }
+    if (topListElement && topListElement.querySelector("input")) {
+        topListElement = false;
+    }
+    if (topListElement) {
         vditor.wysiwyg.popover.innerHTML = "";
 
         const outdent = document.createElement("sapn");
@@ -90,28 +109,26 @@ export const highlightToolbar = (vditor: IVditor) => {
         vditor.wysiwyg.popover.insertAdjacentElement("beforeend", outdent);
         vditor.wysiwyg.popover.insertAdjacentElement("beforeend", indent);
 
-        setPopoverPosition(vditor, topUlElement);
+        setPopoverPosition(vditor, topListElement);
     }
 
     // quote popover
     let blockquoteElement = hasClosestByTag(typeElement, "BLOCKQUOTE") as HTMLTableElement;
     if (blockquoteElement && !(topUlElement && blockquoteElement.contains(topUlElement))) {
         vditor.wysiwyg.popover.innerHTML = "";
-        const insertBefore = genInsertBefore(range, blockquoteElement);
-        const insertAfter = genInsertAfter(range, blockquoteElement);
-        const close = genClose(vditor.wysiwyg.popover, blockquoteElement);
+        const insertBefore = genInsertBefore(range, blockquoteElement, vditor);
+        const insertAfter = genInsertAfter(range, blockquoteElement, vditor);
+        const close = genClose(vditor.wysiwyg.popover, blockquoteElement, vditor);
         vditor.wysiwyg.popover.insertAdjacentElement("beforeend", insertBefore);
         vditor.wysiwyg.popover.insertAdjacentElement("beforeend", insertAfter);
         vditor.wysiwyg.popover.insertAdjacentElement("beforeend", close);
         setPopoverPosition(vditor, blockquoteElement);
-        setCurrentToolbar(vditor.toolbar.elements, ["quote"]);
     } else {
         blockquoteElement = undefined;
-        removeCurrentToolbar(vditor.toolbar.elements, ["ordered-list"]);
     }
 
     // table popover
-    const tableElement = hasClosestByTag(typeElement, "TABLE") as HTMLTableElement;
+    const tableElement = hasClosestByMatchTag(typeElement, "TABLE") as HTMLTableElement;
     if (tableElement) {
         vditor.wysiwyg.popover.innerHTML = "";
         const updateTable = () => {
@@ -187,14 +204,7 @@ export const highlightToolbar = (vditor: IVditor) => {
             }
         };
 
-        const close = document.createElement("sapn");
-        close.innerHTML = trashcanSVG;
-        close.className = "vditor-icon";
-        close.onclick = () => {
-            tableElement.remove();
-            vditor.wysiwyg.popover.style.display = "none";
-        };
-
+        const close = genClose(vditor.wysiwyg.popover, tableElement, vditor);
         vditor.wysiwyg.popover.insertAdjacentElement("beforeend", input);
         vditor.wysiwyg.popover.insertAdjacentHTML("beforeend", " x ");
         vditor.wysiwyg.popover.insertAdjacentElement("beforeend", input2);
@@ -238,16 +248,12 @@ export const highlightToolbar = (vditor: IVditor) => {
         vditor.wysiwyg.popover.insertAdjacentElement("beforeend", input2);
 
         setPopoverPosition(vditor, typeElement);
-
-        disableToolbar(vditor.toolbar.elements, ["link"]);
-    } else {
-        enableToolbar(vditor.toolbar.elements, ["link"]);
     }
 
     // img popover
     let imgElement: HTMLImageElement;
-    if (range.startContainer.nodeType !== 3 && range.startContainer.childNodes.length > range.startOffset
-        && range.startContainer.childNodes[range.startOffset].nodeName === "IMG") {
+    if (range.startContainer.nodeType !== 3 && range.startContainer.childNodes.length > range.startOffset &&
+        range.startContainer.childNodes[range.startOffset].nodeName === "IMG") {
         imgElement = range.startContainer.childNodes[range.startOffset] as HTMLImageElement;
         vditor.wysiwyg.popover.innerHTML = "";
         const updateImg = () => {
@@ -321,9 +327,9 @@ export const highlightToolbar = (vditor: IVditor) => {
 
         const language = document.createElement("input");
         if (blockType.indexOf("block") > -1) {
-            const insertBefore = genInsertBefore(range, blockElement);
-            const insertAfter = genInsertAfter(range, blockElement);
-            const close = genClose(vditor.wysiwyg.popover, blockElement);
+            const insertBefore = genInsertBefore(range, blockElement, vditor);
+            const insertAfter = genInsertAfter(range, blockElement, vditor);
+            const close = genClose(vditor.wysiwyg.popover, blockElement, vditor);
             vditor.wysiwyg.popover.insertAdjacentElement("beforeend", insertBefore);
             vditor.wysiwyg.popover.insertAdjacentElement("beforeend", insertAfter);
             vditor.wysiwyg.popover.insertAdjacentElement("beforeend", close);
@@ -376,23 +382,7 @@ export const highlightToolbar = (vditor: IVditor) => {
         setPopoverPosition(vditor, blockElement);
     }
 
-    if (hasClosestByTag(typeElement, "CODE")) {
-        disableToolbar(vditor.toolbar.elements, ["headings", "bold", "italic", "strike", "line", "quote",
-            "list", "ordered-list", "check", "code", "inline-code", "upload", "link", "table", "record"]);
-    } else {
-        enableToolbar(vditor.toolbar.elements, ["headings", "italic", "strike", "line", "quote",
-            "list", "ordered-list", "check", "code", "inline-code", "upload", "link", "table", "record"]);
-
-        if (hasClosestByTag(typeElement, "H")) {
-            disableToolbar(vditor.toolbar.elements, ["bold"]);
-            setCurrentToolbar(vditor.toolbar.elements, ["headings"]);
-        } else {
-            removeCurrentToolbar(vditor.toolbar.elements, ["headings"]);
-            enableToolbar(vditor.toolbar.elements, ["bold"]);
-        }
-    }
-
-    if (!blockquoteElement && !imgElement && !topUlElement && !tableElement && !blockElement
+    if (!blockquoteElement && !imgElement && !topListElement && !tableElement && !blockElement
         && typeElement.nodeName !== "A" && !hasClosestByClassName(typeElement, "vditor-panel")) {
         vditor.wysiwyg.popover.style.display = "none";
     }
@@ -404,7 +394,7 @@ const setPopoverPosition = (vditor: IVditor, element: HTMLElement) => {
     vditor.wysiwyg.popover.style.display = "block";
 };
 
-const genInsertBefore = (range: Range, element: HTMLElement) => {
+const genInsertBefore = (range: Range, element: HTMLElement, vditor: IVditor) => {
     const insertBefore = document.createElement("span");
     insertBefore.innerHTML = beforeSVG;
     insertBefore.className = "vditor-icon";
@@ -416,11 +406,12 @@ const genInsertBefore = (range: Range, element: HTMLElement) => {
         range.insertNode(node);
         range.collapse(true);
         setSelectionFocus(range);
+        highlightToolbar(vditor);
     };
     return insertBefore;
 };
 
-const genInsertAfter = (range: Range, element: HTMLElement) => {
+const genInsertAfter = (range: Range, element: HTMLElement, vditor: IVditor) => {
     const insertAfter = document.createElement("span");
     insertAfter.innerHTML = afterSVG;
     insertAfter.className = "vditor-icon";
@@ -432,17 +423,19 @@ const genInsertAfter = (range: Range, element: HTMLElement) => {
         range.insertNode(node);
         range.collapse(true);
         setSelectionFocus(range);
+        highlightToolbar(vditor);
     };
     return insertAfter;
 };
 
-const genClose = (popover: HTMLElement, element: HTMLElement) => {
+const genClose = (popover: HTMLElement, element: HTMLElement, vditor: IVditor) => {
     const close = document.createElement("span");
     close.innerHTML = trashcanSVG;
     close.className = "vditor-icon";
     close.onclick = () => {
         element.remove();
         popover.style.display = "none";
+        highlightToolbar(vditor);
     };
     return close;
 };

+ 3 - 3
src/ts/wysiwyg/index.ts

@@ -163,9 +163,9 @@ class WYSIWYG {
 
                 // markdown 纠正
                 // 合并多个 em, strong,s。以防止多个相同元素在一起时不满足 commonmark 规范,出现标记符
-                const vditorHTML = this.element.innerHTML.replace(/<\/strong><strong data-marker="[\*\*|__]">/g, "")
-                    .replace(/<\/em><em data-marker="[\*|_]">/g, "")
-                    .replace(/<\/s><s data-marker="~+">/g, "");
+                const vditorHTML = this.element.innerHTML.replace(/<\/strong><strong data-marker="\W{2}">/g, "")
+                    .replace(/<\/em><em data-marker="\W{1}">/g, "")
+                    .replace(/<\/s><s data-marker="~{1,2}">/g, "");
                 console.log(`SpinVditorDOM-argument:[${
                     vditorHTML.split('<div class="vditor-panel vditor-panel--none"')[0]}]`);
                 this.element.innerHTML = vditor.lute.SpinVditorDOM(vditorHTML);

+ 7 - 2
src/ts/wysiwyg/processPreCode.ts

@@ -10,9 +10,14 @@ export const processPreCode = (editor: HTMLElement) => {
             || "\n");
 
         if (isFocus) {
-            // 解决在 `` 中输入字符后光标错误
             const range = editor.ownerDocument.createRange();
-            range.setStart(codeElement.childNodes[0], codeElement.innerText.length);
+            if (codeElement.childNodes[0].nodeType === 3) {
+                // 解决在 `` 中输入字符后光标错误
+                range.setStart(codeElement.childNodes[0], codeElement.innerText.length);
+            } else {
+                // 输入 ```
+                range.setStartAfter(codeElement.childNodes[0]);
+            }
             range.collapse(true);
             setSelectionFocus(range);
         }