diff --git a/src/ts/util/fixBrowserBehavior.ts b/src/ts/util/fixBrowserBehavior.ts index 610402646..7b9d9fb92 100644 --- a/src/ts/util/fixBrowserBehavior.ts +++ b/src/ts/util/fixBrowserBehavior.ts @@ -9,1477 +9,1479 @@ import {input} from "../wysiwyg/input"; import {isCtrl, isFirefox} from "./compatibility"; import {scrollCenter} from "./editorCommonEvent"; import { - getTopList, - hasClosestBlock, - hasClosestByAttribute, - hasClosestByClassName, - hasClosestByMatchTag, + getTopList, + hasClosestBlock, + hasClosestByAttribute, + hasClosestByClassName, + hasClosestByMatchTag, } from "./hasClosest"; import {getLastNode} from "./hasClosest"; import {highlightToolbar} from "./highlightToolbar"; import {matchHotKey} from "./hotKey"; import {processCodeRender, processPasteCode} from "./processCode"; import { - getEditorRange, - getSelectPosition, - insertHTML, - setRangeByWbr, - setSelectionByPosition, setSelectionFocus, + getEditorRange, + getSelectPosition, + insertHTML, + setRangeByWbr, + setSelectionByPosition, setSelectionFocus, } from "./selection"; // https://github.com/Vanessa219/vditor/issues/508 软键盘无法删除空块 export const fixGSKeyBackspace = (event: KeyboardEvent, vditor: IVditor, startContainer: Node) => { - if (event.keyCode === 229 && event.code === "" && event.key === "Unidentified" && vditor.currentMode !== "sv") { - const blockElement = hasClosestBlock(startContainer); - // 移动端的标点符号都显示为 299,因此需限定为空删除的条件 - if (blockElement && blockElement.textContent.trim() === "") { - vditor[vditor.currentMode].composingLock = true; - return false; + if (event.keyCode === 229 && event.code === "" && event.key === "Unidentified" && vditor.currentMode !== "sv") { + const blockElement = hasClosestBlock(startContainer); + // 移动端的标点符号都显示为 299,因此需限定为空删除的条件 + if (blockElement && blockElement.textContent.trim() === "") { + vditor[vditor.currentMode].composingLock = true; + return false; + } } - } - return true; + return true; }; // https://github.com/Vanessa219/vditor/issues/361 代码块后输入中文 export const fixCJKPosition = (range: Range, vditor: IVditor, event: KeyboardEvent) => { - if (event.key === "Enter" || event.key === "Tab" || event.key === "Backspace" || event.key.indexOf("Arrow") > -1 - || isCtrl(event) || event.key === "Escape" || event.shiftKey || event.altKey) { - return; - } - const pLiElement = hasClosestByMatchTag(range.startContainer, "P") || - hasClosestByMatchTag(range.startContainer, "LI"); - if (pLiElement && getSelectPosition(pLiElement, vditor[vditor.currentMode].element, range).start === 0) { - const zwspNode = document.createTextNode(Constants.ZWSP); - range.insertNode(zwspNode); - range.setStartAfter(zwspNode); - } + if (event.key === "Enter" || event.key === "Tab" || event.key === "Backspace" || event.key.indexOf("Arrow") > -1 + || isCtrl(event) || event.key === "Escape" || event.shiftKey || event.altKey) { + return; + } + const pLiElement = hasClosestByMatchTag(range.startContainer, "P") || + hasClosestByMatchTag(range.startContainer, "LI"); + if (pLiElement && getSelectPosition(pLiElement, vditor[vditor.currentMode].element, range).start === 0) { + const zwspNode = document.createTextNode(Constants.ZWSP); + range.insertNode(zwspNode); + range.setStartAfter(zwspNode); + } }; // https://github.com/Vanessa219/vditor/issues/381 光标在内联数学公式中无法向下移动 export const fixCursorDownInlineMath = (range: Range, key: string) => { - if (key === "ArrowDown" || key === "ArrowUp") { - const inlineElement = hasClosestByAttribute(range.startContainer, "data-type", "math-inline") || - hasClosestByAttribute(range.startContainer, "data-type", "html-entity") || - hasClosestByAttribute(range.startContainer, "data-type", "html-inline"); - if (inlineElement) { - if (key === "ArrowDown") { - range.setStartAfter(inlineElement.parentElement); - } - if (key === "ArrowUp") { - range.setStartBefore(inlineElement.parentElement); - } + if (key === "ArrowDown" || key === "ArrowUp") { + const inlineElement = hasClosestByAttribute(range.startContainer, "data-type", "math-inline") || + hasClosestByAttribute(range.startContainer, "data-type", "html-entity") || + hasClosestByAttribute(range.startContainer, "data-type", "html-inline"); + if (inlineElement) { + if (key === "ArrowDown") { + range.setStartAfter(inlineElement.parentElement); + } + if (key === "ArrowUp") { + range.setStartBefore(inlineElement.parentElement); + } + } } - } }; export const insertEmptyBlock = (vditor: IVditor, position: InsertPosition) => { - const range = getEditorRange(vditor); - const blockElement = hasClosestBlock(range.startContainer); - if (blockElement) { - blockElement.insertAdjacentHTML(position, `

${Constants.ZWSP}\n

`); - setRangeByWbr(vditor[vditor.currentMode].element, range); - highlightToolbar(vditor); - execAfterRender(vditor); - } + const range = getEditorRange(vditor); + const blockElement = hasClosestBlock(range.startContainer); + if (blockElement) { + blockElement.insertAdjacentHTML(position, `

${Constants.ZWSP}\n

`); + setRangeByWbr(vditor[vditor.currentMode].element, range); + highlightToolbar(vditor); + execAfterRender(vditor); + } }; export const isFirstCell = (cellElement: HTMLElement) => { - const tableElement = hasClosestByMatchTag(cellElement, "TABLE") as HTMLTableElement; - if (tableElement && tableElement.rows[0].cells[0].isSameNode(cellElement)) { - return tableElement; - } - return false; + const tableElement = hasClosestByMatchTag(cellElement, "TABLE") as HTMLTableElement; + if (tableElement && tableElement.rows[0].cells[0].isSameNode(cellElement)) { + return tableElement; + } + return false; }; export const isLastCell = (cellElement: HTMLElement) => { - const tableElement = hasClosestByMatchTag(cellElement, "TABLE") as HTMLTableElement; - if (tableElement && tableElement.lastElementChild.lastElementChild.lastElementChild.isSameNode(cellElement)) { - return tableElement; - } - return false; + const tableElement = hasClosestByMatchTag(cellElement, "TABLE") as HTMLTableElement; + if (tableElement && tableElement.lastElementChild.lastElementChild.lastElementChild.isSameNode(cellElement)) { + return tableElement; + } + return false; }; // 光标设置到前一个表格中 const goPreviousCell = (cellElement: HTMLElement, range: Range, isSelected = true) => { - let previousElement = cellElement.previousElementSibling; - if (!previousElement) { - if (cellElement.parentElement.previousElementSibling) { - previousElement = cellElement.parentElement.previousElementSibling.lastElementChild; - } else if (cellElement.parentElement.parentElement.tagName === "TBODY" && - cellElement.parentElement.parentElement.previousElementSibling) { - previousElement = cellElement.parentElement - .parentElement.previousElementSibling.lastElementChild.lastElementChild; - } else { - previousElement = null; + let previousElement = cellElement.previousElementSibling; + if (!previousElement) { + if (cellElement.parentElement.previousElementSibling) { + previousElement = cellElement.parentElement.previousElementSibling.lastElementChild; + } else if (cellElement.parentElement.parentElement.tagName === "TBODY" && + cellElement.parentElement.parentElement.previousElementSibling) { + previousElement = cellElement.parentElement + .parentElement.previousElementSibling.lastElementChild.lastElementChild; + } else { + previousElement = null; + } } - } - if (previousElement) { - range.selectNodeContents(previousElement); - if (!isSelected) { - range.collapse(false); + if (previousElement) { + range.selectNodeContents(previousElement); + if (!isSelected) { + range.collapse(false); + } + setSelectionFocus(range); } - setSelectionFocus(range); - } - return previousElement; + return previousElement; }; export const insertAfterBlock = (vditor: IVditor, event: KeyboardEvent, range: Range, element: HTMLElement, blockElement: HTMLElement) => { - const position = getSelectPosition(element, vditor[vditor.currentMode].element, range); - if ((event.key === "ArrowDown" && element.textContent.trimRight().substr(position.start).indexOf("\n") === -1) || - (event.key === "ArrowRight" && position.start >= element.textContent.trimRight().length)) { - const nextElement = blockElement.nextElementSibling; - if (!nextElement || - (nextElement && (nextElement.tagName === "TABLE" || nextElement.getAttribute("data-type")))) { - blockElement.insertAdjacentHTML("afterend", - `

${Constants.ZWSP}

`); - setRangeByWbr(vditor[vditor.currentMode].element, range); - } else { - range.selectNodeContents(nextElement); - range.collapse(true); - setSelectionFocus(range); + const position = getSelectPosition(element, vditor[vditor.currentMode].element, range); + if ((event.key === "ArrowDown" && element.textContent.trimRight().substr(position.start).indexOf("\n") === -1) || + (event.key === "ArrowRight" && position.start >= element.textContent.trimRight().length)) { + const nextElement = blockElement.nextElementSibling; + if (!nextElement || + (nextElement && (nextElement.tagName === "TABLE" || nextElement.getAttribute("data-type")))) { + blockElement.insertAdjacentHTML("afterend", + `

${Constants.ZWSP}

`); + setRangeByWbr(vditor[vditor.currentMode].element, range); + } else { + range.selectNodeContents(nextElement); + range.collapse(true); + setSelectionFocus(range); + } + event.preventDefault(); + return true; } - event.preventDefault(); - return true; - } - return false; + return false; }; export const insertBeforeBlock = (vditor: IVditor, event: KeyboardEvent, range: Range, element: HTMLElement, blockElement: HTMLElement) => { - const position = getSelectPosition(element, vditor[vditor.currentMode].element, range); - if ((event.key === "ArrowUp" && element.textContent.substr(0, position.start).indexOf("\n") === -1) || - ((event.key === "ArrowLeft" || (event.key === "Backspace" && range.toString() === "")) && - position.start === 0)) { - const previousElement = blockElement.previousElementSibling; - // table || code - if (!previousElement || - (previousElement && (previousElement.tagName === "TABLE" || previousElement.getAttribute("data-type")))) { - blockElement.insertAdjacentHTML("beforebegin", - `

${Constants.ZWSP}

`); - setRangeByWbr(vditor[vditor.currentMode].element, range); - } else { - range.selectNodeContents(previousElement); - range.collapse(false); - setSelectionFocus(range); + const position = getSelectPosition(element, vditor[vditor.currentMode].element, range); + if ((event.key === "ArrowUp" && element.textContent.substr(0, position.start).indexOf("\n") === -1) || + ((event.key === "ArrowLeft" || (event.key === "Backspace" && range.toString() === "")) && + position.start === 0)) { + const previousElement = blockElement.previousElementSibling; + // table || code + if (!previousElement || + (previousElement && (previousElement.tagName === "TABLE" || previousElement.getAttribute("data-type")))) { + blockElement.insertAdjacentHTML("beforebegin", + `

${Constants.ZWSP}

`); + setRangeByWbr(vditor[vditor.currentMode].element, range); + } else { + range.selectNodeContents(previousElement); + range.collapse(false); + setSelectionFocus(range); + } + event.preventDefault(); + return true; } - event.preventDefault(); - return true; - } - return false; + return false; }; export const listToggle = (vditor: IVditor, range: Range, type: string, cancel = true) => { - const itemElement = hasClosestByMatchTag(range.startContainer, "LI"); - vditor[vditor.currentMode].element.querySelectorAll("wbr").forEach((wbr) => { - wbr.remove(); - }); - range.insertNode(document.createElement("wbr")); - - if (cancel && itemElement) { - // 取消 - let pHTML = ""; - for (let i = 0; i < itemElement.parentElement.childElementCount; i++) { - const inputElement = itemElement.parentElement.children[i].querySelector("input"); - if (inputElement) { - inputElement.remove(); - } - pHTML += `

${itemElement.parentElement.children[i].innerHTML.trimLeft()}

`; - } - itemElement.parentElement.insertAdjacentHTML("beforebegin", pHTML); - itemElement.parentElement.remove(); - } else { - if (!itemElement) { - // 添加 - let blockElement = hasClosestByAttribute(range.startContainer, "data-block", "0"); - if (!blockElement) { - vditor[vditor.currentMode].element.querySelector("wbr").remove(); - blockElement = vditor[vditor.currentMode].element.querySelector("p"); - blockElement.innerHTML = ""; - } - if (type === "check") { - blockElement.insertAdjacentHTML("beforebegin", - ``); - blockElement.remove(); - } else if (type === "list") { - blockElement.insertAdjacentHTML("beforebegin", - ``); - blockElement.remove(); - } else if (type === "ordered-list") { - blockElement.insertAdjacentHTML("beforebegin", - `
  1. ${blockElement.innerHTML}
`); - blockElement.remove(); - } + const itemElement = hasClosestByMatchTag(range.startContainer, "LI"); + vditor[vditor.currentMode].element.querySelectorAll("wbr").forEach((wbr) => { + wbr.remove(); + }); + range.insertNode(document.createElement("wbr")); + + if (cancel && itemElement) { + // 取消 + let pHTML = ""; + for (let i = 0; i < itemElement.parentElement.childElementCount; i++) { + const inputElement = itemElement.parentElement.children[i].querySelector("input"); + if (inputElement) { + inputElement.remove(); + } + pHTML += `

${itemElement.parentElement.children[i].innerHTML.trimLeft()}

`; + } + itemElement.parentElement.insertAdjacentHTML("beforebegin", pHTML); + itemElement.parentElement.remove(); } else { - // 切换 - if (type === "check") { - itemElement.parentElement.querySelectorAll("li").forEach((item) => { - item.insertAdjacentHTML("afterbegin", - `${item.textContent.indexOf(" ") === 0 ? "" : " "}`); - item.classList.add("vditor-task"); - }); - } else { - if (itemElement.querySelector("input")) { - itemElement.parentElement.querySelectorAll("li").forEach((item) => { - item.querySelector("input").remove(); - item.classList.remove("vditor-task"); - }); - } - let element; - if (type === "list") { - element = document.createElement("ul"); - element.setAttribute("data-marker", "*"); + if (!itemElement) { + // 添加 + let blockElement = hasClosestByAttribute(range.startContainer, "data-block", "0"); + if (!blockElement) { + vditor[vditor.currentMode].element.querySelector("wbr").remove(); + blockElement = vditor[vditor.currentMode].element.querySelector("p"); + blockElement.innerHTML = ""; + } + if (type === "check") { + blockElement.insertAdjacentHTML("beforebegin", + ``); + blockElement.remove(); + } else if (type === "list") { + blockElement.insertAdjacentHTML("beforebegin", + ``); + blockElement.remove(); + } else if (type === "ordered-list") { + blockElement.insertAdjacentHTML("beforebegin", + `
  1. ${blockElement.innerHTML}
`); + blockElement.remove(); + } } else { - element = document.createElement("ol"); - element.setAttribute("data-marker", "1."); - } - element.setAttribute("data-block", "0"); - element.setAttribute("data-tight", itemElement.parentElement.getAttribute("data-tight")); - element.innerHTML = itemElement.parentElement.innerHTML; - itemElement.parentElement.parentNode.replaceChild(element, itemElement.parentElement); - } + // 切换 + if (type === "check") { + itemElement.parentElement.querySelectorAll("li").forEach((item) => { + item.insertAdjacentHTML("afterbegin", + `${item.textContent.indexOf(" ") === 0 ? "" : " "}`); + item.classList.add("vditor-task"); + }); + } else { + if (itemElement.querySelector("input")) { + itemElement.parentElement.querySelectorAll("li").forEach((item) => { + item.querySelector("input").remove(); + item.classList.remove("vditor-task"); + }); + } + let element; + if (type === "list") { + element = document.createElement("ul"); + element.setAttribute("data-marker", "*"); + } else { + element = document.createElement("ol"); + element.setAttribute("data-marker", "1."); + } + element.setAttribute("data-block", "0"); + element.setAttribute("data-tight", itemElement.parentElement.getAttribute("data-tight")); + element.innerHTML = itemElement.parentElement.innerHTML; + itemElement.parentElement.parentNode.replaceChild(element, itemElement.parentElement); + } + } } - } }; export const listIndent = (vditor: IVditor, liElement: HTMLElement, range: Range) => { - const previousElement = liElement.previousElementSibling; - if (liElement && previousElement) { - const liElements: HTMLElement[] = [liElement]; - Array.from(range.cloneContents().children).forEach((item, index) => { - if (item.nodeType !== 3 && liElement && item.textContent.trim() !== "" - && liElement.getAttribute("data-node-id") === item.getAttribute("data-node-id")) { - if (index !== 0) { - liElements.push(liElement); - } - liElement = liElement.nextElementSibling as HTMLElement; - } - }); + const previousElement = liElement.previousElementSibling; + if (liElement && previousElement) { + const liElements: HTMLElement[] = [liElement]; + Array.from(range.cloneContents().children).forEach((item, index) => { + if (item.nodeType !== 3 && liElement && item.textContent.trim() !== "" + && liElement.getAttribute("data-node-id") === item.getAttribute("data-node-id")) { + if (index !== 0) { + liElements.push(liElement); + } + liElement = liElement.nextElementSibling as HTMLElement; + } + }); - vditor[vditor.currentMode].element.querySelectorAll("wbr").forEach((wbr) => { - wbr.remove(); - }); - range.insertNode(document.createElement("wbr")); - const liParentElement = previousElement.parentElement; - - let liHTML = ""; - liElements.forEach((item: HTMLElement) => { - let marker = item.getAttribute("data-marker"); - if (marker.length !== 1) { - marker = `1${marker.slice(-1)}`; - } - liHTML += `
  • ${item.innerHTML}
  • `; - item.remove(); - }); - previousElement.insertAdjacentHTML("beforeend", - `<${liParentElement.tagName} data-block="0">${liHTML}`); + vditor[vditor.currentMode].element.querySelectorAll("wbr").forEach((wbr) => { + wbr.remove(); + }); + range.insertNode(document.createElement("wbr")); + const liParentElement = previousElement.parentElement; + + let liHTML = ""; + liElements.forEach((item: HTMLElement) => { + let marker = item.getAttribute("data-marker"); + if (marker.length !== 1) { + marker = `1${marker.slice(-1)}`; + } + liHTML += `
  • ${item.innerHTML}
  • `; + item.remove(); + }); + previousElement.insertAdjacentHTML("beforeend", + `<${liParentElement.tagName} data-block="0">${liHTML}`); - if (vditor.currentMode === "wysiwyg") { - liParentElement.outerHTML = vditor.lute.SpinVditorDOM(liParentElement.outerHTML); - } else { - liParentElement.outerHTML = vditor.lute.SpinVditorIRDOM(liParentElement.outerHTML); - } + if (vditor.currentMode === "wysiwyg") { + liParentElement.outerHTML = vditor.lute.SpinVditorDOM(liParentElement.outerHTML); + } else { + liParentElement.outerHTML = vditor.lute.SpinVditorIRDOM(liParentElement.outerHTML); + } - setRangeByWbr(vditor[vditor.currentMode].element, range); - const tempTopListElement = getTopList(range.startContainer); - if (tempTopListElement) { - tempTopListElement.querySelectorAll(`.vditor-${vditor.currentMode}__preview[data-render='2']`) - .forEach((item: HTMLElement) => { - processCodeRender(item, vditor); - if (vditor.currentMode === "wysiwyg") { - item.previousElementSibling.setAttribute("style", "display:none"); - } - }); + setRangeByWbr(vditor[vditor.currentMode].element, range); + const tempTopListElement = getTopList(range.startContainer); + if (tempTopListElement) { + tempTopListElement.querySelectorAll(`.vditor-${vditor.currentMode}__preview[data-render='2']`) + .forEach((item: HTMLElement) => { + processCodeRender(item, vditor); + if (vditor.currentMode === "wysiwyg") { + item.previousElementSibling.setAttribute("style", "display:none"); + } + }); + } + execAfterRender(vditor); + highlightToolbar(vditor); + } else { + vditor[vditor.currentMode].element.focus(); } - execAfterRender(vditor); - highlightToolbar(vditor); - } else { - vditor[vditor.currentMode].element.focus(); - } }; export const listOutdent = (vditor: IVditor, liElement: HTMLElement, range: Range, topListElement: HTMLElement) => { - const liParentLiElement = hasClosestByMatchTag(liElement.parentElement, "LI"); - if (liParentLiElement) { - vditor[vditor.currentMode].element.querySelectorAll("wbr").forEach((wbr) => { - wbr.remove(); - }); - range.insertNode(document.createElement("wbr")); + const liParentLiElement = hasClosestByMatchTag(liElement.parentElement, "LI"); + if (liParentLiElement) { + vditor[vditor.currentMode].element.querySelectorAll("wbr").forEach((wbr) => { + wbr.remove(); + }); + range.insertNode(document.createElement("wbr")); + + const liParentElement = liElement.parentElement; + const liParentAfterElement = liParentElement.cloneNode() as HTMLElement; + const liElements: HTMLElement[] = [liElement]; + Array.from(range.cloneContents().children).forEach((item, index) => { + if (item.nodeType !== 3 && liElement && item.textContent.trim() !== "" && + liElement.getAttribute("data-node-id") === item.getAttribute("data-node-id")) { + if (index !== 0) { + liElements.push(liElement); + } + liElement = liElement.nextElementSibling as HTMLElement; + } + }); + let isMatch = false; + let afterHTML = ""; + liParentElement.querySelectorAll("li").forEach((item) => { + if (isMatch) { + afterHTML += item.outerHTML; + if (!item.nextElementSibling && !item.previousElementSibling) { + item.parentElement.remove(); + } else { + item.remove(); + } + } + if (item.isSameNode(liElements[liElements.length - 1])) { + isMatch = true; + } + }); - const liParentElement = liElement.parentElement; - const liParentAfterElement = liParentElement.cloneNode() as HTMLElement; - const liElements: HTMLElement[] = [liElement]; - Array.from(range.cloneContents().children).forEach((item, index) => { - if (item.nodeType !== 3 && liElement && item.textContent.trim() !== "" && - liElement.getAttribute("data-node-id") === item.getAttribute("data-node-id")) { - if (index !== 0) { - liElements.push(liElement); - } - liElement = liElement.nextElementSibling as HTMLElement; - } - }); - let isMatch = false; - let afterHTML = ""; - liParentElement.querySelectorAll("li").forEach((item) => { - if (isMatch) { - afterHTML += item.outerHTML; - if (!item.nextElementSibling && !item.previousElementSibling) { - item.parentElement.remove(); - } else { - item.remove(); - } - } - if (item.isSameNode(liElements[liElements.length - 1])) { - isMatch = true; - } - }); + liElements.reverse().forEach((item) => { + liParentLiElement.insertAdjacentElement("afterend", item); + }); - liElements.reverse().forEach((item) => { - liParentLiElement.insertAdjacentElement("afterend", item); - }); + if (afterHTML) { + liParentAfterElement.innerHTML = afterHTML; + liElements[0].insertAdjacentElement("beforeend", liParentAfterElement); + } - if (afterHTML) { - liParentAfterElement.innerHTML = afterHTML; - liElements[0].insertAdjacentElement("beforeend", liParentAfterElement); - } + if (vditor.currentMode === "wysiwyg") { + topListElement.outerHTML = vditor.lute.SpinVditorDOM(topListElement.outerHTML); + } else { + topListElement.outerHTML = vditor.lute.SpinVditorIRDOM(topListElement.outerHTML); + } - if (vditor.currentMode === "wysiwyg") { - topListElement.outerHTML = vditor.lute.SpinVditorDOM(topListElement.outerHTML); + setRangeByWbr(vditor[vditor.currentMode].element, range); + const tempTopListElement = getTopList(range.startContainer); + if (tempTopListElement) { + tempTopListElement.querySelectorAll(`.vditor-${vditor.currentMode}__preview[data-render='2']`) + .forEach((item: HTMLElement) => { + processCodeRender(item, vditor); + if (vditor.currentMode === "wysiwyg") { + item.previousElementSibling.setAttribute("style", "display:none"); + } + }); + } + execAfterRender(vditor); + highlightToolbar(vditor); } else { - topListElement.outerHTML = vditor.lute.SpinVditorIRDOM(topListElement.outerHTML); + vditor[vditor.currentMode].element.focus(); } - - setRangeByWbr(vditor[vditor.currentMode].element, range); - const tempTopListElement = getTopList(range.startContainer); - if (tempTopListElement) { - tempTopListElement.querySelectorAll(`.vditor-${vditor.currentMode}__preview[data-render='2']`) - .forEach((item: HTMLElement) => { - processCodeRender(item, vditor); - if (vditor.currentMode === "wysiwyg") { - item.previousElementSibling.setAttribute("style", "display:none"); - } - }); - } - execAfterRender(vditor); - highlightToolbar(vditor); - } else { - vditor[vditor.currentMode].element.focus(); - } }; export const setTableAlign = (tableElement: HTMLTableElement, type: string) => { - const cell = getSelection().getRangeAt(0).startContainer.parentElement; - - const columnCnt = tableElement.rows[0].cells.length; - const rowCnt = tableElement.rows.length; - let currentColumn = 0; - - for (let i = 0; i < rowCnt; i++) { - for (let j = 0; j < columnCnt; j++) { - if (tableElement.rows[i].cells[j].isSameNode(cell)) { - currentColumn = j; - break; - } + const cell = getSelection().getRangeAt(0).startContainer.parentElement; + + const columnCnt = tableElement.rows[0].cells.length; + const rowCnt = tableElement.rows.length; + let currentColumn = 0; + + for (let i = 0; i < rowCnt; i++) { + for (let j = 0; j < columnCnt; j++) { + if (tableElement.rows[i].cells[j].isSameNode(cell)) { + currentColumn = j; + break; + } + } + } + for (let k = 0; k < rowCnt; k++) { + tableElement.rows[k].cells[currentColumn].setAttribute("align", type); } - } - for (let k = 0; k < rowCnt; k++) { - tableElement.rows[k].cells[currentColumn].setAttribute("align", type); - } }; export const isHrMD = (text: string) => { - // - _ * - const marker = text.trimRight().split("\n").pop(); - if (marker === "") { - return false; - } - if (marker.replace(/ |-/g, "") === "" - || marker.replace(/ |_/g, "") === "" - || marker.replace(/ |\*/g, "") === "") { - if (marker.replace(/ /g, "").length > 2) { - if (marker.indexOf("-") > -1 && marker.trimLeft().indexOf(" ") === -1 - && text.trimRight().split("\n").length > 1) { - // 满足 heading + // - _ * + const marker = text.trimRight().split("\n").pop(); + if (marker === "") { return false; - } - if (marker.indexOf(" ") === 0 || marker.indexOf("\t") === 0) { - // 代码块 + } + if (marker.replace(/ |-/g, "") === "" + || marker.replace(/ |_/g, "") === "" + || marker.replace(/ |\*/g, "") === "") { + if (marker.replace(/ /g, "").length > 2) { + if (marker.indexOf("-") > -1 && marker.trimLeft().indexOf(" ") === -1 + && text.trimRight().split("\n").length > 1) { + // 满足 heading + return false; + } + if (marker.indexOf(" ") === 0 || marker.indexOf("\t") === 0) { + // 代码块 + return false; + } + return true; + } return false; - } - return true; } return false; - } - return false; }; export const isHeadingMD = (text: string) => { - // - = - const textArray = text.trimRight().split("\n"); - text = textArray.pop(); + // - = + const textArray = text.trimRight().split("\n"); + text = textArray.pop(); - if (text.indexOf(" ") === 0 || text.indexOf("\t") === 0) { - return false; - } + if (text.indexOf(" ") === 0 || text.indexOf("\t") === 0) { + return false; + } - text = text.trimLeft(); - if (text === "" || textArray.length === 0) { + text = text.trimLeft(); + if (text === "" || textArray.length === 0) { + return false; + } + if (text.replace(/-/g, "") === "" + || text.replace(/=/g, "") === "") { + return true; + } return false; - } - if (text.replace(/-/g, "") === "" - || text.replace(/=/g, "") === "") { - return true; - } - return false; }; export const execAfterRender = (vditor: IVditor, options = { - enableAddUndoStack: true, - enableHint: false, - enableInput: true, + enableAddUndoStack: true, + enableHint: false, + enableInput: true, }) => { - if (vditor.currentMode === "wysiwyg") { - afterRenderEvent(vditor, options); - } else if (vditor.currentMode === "ir") { - processAfterRender(vditor, options); - } else if (vditor.currentMode === "sv") { - processSVAfterRender(vditor, options); - } + if (vditor.currentMode === "wysiwyg") { + afterRenderEvent(vditor, options); + } else if (vditor.currentMode === "ir") { + processAfterRender(vditor, options); + } else if (vditor.currentMode === "sv") { + processSVAfterRender(vditor, options); + } }; export const fixList = (range: Range, vditor: IVditor, pElement: HTMLElement | false, event: KeyboardEvent) => { - const startContainer = range.startContainer; - const liElement = hasClosestByMatchTag(startContainer, "LI"); - if (liElement) { - if (!isCtrl(event) && !event.altKey && event.key === "Enter" && - // fix li 中有多个 P 时,在第一个 P 中换行会在下方生成新的 li - (!event.shiftKey && pElement && liElement.contains(pElement) && pElement.nextElementSibling)) { - if (liElement && !liElement.textContent.endsWith("\n")) { - // li 结尾需 \n - liElement.insertAdjacentText("beforeend", "\n"); - } - range.insertNode(document.createTextNode("\n\n")); - range.collapse(false); - execAfterRender(vditor); - event.preventDefault(); - return true; - } + const startContainer = range.startContainer; + const liElement = hasClosestByMatchTag(startContainer, "LI"); + if (liElement) { + if (!isCtrl(event) && !event.altKey && event.key === "Enter" && + // fix li 中有多个 P 时,在第一个 P 中换行会在下方生成新的 li + (!event.shiftKey && pElement && liElement.contains(pElement) && pElement.nextElementSibling)) { + if (liElement && !liElement.textContent.endsWith("\n")) { + // li 结尾需 \n + liElement.insertAdjacentText("beforeend", "\n"); + } + range.insertNode(document.createTextNode("\n\n")); + range.collapse(false); + execAfterRender(vditor); + event.preventDefault(); + return true; + } - if (!isCtrl(event) && !event.shiftKey && !event.altKey && event.key === "Backspace" && - !liElement.previousElementSibling && range.toString() === "" && - getSelectPosition(liElement, vditor[vditor.currentMode].element, range).start === 0) { - // 光标位于点和第一个字符中间时,无法删除 li 元素 - if (liElement.nextElementSibling) { - liElement.parentElement.insertAdjacentHTML("beforebegin", - `

    ${liElement.innerHTML}

    `); - liElement.remove(); - } else { - liElement.parentElement.outerHTML = `

    ${liElement.innerHTML}

    `; - } - setRangeByWbr(vditor[vditor.currentMode].element, range); - execAfterRender(vditor); - event.preventDefault(); - return true; - } + if (!isCtrl(event) && !event.shiftKey && !event.altKey && event.key === "Backspace" && + !liElement.previousElementSibling && range.toString() === "" && + getSelectPosition(liElement, vditor[vditor.currentMode].element, range).start === 0) { + // 光标位于点和第一个字符中间时,无法删除 li 元素 + if (liElement.nextElementSibling) { + liElement.parentElement.insertAdjacentHTML("beforebegin", + `

    ${liElement.innerHTML}

    `); + liElement.remove(); + } else { + liElement.parentElement.outerHTML = `

    ${liElement.innerHTML}

    `; + } + setRangeByWbr(vditor[vditor.currentMode].element, range); + execAfterRender(vditor); + event.preventDefault(); + return true; + } - // 空列表删除后与上一级段落对齐 - if (!isCtrl(event) && !event.shiftKey && !event.altKey && event.key === "Backspace" && - liElement.textContent.trim().replace(Constants.ZWSP, "") === "" && - range.toString() === "" && liElement.previousElementSibling?.tagName === "LI") { - liElement.previousElementSibling.insertAdjacentText("beforeend", "\n\n"); - range.selectNodeContents(liElement.previousElementSibling); - range.collapse(false); - liElement.remove(); - setRangeByWbr(vditor[vditor.currentMode].element, range); - execAfterRender(vditor); - event.preventDefault(); - return true; - } + // 空列表删除后与上一级段落对齐 + if (!isCtrl(event) && !event.shiftKey && !event.altKey && event.key === "Backspace" && + liElement.textContent.trim().replace(Constants.ZWSP, "") === "" && + range.toString() === "" && liElement.previousElementSibling?.tagName === "LI") { + liElement.previousElementSibling.insertAdjacentText("beforeend", "\n\n"); + range.selectNodeContents(liElement.previousElementSibling); + range.collapse(false); + liElement.remove(); + setRangeByWbr(vditor[vditor.currentMode].element, range); + execAfterRender(vditor); + event.preventDefault(); + return true; + } - if (!isCtrl(event) && !event.altKey && event.key === "Tab") { - // 光标位于第一/零字符时,tab 用于列表的缩进 - let isFirst = false; - if (range.startOffset === 0 - && ((startContainer.nodeType === 3 && !startContainer.previousSibling) - || (startContainer.nodeType !== 3 && startContainer.nodeName === "LI"))) { - // 有序/无序列表 - isFirst = true; - } else if (liElement.classList.contains("vditor-task") && range.startOffset === 1 - && startContainer.previousSibling.nodeType !== 3 - && (startContainer.previousSibling as HTMLElement).tagName === "INPUT") { - // 任务列表 - isFirst = true; - } - - if (isFirst || range.toString() !== "") { - if (event.shiftKey) { - listOutdent(vditor, liElement, range, liElement.parentElement); - } else { - listIndent(vditor, liElement, range); + if (!isCtrl(event) && !event.altKey && event.key === "Tab") { + // 光标位于第一/零字符时,tab 用于列表的缩进 + let isFirst = false; + if (range.startOffset === 0 + && ((startContainer.nodeType === 3 && !startContainer.previousSibling) + || (startContainer.nodeType !== 3 && startContainer.nodeName === "LI"))) { + // 有序/无序列表 + isFirst = true; + } else if (liElement.classList.contains("vditor-task") && range.startOffset === 1 + && startContainer.previousSibling.nodeType !== 3 + && (startContainer.previousSibling as HTMLElement).tagName === "INPUT") { + // 任务列表 + isFirst = true; + } + + if (isFirst || range.toString() !== "") { + if (event.shiftKey) { + listOutdent(vditor, liElement, range, liElement.parentElement); + } else { + listIndent(vditor, liElement, range); + } + event.preventDefault(); + return true; + } } - event.preventDefault(); - return true; - } } - } - return false; + return false; }; // tab 处理: block code render, table, 列表第一个字符中的 tab 处理单独写在上面 export const fixTab = (vditor: IVditor, range: Range, event: KeyboardEvent) => { - if (vditor.options.tab && event.key === "Tab") { - if (event.shiftKey) { - // TODO shift+tab - } else { - if (range.toString() === "") { - range.insertNode(document.createTextNode(vditor.options.tab)); - range.collapse(false); - } else { - range.extractContents(); - range.insertNode(document.createTextNode(vditor.options.tab)); - range.collapse(false); - } + if (vditor.options.tab && event.key === "Tab") { + if (event.shiftKey) { + // TODO shift+tab + } else { + if (range.toString() === "") { + range.insertNode(document.createTextNode(vditor.options.tab)); + range.collapse(false); + } else { + range.extractContents(); + range.insertNode(document.createTextNode(vditor.options.tab)); + range.collapse(false); + } + } + setSelectionFocus(range); + execAfterRender(vditor); + event.preventDefault(); + return true; } - setSelectionFocus(range); - execAfterRender(vditor); - event.preventDefault(); - return true; - } }; export const fixMarkdown = (event: KeyboardEvent, vditor: IVditor, pElement: HTMLElement | false, range: Range) => { - if (!pElement) { - return; - } - if (!isCtrl(event) && !event.altKey && event.key === "Enter") { - const pText = String.raw`${pElement.textContent}`.replace(/\\\|/g, "").trim(); - const pTextList = pText.split("|"); - if (pText.startsWith("|") && pText.endsWith("|") && pTextList.length > 3) { - // table 自动完成 - let tableHeaderMD = pTextList.map(() => "---").join("|"); - tableHeaderMD = - pElement.textContent + "\n" + tableHeaderMD.substring(3, tableHeaderMD.length - 3) + "\n|"; - pElement.outerHTML = vditor.lute.SpinVditorDOM(tableHeaderMD); - setRangeByWbr(vditor[vditor.currentMode].element, range); - execAfterRender(vditor); - scrollCenter(vditor); - event.preventDefault(); - return true; + if (!pElement) { + return; } + if (!isCtrl(event) && !event.altKey && event.key === "Enter") { + const pText = String.raw`${pElement.textContent}`.replace(/\\\|/g, "").trim(); + const pTextList = pText.split("|"); + if (pText.startsWith("|") && pText.endsWith("|") && pTextList.length > 3) { + // table 自动完成 + let tableHeaderMD = pTextList.map(() => "---").join("|"); + tableHeaderMD = + pElement.textContent + "\n" + tableHeaderMD.substring(3, tableHeaderMD.length - 3) + "\n|"; + pElement.outerHTML = vditor.lute.SpinVditorDOM(tableHeaderMD); + setRangeByWbr(vditor[vditor.currentMode].element, range); + execAfterRender(vditor); + scrollCenter(vditor); + event.preventDefault(); + return true; + } - // hr 渲染 - if (isHrMD(pElement.innerHTML) && pElement.previousElementSibling) { - // 软换行后 hr 前有内容 - let pInnerHTML = ""; - const innerHTMLList = pElement.innerHTML.trimRight().split("\n"); - if (innerHTMLList.length > 1) { - innerHTMLList.pop(); - pInnerHTML = `

    ${innerHTMLList.join("\n")}

    `; - } - - pElement.insertAdjacentHTML("afterend", - `${pInnerHTML}

    \n

    `); - pElement.remove(); - setRangeByWbr(vditor[vditor.currentMode].element, range); - execAfterRender(vditor); - scrollCenter(vditor); - event.preventDefault(); - return true; - } + // hr 渲染 + if (isHrMD(pElement.innerHTML) && pElement.previousElementSibling) { + // 软换行后 hr 前有内容 + let pInnerHTML = ""; + const innerHTMLList = pElement.innerHTML.trimRight().split("\n"); + if (innerHTMLList.length > 1) { + innerHTMLList.pop(); + pInnerHTML = `

    ${innerHTMLList.join("\n")}

    `; + } + + pElement.insertAdjacentHTML("afterend", + `${pInnerHTML}

    \n

    `); + pElement.remove(); + setRangeByWbr(vditor[vditor.currentMode].element, range); + execAfterRender(vditor); + scrollCenter(vditor); + event.preventDefault(); + return true; + } - if (isHeadingMD(pElement.innerHTML)) { - // heading 渲染 - if (vditor.currentMode === "wysiwyg") { - pElement.outerHTML = vditor.lute.SpinVditorDOM(pElement.innerHTML + '

    \n

    '); - } else { - pElement.outerHTML = vditor.lute.SpinVditorIRDOM(pElement.innerHTML + '

    \n

    '); - } - setRangeByWbr(vditor[vditor.currentMode].element, range); - execAfterRender(vditor); - scrollCenter(vditor); - event.preventDefault(); - return true; + if (isHeadingMD(pElement.innerHTML)) { + // heading 渲染 + if (vditor.currentMode === "wysiwyg") { + pElement.outerHTML = vditor.lute.SpinVditorDOM(pElement.innerHTML + '

    \n

    '); + } else { + pElement.outerHTML = vditor.lute.SpinVditorIRDOM(pElement.innerHTML + '

    \n

    '); + } + setRangeByWbr(vditor[vditor.currentMode].element, range); + execAfterRender(vditor); + scrollCenter(vditor); + event.preventDefault(); + return true; + } } - } - - // 软换行会被切割 https://github.com/Vanessa219/vditor/issues/220 - if (range.collapsed && pElement.previousElementSibling && event.key === "Backspace" && - !isCtrl(event) && !event.altKey && !event.shiftKey && - pElement.textContent.trimRight().split("\n").length > 1 && - getSelectPosition(pElement, vditor[vditor.currentMode].element, range).start === 0) { - const lastElement = getLastNode(pElement.previousElementSibling) as HTMLElement; - if (!lastElement.textContent.endsWith("\n")) { - lastElement.textContent = lastElement.textContent + "\n"; + + // 软换行会被切割 https://github.com/Vanessa219/vditor/issues/220 + if (range.collapsed && pElement.previousElementSibling && event.key === "Backspace" && + !isCtrl(event) && !event.altKey && !event.shiftKey && + pElement.textContent.trimRight().split("\n").length > 1 && + getSelectPosition(pElement, vditor[vditor.currentMode].element, range).start === 0) { + const lastElement = getLastNode(pElement.previousElementSibling) as HTMLElement; + if (!lastElement.textContent.endsWith("\n")) { + lastElement.textContent = lastElement.textContent + "\n"; + } + lastElement.parentElement.insertAdjacentHTML("beforeend", `${pElement.innerHTML}`); + pElement.remove(); + setRangeByWbr(vditor[vditor.currentMode].element, range); + return false; } - lastElement.parentElement.insertAdjacentHTML("beforeend", `${pElement.innerHTML}`); - pElement.remove(); - setRangeByWbr(vditor[vditor.currentMode].element, range); return false; - } - return false; }; export const insertRow = (vditor: IVditor, range: Range, cellElement: HTMLElement) => { - let rowHTML = ""; - for (let m = 0; m < cellElement.parentElement.childElementCount; m++) { - rowHTML += ` `; - } - if (cellElement.tagName === "TH") { - cellElement.parentElement.parentElement.insertAdjacentHTML("afterend", - `${rowHTML}`); - } else { - cellElement.parentElement.insertAdjacentHTML("afterend", `${rowHTML}`); - } - execAfterRender(vditor); + let rowHTML = ""; + for (let m = 0; m < cellElement.parentElement.childElementCount; m++) { + rowHTML += ` `; + } + if (cellElement.tagName === "TH") { + cellElement.parentElement.parentElement.insertAdjacentHTML("afterend", + `${rowHTML}`); + } else { + cellElement.parentElement.insertAdjacentHTML("afterend", `${rowHTML}`); + } + execAfterRender(vditor); }; export const insertRowAbove = (vditor: IVditor, range: Range, cellElement: HTMLElement) => { - let rowHTML = ""; - for (let m = 0; m < cellElement.parentElement.childElementCount; m++) { + let rowHTML = ""; + for (let m = 0; m < cellElement.parentElement.childElementCount; m++) { + if (cellElement.tagName === "TH") { + rowHTML += ` `; + } else { + rowHTML += ` `; + } + } if (cellElement.tagName === "TH") { - rowHTML += ` `; + cellElement.parentElement.parentElement.insertAdjacentHTML("beforebegin", `${rowHTML}`); + + range.insertNode(document.createElement("wbr")); + const theadHTML = cellElement.parentElement.innerHTML.replace(//g, "").replace(/<\/th>/g, ""); + cellElement.parentElement.parentElement.nextElementSibling.insertAdjacentHTML("afterbegin", theadHTML); + + cellElement.parentElement.parentElement.remove(); + setRangeByWbr(vditor.ir.element, range); } else { - rowHTML += ` `; + cellElement.parentElement.insertAdjacentHTML("beforebegin", `${rowHTML}`); } - } - if (cellElement.tagName === "TH") { - cellElement.parentElement.parentElement.insertAdjacentHTML("beforebegin", `${rowHTML}`); - - range.insertNode(document.createElement("wbr")); - const theadHTML = cellElement.parentElement.innerHTML.replace(//g, "").replace(/<\/th>/g, ""); - cellElement.parentElement.parentElement.nextElementSibling.insertAdjacentHTML("afterbegin", theadHTML); - - cellElement.parentElement.parentElement.remove(); - setRangeByWbr(vditor.ir.element, range); - } else { - cellElement.parentElement.insertAdjacentHTML("beforebegin", `${rowHTML}`); - } - execAfterRender(vditor); + execAfterRender(vditor); }; export const insertColumn = - (vditor: IVditor, tableElement: HTMLTableElement, cellElement: HTMLElement, type: InsertPosition = "afterend") => { - let index = 0; - let previousElement = cellElement.previousElementSibling; - while (previousElement) { - index++; - previousElement = previousElement.previousElementSibling; - } - for (let i = 0; i < tableElement.rows.length; i++) { - if (i === 0) { - tableElement.rows[i].cells[index].insertAdjacentHTML(type, " "); - } else { - tableElement.rows[i].cells[index].insertAdjacentHTML(type, " "); - } - } - execAfterRender(vditor); - }; + (vditor: IVditor, tableElement: HTMLTableElement, cellElement: HTMLElement, type: InsertPosition = "afterend") => { + let index = 0; + let previousElement = cellElement.previousElementSibling; + while (previousElement) { + index++; + previousElement = previousElement.previousElementSibling; + } + for (let i = 0; i < tableElement.rows.length; i++) { + if (i === 0) { + tableElement.rows[i].cells[index].insertAdjacentHTML(type, " "); + } else { + tableElement.rows[i].cells[index].insertAdjacentHTML(type, " "); + } + } + execAfterRender(vditor); + }; export const deleteRow = (vditor: IVditor, range: Range, cellElement: HTMLElement) => { - if (cellElement.tagName === "TD") { - const tbodyElement = cellElement.parentElement.parentElement; - if (cellElement.parentElement.previousElementSibling) { - range.selectNodeContents(cellElement.parentElement.previousElementSibling.lastElementChild); - } else { - range.selectNodeContents(tbodyElement.previousElementSibling.lastElementChild.lastElementChild); - } + if (cellElement.tagName === "TD") { + const tbodyElement = cellElement.parentElement.parentElement; + if (cellElement.parentElement.previousElementSibling) { + range.selectNodeContents(cellElement.parentElement.previousElementSibling.lastElementChild); + } else { + range.selectNodeContents(tbodyElement.previousElementSibling.lastElementChild.lastElementChild); + } - if (tbodyElement.childElementCount === 1) { - tbodyElement.remove(); - } else { - cellElement.parentElement.remove(); - } + if (tbodyElement.childElementCount === 1) { + tbodyElement.remove(); + } else { + cellElement.parentElement.remove(); + } - range.collapse(false); - setSelectionFocus(range); - execAfterRender(vditor); - } + range.collapse(false); + setSelectionFocus(range); + execAfterRender(vditor); + } }; export const deleteColumn = - (vditor: IVditor, range: Range, tableElement: HTMLTableElement, cellElement: HTMLElement) => { - let index = 0; - let previousElement = cellElement.previousElementSibling; - while (previousElement) { - index++; - previousElement = previousElement.previousElementSibling; - } - if (cellElement.previousElementSibling || cellElement.nextElementSibling) { - range.selectNodeContents(cellElement.previousElementSibling || cellElement.nextElementSibling); - range.collapse(true); - } - for (let i = 0; i < tableElement.rows.length; i++) { - const cells = tableElement.rows[i].cells; - if (cells.length === 1) { - tableElement.remove(); - highlightToolbar(vditor); - break; - } - cells[index].remove(); - } - setSelectionFocus(range); - execAfterRender(vditor); - }; + (vditor: IVditor, range: Range, tableElement: HTMLTableElement, cellElement: HTMLElement) => { + let index = 0; + let previousElement = cellElement.previousElementSibling; + while (previousElement) { + index++; + previousElement = previousElement.previousElementSibling; + } + if (cellElement.previousElementSibling || cellElement.nextElementSibling) { + range.selectNodeContents(cellElement.previousElementSibling || cellElement.nextElementSibling); + range.collapse(true); + } + for (let i = 0; i < tableElement.rows.length; i++) { + const cells = tableElement.rows[i].cells; + if (cells.length === 1) { + tableElement.remove(); + highlightToolbar(vditor); + break; + } + cells[index].remove(); + } + setSelectionFocus(range); + execAfterRender(vditor); + }; export const fixTable = (vditor: IVditor, event: KeyboardEvent, range: Range) => { - const startContainer = range.startContainer; - const cellElement = hasClosestByMatchTag(startContainer, "TD") || - hasClosestByMatchTag(startContainer, "TH"); - if (cellElement) { - // 换行或软换行:在 cell 中添加 br - if (!isCtrl(event) && !event.altKey && event.key === "Enter") { - if (!cellElement.lastElementChild || - (cellElement.lastElementChild && (!cellElement.lastElementChild.isSameNode(cellElement.lastChild) || - cellElement.lastElementChild.tagName !== "BR"))) { - cellElement.insertAdjacentHTML("beforeend", "
    "); - } - const brElement = document.createElement("br"); - range.insertNode(brElement); - range.setStartAfter(brElement); - execAfterRender(vditor); - scrollCenter(vditor); - event.preventDefault(); - return true; - } + const startContainer = range.startContainer; + const cellElement = hasClosestByMatchTag(startContainer, "TD") || + hasClosestByMatchTag(startContainer, "TH"); + if (cellElement) { + // 换行或软换行:在 cell 中添加 br + if (!isCtrl(event) && !event.altKey && event.key === "Enter") { + if (!cellElement.lastElementChild || + (cellElement.lastElementChild && (!cellElement.lastElementChild.isSameNode(cellElement.lastChild) || + cellElement.lastElementChild.tagName !== "BR"))) { + cellElement.insertAdjacentHTML("beforeend", "
    "); + } + const brElement = document.createElement("br"); + range.insertNode(brElement); + range.setStartAfter(brElement); + execAfterRender(vditor); + scrollCenter(vditor); + event.preventDefault(); + return true; + } - // tab:光标移向下一个 cell - if (event.key === "Tab") { - if (event.shiftKey) { - // shift + tab 光标移动到前一个 cell - goPreviousCell(cellElement, range); - event.preventDefault(); - return true; - } - - let nextElement = cellElement.nextElementSibling; - if (!nextElement) { - if (cellElement.parentElement.nextElementSibling) { - nextElement = cellElement.parentElement.nextElementSibling.firstElementChild; - } else if (cellElement.parentElement.parentElement.tagName === "THEAD" && - cellElement.parentElement.parentElement.nextElementSibling) { - nextElement = - cellElement.parentElement.parentElement.nextElementSibling.firstElementChild.firstElementChild; - } else { - nextElement = null; + // tab:光标移向下一个 cell + if (event.key === "Tab") { + if (event.shiftKey) { + // shift + tab 光标移动到前一个 cell + goPreviousCell(cellElement, range); + event.preventDefault(); + return true; + } + + let nextElement = cellElement.nextElementSibling; + if (!nextElement) { + if (cellElement.parentElement.nextElementSibling) { + nextElement = cellElement.parentElement.nextElementSibling.firstElementChild; + } else if (cellElement.parentElement.parentElement.tagName === "THEAD" && + cellElement.parentElement.parentElement.nextElementSibling) { + nextElement = + cellElement.parentElement.parentElement.nextElementSibling.firstElementChild.firstElementChild; + } else { + nextElement = null; + } + } + if (nextElement) { + range.selectNodeContents(nextElement); + setSelectionFocus(range); + } + event.preventDefault(); + return true; } - } - if (nextElement) { - range.selectNodeContents(nextElement); - setSelectionFocus(range); - } - event.preventDefault(); - return true; - } - const tableElement = cellElement.parentElement.parentElement.parentElement as HTMLTableElement; - if (event.key === "ArrowUp") { - event.preventDefault(); - if (cellElement.tagName === "TH") { - if (tableElement.previousElementSibling) { - range.selectNodeContents(tableElement.previousElementSibling); - range.collapse(false); - setSelectionFocus(range); - } else { - insertEmptyBlock(vditor, "beforebegin"); + const tableElement = cellElement.parentElement.parentElement.parentElement as HTMLTableElement; + if (event.key === "ArrowUp") { + event.preventDefault(); + if (cellElement.tagName === "TH") { + if (tableElement.previousElementSibling) { + range.selectNodeContents(tableElement.previousElementSibling); + range.collapse(false); + setSelectionFocus(range); + } else { + insertEmptyBlock(vditor, "beforebegin"); + } + return true; + } + + let m = 0; + const trElement = cellElement.parentElement as HTMLTableRowElement; + for (; m < trElement.cells.length; m++) { + if (trElement.cells[m].isSameNode(cellElement)) { + break; + } + } + + let previousElement = trElement.previousElementSibling as HTMLTableRowElement; + if (!previousElement) { + previousElement = trElement.parentElement.previousElementSibling.firstChild as HTMLTableRowElement; + } + range.selectNodeContents(previousElement.cells[m]); + range.collapse(false); + setSelectionFocus(range); + return true; } - return true; - } - - let m = 0; - const trElement = cellElement.parentElement as HTMLTableRowElement; - for (; m < trElement.cells.length; m++) { - if (trElement.cells[m].isSameNode(cellElement)) { - break; - } - } - - let previousElement = trElement.previousElementSibling as HTMLTableRowElement; - if (!previousElement) { - previousElement = trElement.parentElement.previousElementSibling.firstChild as HTMLTableRowElement; - } - range.selectNodeContents(previousElement.cells[m]); - range.collapse(false); - setSelectionFocus(range); - return true; - } - if (event.key === "ArrowDown") { - event.preventDefault(); - const trElement = cellElement.parentElement as HTMLTableRowElement; - if (!trElement.nextElementSibling && cellElement.tagName === "TD") { - if (tableElement.nextElementSibling) { - range.selectNodeContents(tableElement.nextElementSibling); - range.collapse(true); - setSelectionFocus(range); - } else { - insertEmptyBlock(vditor, "afterend"); + if (event.key === "ArrowDown") { + event.preventDefault(); + const trElement = cellElement.parentElement as HTMLTableRowElement; + if (!trElement.nextElementSibling && cellElement.tagName === "TD") { + if (tableElement.nextElementSibling) { + range.selectNodeContents(tableElement.nextElementSibling); + range.collapse(true); + setSelectionFocus(range); + } else { + insertEmptyBlock(vditor, "afterend"); + } + return true; + } + + let m = 0; + for (; m < trElement.cells.length; m++) { + if (trElement.cells[m].isSameNode(cellElement)) { + break; + } + } + + let nextElement = trElement.nextElementSibling as HTMLTableRowElement; + if (!nextElement) { + nextElement = trElement.parentElement.nextElementSibling.firstChild as HTMLTableRowElement; + } + range.selectNodeContents(nextElement.cells[m]); + range.collapse(true); + setSelectionFocus(range); + return true; } - return true; - } - - let m = 0; - for (; m < trElement.cells.length; m++) { - if (trElement.cells[m].isSameNode(cellElement)) { - break; - } - } - - let nextElement = trElement.nextElementSibling as HTMLTableRowElement; - if (!nextElement) { - nextElement = trElement.parentElement.nextElementSibling.firstChild as HTMLTableRowElement; - } - range.selectNodeContents(nextElement.cells[m]); - range.collapse(true); - setSelectionFocus(range); - return true; - } - // focus row input, only wysiwyg - if (vditor.currentMode === "wysiwyg" && - !isCtrl(event) && event.key === "Enter" && !event.shiftKey && event.altKey) { - const inputElement = (vditor.wysiwyg.popover.querySelector(".vditor-input") as HTMLInputElement); - inputElement.focus(); - inputElement.select(); - event.preventDefault(); - return true; - } + // focus row input, only wysiwyg + if (vditor.currentMode === "wysiwyg" && + !isCtrl(event) && event.key === "Enter" && !event.shiftKey && event.altKey) { + const inputElement = (vditor.wysiwyg.popover.querySelector(".vditor-input") as HTMLInputElement); + inputElement.focus(); + inputElement.select(); + event.preventDefault(); + return true; + } - // Backspace:光标移动到前一个 cell - if (!isCtrl(event) && !event.shiftKey && !event.altKey && event.key === "Backspace" - && range.startOffset === 0 && range.toString() === "") { - const previousCellElement = goPreviousCell(cellElement, range, false); - if (!previousCellElement && tableElement) { - if (tableElement.textContent.trim() === "") { - tableElement.outerHTML = `

    \n

    `; - setRangeByWbr(vditor[vditor.currentMode].element, range); - } else { - range.setStartBefore(tableElement); - range.collapse(true); + // Backspace:光标移动到前一个 cell + if (!isCtrl(event) && !event.shiftKey && !event.altKey && event.key === "Backspace" + && range.startOffset === 0 && range.toString() === "") { + const previousCellElement = goPreviousCell(cellElement, range, false); + if (!previousCellElement && tableElement) { + if (tableElement.textContent.trim() === "") { + tableElement.outerHTML = `

    \n

    `; + setRangeByWbr(vditor[vditor.currentMode].element, range); + } else { + range.setStartBefore(tableElement); + range.collapse(true); + } + execAfterRender(vditor); + } + event.preventDefault(); + return true; + } + // 上方新添加一行 + if (matchHotKey("⇧⌘F", event)) { + insertRowAbove(vditor, range, cellElement); + event.preventDefault(); + return true; } - execAfterRender(vditor); - } - event.preventDefault(); - return true; - } - // 上方新添加一行 - if (matchHotKey("⇧⌘F", event)) { - insertRowAbove(vditor, range, cellElement); - event.preventDefault(); - return true; - } - // 下方新添加一行 https://github.com/Vanessa219/vditor/issues/46 - if (matchHotKey("⌘=", event)) { - insertRow(vditor, range, cellElement); - event.preventDefault(); - return true; - } + // 下方新添加一行 https://github.com/Vanessa219/vditor/issues/46 + if (matchHotKey("⌘=", event)) { + insertRow(vditor, range, cellElement); + event.preventDefault(); + return true; + } - // 左方新添加一列 - if (matchHotKey("⇧⌘G", event)) { - insertColumn(vditor, tableElement, cellElement, "beforebegin"); - event.preventDefault(); - return true; - } + // 左方新添加一列 + if (matchHotKey("⇧⌘G", event)) { + insertColumn(vditor, tableElement, cellElement, "beforebegin"); + event.preventDefault(); + return true; + } - // 后方新添加一列 - if (matchHotKey("⇧⌘=", event)) { - insertColumn(vditor, tableElement, cellElement); - event.preventDefault(); - return true; - } + // 后方新添加一列 + if (matchHotKey("⇧⌘=", event)) { + insertColumn(vditor, tableElement, cellElement); + event.preventDefault(); + return true; + } - // 删除当前行 - if (matchHotKey("⌘-", event)) { - deleteRow(vditor, range, cellElement); - event.preventDefault(); - return true; - } + // 删除当前行 + if (matchHotKey("⌘-", event)) { + deleteRow(vditor, range, cellElement); + event.preventDefault(); + return true; + } - // 删除当前列 - if (matchHotKey("⇧⌘-", event)) { - deleteColumn(vditor, range, tableElement, cellElement); - event.preventDefault(); - return true; - } + // 删除当前列 + if (matchHotKey("⇧⌘-", event)) { + deleteColumn(vditor, range, tableElement, cellElement); + event.preventDefault(); + return true; + } - // 剧左 - if (matchHotKey("⇧⌘L", event)) { - if (vditor.currentMode === "ir") { - setTableAlign(tableElement, "left"); - execAfterRender(vditor); - event.preventDefault(); - return true; - } else { - const itemElement: HTMLElement = vditor.wysiwyg.popover.querySelector('[data-type="left"]'); - if (itemElement) { - itemElement.click(); - event.preventDefault(); - return true; - } - } + // 剧左 + if (matchHotKey("⇧⌘L", event)) { + if (vditor.currentMode === "ir") { + setTableAlign(tableElement, "left"); + execAfterRender(vditor); + event.preventDefault(); + return true; + } else { + const itemElement: HTMLElement = vditor.wysiwyg.popover.querySelector('[data-type="left"]'); + if (itemElement) { + itemElement.click(); + event.preventDefault(); + return true; + } + } + } + + // 剧中 + if (matchHotKey("⇧⌘C", event)) { + if (vditor.currentMode === "ir") { + setTableAlign(tableElement, "center"); + execAfterRender(vditor); + event.preventDefault(); + return true; + } else { + const itemElement: HTMLElement = vditor.wysiwyg.popover.querySelector('[data-type="center"]'); + if (itemElement) { + itemElement.click(); + event.preventDefault(); + return true; + } + } + } + // 剧右 + if (matchHotKey("⇧⌘R", event)) { + if (vditor.currentMode === "ir") { + setTableAlign(tableElement, "right"); + execAfterRender(vditor); + event.preventDefault(); + return true; + } else { + const itemElement: HTMLElement = vditor.wysiwyg.popover.querySelector('[data-type="right"]'); + if (itemElement) { + itemElement.click(); + event.preventDefault(); + return true; + } + } + } } + return false; +}; - // 剧中 - if (matchHotKey("⇧⌘C", event)) { - if (vditor.currentMode === "ir") { - setTableAlign(tableElement, "center"); - execAfterRender(vditor); +export const fixCodeBlock = (vditor: IVditor, event: KeyboardEvent, codeRenderElement: HTMLElement, range: Range) => { + // 行级代码块中 command + a,近对当前代码块进行全选 + if (codeRenderElement.tagName === "PRE" && matchHotKey("⌘A", event)) { + range.selectNodeContents(codeRenderElement.firstElementChild); event.preventDefault(); return true; - } else { - const itemElement: HTMLElement = vditor.wysiwyg.popover.querySelector('[data-type="center"]'); - if (itemElement) { - itemElement.click(); - event.preventDefault(); - return true; - } - } } - // 剧右 - if (matchHotKey("⇧⌘R", event)) { - if (vditor.currentMode === "ir") { - setTableAlign(tableElement, "right"); + + // tab + // TODO shift + tab, shift and 选中文字 + if (vditor.options.tab && event.key === "Tab" && !event.shiftKey && range.toString() === "") { + range.insertNode(document.createTextNode(vditor.options.tab)); + range.collapse(false); execAfterRender(vditor); event.preventDefault(); return true; - } else { - const itemElement: HTMLElement = vditor.wysiwyg.popover.querySelector('[data-type="right"]'); - if (itemElement) { - itemElement.click(); - event.preventDefault(); - return true; - } - } } - } - return false; -}; -export const fixCodeBlock = (vditor: IVditor, event: KeyboardEvent, codeRenderElement: HTMLElement, range: Range) => { - // 行级代码块中 command + a,近对当前代码块进行全选 - if (codeRenderElement.tagName === "PRE" && matchHotKey("⌘A", event)) { - range.selectNodeContents(codeRenderElement.firstElementChild); - event.preventDefault(); - return true; - } - - // tab - // TODO shift + tab, shift and 选中文字 - if (vditor.options.tab && event.key === "Tab" && !event.shiftKey && range.toString() === "") { - range.insertNode(document.createTextNode(vditor.options.tab)); - range.collapse(false); - execAfterRender(vditor); - event.preventDefault(); - return true; - } - - // Backspace: 光标位于第零个字符,仅删除代码块标签 - if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey) { - const codePosition = getSelectPosition(codeRenderElement, vditor[vditor.currentMode].element, range); - if ((codePosition.start === 0 || - (codePosition.start === 1 && codeRenderElement.innerText === "\n")) // 空代码块,光标在 \n 后 - && range.toString() === "") { - codeRenderElement.parentElement.outerHTML = - `

    ${codeRenderElement.firstElementChild.innerHTML}

    `; - setRangeByWbr(vditor[vditor.currentMode].element, range); - execAfterRender(vditor); - event.preventDefault(); - return true; + // Backspace: 光标位于第零个字符,仅删除代码块标签 + if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey) { + const codePosition = getSelectPosition(codeRenderElement, vditor[vditor.currentMode].element, range); + if ((codePosition.start === 0 || + (codePosition.start === 1 && codeRenderElement.innerText === "\n")) // 空代码块,光标在 \n 后 + && range.toString() === "") { + codeRenderElement.parentElement.outerHTML = + `

    ${codeRenderElement.firstElementChild.innerHTML}

    `; + setRangeByWbr(vditor[vditor.currentMode].element, range); + execAfterRender(vditor); + event.preventDefault(); + return true; + } } - } - // 换行 - if (!isCtrl(event) && !event.altKey && event.key === "Enter") { - if (!codeRenderElement.firstElementChild.textContent.endsWith("\n")) { - codeRenderElement.firstElementChild.insertAdjacentText("beforeend", "\n"); - } - range.extractContents(); - range.insertNode(document.createTextNode("\n")); - range.collapse(false); - setSelectionFocus(range); - if (!isFirefox()) { - if (vditor.currentMode === "wysiwyg") { - input(vditor, range); - } else { - IRInput(vditor, range); - } + // 换行 + if (!isCtrl(event) && !event.altKey && event.key === "Enter") { + if (!codeRenderElement.firstElementChild.textContent.endsWith("\n")) { + codeRenderElement.firstElementChild.insertAdjacentText("beforeend", "\n"); + } + range.extractContents(); + range.insertNode(document.createTextNode("\n")); + range.collapse(false); + setSelectionFocus(range); + if (!isFirefox()) { + if (vditor.currentMode === "wysiwyg") { + input(vditor, range); + } else { + IRInput(vditor, range); + } + } + scrollCenter(vditor); + event.preventDefault(); + return true; } - scrollCenter(vditor); - event.preventDefault(); - return true; - } - return false; + return false; }; export const fixBlockquote = (vditor: IVditor, range: Range, event: KeyboardEvent, pElement: HTMLElement | false) => { - const startContainer = range.startContainer; - const blockquoteElement = hasClosestByMatchTag(startContainer, "BLOCKQUOTE"); - if (blockquoteElement && range.toString() === "") { - if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey && - getSelectPosition(blockquoteElement, vditor[vditor.currentMode].element, range).start === 0) { - // Backspace: 光标位于引用中的第零个字符,仅删除引用标签 - range.insertNode(document.createElement("wbr")); - blockquoteElement.outerHTML = blockquoteElement.innerHTML; - setRangeByWbr(vditor[vditor.currentMode].element, range); - execAfterRender(vditor); - event.preventDefault(); - return true; - } + const startContainer = range.startContainer; + const blockquoteElement = hasClosestByMatchTag(startContainer, "BLOCKQUOTE"); + if (blockquoteElement && range.toString() === "") { + if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey && + getSelectPosition(blockquoteElement, vditor[vditor.currentMode].element, range).start === 0) { + // Backspace: 光标位于引用中的第零个字符,仅删除引用标签 + range.insertNode(document.createElement("wbr")); + blockquoteElement.outerHTML = blockquoteElement.innerHTML; + setRangeByWbr(vditor[vditor.currentMode].element, range); + execAfterRender(vditor); + event.preventDefault(); + return true; + } - if (pElement && event.key === "Enter" && !isCtrl(event) && !event.shiftKey && !event.altKey - && pElement.parentElement.tagName === "BLOCKQUOTE") { - // Enter: 空行回车应逐层跳出 - let isEmpty = false; - if (pElement.innerHTML.replace(Constants.ZWSP, "") === "\n" || - pElement.innerHTML.replace(Constants.ZWSP, "") === "") { - // 空 P - isEmpty = true; - pElement.remove(); - } else if (pElement.innerHTML.endsWith("\n\n") && - getSelectPosition(pElement, vditor[vditor.currentMode].element, range).start === - pElement.textContent.length - 1) { - // 软换行 - pElement.innerHTML = pElement.innerHTML.substr(0, pElement.innerHTML.length - 2); - isEmpty = true; - } - if (isEmpty) { - // 需添加零宽字符,否则的话无法记录 undo - blockquoteElement.insertAdjacentHTML("afterend", `

    ${Constants.ZWSP}\n

    `); - setRangeByWbr(vditor[vditor.currentMode].element, range); - execAfterRender(vditor); - event.preventDefault(); - return true; - } - } - const blockElement = hasClosestBlock(startContainer); - if (vditor.currentMode === "wysiwyg" && blockElement && matchHotKey("⇧⌘;", event)) { - // 插入 blockquote - range.insertNode(document.createElement("wbr")); - blockElement.outerHTML = `
    ${blockElement.outerHTML}
    `; - setRangeByWbr(vditor.wysiwyg.element, range); - afterRenderEvent(vditor); - event.preventDefault(); - return true; - } + if (pElement && event.key === "Enter" && !isCtrl(event) && !event.shiftKey && !event.altKey + && pElement.parentElement.tagName === "BLOCKQUOTE") { + // Enter: 空行回车应逐层跳出 + let isEmpty = false; + if (pElement.innerHTML.replace(Constants.ZWSP, "") === "\n" || + pElement.innerHTML.replace(Constants.ZWSP, "") === "") { + // 空 P + isEmpty = true; + pElement.remove(); + } else if (pElement.innerHTML.endsWith("\n\n") && + getSelectPosition(pElement, vditor[vditor.currentMode].element, range).start === + pElement.textContent.length - 1) { + // 软换行 + pElement.innerHTML = pElement.innerHTML.substr(0, pElement.innerHTML.length - 2); + isEmpty = true; + } + if (isEmpty) { + // 需添加零宽字符,否则的话无法记录 undo + blockquoteElement.insertAdjacentHTML("afterend", `

    ${Constants.ZWSP}\n

    `); + setRangeByWbr(vditor[vditor.currentMode].element, range); + execAfterRender(vditor); + event.preventDefault(); + return true; + } + } + const blockElement = hasClosestBlock(startContainer); + if (vditor.currentMode === "wysiwyg" && blockElement && matchHotKey("⇧⌘;", event)) { + // 插入 blockquote + range.insertNode(document.createElement("wbr")); + blockElement.outerHTML = `
    ${blockElement.outerHTML}
    `; + setRangeByWbr(vditor.wysiwyg.element, range); + afterRenderEvent(vditor); + event.preventDefault(); + return true; + } - if (insertAfterBlock(vditor, event, range, blockquoteElement, blockquoteElement)) { - return true; - } - if (insertBeforeBlock(vditor, event, range, blockquoteElement, blockquoteElement)) { - return true; + if (insertAfterBlock(vditor, event, range, blockquoteElement, blockquoteElement)) { + return true; + } + if (insertBeforeBlock(vditor, event, range, blockquoteElement, blockquoteElement)) { + return true; + } } - } - return false; + return false; }; export const fixTask = (vditor: IVditor, range: Range, event: KeyboardEvent) => { - const startContainer = range.startContainer; - const taskItemElement = hasClosestByClassName(startContainer, "vditor-task"); - if (taskItemElement) { - if (matchHotKey("⇧⌘J", event)) { - // ctrl + shift: toggle checked - const inputElement = taskItemElement.firstElementChild as HTMLInputElement; - if (inputElement.checked) { - inputElement.removeAttribute("checked"); - } else { - inputElement.setAttribute("checked", "checked"); - } - execAfterRender(vditor); - event.preventDefault(); - return true; - } - - // Backspace: 在选择框前进行删除 - if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey && range.toString() === "" - && range.startOffset === 1 - && ((startContainer.nodeType === 3 && startContainer.previousSibling && - (startContainer.previousSibling as HTMLElement).tagName === "INPUT") - || startContainer.nodeType !== 3)) { - const previousElement = taskItemElement.previousElementSibling; - taskItemElement.querySelector("input").remove(); - if (previousElement) { - const lastNode = getLastNode(previousElement); - lastNode.parentElement.insertAdjacentHTML("beforeend", "" + taskItemElement.innerHTML.trim()); - taskItemElement.remove(); - } else { - taskItemElement.parentElement.insertAdjacentHTML("beforebegin", - `

    ${taskItemElement.innerHTML.trim() || "\n"}

    `); - if (taskItemElement.nextElementSibling) { - taskItemElement.remove(); - } else { - taskItemElement.parentElement.remove(); + const startContainer = range.startContainer; + const taskItemElement = hasClosestByClassName(startContainer, "vditor-task"); + if (taskItemElement) { + if (matchHotKey("⇧⌘J", event)) { + // ctrl + shift: toggle checked + const inputElement = taskItemElement.firstElementChild as HTMLInputElement; + if (inputElement.checked) { + inputElement.removeAttribute("checked"); + } else { + inputElement.setAttribute("checked", "checked"); + } + execAfterRender(vditor); + event.preventDefault(); + return true; } - } - setRangeByWbr(vditor[vditor.currentMode].element, range); - execAfterRender(vditor); - event.preventDefault(); - return true; - } - if (event.key === "Enter" && !isCtrl(event) && !event.shiftKey && !event.altKey) { - if (taskItemElement.textContent.trim() === "") { - // 当前任务列表无文字 - if (hasClosestByClassName(taskItemElement.parentElement, "vditor-task")) { - // 为子元素时,需进行反向缩进 - const topListElement = getTopList(startContainer); - if (topListElement) { - listOutdent(vditor, taskItemElement, range, topListElement); - } - } else { - // 仅有一级任务列表 - if (taskItemElement.nextElementSibling) { - // 任务列表下方还有元素,需要使用用段落隔断 - let afterHTML = ""; - let beforeHTML = ""; - let isAfter = false; - Array.from(taskItemElement.parentElement.children).forEach((taskItem) => { - if (taskItemElement.isSameNode(taskItem)) { - isAfter = true; - } else { - if (isAfter) { - afterHTML += taskItem.outerHTML; + // Backspace: 在选择框前进行删除 + if (event.key === "Backspace" && !isCtrl(event) && !event.shiftKey && !event.altKey && range.toString() === "" + && range.startOffset === 1 + && ((startContainer.nodeType === 3 && startContainer.previousSibling && + (startContainer.previousSibling as HTMLElement).tagName === "INPUT") + || startContainer.nodeType !== 3)) { + const previousElement = taskItemElement.previousElementSibling; + taskItemElement.querySelector("input").remove(); + if (previousElement) { + const lastNode = getLastNode(previousElement); + lastNode.parentElement.insertAdjacentHTML("beforeend", "" + taskItemElement.innerHTML.trim()); + taskItemElement.remove(); + } else { + taskItemElement.parentElement.insertAdjacentHTML("beforebegin", + `

    ${taskItemElement.innerHTML.trim() || "\n"}

    `); + if (taskItemElement.nextElementSibling) { + taskItemElement.remove(); } else { - beforeHTML += taskItem.outerHTML; + taskItemElement.parentElement.remove(); } - } - }); - const parentTagName = taskItemElement.parentElement.tagName; - const dataMarker = taskItemElement.parentElement.tagName === "OL" ? "" : ` data-marker="${taskItemElement.parentElement.getAttribute("data-marker")}"`; - let startAttribute = ""; - if (beforeHTML) { - startAttribute = taskItemElement.parentElement.tagName === "UL" ? "" : ` start="1"`; - beforeHTML = `<${parentTagName} data-tight="true"${dataMarker} data-block="0">${beforeHTML}`; } - //

    \n

    =>

    \n

    - // https://github.com/Vanessa219/vditor/issues/430 - taskItemElement.parentElement.outerHTML = `${beforeHTML}

    \n

    <${parentTagName} + setRangeByWbr(vditor[vditor.currentMode].element, range); + execAfterRender(vditor); + event.preventDefault(); + return true; + } + + if (event.key === "Enter" && !isCtrl(event) && !event.shiftKey && !event.altKey) { + if (taskItemElement.textContent.trim() === "") { + // 当前任务列表无文字 + if (hasClosestByClassName(taskItemElement.parentElement, "vditor-task")) { + // 为子元素时,需进行反向缩进 + const topListElement = getTopList(startContainer); + if (topListElement) { + listOutdent(vditor, taskItemElement, range, topListElement); + } + } else { + // 仅有一级任务列表 + if (taskItemElement.nextElementSibling) { + // 任务列表下方还有元素,需要使用用段落隔断 + let afterHTML = ""; + let beforeHTML = ""; + let isAfter = false; + Array.from(taskItemElement.parentElement.children).forEach((taskItem) => { + if (taskItemElement.isSameNode(taskItem)) { + isAfter = true; + } else { + if (isAfter) { + afterHTML += taskItem.outerHTML; + } else { + beforeHTML += taskItem.outerHTML; + } + } + }); + const parentTagName = taskItemElement.parentElement.tagName; + const dataMarker = taskItemElement.parentElement.tagName === "OL" ? "" : ` data-marker="${taskItemElement.parentElement.getAttribute("data-marker")}"`; + let startAttribute = ""; + if (beforeHTML) { + startAttribute = taskItemElement.parentElement.tagName === "UL" ? "" : ` start="1"`; + beforeHTML = `<${parentTagName} data-tight="true"${dataMarker} data-block="0">${beforeHTML}`; + } + //

    \n

    =>

    \n

    + // https://github.com/Vanessa219/vditor/issues/430 + taskItemElement.parentElement.outerHTML = `${beforeHTML}

    \n

    <${parentTagName} data-tight="true"${dataMarker} data-block="0"${startAttribute}>${afterHTML}`; - } else { - // 任务列表下方无任务列表元素 - taskItemElement.parentElement.insertAdjacentHTML("afterend", `

    \n

    `); - if (taskItemElement.parentElement.querySelectorAll("li").length === 1) { - // 任务列表仅有一项时,使用 p 元素替换 - taskItemElement.parentElement.remove(); + } else { + // 任务列表下方无任务列表元素 + taskItemElement.parentElement.insertAdjacentHTML("afterend", `

    \n

    `); + if (taskItemElement.parentElement.querySelectorAll("li").length === 1) { + // 任务列表仅有一项时,使用 p 元素替换 + taskItemElement.parentElement.remove(); + } else { + // 任务列表有多项时,当前任务列表位于最后一项,移除该任务列表 + taskItemElement.remove(); + } + } + } + } else if (startContainer.nodeType !== 3 && range.startOffset === 0 && + (startContainer.firstChild as HTMLElement).tagName === "INPUT") { + // 光标位于 input 之前 + range.setStart(startContainer.childNodes[1], 1); } else { - // 任务列表有多项时,当前任务列表位于最后一项,移除该任务列表 - taskItemElement.remove(); + // 当前任务列表有文字,光标后的文字需添加到新任务列表中 + range.setEndAfter(taskItemElement.lastChild); + taskItemElement.insertAdjacentHTML("afterend", `
  • `); + document.querySelector("wbr").after(range.extractContents()); } - } - } - } else if (startContainer.nodeType !== 3 && range.startOffset === 0 && - (startContainer.firstChild as HTMLElement).tagName === "INPUT") { - // 光标位于 input 之前 - range.setStart(startContainer.childNodes[1], 1); - } else { - // 当前任务列表有文字,光标后的文字需添加到新任务列表中 - range.setEndAfter(taskItemElement.lastChild); - taskItemElement.insertAdjacentHTML("afterend", `
  • `); - document.querySelector("wbr").after(range.extractContents()); - } - setRangeByWbr(vditor[vditor.currentMode].element, range); - execAfterRender(vditor); - scrollCenter(vditor); - event.preventDefault(); - return true; + setRangeByWbr(vditor[vditor.currentMode].element, range); + execAfterRender(vditor); + scrollCenter(vditor); + event.preventDefault(); + return true; + } } - } - return false; + return false; }; export const fixDelete = (vditor: IVditor, range: Range, event: KeyboardEvent, pElement: HTMLElement | false) => { - if (range.startContainer.nodeType !== 3) { - // 光标位于 hr 前,hr 前有内容 - const rangeElement = (range.startContainer as HTMLElement).children[range.startOffset]; - if (rangeElement && rangeElement.tagName === "HR") { - range.selectNodeContents(rangeElement.previousElementSibling); - range.collapse(false); - event.preventDefault(); - return true; + if (range.startContainer.nodeType !== 3) { + // 光标位于 hr 前,hr 前有内容 + const rangeElement = (range.startContainer as HTMLElement).children[range.startOffset]; + if (rangeElement && rangeElement.tagName === "HR") { + range.selectNodeContents(rangeElement.previousElementSibling); + range.collapse(false); + event.preventDefault(); + return true; + } } - } - - if (pElement) { - const previousElement = pElement.previousElementSibling; - if (previousElement && getSelectPosition(pElement, vditor[vditor.currentMode].element, range).start === 0 && - ((isFirefox() && previousElement.tagName === "HR") || previousElement.tagName === "TABLE")) { - if (previousElement.tagName === "TABLE") { - // table 后删除 https://github.com/Vanessa219/vditor/issues/243 - const lastCellElement = previousElement.lastElementChild.lastElementChild.lastElementChild; - lastCellElement.innerHTML = - lastCellElement.innerHTML.trimLeft() + "" + pElement.textContent.trim(); - pElement.remove(); - } else { - // 光标位于 hr 后进行删除 - previousElement.remove(); - } - setRangeByWbr(vditor[vditor.currentMode].element, range); - execAfterRender(vditor); - event.preventDefault(); - return true; + + if (pElement) { + const previousElement = pElement.previousElementSibling; + if (previousElement && getSelectPosition(pElement, vditor[vditor.currentMode].element, range).start === 0 && + ((isFirefox() && previousElement.tagName === "HR") || previousElement.tagName === "TABLE")) { + if (previousElement.tagName === "TABLE") { + // table 后删除 https://github.com/Vanessa219/vditor/issues/243 + const lastCellElement = previousElement.lastElementChild.lastElementChild.lastElementChild; + lastCellElement.innerHTML = + lastCellElement.innerHTML.trimLeft() + "" + pElement.textContent.trim(); + pElement.remove(); + } else { + // 光标位于 hr 后进行删除 + previousElement.remove(); + } + setRangeByWbr(vditor[vditor.currentMode].element, range); + execAfterRender(vditor); + event.preventDefault(); + return true; + } } - } - return false; + return false; }; export const fixHR = (range: Range) => { - if (isFirefox() && range.startContainer.nodeType !== 3 && - (range.startContainer as HTMLElement).tagName === "HR") { - range.setStartBefore(range.startContainer); - } + if (isFirefox() && range.startContainer.nodeType !== 3 && + (range.startContainer as HTMLElement).tagName === "HR") { + range.setStartBefore(range.startContainer); + } }; // firefox https://github.com/Vanessa219/vditor/issues/407 export const fixFirefoxArrowUpTable = (event: KeyboardEvent, blockElement: false | HTMLElement, range: Range) => { - if (!isFirefox()) { + if (!isFirefox()) { + return false; + } + if (event.key === "ArrowUp" && blockElement && blockElement.previousElementSibling?.tagName === "TABLE") { + const tableElement = blockElement.previousElementSibling as HTMLTableElement; + range.selectNodeContents(tableElement.rows[tableElement.rows.length - 1].lastElementChild); + range.collapse(false); + event.preventDefault(); + return true; + } + if (event.key === "ArrowDown" && blockElement && blockElement.nextElementSibling?.tagName === "TABLE") { + range.selectNodeContents((blockElement.nextElementSibling as HTMLTableElement).rows[0].cells[0]); + range.collapse(true); + event.preventDefault(); + return true; + } return false; - } - if (event.key === "ArrowUp" && blockElement && blockElement.previousElementSibling?.tagName === "TABLE") { - const tableElement = blockElement.previousElementSibling as HTMLTableElement; - range.selectNodeContents(tableElement.rows[tableElement.rows.length - 1].lastElementChild); - range.collapse(false); - event.preventDefault(); - return true; - } - if (event.key === "ArrowDown" && blockElement && blockElement.nextElementSibling?.tagName === "TABLE") { - range.selectNodeContents((blockElement.nextElementSibling as HTMLTableElement).rows[0].cells[0]); - range.collapse(true); - event.preventDefault(); - return true; - } - return false; }; export const paste = async (vditor: IVditor, event: (ClipboardEvent | DragEvent) & { target: HTMLElement }, callback: { - pasteCode(code: string): void, + pasteCode(code: string): void, }) => { - if (vditor[vditor.currentMode].element.getAttribute("contenteditable") !== "true") { - return; - } - event.stopPropagation(); - event.preventDefault(); - let textHTML; - let textPlain; - let files; - - if ("clipboardData" in event) { - textHTML = event.clipboardData.getData("text/html"); - textPlain = event.clipboardData.getData("text/plain"); - files = event.clipboardData.files; - } else { - textHTML = event.dataTransfer.getData("text/html"); - textPlain = event.dataTransfer.getData("text/plain"); - if (event.dataTransfer.types.includes("Files")) { - files = event.dataTransfer.items; + if (vditor[vditor.currentMode].element.getAttribute("contenteditable") !== "true") { + return; } - } - const renderers: { - HTML2VditorDOM?: ILuteRender, - HTML2VditorIRDOM?: ILuteRender, - Md2VditorDOM?: ILuteRender, - Md2VditorIRDOM?: ILuteRender, - Md2VditorSVDOM?: ILuteRender, - } = {}; - const renderLinkDest: ILuteRenderCallback = (node, entering) => { - if (!entering) { - return ["", Lute.WalkContinue]; + event.stopPropagation(); + event.preventDefault(); + let textHTML; + let textPlain; + let files; + + if ("clipboardData" in event) { + textHTML = event.clipboardData.getData("text/html"); + textPlain = event.clipboardData.getData("text/plain"); + files = event.clipboardData.files; + } else { + textHTML = event.dataTransfer.getData("text/html"); + textPlain = event.dataTransfer.getData("text/plain"); + if (event.dataTransfer.types.includes("Files")) { + files = event.dataTransfer.items; + } } + const renderers: { + HTML2VditorDOM?: ILuteRender, + HTML2VditorIRDOM?: ILuteRender, + Md2VditorDOM?: ILuteRender, + Md2VditorIRDOM?: ILuteRender, + Md2VditorSVDOM?: ILuteRender, + } = {}; + const renderLinkDest: ILuteRenderCallback = (node, entering) => { + if (!entering) { + return ["", Lute.WalkContinue]; + } - const src = node.TokensStr(); - if (node.__internal_object__.Parent.Type === 34 && src && src.indexOf("file://") === -1 && - vditor.options.upload.linkToImgUrl) { - const xhr = new XMLHttpRequest(); - xhr.open("POST", vditor.options.upload.linkToImgUrl); - if (vditor.options.upload.token) { - xhr.setRequestHeader("X-Upload-Token", vditor.options.upload.token); - } - if (vditor.options.upload.withCredentials) { - xhr.withCredentials = true; - } - setHeaders(vditor, xhr); - xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8"); - xhr.onreadystatechange = () => { - if (xhr.readyState === XMLHttpRequest.DONE) { - if (xhr.status === 200) { - let responseText = xhr.responseText; - if (vditor.options.upload.linkToImgFormat) { - responseText = vditor.options.upload.linkToImgFormat(xhr.responseText); + const src = node.TokensStr(); + if (node.__internal_object__.Parent.Type === 34 && src && src.indexOf("file://") === -1 && + vditor.options.upload.linkToImgUrl) { + const xhr = new XMLHttpRequest(); + xhr.open("POST", vditor.options.upload.linkToImgUrl); + if (vditor.options.upload.token) { + xhr.setRequestHeader("X-Upload-Token", vditor.options.upload.token); } - const responseJSON = JSON.parse(responseText); - if (responseJSON.code !== 0) { - vditor.tip.show(responseJSON.msg); - return; + if (vditor.options.upload.withCredentials) { + xhr.withCredentials = true; } - const original = responseJSON.data.originalURL; - if (vditor.currentMode === "sv") { - vditor.sv.element.querySelectorAll(".vditor-sv__marker--link") - .forEach((item: HTMLElement) => { - if (item.textContent === original) { - item.textContent = responseJSON.data.url; - } - }); - } else { - const imgElement: HTMLImageElement = - vditor[vditor.currentMode].element.querySelector(`img[src="${original}"]`); - imgElement.src = responseJSON.data.url; - if (vditor.currentMode === "ir") { - imgElement.previousElementSibling.previousElementSibling.innerHTML = - responseJSON.data.url; - } + setHeaders(vditor, xhr); + xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8"); + xhr.onreadystatechange = () => { + if (xhr.readyState === XMLHttpRequest.DONE) { + if (xhr.status === 200) { + let responseText = xhr.responseText; + if (vditor.options.upload.linkToImgFormat) { + responseText = vditor.options.upload.linkToImgFormat(xhr.responseText); + } + const responseJSON = JSON.parse(responseText); + if (responseJSON.code !== 0) { + vditor.tip.show(responseJSON.msg); + return; + } + const original = responseJSON.data.originalURL; + if (vditor.currentMode === "sv") { + vditor.sv.element.querySelectorAll(".vditor-sv__marker--link") + .forEach((item: HTMLElement) => { + if (item.textContent === original) { + item.textContent = responseJSON.data.url; + } + }); + } else { + const imgElement: HTMLImageElement = + vditor[vditor.currentMode].element.querySelector(`img[src="${original}"]`); + imgElement.src = responseJSON.data.url; + if (vditor.currentMode === "ir") { + imgElement.previousElementSibling.previousElementSibling.innerHTML = + responseJSON.data.url; + } + } + execAfterRender(vditor); + } else { + vditor.tip.show(xhr.responseText); + } + if (vditor.options.upload.linkToImgCallback) { + vditor.options.upload.linkToImgCallback(xhr.responseText); + } + } + }; + xhr.send(JSON.stringify({url: src})); + } + if (vditor.currentMode === "ir") { + return [`${src}`, Lute.WalkContinue]; + } else if (vditor.currentMode === "wysiwyg") { + return ["", Lute.WalkContinue]; + } else { + return [`${src}`, Lute.WalkContinue]; + } + }; + + // 浏览器地址栏拷贝处理 + if (textHTML.replace(/&/g, "&").replace(/<(|\/)(html|body|meta)[^>]*?>/ig, "").trim() === + `${textPlain}` || + textHTML.replace(/&/g, "&").replace(/<(|\/)(html|body|meta)[^>]*?>/ig, "").trim() === + `${textPlain}`) { + textHTML = ""; + } + + // process word + const doc = new DOMParser().parseFromString(textHTML, "text/html"); + if (doc.body) { + textHTML = doc.body.innerHTML; + } + textHTML = Lute.Sanitize(textHTML); + vditor.wysiwyg.getComments(vditor); + + // process code + const height = vditor[vditor.currentMode].element.scrollHeight; + const code = processPasteCode(textHTML, textPlain, vditor.currentMode); + const codeElement = vditor.currentMode === "sv" ? + hasClosestByAttribute(event.target, "data-type", "code-block") : + hasClosestByMatchTag(event.target, "CODE"); + if (codeElement) { + // 粘贴在代码位置 + if (vditor.currentMode === "sv") { + document.execCommand("insertHTML", false, textPlain.replace(/&/g, "&").replace(/${src}`, Lute.WalkContinue]; - } else if (vditor.currentMode === "wysiwyg") { - return ["", Lute.WalkContinue]; - } else { - return [`${src}`, Lute.WalkContinue]; - } - }; - - // 浏览器地址栏拷贝处理 - if (textHTML.replace(/&/g, "&").replace(/<(|\/)(html|body|meta)[^>]*?>/ig, "").trim() === - `${textPlain}` || - textHTML.replace(/&/g, "&").replace(/<(|\/)(html|body|meta)[^>]*?>/ig, "").trim() === - `${textPlain}`) { - textHTML = ""; - } - - // process word - const doc = new DOMParser().parseFromString(textHTML, "text/html"); - if (doc.body) { - textHTML = doc.body.innerHTML; - } - textHTML = Lute.Sanitize(textHTML); - vditor.wysiwyg.getComments(vditor); - - // process code - const height = vditor[vditor.currentMode].element.scrollHeight; - const code = processPasteCode(textHTML, textPlain, vditor.currentMode); - const codeElement = vditor.currentMode === "sv" ? - hasClosestByAttribute(event.target, "data-type", "code-block") : - hasClosestByMatchTag(event.target, "CODE"); - if (codeElement) { - // 粘贴在代码位置 - if (vditor.currentMode === "sv") { - document.execCommand("insertHTML", false, textPlain.replace(/&/g, "&").replace(/ { + e.removeAttribute("style"); + }); + tempElement.querySelectorAll(".vditor-copy").forEach((e) => { + e.remove(); + }); + if (vditor.currentMode === "ir") { + renderers.HTML2VditorIRDOM = {renderLinkDest}; + vditor.lute.SetJSRenderers({renderers}); + insertHTML(vditor.lute.HTML2VditorIRDOM(tempElement.innerHTML), vditor); + } else if (vditor.currentMode === "wysiwyg") { + renderers.HTML2VditorDOM = {renderLinkDest}; + vditor.lute.SetJSRenderers({renderers}); + insertHTML(vditor.lute.HTML2VditorDOM(tempElement.innerHTML), vditor); + } else { + renderers.Md2VditorSVDOM = {renderLinkDest}; + vditor.lute.SetJSRenderers({renderers}); + processPaste(vditor, vditor.lute.HTML2Md(tempElement.innerHTML).trimRight()); + } + vditor.outline.render(vditor); + } else if (files.length > 0) { + if (vditor.options.upload.url || vditor.options.upload.handler) { + await uploadFiles(vditor, files); + } else { + const fileReader = new FileReader(); + let file: File; + if ("clipboardData" in event) { + files = event.clipboardData.files; + file = files[0]; + } else if (event.dataTransfer.types.includes("Files")) { + files = event.dataTransfer.items; + file = files[0].getAsFile(); + } + if (file && file.type.startsWith("image")) { + fileReader.readAsDataURL(file); + fileReader.onload = () => { + let imgHTML = '' + if (vditor.currentMode === "wysiwyg") { + imgHTML += `${file.name}\n`; + } else { + imgHTML += `![${file.name}](${fileReader.result.toString()})\n`; + } + document.execCommand("insertHTML", false, imgHTML); + } + } + } + } else if (textPlain.trim() !== "" && files.length === 0) { + if (vditor.currentMode === "ir") { + renderers.Md2VditorIRDOM = {renderLinkDest}; + vditor.lute.SetJSRenderers({renderers}); + insertHTML(vditor.lute.Md2VditorIRDOM(textPlain), vditor); + } else if (vditor.currentMode === "wysiwyg") { + renderers.Md2VditorDOM = {renderLinkDest}; + vditor.lute.SetJSRenderers({renderers}); + insertHTML(vditor.lute.Md2VditorDOM(textPlain), vditor); + } else { + renderers.Md2VditorSVDOM = {renderLinkDest}; + vditor.lute.SetJSRenderers({renderers}); + processPaste(vditor, textPlain); + } + vditor.outline.render(vditor); + } } - } else if (code) { - callback.pasteCode(code); - } else { - if (textHTML.trim() !== "") { - const tempElement = document.createElement("div"); - tempElement.innerHTML = textHTML; - tempElement.querySelectorAll("[style]").forEach((e) => { - e.removeAttribute("style"); - }); - tempElement.querySelectorAll(".vditor-copy").forEach((e) => { - e.remove(); - }); - if (vditor.currentMode === "ir") { - renderers.HTML2VditorIRDOM = {renderLinkDest}; - vditor.lute.SetJSRenderers({renderers}); - insertHTML(vditor.lute.HTML2VditorIRDOM(tempElement.innerHTML), vditor); - } else if (vditor.currentMode === "wysiwyg") { - renderers.HTML2VditorDOM = {renderLinkDest}; - vditor.lute.SetJSRenderers({renderers}); - insertHTML(vditor.lute.HTML2VditorDOM(tempElement.innerHTML), vditor); - } else { - renderers.Md2VditorSVDOM = {renderLinkDest}; - vditor.lute.SetJSRenderers({renderers}); - processPaste(vditor, vditor.lute.HTML2Md(tempElement.innerHTML).trimRight()); - } - vditor.outline.render(vditor); - } else if (files.length > 0 && (vditor.options.upload.url || vditor.options.upload.handler)) { - await uploadFiles(vditor, files); - } else if (files.length > 0 && (!vditor.options.upload.url || !vditor.options.upload.handler)) { - var fileReader = new FileReader(); - var file: File; - if ("clipboardData" in event) { - files = event.clipboardData.files; - file = files[0]; - } else { - if (event.dataTransfer.types.includes("Files")) { - files = event.dataTransfer.items; - file = files[0].getAsFile(); - } - } - fileReader.readAsDataURL(file); - fileReader.onload = function() { - // Get the base64 format content of target file. - var result = fileReader.result; - //console.log("This is an image.", result); - // Image in Markdown:![title or file name](dataurl) - // Put it in a newline. - var png = "\r![" + file.name + "](" + result.toString() + ")\r"; - insertHTML(vditor.lute.Md2VditorIRDOM(png), vditor); - } - } else if (textPlain.trim() !== "" && files.length === 0) { - if (vditor.currentMode === "ir") { - renderers.Md2VditorIRDOM = {renderLinkDest}; - vditor.lute.SetJSRenderers({renderers}); - insertHTML(vditor.lute.Md2VditorIRDOM(textPlain), vditor); - } else if (vditor.currentMode === "wysiwyg") { - renderers.Md2VditorDOM = {renderLinkDest}; - vditor.lute.SetJSRenderers({renderers}); - insertHTML(vditor.lute.Md2VditorDOM(textPlain), vditor); - } else { - renderers.Md2VditorSVDOM = {renderLinkDest}; - vditor.lute.SetJSRenderers({renderers}); - processPaste(vditor, textPlain); - } - vditor.outline.render(vditor); + if (vditor.currentMode !== "sv") { + const blockElement = hasClosestBlock(getEditorRange(vditor).startContainer); + if (blockElement) { + // https://github.com/Vanessa219/vditor/issues/591 + const range = getEditorRange(vditor); + vditor[vditor.currentMode].element.querySelectorAll("wbr").forEach((wbr) => { + wbr.remove(); + }); + range.insertNode(document.createElement("wbr")); + if (vditor.currentMode === "wysiwyg") { + blockElement.outerHTML = vditor.lute.SpinVditorDOM(blockElement.outerHTML); + } else { + blockElement.outerHTML = vditor.lute.SpinVditorIRDOM(blockElement.outerHTML); + } + setRangeByWbr(vditor[vditor.currentMode].element, range); + } + vditor[vditor.currentMode].element.querySelectorAll(`.vditor-${vditor.currentMode}__preview[data-render='2']`) + .forEach((item: HTMLElement) => { + processCodeRender(item, vditor); + }); } - } - if (vditor.currentMode !== "sv") { - const blockElement = hasClosestBlock(getEditorRange(vditor).startContainer); - if (blockElement) { - // https://github.com/Vanessa219/vditor/issues/591 - const range = getEditorRange(vditor); - vditor[vditor.currentMode].element.querySelectorAll("wbr").forEach((wbr) => { - wbr.remove(); - }); - range.insertNode(document.createElement("wbr")); - if (vditor.currentMode === "wysiwyg") { - blockElement.outerHTML = vditor.lute.SpinVditorDOM(blockElement.outerHTML); - } else { - blockElement.outerHTML = vditor.lute.SpinVditorIRDOM(blockElement.outerHTML); - } - setRangeByWbr(vditor[vditor.currentMode].element, range); + vditor.wysiwyg.triggerRemoveComment(vditor); + execAfterRender(vditor); + if (vditor[vditor.currentMode].element.scrollHeight - height > + Math.min(vditor[vditor.currentMode].element.clientHeight, window.innerHeight) / 2) { + scrollCenter(vditor); } - vditor[vditor.currentMode].element.querySelectorAll(`.vditor-${vditor.currentMode}__preview[data-render='2']`) - .forEach((item: HTMLElement) => { - processCodeRender(item, vditor); - }); - } - vditor.wysiwyg.triggerRemoveComment(vditor); - execAfterRender(vditor); - if (vditor[vditor.currentMode].element.scrollHeight - height > - Math.min(vditor[vditor.currentMode].element.clientHeight, window.innerHeight) / 2) { - scrollCenter(vditor); - } };