UNPKG

vditor

Version:

♏ 易于使用的 Markdown 编辑器,为适配不同的应用场景而生

247 lines (219 loc) 10.1 kB
import {Constants} from "../constants"; import {isHeadingMD, isHrMD} from "../util/fixBrowserBehavior"; import { getTopList, hasClosestBlock, hasClosestByAttribute, hasClosestByClassName, } from "../util/hasClosest"; import {hasClosestByTag} from "../util/hasClosestByHeadings"; import {log} from "../util/log"; import {processCodeRender} from "../util/processCode"; import {getSelectPosition, setRangeByWbr} from "../util/selection"; import {renderToc} from "../util/toc"; import {processAfterRender} from "./process"; import {getMarkdown} from "../markdown/getMarkdown"; export const input = (vditor: IVditor, range: Range, ignoreSpace = false, event?: InputEvent) => { let blockElement = hasClosestBlock(range.startContainer); // 前后可以输入空格 if (blockElement && !ignoreSpace && blockElement.getAttribute("data-type") !== "code-block") { if ((isHrMD(blockElement.innerHTML) && blockElement.previousElementSibling) || isHeadingMD(blockElement.innerHTML)) { return; } // 前后空格处理 const startOffset = getSelectPosition(blockElement, vditor.ir.element, range).start; // 开始可以输入空格 let startSpace = true; for (let i = startOffset - 1; // 软换行后有空格 i > blockElement.textContent.substr(0, startOffset).lastIndexOf("\n"); i--) { if (blockElement.textContent.charAt(i) !== " " && // 多个 tab 前删除不形成代码块 https://github.com/Vanessa219/vditor/issues/162 1 blockElement.textContent.charAt(i) !== "\t") { startSpace = false; break; } } if (startOffset === 0) { startSpace = false; } // 结尾可以输入空格 let endSpace = true; for (let i = startOffset - 1; i < blockElement.textContent.length; i++) { if (blockElement.textContent.charAt(i) !== " " && blockElement.textContent.charAt(i) !== "\n") { endSpace = false; break; } } if (startSpace) { if (typeof vditor.options.input === "function") { vditor.options.input(getMarkdown(vditor)); } return; } // https://github.com/Vanessa219/vditor/issues/729 if (endSpace && /^#{1,6} $/.test(blockElement.textContent)) { endSpace = false; } if (endSpace) { const markerElement = hasClosestByClassName(range.startContainer, "vditor-ir__marker"); if (markerElement) { // inline marker space https://github.com/Vanessa219/vditor/issues/239 } else { const previousNode = range.startContainer.previousSibling as HTMLElement; if (previousNode && previousNode.nodeType !== 3 && previousNode.classList.contains("vditor-ir__node--expand")) { // FireFox https://github.com/Vanessa219/vditor/issues/239 previousNode.classList.remove("vditor-ir__node--expand"); } if (typeof vditor.options.input === "function") { vditor.options.input(getMarkdown(vditor)); } return; } } } vditor.ir.element.querySelectorAll(".vditor-ir__node--expand").forEach((item) => { item.classList.remove("vditor-ir__node--expand"); }); if (!blockElement) { // 使用顶级块元素,应使用 innerHTML blockElement = vditor.ir.element; } // document.exeComment insertHTML 会插入 wbr if (!blockElement.querySelector("wbr")) { const previewRenderElement = hasClosestByClassName(range.startContainer, "vditor-ir__preview"); if (previewRenderElement) { previewRenderElement.previousElementSibling.insertAdjacentHTML("beforeend", "<wbr>"); } else { range.insertNode(document.createElement("wbr")); } } // 清除浏览器自带的样式 blockElement.querySelectorAll("[style]").forEach((item) => { item.removeAttribute("style"); }); if (blockElement.getAttribute("data-type") === "link-ref-defs-block") { // 修改链接引用 blockElement = vditor.ir.element; } const isIRElement = blockElement.isEqualNode(vditor.ir.element); const footnoteElement = hasClosestByAttribute(blockElement, "data-type", "footnotes-block"); let html = ""; if (!isIRElement) { const blockquoteElement = hasClosestByTag(range.startContainer, "BLOCKQUOTE"); // 列表需要到最顶层 const topListElement = getTopList(range.startContainer); if (topListElement) { blockElement = topListElement; } // 应到引用层,否则 > --- 会解析为 front-matter;列表中有 blockquote 则解析 blockquote;blockquote 中有列表则解析列表 if (blockquoteElement && (!topListElement || (topListElement && !blockquoteElement.contains(topListElement)))) { blockElement = blockquoteElement; } // 修改脚注 if (footnoteElement) { blockElement = footnoteElement; } html = blockElement.outerHTML; if (blockElement.tagName === "UL" || blockElement.tagName === "OL") { // 如果为列表的话,需要把上下的列表都重绘 const listPrevElement = blockElement.previousElementSibling; const listNextElement = blockElement.nextElementSibling; if (listPrevElement && (listPrevElement.tagName === "UL" || listPrevElement.tagName === "OL")) { html = listPrevElement.outerHTML + html; listPrevElement.remove(); } if (listNextElement && (listNextElement.tagName === "UL" || listNextElement.tagName === "OL")) { html = html + listNextElement.outerHTML; listNextElement.remove(); } // firefox 列表回车不会产生新的 list item https://github.com/Vanessa219/vditor/issues/194 html = html.replace("<div><wbr><br></div>", "<li><p><wbr><br></p></li>"); } else if (blockElement.previousElementSibling && blockElement.previousElementSibling.textContent.replace(Constants.ZWSP, "") !== "" && event && event.inputType === "insertParagraph") { // 换行时需要处理上一段落 html = blockElement.previousElementSibling.outerHTML + html; blockElement.previousElementSibling.remove(); } if (!blockElement.innerText.startsWith("```")) { // 添加链接引用 vditor.ir.element.querySelectorAll("[data-type='link-ref-defs-block']").forEach((item) => { if (item && !(blockElement as HTMLElement).isEqualNode(item)) { html += item.outerHTML; item.remove(); } }); // 添加脚注 vditor.ir.element.querySelectorAll("[data-type='footnotes-block']").forEach((item) => { if (item && !(blockElement as HTMLElement).isEqualNode(item)) { html += item.outerHTML; item.remove(); } }); } } else { html = blockElement.innerHTML; } log("SpinVditorIRDOM", html, "argument", vditor.options.debugger); html = vditor.lute.SpinVditorIRDOM(html); log("SpinVditorIRDOM", html, "result", vditor.options.debugger); if (isIRElement) { blockElement.innerHTML = html; } else { blockElement.outerHTML = html; // 更新正文中的 tip if (footnoteElement) { const footnoteItemElement = hasClosestByAttribute(vditor.ir.element.querySelector("wbr"), "data-type", "footnotes-def"); if (footnoteItemElement) { const footnoteItemText = footnoteItemElement.textContent; const marker = footnoteItemText.substring(1, footnoteItemText.indexOf("]:")); const footnoteRefElement = vditor.ir.element.querySelector(`sup[data-type="footnotes-ref"][data-footnotes-label="${marker}"]`); if (footnoteRefElement) { footnoteRefElement.setAttribute("aria-label", footnoteItemText.substr(marker.length + 3).trim().substr(0, 24)); } } } } // linkref 合并及添加 let firstLinkRefDefElement: HTMLElement; const allLinkRefDefsElement = vditor.ir.element.querySelectorAll("[data-type='link-ref-defs-block']"); allLinkRefDefsElement.forEach((item: HTMLElement, index) => { if (index === 0) { firstLinkRefDefElement = item; } else { firstLinkRefDefElement.insertAdjacentHTML("beforeend", item.innerHTML); item.remove(); } }); if (allLinkRefDefsElement.length > 0) { vditor.ir.element.insertAdjacentElement("beforeend", allLinkRefDefsElement[0]); } // 脚注合并后添加的末尾 let firstFootnoteElement: HTMLElement; const allFootnoteElement = vditor.ir.element.querySelectorAll("[data-type='footnotes-block']"); allFootnoteElement.forEach((item: HTMLElement, index) => { if (index === 0) { firstFootnoteElement = item; } else { firstFootnoteElement.insertAdjacentHTML("beforeend", item.innerHTML); item.remove(); } }); if (allFootnoteElement.length > 0) { vditor.ir.element.insertAdjacentElement("beforeend", allFootnoteElement[0]); } setRangeByWbr(vditor.ir.element, range); vditor.ir.element.querySelectorAll(".vditor-ir__preview[data-render='2']").forEach((item: HTMLElement) => { processCodeRender(item, vditor); }); renderToc(vditor); processAfterRender(vditor, { enableAddUndoStack: true, enableHint: true, enableInput: true, }); };