Parcourir la source

:art: #27 quote & link

Liyuan Li il y a 5 ans
Parent
commit
e0aaa0a5ba

+ 12 - 0
src/assets/scss/_ir.scss

@@ -127,6 +127,18 @@
     }
   }
 
+  blockquote:empty::before,
+  pre > code:empty::before,
+  p:empty::before,
+  h1:empty::after,
+  h2:empty::after,
+  h3:empty::after,
+  h4:empty::after,
+  h5:empty::after,
+  h6:empty::after {
+    content: ' ';
+  }
+
   // block title
   h1:before,
   h2:before,

+ 17 - 4
src/ts/ir/highlightToolbar.ts

@@ -1,5 +1,5 @@
 import {enableToolbar, removeCurrentToolbar, setCurrentToolbar} from "../toolbar/setToolbar";
-import {hasClosestByTag} from "../util/hasClosest";
+import {hasClosestByAttribute, hasClosestByMatchTag, hasClosestByTag} from "../util/hasClosest";
 import {getEditorRange, selectIsEditor} from "../util/selection";
 
 export const highlightToolbar = (vditor: IVditor) => {
@@ -18,18 +18,31 @@ export const highlightToolbar = (vditor: IVditor) => {
         enableToolbar(vditor.toolbar.elements, allToolbar);
 
         const range = getEditorRange(vditor.ir.element);
-        let typeElement = range.startContainer as HTMLElement;
+        let typeElement = range.startContainer as HTMLElement
         if (range.startContainer.nodeType === 3) {
             typeElement = range.startContainer.parentElement;
         }
         if (typeElement.classList.contains("vditor-reset")) {
-            typeElement = typeElement.childNodes[range.startOffset] as HTMLElement;
+            typeElement = typeElement.childNodes[range.startOffset] as HTMLElement
         }
 
-        const headingElement = hasClosestByTag(typeElement, "H") as HTMLElement;
+        const headingElement = hasClosestByTag(typeElement, "H")
         if (headingElement && headingElement.tagName.length === 2) {
             setCurrentToolbar(vditor.toolbar.elements, ["headings"]);
         }
 
+        const quoteElement = hasClosestByMatchTag(typeElement, "BLOCKQUOTE")
+        if (quoteElement) {
+            setCurrentToolbar(vditor.toolbar.elements, ["quote"]);
+        }
+        const aElement = hasClosestByAttribute(typeElement, "data-type", "a")
+        if (aElement) {
+            setCurrentToolbar(vditor.toolbar.elements, ["link"]);
+        }
+        const emElement = hasClosestByAttribute(typeElement, "data-type", "em")
+        if (emElement) {
+            setCurrentToolbar(vditor.toolbar.elements, ["italic"]);
+        }
+
     }, 200);
 };

+ 9 - 1
src/ts/ir/input.ts

@@ -50,7 +50,15 @@ export const input = (vditor: IVditor, range: Range) => {
         // 使用顶级块元素,应使用 innerHTML
         blockElement = vditor.ir.element;
     }
-    range.insertNode(document.createElement("wbr"));
+    if (!blockElement.querySelector('wbr')) {
+        // document.exeComment insertHTML 会插入 wbr
+        range.insertNode(document.createElement("wbr"));
+    }
+    // 清除浏览器自带的样式
+    blockElement.querySelectorAll("[style]").forEach((item) => {
+        item.removeAttribute("style");
+    });
+
     const isIRElement = blockElement.isEqualNode(vditor.ir.element);
     let html = "";
     if (!isIRElement) {

+ 45 - 9
src/ts/ir/process.ts

@@ -8,7 +8,7 @@ import {mathRender} from "../markdown/mathRender";
 import {mermaidRender} from "../markdown/mermaidRender";
 import {isSafari} from "../util/compatibility";
 import {getMarkdown} from "../util/getMarkdown";
-import {hasClosestBlock, hasClosestByAttribute} from "../util/hasClosest";
+import {hasClosestBlock, hasClosestByAttribute, hasClosestByClassName, hasClosestByMatchTag} from "../util/hasClosest";
 import {getEditorRange, setRangeByWbr} from "../util/selection";
 import {highlightToolbar} from "./highlightToolbar";
 
@@ -106,19 +106,55 @@ export const processHeading = (vditor: IVditor, value: string) => {
 export const processToolbar = (vditor: IVditor, actionBtn: Element) => {
     const range = getEditorRange(vditor.ir.element);
     const commandName = actionBtn.getAttribute("data-type");
+    let typeElement = range.startContainer as HTMLElement
+    if (range.startContainer.nodeType !== 3 && typeElement.classList.contains("vditor-reset")) {
+        typeElement = typeElement.childNodes[range.startOffset] as HTMLElement
+    }
     // 移除
     if (actionBtn.classList.contains("vditor-menu--current")) {
-
+        if (commandName === "quote") {
+            const quoteElement = hasClosestByMatchTag(typeElement, "BLOCKQUOTE");
+            if (quoteElement) {
+                range.insertNode(document.createElement("wbr"));
+                quoteElement.outerHTML = quoteElement.innerHTML.trim() === "" ?
+                    `<p data-block="0">${quoteElement.innerHTML}</p>` : quoteElement.innerHTML;
+            }
+        } else if (commandName === "link") {
+            const aElement = hasClosestByAttribute(range.startContainer, "data-type", "a") as HTMLElement;
+            if (aElement) {
+                const aTextElement = hasClosestByClassName(range.startContainer, "vditor-ir__link")
+                if (aTextElement) {
+                    range.insertNode(document.createElement("wbr"));
+                    aElement.outerHTML = aTextElement.innerHTML;
+                } else {
+                    aElement.outerHTML = aElement.querySelector('.vditor-ir__link').innerHTML + "<wbr>"
+                }
+            }
+        }
     } else {
         // 添加
+        if (vditor.ir.element.childNodes.length === 0) {
+            vditor.ir.element.innerHTML = '<p data-block="0"><wbr></p>';
+            setRangeByWbr(vditor.ir.element, range);
+        }
+
         if (commandName === "line") {
-            let element = range.startContainer as HTMLElement;
-            if (element.nodeType === 3) {
-                element = range.startContainer.parentElement;
+            typeElement.insertAdjacentHTML("afterend", '<hr data-block="0"><p data-block="0">\n<wbr></p>');
+        } else if (commandName === "quote") {
+            const blockElement = hasClosestBlock(range.startContainer);
+            if (blockElement) {
+                range.insertNode(document.createElement("wbr"));
+                blockElement.outerHTML = `<blockquote data-block="0">${blockElement.outerHTML}</blockquote>`;
+            }
+        } else if (commandName === "link") {
+            if (range.toString() === "") {
+                document.execCommand("insertHTML", false, "[<wbr>]()")
+            } else {
+                document.execCommand("insertHTML", false, `[${range.toString()}](<wbr>)`)
             }
-            element.insertAdjacentHTML("afterend", '<hr data-block="0"><p data-block="0">\n<wbr></p>');
-            setRangeByWbr(vditor.ir.element, range);
-            processAfterRender(vditor);
         }
     }
-};
+    setRangeByWbr(vditor.ir.element, range);
+    processAfterRender(vditor);
+    highlightToolbar(vditor);
+}

+ 1 - 1
src/ts/toolbar/EditMode.ts

@@ -27,7 +27,7 @@ export const setEditMode = (vditor: IVditor, type: string, event?: Event) => {
     enableToolbar(vditor.toolbar.elements, allToolbar);
     removeCurrentToolbar(vditor.toolbar.elements, allToolbar);
 
-    const irUnUsedToolbar = ["bold", "italic", "strike", "link", "list", "ordered-list", "check", "quote", "code", "inline-code", "table"];
+    const irUnUsedToolbar = ["bold", "italic", "strike", "list", "ordered-list", "check", "code", "inline-code", "table"];
     showToolbar(vditor.toolbar.elements, irUnUsedToolbar);
     if (type === "ir") {
         hideToolbar(vditor.toolbar.elements, ["format", "both", "preview"].concat(irUnUsedToolbar));