Vanessa 4 years ago
parent
commit
74e377a2e6

+ 1 - 0
CHANGELOG.md

@@ -98,6 +98,7 @@
 
 ### v3.8.2 / 2021-02-xx
 
+* [720](https://github.com/Vanessa219/vditor/issues/720) 在光标位置插入内容的问题 `改进功能`
 * [751](https://github.com/Vanessa219/vditor/issues/751) firefox 代码块中 enter 键换行问题 `修复缺陷`
 * [923](https://github.com/Vanessa219/vditor/issues/923) 隐藏预览操作栏 `改进功能`
 

+ 2 - 2
src/index.ts

@@ -277,7 +277,7 @@ class Vditor extends VditorMethod {
 
     /** 在焦点处插入内容,并默认进行 Markdown 渲染 */
     public insertValue(value: string, render = true) {
-        const range = getEditorRange(this.vditor[this.vditor.currentMode].element);
+        const range = getEditorRange(this.vditor);
         range.collapse(true);
         const tmpElement = document.createElement("template");
         tmpElement.innerHTML = value;
@@ -426,7 +426,7 @@ class Vditor extends VditorMethod {
             });
             if (ids.length === 0) {
                 item.outerHTML = item.innerHTML;
-                getEditorRange(this.vditor.element).collapse(true);
+                getEditorRange(this.vditor).collapse(true);
             } else {
                 item.setAttribute("data-cmtids", ids.join(" "));
             }

+ 202 - 0
src/js/mathjax/LICENSE

@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 1 - 1
src/ts/ir/highlightToolbarIR.ts

@@ -17,7 +17,7 @@ export const highlightToolbarIR = (vditor: IVditor) => {
         removeCurrentToolbar(vditor.toolbar.elements, Constants.EDIT_TOOLBARS);
         enableToolbar(vditor.toolbar.elements, Constants.EDIT_TOOLBARS);
 
-        const range = getEditorRange(vditor[vditor.currentMode].element);
+        const range = getEditorRange(vditor);
         let typeElement = range.startContainer as HTMLElement;
         if (range.startContainer.nodeType === 3) {
             typeElement = range.startContainer.parentElement;

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

@@ -22,6 +22,7 @@ import {input} from "./input";
 import {processAfterRender, processHint} from "./process";
 
 class IR {
+    public range: Range;
     public element: HTMLPreElement;
     public processTimeoutId: number;
     public hlToolbarTimeoutId: number;
@@ -111,7 +112,7 @@ class IR {
                 return;
             }
 
-            const range = getEditorRange(this.element);
+            const range = getEditorRange(vditor);
 
             // 点击后光标落于预览区
             let previewElement = hasClosestByClassName(event.target, "vditor-ir__preview");
@@ -161,7 +162,7 @@ class IR {
             } else {
                 // https://github.com/Vanessa219/vditor/pull/681 当点击选中区域时 eventTarget 与 range 不一致,需延迟等待 range 发生变化
                 setTimeout(() => {
-                    expandMarker(getEditorRange(this.element), vditor);
+                    expandMarker(getEditorRange(vditor), vditor);
                 });
             }
             clickToc(event, vditor);
@@ -185,7 +186,7 @@ class IR {
                 vditor.ir.element.innerHTML = "";
                 return;
             }
-            const range = getEditorRange(this.element);
+            const range = getEditorRange(vditor);
             if (event.key === "Backspace") {
                 // firefox headings https://github.com/Vanessa219/vditor/issues/211
                 if (isFirefox() && range.startContainer.textContent === "\n" && range.startOffset === 1) {

+ 4 - 4
src/ts/ir/process.ts

@@ -10,13 +10,13 @@ import {input} from "./input";
 
 export const processHint = (vditor: IVditor) => {
     vditor.hint.render(vditor);
-    const startContainer = getEditorRange(vditor.ir.element).startContainer;
+    const startContainer = getEditorRange(vditor).startContainer;
     // 代码块语言提示
     const preBeforeElement = hasClosestByAttribute(startContainer, "data-type", "code-block-info");
     if (preBeforeElement) {
         if (preBeforeElement.textContent.replace(Constants.ZWSP, "") === "" && vditor.hint.recentLanguage) {
             preBeforeElement.textContent = Constants.ZWSP + vditor.hint.recentLanguage;
-            const range = getEditorRange(vditor.ir.element);
+            const range = getEditorRange(vditor);
             range.selectNodeContents(preBeforeElement);
         } else {
             const matchLangData: IHintData[] = [];
@@ -77,7 +77,7 @@ export const processAfterRender = (vditor: IVditor, options = {
 };
 
 export const processHeading = (vditor: IVditor, value: string) => {
-    const range = getEditorRange(vditor.ir.element);
+    const range = getEditorRange(vditor);
     const headingElement = hasClosestBlock(range.startContainer) || range.startContainer as HTMLElement;
     if (headingElement) {
         const headingMarkerElement = headingElement.querySelector(".vditor-ir__marker--heading");
@@ -106,7 +106,7 @@ const removeInline = (range: Range, vditor: IVditor, type: string) => {
 };
 
 export const processToolbar = (vditor: IVditor, actionBtn: Element, prefix: string, suffix: string) => {
-    const range = getEditorRange(vditor.ir.element);
+    const range = getEditorRange(vditor);
     const commandName = actionBtn.getAttribute("data-type");
     let typeElement = range.startContainer as HTMLElement;
     if (typeElement.nodeType === 3) {

+ 1 - 1
src/ts/ir/processKeydown.ts

@@ -37,7 +37,7 @@ export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
         vditor.undo.recordFirstPosition(vditor, event);
     }
 
-    const range = getEditorRange(vditor.ir.element);
+    const range = getEditorRange(vditor);
     const startContainer = range.startContainer;
 
     if (!fixGSKeyBackspace(event, vditor, startContainer)) {

+ 1 - 0
src/ts/sv/index.ts

@@ -13,6 +13,7 @@ import {getSelectText} from "../util/getSelectText";
 import {inputEvent} from "./inputEvent";
 
 class Editor {
+    public range: Range;
     public element: HTMLPreElement;
     public composingLock: boolean = false;
     public processTimeoutId: number;

+ 3 - 3
src/ts/sv/process.ts

@@ -8,7 +8,7 @@ import {getEditorRange, setRangeByWbr} from "../util/selection";
 import {inputEvent} from "./inputEvent";
 
 export const processPaste = (vditor: IVditor, text: string) => {
-    const range = getEditorRange(vditor.sv.element);
+    const range = getEditorRange(vditor);
     range.extractContents();
     range.insertNode(document.createTextNode(Lute.Caret));
     range.insertNode(document.createTextNode(text));
@@ -136,7 +136,7 @@ export const processAfterRender = (vditor: IVditor, options = {
 };
 
 export const processHeading = (vditor: IVditor, value: string) => {
-    const range = getEditorRange(vditor.sv.element);
+    const range = getEditorRange(vditor);
     const headingElement = hasClosestByTag(range.startContainer, "SPAN");
     if (headingElement && headingElement.textContent.trim() !== "") {
         value = "\n" + value;
@@ -146,7 +146,7 @@ export const processHeading = (vditor: IVditor, value: string) => {
 };
 
 export const processToolbar = (vditor: IVditor, actionBtn: Element, prefix: string, suffix: string) => {
-    const range = getEditorRange(vditor.sv.element);
+    const range = getEditorRange(vditor);
     const commandName = actionBtn.getAttribute("data-type");
     // 添加
     if (vditor.sv.element.childNodes.length === 0) {

+ 1 - 1
src/ts/sv/processKeydown.ts

@@ -21,7 +21,7 @@ export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
         && !isCtrl(event) && event.key !== "Escape") {
         return false;
     }
-    const range = getEditorRange(vditor.sv.element);
+    const range = getEditorRange(vditor);
     let startContainer = range.startContainer;
     if (range.startContainer.nodeType !== 3 && (range.startContainer as HTMLElement).tagName === "DIV") {
         startContainer = range.startContainer.childNodes[range.startOffset - 1];

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

@@ -43,7 +43,7 @@ data-value=":${key}: " data-key=":${key}:" class="vditor-emojis__icon" src="${em
             element.addEventListener(getEventName(), (event: Event) => {
                 event.preventDefault();
                 const value = element.getAttribute("data-value");
-                const range = getEditorRange(vditor[vditor.currentMode].element);
+                const range = getEditorRange(vditor);
                 let html = value;
                 if (vditor.currentMode === "wysiwyg") {
                     html = vditor.lute.SpinVditorDOM(value);

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

@@ -15,7 +15,7 @@ export class Indent extends MenuItem {
                 vditor.currentMode === "sv") {
                 return;
             }
-            const range = getEditorRange(vditor[vditor.currentMode].element);
+            const range = getEditorRange(vditor);
             const liElement = hasClosestByMatchTag(range.startContainer, "LI");
             if (liElement) {
                 listIndent(vditor, liElement, range);

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

@@ -14,7 +14,7 @@ export class Outdent extends MenuItem {
                 vditor.currentMode === "sv") {
                 return;
             }
-            const range = getEditorRange(vditor[vditor.currentMode].element);
+            const range = getEditorRange(vditor);
             const liElement = hasClosestByMatchTag(range.startContainer, "LI");
             if (liElement) {
                 listOutdent(vditor, liElement, range, liElement.parentElement);

+ 1 - 1
src/ts/upload/index.ts

@@ -183,7 +183,7 @@ const uploadFiles =
         }
         const editorElement = getElement(vditor);
 
-        vditor.upload.range = getEditorRange(editorElement);
+        vditor.upload.range = getEditorRange(vditor);
 
         const validateResult = validateFile(vditor, fileList);
         if (validateResult.length === 0) {

+ 2 - 1
src/ts/util/editorCommonEvent.ts

@@ -15,7 +15,7 @@ import {execAfterRender, paste} from "./fixBrowserBehavior";
 import {getSelectText} from "./getSelectText";
 import {hasClosestByAttribute, hasClosestByMatchTag} from "./hasClosest";
 import {matchHotKey} from "./hotKey";
-import {getCursorPosition} from "./selection";
+import {getCursorPosition, getEditorRange} from "./selection";
 
 export const focusEvent = (vditor: IVditor, editorElement: HTMLElement) => {
     editorElement.addEventListener("focus", () => {
@@ -45,6 +45,7 @@ export const blurEvent = (vditor: IVditor, editorElement: HTMLElement) => {
             !vditor.wysiwyg.selectPopover.contains(event.relatedTarget as HTMLElement)) {
             vditor.wysiwyg.hideComment();
         }
+        vditor[vditor.currentMode].range = getEditorRange(vditor);
         if (vditor.options.blur) {
             vditor.options.blur(getMarkdown(vditor));
         }

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

@@ -73,7 +73,7 @@ export const fixCursorDownInlineMath = (range: Range, key: string) => {
 };
 
 export const insertEmptyBlock = (vditor: IVditor, position: InsertPosition) => {
-    const range = getEditorRange(vditor[vditor.currentMode].element);
+    const range = getEditorRange(vditor);
     const blockElement = hasClosestBlock(range.startContainer);
     if (blockElement) {
         blockElement.insertAdjacentHTML(position, `<p data-block="0">${Constants.ZWSP}<wbr>\n</p>`);
@@ -1426,10 +1426,10 @@ export const paste = async (vditor: IVditor, event: (ClipboardEvent | DragEvent)
         }
     }
     if (vditor.currentMode !== "sv") {
-        const blockElement = hasClosestBlock(getEditorRange(vditor[vditor.currentMode].element).startContainer);
+        const blockElement = hasClosestBlock(getEditorRange(vditor).startContainer);
         if (blockElement) {
             // https://github.com/Vanessa219/vditor/issues/591
-            const range = getEditorRange(vditor[vditor.currentMode].element);
+            const range = getEditorRange(vditor);
             vditor[vditor.currentMode].element.querySelectorAll("wbr").forEach((wbr) => {
                 wbr.remove();
             });

+ 6 - 2
src/ts/util/selection.ts

@@ -2,14 +2,18 @@ import {Constants} from "../constants";
 import {isChrome} from "./compatibility";
 import {hasClosestBlock, hasClosestByClassName} from "./hasClosest";
 
-export const getEditorRange = (element: HTMLElement) => {
+export const getEditorRange = (vditor: IVditor) => {
     let range: Range;
+    const element = vditor[vditor.currentMode].element;
     if (getSelection().rangeCount > 0) {
         range = getSelection().getRangeAt(0);
         if (element.isEqualNode(range.startContainer) || element.contains(range.startContainer)) {
             return range;
         }
     }
+    if (vditor[vditor.currentMode].range) {
+        return vditor[vditor.currentMode].range;
+    }
     element.focus();
     range = element.ownerDocument.createRange();
     range.setStart(element, 0);
@@ -244,7 +248,7 @@ export const insertHTML = (html: string, vditor: IVditor) => {
     const pasteElement = document.createElement("div");
     pasteElement.innerHTML = html;
 
-    const range = getEditorRange(vditor[vditor.currentMode].element);
+    const range = getEditorRange(vditor);
     if (range.toString() !== "") {
         vditor[vditor.currentMode].preventInput = true;
         document.execCommand("delete", false, "");

+ 8 - 8
src/ts/wysiwyg/highlightToolbarWYSIWYG.ts

@@ -699,7 +699,7 @@ export const genLinkRefPopover = (vditor: IVditor, linkRefElement: HTMLElement)
         if (removeBlockElement(vditor, event)) {
             return;
         }
-        linkHotkey(vditor.wysiwyg.element, linkRefElement, event, input1);
+        linkHotkey(vditor, linkRefElement, event, input1);
     };
 
     const input1Wrap = document.createElement("span");
@@ -717,7 +717,7 @@ export const genLinkRefPopover = (vditor: IVditor, linkRefElement: HTMLElement)
         if (removeBlockElement(vditor, event)) {
             return;
         }
-        linkHotkey(vditor.wysiwyg.element, linkRefElement, event, input);
+        linkHotkey(vditor, linkRefElement, event, input);
     };
 
     genClose(linkRefElement, vditor);
@@ -781,7 +781,7 @@ const genClose = (element: HTMLElement, vditor: IVditor) => {
     close.innerHTML = '<svg><use xlink:href="#vditor-icon-trashcan"></use></svg>';
     close.className = "vditor-icon vditor-tooltipped vditor-tooltipped__n";
     close.onclick = () => {
-        const range = getEditorRange(vditor.wysiwyg.element);
+        const range = getEditorRange(vditor);
         range.setStartAfter(element);
         setSelectionFocus(range);
         element.remove();
@@ -791,7 +791,7 @@ const genClose = (element: HTMLElement, vditor: IVditor) => {
     vditor.wysiwyg.popover.insertAdjacentElement("beforeend", close);
 };
 
-const linkHotkey = (editor: HTMLElement, element: HTMLElement, event: KeyboardEvent,
+const linkHotkey = (vditor: IVditor, element: HTMLElement, event: KeyboardEvent,
                     nextInputElement: HTMLInputElement) => {
     if (event.isComposing) {
         return;
@@ -803,7 +803,7 @@ const linkHotkey = (editor: HTMLElement, element: HTMLElement, event: KeyboardEv
         return;
     }
     if (!isCtrl(event) && !event.shiftKey && event.altKey && event.key === "Enter") {
-        const range = getEditorRange(editor);
+        const range = getEditorRange(vditor);
         // firefox 不会打断 link https://github.com/Vanessa219/vditor/issues/193
         element.insertAdjacentHTML("afterend", Constants.ZWSP);
         range.setStartAfter(element.nextSibling);
@@ -843,7 +843,7 @@ export const genAPopover = (vditor: IVditor, aElement: HTMLElement) => {
         if (removeBlockElement(vditor, event)) {
             return;
         }
-        linkHotkey(vditor.wysiwyg.element, aElement, event, input1);
+        linkHotkey(vditor, aElement, event, input1);
     };
 
     const input1Wrap = document.createElement("span");
@@ -861,7 +861,7 @@ export const genAPopover = (vditor: IVditor, aElement: HTMLElement) => {
         if (removeBlockElement(vditor, event)) {
             return;
         }
-        linkHotkey(vditor.wysiwyg.element, aElement, event, input2);
+        linkHotkey(vditor, aElement, event, input2);
     };
 
     const input2Wrap = document.createElement("span");
@@ -880,7 +880,7 @@ export const genAPopover = (vditor: IVditor, aElement: HTMLElement) => {
         if (removeBlockElement(vditor, event)) {
             return;
         }
-        linkHotkey(vditor.wysiwyg.element, aElement, event, input);
+        linkHotkey(vditor, aElement, event, input);
     };
 
     genClose(aElement, vditor);

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

@@ -31,6 +31,7 @@ import {input} from "./input";
 import {showCode} from "./showCode";
 
 class WYSIWYG {
+    public range: Range;
     public element: HTMLPreElement;
     public popover: HTMLDivElement;
     public selectPopover: HTMLDivElement;
@@ -289,7 +290,7 @@ class WYSIWYG {
         this.element.addEventListener("paste", (event: ClipboardEvent & { target: HTMLElement }) => {
             paste(vditor, event, {
                 pasteCode: (code: string) => {
-                    const range = getEditorRange(this.element);
+                    const range = getEditorRange(vditor);
                     const node = document.createElement("template");
                     node.innerHTML = code;
                     range.insertNode(node.content.cloneNode(true));
@@ -411,7 +412,7 @@ class WYSIWYG {
                 return;
             }
 
-            const range = getEditorRange(this.element);
+            const range = getEditorRange(vditor);
             if (event.target.isEqualNode(this.element) && this.element.lastElementChild && range.collapsed) {
                 const lastRect = this.element.lastElementChild.getBoundingClientRect();
                 if (event.y > lastRect.top + lastRect.height) {
@@ -432,7 +433,7 @@ class WYSIWYG {
             // 点击后光标落于预览区,需展开代码块
             let previewElement = hasClosestByClassName(event.target, "vditor-wysiwyg__preview");
             if (!previewElement) {
-                previewElement = hasClosestByClassName(getEditorRange(this.element).startContainer, "vditor-wysiwyg__preview");
+                previewElement = hasClosestByClassName(getEditorRange(vditor).startContainer, "vditor-wysiwyg__preview");
             }
             if (previewElement) {
                 showCode(previewElement, vditor);
@@ -458,7 +459,7 @@ class WYSIWYG {
                 // 为空时显示 placeholder
                 vditor.wysiwyg.element.innerHTML = "";
             }
-            const range = getEditorRange(this.element);
+            const range = getEditorRange(vditor);
             if (event.key === "Backspace") {
                 // firefox headings https://github.com/Vanessa219/vditor/issues/211
                 if (isFirefox() && range.startContainer.textContent === "\n" && range.startOffset === 1) {

+ 1 - 1
src/ts/wysiwyg/processKeydown.ts

@@ -39,7 +39,7 @@ export const processKeydown = (vditor: IVditor, event: KeyboardEvent) => {
         vditor.undo.recordFirstPosition(vditor, event);
     }
 
-    const range = getEditorRange(vditor.wysiwyg.element);
+    const range = getEditorRange(vditor);
     const startContainer = range.startContainer;
 
     if (!fixGSKeyBackspace(event, vditor, startContainer)) {

+ 1 - 1
src/ts/wysiwyg/setHeading.ts

@@ -3,7 +3,7 @@ import {getEditorRange, setRangeByWbr} from "../util/selection";
 import {renderToc} from "../util/toc";
 
 export const setHeading = (vditor: IVditor, tagName: string) => {
-    const range = getEditorRange(vditor.wysiwyg.element);
+    const range = getEditorRange(vditor);
     let blockElement = hasClosestBlock(range.startContainer);
     if (!blockElement) {
         blockElement = range.startContainer.childNodes[range.startOffset] as HTMLElement;

+ 1 - 1
src/ts/wysiwyg/toolbarEvent.ts

@@ -85,7 +85,7 @@ export const toolbarEvent = (vditor: IVditor, actionBtn: Element, event: Event)
     if (vditor.wysiwyg.element.querySelector("wbr")) {
         vditor.wysiwyg.element.querySelector("wbr").remove();
     }
-    const range = getEditorRange(vditor.wysiwyg.element);
+    const range = getEditorRange(vditor);
 
     let commandName = actionBtn.getAttribute("data-type");
 

+ 3 - 0
types/index.d.ts

@@ -634,6 +634,7 @@ interface IVditor {
         resetIcon(vditor: IVditor): void,
     };
     wysiwyg?: {
+        range: Range,
         element: HTMLPreElement,
         selectPopover: HTMLDivElement,
         popover: HTMLDivElement,
@@ -648,6 +649,7 @@ interface IVditor {
         hideComment(): void,
     };
     ir?: {
+        range: Range,
         element: HTMLPreElement,
         composingLock: boolean,
         preventInput: boolean,
@@ -655,6 +657,7 @@ interface IVditor {
         hlToolbarTimeoutId: number,
     };
     sv?: {
+        range: Range,
         element: HTMLPreElement,
         processTimeoutId: number,
         hlToolbarTimeoutId: number,