Liyuan Li 5 years ago
parent
commit
a7384f49ba

+ 1 - 0
CHANGELOG.md

@@ -51,6 +51,7 @@
 
 ### v3.0.7 / 2020-03-xx
 
+* [249](https://github.com/Vanessa219/vditor/issues/249) 代码块语言选择优化 `改进功能`
 * [211](https://github.com/Vanessa219/vditor/issues/211) Heading when backspace (Windows Firefox) `修复缺陷`
 * [239](https://github.com/Vanessa219/vditor/issues/239) be converted after spaces in FF `修复缺陷`
 

+ 6 - 2
src/ts/hint/index.ts

@@ -12,11 +12,13 @@ import {processCodeRender} from "../wysiwyg/processCodeRender";
 export class Hint {
     public timeId: number;
     public element: HTMLDivElement;
+    public recentLanguage: string;
 
     constructor() {
         this.timeId = -1;
         this.element = document.createElement("div");
         this.element.className = "vditor-hint";
+        this.recentLanguage = "";
     }
 
     public render(vditor: IVditor) {
@@ -146,6 +148,7 @@ ${i === 0 ? "class='vditor-hint--current'" : ""}> ${html}</button>`;
                         item.className = "language-" + value.trimRight();
                     });
                     processIRCodeRender(preBeforeElement.parentElement.querySelector(".vditor-ir__preview"), vditor);
+                    this.recentLanguage = value.trimRight();
                     return;
                 }
             }
@@ -156,6 +159,7 @@ ${i === 0 ? "class='vditor-hint--current'" : ""}> ${html}</button>`;
                 range.selectNodeContents(inputElement);
                 range.collapse(false);
                 inputElement.dispatchEvent(new CustomEvent("input"));
+                this.recentLanguage = value.trimRight();
                 return;
             }
 
@@ -200,7 +204,7 @@ ${i === 0 ? "class='vditor-hint--current'" : ""}> ${html}</button>`;
 
         const currentHintElement: HTMLElement = this.element.querySelector(".vditor-hint--current");
 
-        if (event.key === "ArrowDown" || event.key === "ArrowRight") {
+        if (event.key === "ArrowDown") {
             event.preventDefault();
             event.stopPropagation();
             currentHintElement.removeAttribute("class");
@@ -210,7 +214,7 @@ ${i === 0 ? "class='vditor-hint--current'" : ""}> ${html}</button>`;
                 currentHintElement.nextElementSibling.className = "vditor-hint--current";
             }
             return true;
-        } else if (event.key === "ArrowUp" || event.key === "ArrowLeft") {
+        } else if (event.key === "ArrowUp") {
             event.preventDefault();
             event.stopPropagation();
             currentHintElement.removeAttribute("class");

+ 4 - 1
src/ts/ir/index.ts

@@ -13,7 +13,7 @@ import {
 import {expandMarker} from "./expandMarker";
 import {highlightToolbar} from "./highlightToolbar";
 import {input} from "./input";
-import {processAfterRender, processCodeRender} from "./process";
+import {processAfterRender, processCodeRender, processHint} from "./process";
 
 class IR {
     public element: HTMLPreElement;
@@ -252,6 +252,9 @@ class IR {
                     }
                 });
             } else if (event.key.indexOf("Arrow") > -1) {
+                if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
+                    processHint(vditor);
+                }
                 expandMarker(range, vditor);
             }
 

+ 21 - 10
src/ts/ir/process.ts

@@ -10,22 +10,23 @@ import {isSafari} from "../util/compatibility";
 import {listToggle} from "../util/fixBrowserBehavior";
 import {getMarkdown} from "../util/getMarkdown";
 import {hasClosestBlock, hasClosestByAttribute, hasClosestByClassName, hasClosestByMatchTag} from "../util/hasClosest";
-import {getEditorRange, setRangeByWbr} from "../util/selection";
+import {getEditorRange, getSelectPosition, setRangeByWbr} from "../util/selection";
 import {highlightToolbar} from "./highlightToolbar";
 
-export const processAfterRender = (vditor: IVditor, options = {
-    enableAddUndoStack: true,
-    enableHint: false,
-    enableInput: true,
-}) => {
+export const processHint = (vditor: IVditor) => {
+    vditor.hint.render(vditor);
     const startContainer = getEditorRange(vditor.ir.element).startContainer;
     // 代码块语言提示
     const preBeforeElement = hasClosestByAttribute(startContainer, "data-type", "code-block-info");
-    if (options.enableHint) {
-        vditor.hint.render(vditor);
-        if (preBeforeElement) {
+    if (preBeforeElement) {
+        if (preBeforeElement.textContent.replace(Constants.ZWSP, "") === "" && vditor.hint.recentLanguage) {
+            preBeforeElement.textContent = Constants.ZWSP + vditor.hint.recentLanguage;
+            const range = getEditorRange(vditor.ir.element);
+            range.selectNodeContents(preBeforeElement);
+        } else {
             const matchLangData: IHintData[] = [];
-            const key = preBeforeElement.textContent.replace(Constants.ZWSP, "").trim();
+            const key = preBeforeElement.textContent.substring(0, getSelectPosition(preBeforeElement).start)
+                .replace(Constants.ZWSP, "");
             Constants.CODE_LANGUAGES.forEach((keyName) => {
                 if (keyName.indexOf(key.toLowerCase()) > -1) {
                     matchLangData.push({
@@ -37,6 +38,16 @@ export const processAfterRender = (vditor: IVditor, options = {
             vditor.hint.genHTML(matchLangData, key, vditor);
         }
     }
+};
+
+export const processAfterRender = (vditor: IVditor, options = {
+    enableAddUndoStack: true,
+    enableHint: false,
+    enableInput: true,
+}) => {
+    if (options.enableHint) {
+        processHint(vditor);
+    }
 
     clearTimeout(vditor.ir.processTimeoutId);
     vditor.ir.processTimeoutId = window.setTimeout(() => {

+ 15 - 11
src/ts/ir/processKeydown.ts

@@ -1,4 +1,3 @@
-import {Constants} from "../constants";
 import {isCtrl} from "../util/compatibility";
 import {scrollCenter} from "../util/editorCommenEvent";
 import {
@@ -68,6 +67,9 @@ export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
     const preRenderElement = hasClosestByClassName(startContainer, "vditor-ir__marker--pre");
     if (preRenderElement && preRenderElement.tagName === "PRE") {
         const codeRenderElement = preRenderElement.firstChild as HTMLElement;
+        if (fixCodeBlock(vditor, event, preRenderElement, range)) {
+            return true;
+        }
         // 数学公式上无元素,按上或左将添加新块
         if (codeRenderElement.getAttribute("data-type") === "math-block" &&
             insertBeforeBlock(vditor, event, range, codeRenderElement, preRenderElement.parentElement)) {
@@ -78,25 +80,27 @@ export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
         if (insertAfterBlock(vditor, event, range, codeRenderElement, preRenderElement.parentElement)) {
             return true;
         }
-
-        if (fixCodeBlock(vditor, event, preRenderElement, range)) {
-            return true;
-        }
     }
     // 代码块语言
     const preBeforeElement = hasClosestByAttribute(startContainer, "data-type", "code-block-info");
-    if (preBeforeElement && range.toString() === "") {
-        if (event.key === "Backspace" && preBeforeElement.textContent.replace(Constants.ZWSP, "").trim() === "") {
-            event.preventDefault();
-            return true;
-        }
-        if (event.key === "Enter") {
+    if (preBeforeElement) {
+        if (event.key === "Enter" || event.key === "Tab") {
             range.selectNodeContents(preBeforeElement.nextElementSibling.firstChild);
             range.collapse(true);
             event.preventDefault();
             return true;
         }
 
+        if (event.key === "Backspace") {
+            if (range.startOffset === 1) {
+                range.setStart(startContainer, 0);
+            }
+            if (range.startOffset === 2) {
+                // 删除时清空语言
+                vditor.hint.recentLanguage = "";
+            }
+        }
+
         // 上无元素,按上或左将添加新块
         if (insertBeforeBlock(vditor, event, range, preBeforeElement, preBeforeElement.parentElement)) {
             return true;

+ 1 - 1
src/ts/util/fixBrowserBehavior.ts

@@ -80,7 +80,7 @@ export const insertBeforeBlock = (vditor: IVditor, event: KeyboardEvent, range:
                                   blockElement: HTMLElement) => {
     const position = getSelectPosition(element, range);
     if ((event.key === "ArrowUp" && element.textContent.substr(position.start).indexOf("\n") === -1) ||
-        (event.key === "ArrowLeft" && position.start === 0)) {
+        ((event.key === "ArrowLeft" || event.key === "Backspace") && position.start === 0)) {
         const previousElement = blockElement.previousElementSibling;
         // table || code
         if (!previousElement ||

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

@@ -559,7 +559,7 @@ export const highlightToolbar = (vditor: IVditor) => {
                     language.className = "vditor-input";
                     language.setAttribute("placeholder", i18n[vditor.options.lang].language + "<" + updateHotkeyTip("⌥-Enter") + ">");
                     language.value = codeElement.className.indexOf("language-") > -1 ?
-                        codeElement.className.split("-")[1].split(" ")[0] : "";
+                        codeElement.className.split("-")[1].split(" ")[0] : vditor.hint.recentLanguage;
                     language.oninput = () => {
                         updateLanguage();
                         processCodeRender(blockRenderElement, vditor);
@@ -577,11 +577,11 @@ export const highlightToolbar = (vditor: IVditor) => {
                         vditor.hint.select(event, vditor);
                     };
                     language.onkeyup = (event: KeyboardEvent) => {
-                        if (event.isComposing || event.key.indexOf("Arrow") > -1 || event.key === "Enter") {
+                        if (event.isComposing || event.key === "Enter" || event.key === "ArrowUp" || event.key === "ArrowDown") {
                             return;
                         }
                         const matchLangData: IHintData[] = [];
-                        const key = language.value;
+                        const key = language.value.substring(0, language.selectionStart);
                         Constants.CODE_LANGUAGES.forEach((keyName) => {
                             if (keyName.indexOf(key.toLowerCase()) > -1) {
                                 matchLangData.push({

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

@@ -13,7 +13,7 @@ import {
     insertHTML,
     setRangeByWbr,
     setSelectionByPosition,
-    setSelectionFocus
+    setSelectionFocus,
 } from "../util/selection";
 import {afterRenderEvent} from "./afterRenderEvent";
 import {highlightToolbar} from "./highlightToolbar";
@@ -358,6 +358,10 @@ class WYSIWYG {
                 return;
             }
 
+            if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
+                vditor.hint.render(vditor);
+            }
+
             // 上下左右,删除遇到块预览的处理
             let previewElement = hasClosestByClassName(range.startContainer, "vditor-wysiwyg__preview");
             if (!previewElement && range.startContainer.nodeType !== 3 && range.startOffset > 0) {