Browse Source

:sparkles: 添加 debugger 参数

Van 6 years ago
parent
commit
167e77619e

+ 2 - 0
CHANGELOG.md

@@ -4,6 +4,7 @@
 
 * v2.0
   * 默认为 WYSIWYG 模式,可根据需要修改 option.mode 参数
+  * 添加 options.debugger 
 * v1.9
   * preview 静态方法参数修改为 `(previewElement: HTMLDivElement, markdown: string, options?: IPreviewOptions)`,其中参数 `IPreviewOptions` 修改为
     ```ts
@@ -47,6 +48,7 @@
 * [2](https://github.com/Vanessa219/vditor/issues/2) 所见即所得 `enhancement`
 * 文档更新
   * 添加 option.mode?: "wysiwyg-show" | "markdown-show" | "wysiwyg-only" | "markdown-only" 参数
+  * 添加 options.debugger
 
 ### v1.10.11 / 2019-12-12
 

+ 2 - 1
demo/index.js

@@ -2,10 +2,11 @@ import Vditor from '../src/index'
 import '../src/assets/scss/classic.scss'
 
 window.vditor = new Vditor('vditor', {
+  debugger: true,
   typewriterMode: false,
   placeholder: 'placeholder',
   counter: 100,
-  height: 300,
+  height: 600,
   hint: {
     emojiPath: 'https://cdn.jsdelivr.net/npm/[email protected]/dist/images/emoji',
     emojiTail: '<a href="https://hacpai.com/settings/function" target="_blank">设置常用表情</a>',

+ 16 - 3
src/assets/scss/_wysiwyg.scss

@@ -31,8 +31,8 @@
       margin-bottom: -1em;
 
       & > code {
-        background-color: $hoverBg !important;
-        color: $hoverColor;
+        background-color: #fff !important;
+        border: 1px solid $borderColor;
         overflow: auto !important;
       }
     }
@@ -41,6 +41,7 @@
   &__preview {
     cursor: pointer;
     white-space: initial;
+    min-height: 27px;
 
     pre {
       margin-bottom: 1em !important;
@@ -52,7 +53,8 @@
   h3:before,
   h4:before,
   h5:before,
-  h6:before {
+  h6:before,
+  div.vditor-wysiwyg__block:before {
     float: left;
     padding-right: 4px;
     margin-left: -20px;
@@ -82,4 +84,15 @@
   h6:before {
     content: 'h6';
   }
+
+  div.vditor-wysiwyg__block {
+    &:before {
+      content: attr(data-type);
+      margin-left: -93px;
+    }
+  }
+
+  details {
+    white-space: initial;
+  }
 }

+ 2 - 2
src/ts/markdown/md2html.ts

@@ -10,8 +10,8 @@ export const loadLuteJs = async (vditor: IVditor | string) => {
     } else if (typeof vditor === "object" && vditor.options.cdn) {
         cdn = vditor.options.cdn;
     }
-    addScript(`${cdn}/dist/js/lute/lute.min.js`, "vditorLuteScript");
-    // addScript(`http://192.168.0.107:9090/lute.min.js?${new Date().getTime()}`, "vditorLuteScript");
+    // addScript(`${cdn}/dist/js/lute/lute.min.js`, "vditorLuteScript");
+    addScript(`http://192.168.0.107:9090/lute.min.js?${new Date().getTime()}`, "vditorLuteScript");
 
     if (vditor && typeof vditor === "object" && !vditor.lute) {
         vditor.lute = Lute.New();

+ 5 - 3
src/ts/toolbar/MenuItem.ts

@@ -6,6 +6,7 @@ import {hasClosestByMatchTag} from "../util/hasClosest";
 import {afterRenderEvent} from "../wysiwyg/afterRenderEvent";
 import {highlightToolbar} from "../wysiwyg/highlightToolbar";
 import {setCurrentToolbar} from "./setCurrentToolbar";
+import {processCodeRender} from "../wysiwyg/processCodeRender";
 
 export class MenuItem {
     public element: HTMLElement;
@@ -127,8 +128,8 @@ export class MenuItem {
                         useHighlight = false;
                         setCurrentToolbar(vditor.toolbar.elements, ["inline-code"]);
                     } else if (commandName === "code") {
+                        const node = document.createElement("div");
                         if (range.collapsed) {
-                            const node = document.createElement("div");
                             node.className = "vditor-wysiwyg__block";
                             node.setAttribute("data-type", "code-block");
                             node.innerHTML = `<pre data-block="0"><code></code></pre>`;
@@ -136,15 +137,16 @@ export class MenuItem {
                             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 data-block="0"><code>${range.toString()}</code></pre>`;
+                            node.innerHTML = `<pre data-block="0"><code data-code="${
+                                decodeURIComponent(range.toString())}">${range.toString()}</code></pre>`;
                             range.deleteContents();
                             range.insertNode(node);
                             range.selectNodeContents(node.firstChild.firstChild);
                             setSelectionFocus(range);
                         }
+                        processCodeRender(node, vditor);
                     } else if (commandName === "link") {
                         if (range.collapsed) {
                             const textNode = document.createTextNode("[]()");

+ 1 - 0
src/ts/types/index.d.ts

@@ -182,6 +182,7 @@ interface IResize {
 }
 
 interface IOptions {
+    debugger?: boolean;
     after?: () => void;
     typewriterMode?: boolean;
     keymap?: { [key: string]: string };

+ 2 - 2
src/ts/ui/index.ts

@@ -82,9 +82,9 @@ export class Ui {
         if (vditor.wysiwyg) {
             const padding = (vditor.wysiwyg.element.parentElement.scrollWidth - vditor.options.preview.maxWidth) / 2;
             if (vditor.options.typewriterMode) {
-                vditor.wysiwyg.element.style.padding = `21px ${Math.max(10, padding)}px ${height / 2}px`;
+                vditor.wysiwyg.element.style.padding = `21px ${Math.max(100, padding)}px ${height / 2}px`;
             } else {
-                vditor.wysiwyg.element.style.padding = `21px ${Math.max(10, padding)}px 10px`;
+                vditor.wysiwyg.element.style.padding = `21px ${Math.max(100, padding)}px 10px`;
             }
         }
 

+ 1 - 0
src/ts/util/Options.ts

@@ -10,6 +10,7 @@ export class Options {
             preview: "",
         },
         counter: 0,
+        debugger: false,
         height: "auto",
         hint: {
             delay: 200,

+ 41 - 17
src/ts/util/editorCommenEvent.ts

@@ -166,25 +166,49 @@ export const hotkeyEvent = (vditor: IVditor, editorElement: HTMLElement) => {
         }
 
         // delete
-        if (!event.metaKey && !event.ctrlKey && !event.shiftKey && event.keyCode === 8
-            && vditor.currentMode === "markdown") {
-            const position = getSelectPosition(editorElement);
-            if (position.start !== position.end) {
-                insertText(vditor, "", "", true);
+        if (!event.metaKey && !event.ctrlKey && !event.shiftKey && event.keyCode === 8) {
+            if (vditor.currentMode === "markdown") {
+                const position = getSelectPosition(editorElement);
+                if (position.start !== position.end) {
+                    insertText(vditor, "", "", true);
+                } else {
+                    // delete emoji
+                    const text = getText(vditor);
+                    const emojiMatch = text.substring(0, position.start).match(/([\u{1F300}-\u{1F5FF}][\u{2000}-\u{206F}][\u{2700}-\u{27BF}]|([\u{1F900}-\u{1F9FF}]|[\u{1F300}-\u{1F5FF}]|[\u{1F680}-\u{1F6FF}]|[\u{1F600}-\u{1F64F}])[\u{2000}-\u{206F}][\u{2600}-\u{26FF}]|[\u{1F300}-\u{1F5FF}]|[\u{1F100}-\u{1F1FF}]|[\u{1F600}-\u{1F64F}]|[\u{1F680}-\u{1F6FF}]|[\u{1F200}-\u{1F2FF}]|[\u{1F900}-\u{1F9FF}]|[\u{1F000}-\u{1F02F}]|[\u{FE00}-\u{FE0F}]|[\u{1F0A0}-\u{1F0FF}]|[\u{0000}-\u{007F}][\u{20D0}-\u{20FF}]|[\u{0000}-\u{007F}][\u{FE00}-\u{FE0F}][\u{20D0}-\u{20FF}])$/u);
+                    const deleteChar = emojiMatch ? emojiMatch[0].length : 1;
+                    formatRender(vditor,
+                        text.substring(0, position.start - deleteChar) + text.substring(position.start),
+                        {
+                            end: position.start - deleteChar,
+                            start: position.start - deleteChar,
+                        });
+                }
+                event.preventDefault();
+                event.stopPropagation();
             } else {
-                // delete emoji
-                const text = getText(vditor);
-                const emojiMatch = text.substring(0, position.start).match(/([\u{1F300}-\u{1F5FF}][\u{2000}-\u{206F}][\u{2700}-\u{27BF}]|([\u{1F900}-\u{1F9FF}]|[\u{1F300}-\u{1F5FF}]|[\u{1F680}-\u{1F6FF}]|[\u{1F600}-\u{1F64F}])[\u{2000}-\u{206F}][\u{2600}-\u{26FF}]|[\u{1F300}-\u{1F5FF}]|[\u{1F100}-\u{1F1FF}]|[\u{1F600}-\u{1F64F}]|[\u{1F680}-\u{1F6FF}]|[\u{1F200}-\u{1F2FF}]|[\u{1F900}-\u{1F9FF}]|[\u{1F000}-\u{1F02F}]|[\u{FE00}-\u{FE0F}]|[\u{1F0A0}-\u{1F0FF}]|[\u{0000}-\u{007F}][\u{20D0}-\u{20FF}]|[\u{0000}-\u{007F}][\u{FE00}-\u{FE0F}][\u{20D0}-\u{20FF}])$/u);
-                const deleteChar = emojiMatch ? emojiMatch[0].length : 1;
-                formatRender(vditor,
-                    text.substring(0, position.start - deleteChar) + text.substring(position.start),
-                    {
-                        end: position.start - deleteChar,
-                        start: position.start - deleteChar,
-                    });
+                const range = getSelection().getRangeAt(0);
+                if (range.startContainer.nodeType === 3 && range.startOffset === 0) {
+                    const blockRenderElement = range.startContainer.parentElement.previousElementSibling as HTMLElement;
+                    if (blockRenderElement && blockRenderElement.classList.contains('vditor-wysiwyg__block')) {
+
+                        (blockRenderElement.lastElementChild as HTMLElement).click()
+                        event.preventDefault();
+                        event.stopPropagation();
+                    }
+                }
+                if (range.startOffset === 0 && range.startContainer.parentElement.tagName === "CODE" &&
+                    range.startContainer.parentElement.parentElement.parentElement.classList
+                        .contains("vditor-wysiwyg__block")) {
+                    // 渲染代码块中在第一个字符前进行删除时,仅删除代码块,其内容不变
+                    const text = document.createTextNode(range.startContainer.parentElement.textContent)
+                    range.setStartBefore(range.startContainer.parentElement.parentElement.parentElement);
+                    range.insertNode(text);
+                    range.collapse(true);
+                    (vditor.wysiwyg.popover.firstElementChild as HTMLElement).click();
+                    event.preventDefault();
+                    event.stopPropagation();
+                }
             }
-            event.preventDefault();
-            event.stopPropagation();
             return;
         }
 

+ 6 - 0
src/ts/util/log.ts

@@ -0,0 +1,6 @@
+export const log = (method: string, content: string, type: string, print: boolean) => {
+    if (print) {
+        // @ts-ignore
+        console.log(`${method} - ${type}: ${content}`);
+    }
+};

+ 49 - 19
src/ts/wysiwyg/index.ts

@@ -1,14 +1,16 @@
 import {getSelectPosition} from "../editor/getSelectPosition";
-import {setSelectionFocus} from "../editor/setSelection";
+import {setSelectionByPosition, setSelectionFocus} from "../editor/setSelection";
 import {uploadFiles} from "../upload";
 import {focusEvent, hotkeyEvent, scrollCenter, selectEvent} from "../util/editorCommenEvent";
 import {hasClosestByClassName, hasClosestByTag} from "../util/hasClosest";
+import {log} from "../util/log";
 import {processPasteCode} from "../util/processPasteCode";
 import {afterRenderEvent} from "./afterRenderEvent";
 import {getParentBlock} from "./getParentBlock";
 import {highlightToolbar} from "./highlightToolbar";
 import {input} from "./input";
 import {insertHTML} from "./insertHTML";
+import {processCodeData} from "./processCodeData";
 import {processCodeRender} from "./processCodeRender";
 
 class WYSIWYG {
@@ -74,7 +76,7 @@ class WYSIWYG {
                     decodeURIComponent(codeElement.getAttribute("data-code")));
             });
 
-            event.clipboardData.setData("text/plain", vditor.lute.VditorDOM2Md(tempElement.innerHTML));
+            event.clipboardData.setData("text/plain", vditor.lute.VditorDOM2Md(tempElement.innerHTML).trim());
             event.clipboardData.setData("text/html", "");
         });
 
@@ -97,11 +99,16 @@ class WYSIWYG {
             const code = processPasteCode(textHTML, textPlain, "wysiwyg");
             if (event.target.tagName === "CODE") {
                 // 粘贴在代码位置
-                insertHTML(textPlain, this.element);
-                event.target.setAttribute("data-code", encodeURIComponent(event.target.innerText));
+                const position = getSelectPosition(event.target);
+                event.target.textContent = event.target.textContent.substring(0, position.start)
+                    + textPlain + event.target.textContent.substring(position.end);
+                event.target.setAttribute("data-code", encodeURIComponent(event.target.textContent));
+                setSelectionByPosition(position.start + textPlain.length, position.start + textPlain.length,
+                    event.target.parentElement);
             } else if (code) {
                 insertHTML(`<div class="vditor-wysiwyg__block" data-type="code-block"><pre><code data-code="${
-                    encodeURIComponent(code)}"></code></pre></div>`, this.element);
+                    encodeURIComponent(code)}"></code></pre></div>`);
+                processCodeData(this.element);
             } else {
                 if (textHTML.trim() !== "") {
                     const tempElement = document.createElement("div");
@@ -109,18 +116,22 @@ class WYSIWYG {
                     tempElement.querySelectorAll("[style]").forEach((e) => {
                         e.removeAttribute("style");
                     });
-                    insertHTML(vditor.lute.HTML2VditorDOM(tempElement.innerHTML), this.element);
+                    insertHTML(vditor.lute.HTML2VditorDOM(tempElement.innerHTML));
+                    processCodeData(this.element);
                 } else if (event.clipboardData.files.length > 0 && vditor.options.upload.url) {
                     uploadFiles(vditor, event.clipboardData.files);
                 } else if (textPlain.trim() !== "" && event.clipboardData.files.length === 0) {
+                    log("Md2VditorDOM", textPlain, "argument", vditor.options.debugger);
                     let vditorDomHTML = vditor.lute.Md2VditorDOM(textPlain);
+                    log("Md2VditorDOM", vditorDomHTML, "result", vditor.options.debugger);
                     const tempElement = document.createElement("div");
                     tempElement.innerHTML = vditorDomHTML;
                     const pElements = tempElement.querySelectorAll("p");
                     if (pElements.length === 1) {
                         vditorDomHTML = pElements[0].innerHTML;
                     }
-                    insertHTML(vditorDomHTML, this.element);
+                    insertHTML(vditorDomHTML);
+                    processCodeData(this.element);
                 }
             }
 
@@ -205,27 +216,46 @@ class WYSIWYG {
             }
             highlightToolbar(vditor);
 
+            if (event.key !== "ArrowDown" && event.key !== "ArrowRight" && event.key !== "Backspace"
+                && event.key !== "ArrowLeft" && event.key !== "ArrowUp") {
+                return;
+            }
             // 上下左右遇到块预览的处理
             const range = getSelection().getRangeAt(0);
             const element = range.startContainer.nodeType === 3 ?
                 range.startContainer.parentElement : range.startContainer as HTMLElement;
             const previewElement = hasClosestByClassName(element, "vditor-wysiwyg__preview");
-            if (previewElement) {
-                if ((previewElement.previousElementSibling as HTMLElement).style.display === "none") {
-                    previewElement.click();
-                } else {
-                    if (event.key === "ArrowDown" || event.key === "ArrowRight") {
-                        if (previewElement.parentElement.nextElementSibling &&
-                            previewElement.parentElement.nextElementSibling.classList
-                                .contains("vditor-panel")) {
-                            range.selectNodeContents(previewElement.previousElementSibling);
-                            range.collapse(false);
+            if (!previewElement) {
+                return;
+            }
+            if ((previewElement.previousElementSibling as HTMLElement).style.display === "none") {
+                previewElement.click();
+            } else {
+                if (event.key === "ArrowDown" || event.key === "ArrowRight") {
+                    const blockRenderElement = previewElement.parentElement;
+                    if (blockRenderElement.nextElementSibling &&
+                        blockRenderElement.nextElementSibling.classList
+                            .contains("vditor-panel")) {
+                        // 渲染块处于末尾时,光标重置到该渲染块中的代码尾部
+                        range.selectNodeContents(previewElement.previousElementSibling.firstElementChild);
+                        range.collapse(false);
+                    } else {
+                        if (blockRenderElement.nextElementSibling &&
+                            blockRenderElement.nextElementSibling.classList.contains("vditor-wysiwyg__block")) {
+                            // 下一节点依旧为代码渲染块
+                            (blockRenderElement.nextElementSibling
+                                .querySelector(".vditor-wysiwyg__preview") as HTMLElement).click();
+                            range.setStart(blockRenderElement.nextElementSibling.firstElementChild.firstElementChild.firstChild, 0)
                         } else {
-                            range.setStartAfter(previewElement.parentElement);
+                            // 跳过渲染块,光标移动到下一个节点
+                            range.setStartAfter(blockRenderElement);
                         }
-                        setSelectionFocus(range);
                     }
+                } else {
+                    range.selectNodeContents(previewElement.previousElementSibling.firstElementChild);
+                    range.collapse(false);
                 }
+                setSelectionFocus(range);
             }
         });
 

+ 7 - 0
src/ts/wysiwyg/input.ts

@@ -75,6 +75,13 @@ export const input = (event: IHTMLInputEvent, vditor: IVditor, range: Range) =>
         if (blockElement && blockElement.querySelectorAll("code").length > 0) {
             // 对返回值中包含 inline-code, inline math 的进行 decode
             processCodeData(blockElement);
+            // 对返回值中需要渲染的代码块进行处理
+            if (blockElement.classList.contains("vditor-wysiwyg__block")) {
+                processCodeRender(blockElement, vditor);
+            }
+            blockElement.querySelectorAll(".vditor-wysiwyg__block").forEach((blockRenderElement: HTMLElement) => {
+                processCodeRender(blockRenderElement, vditor);
+            });
         }
     }
 

+ 1 - 5
src/ts/wysiwyg/insertHTML.ts

@@ -1,6 +1,4 @@
-import {processCodeData} from "./processCodeData";
-
-export const insertHTML = (html: string, editor: HTMLElement) => {
+export const insertHTML = (html: string) => {
     const pasteElement = document.createElement("template");
     pasteElement.innerHTML = html;
 
@@ -10,6 +8,4 @@ export const insertHTML = (html: string, editor: HTMLElement) => {
     }
     range.insertNode(pasteElement.content.cloneNode(true));
     range.collapse(false);
-
-    processCodeData(editor);
 };

+ 10 - 10
src/ts/wysiwyg/processCodeRender.ts

@@ -6,7 +6,7 @@ import {highlightRender} from "../markdown/highlightRender";
 import {mathRenderByLute} from "../markdown/mathRenderByLute";
 import {mermaidRender} from "../markdown/mermaidRender";
 
-// code block, math, math-inline, abc, html, chart, mermaid
+// html, math, math-inline, code block, abc, chart, mermaid
 export const processCodeRender = (blockElement: HTMLElement, vditor: IVditor) => {
     const blockType = blockElement.getAttribute("data-type");
     if (!blockType) {
@@ -18,26 +18,28 @@ export const processCodeRender = (blockElement: HTMLElement, vditor: IVditor) =>
         blockElement.insertAdjacentHTML("beforeend", `<${tagName} class="vditor-wysiwyg__preview"></${tagName}>`);
         previewPanel = blockElement.querySelector(".vditor-wysiwyg__preview");
         previewPanel.setAttribute("data-render", "false");
-        previewPanel.addEventListener("click", (event) => {
+        const showCode = () => {
             const range = preElement.ownerDocument.createRange();
             if (preElement.getAttribute("data-type") === "math-inline") {
                 preElement.style.display = "inline";
                 range.selectNodeContents(preElement);
             } else {
                 preElement.style.display = "block";
-                range.selectNodeContents(preElement.querySelector("code"));
+                range.setStart(preElement.firstElementChild.firstChild, 0);
             }
             range.collapse(true);
             setSelectionFocus(range);
+        };
+        previewPanel.addEventListener("click", () => {
+            showCode();
         });
     }
 
     const preElement = previewPanel.previousElementSibling as HTMLElement;
-
+    const innerHTML = decodeURIComponent((blockElement.querySelector("code").getAttribute("data-code")) || '')
     if (blockType === "code-block") {
         const language = preElement.querySelector("code").className.replace("language-", "");
-        previewPanel.innerHTML =
-            `<pre>${blockElement.firstElementChild.innerHTML}</pre>`;
+        previewPanel.innerHTML = `<pre><code>${innerHTML}</code></pre>`;
         if (language === "abc") {
             abcRender(previewPanel, vditor.options.cdn);
         } else if (language === "mermaid") {
@@ -50,11 +52,9 @@ export const processCodeRender = (blockElement: HTMLElement, vditor: IVditor) =>
             codeRender(previewPanel, vditor.options.lang);
         }
     } else if (blockType.indexOf("html") > -1) {
-        previewPanel.innerHTML =
-            decodeURIComponent(blockElement.querySelector("code").getAttribute("data-code"));
+        previewPanel.innerHTML = innerHTML;
     } else if (blockType.indexOf("math") > -1) {
-        previewPanel.innerHTML =
-            `<${tagName} class="vditor-math">${blockElement.firstChild.textContent}</${tagName}>`;
+        previewPanel.innerHTML = `<${tagName} class="vditor-math">${innerHTML}</${tagName}>`;
         mathRenderByLute(previewPanel, vditor.options.cdn);
     }
 };