import {Constants} from "../constants"; import {i18n} from "../i18n"; import {disableToolbar} from "../toolbar/setToolbar"; import {enableToolbar} from "../toolbar/setToolbar"; import {removeCurrentToolbar} from "../toolbar/setToolbar"; import {setCurrentToolbar} from "../toolbar/setToolbar"; import {isCtrl, updateHotkeyTip} from "../util/compatibility"; // import {scrollCenter} from "../util/editorCommonEvent"; import { deleteColumn, deleteRow, insertColumn, insertRow, insertRowAbove, setTableAlign, } from "../util/fixBrowserBehavior"; import { hasClosestByAttribute, hasClosestByClassName, hasClosestByMatchTag, } from "../util/hasClosest"; import {hasClosestByHeadings, hasClosestByTag} from "../util/hasClosestByHeadings"; import {processCodeRender} from "../util/processCode"; // import { getEditorRange, selectIsEditor, setRangeByWbr, setSelectionFocus } from "../util/selection"; import {getEditorRange, selectIsEditor, setSelectionFocus} from "../util/selection"; import {afterRenderEvent} from "./afterRenderEvent"; import {removeBlockElement} from "./processKeydown"; export const highlightToolbarWYSIWYG = (vditor: IVditor) => { clearTimeout(vditor.wysiwyg.hlToolbarTimeoutId); vditor.wysiwyg.hlToolbarTimeoutId = window.setTimeout(() => { if (vditor.wysiwyg.element.getAttribute("contenteditable") === "false") { return; } if (!selectIsEditor(vditor.wysiwyg.element)) { return; } removeCurrentToolbar(vditor.toolbar.elements, Constants.EDIT_TOOLBARS); enableToolbar(vditor.toolbar.elements, Constants.EDIT_TOOLBARS); const range = getSelection().getRangeAt(0); let typeElement = range.startContainer as HTMLElement; if (range.startContainer.nodeType === 3) { typeElement = range.startContainer.parentElement; } else { typeElement = typeElement.childNodes[range.startOffset >= typeElement.childNodes.length ? typeElement.childNodes.length - 1 : range.startOffset] as HTMLElement; } const footnotesElement = hasClosestByAttribute(typeElement, "data-type", "footnotes-block"); if (footnotesElement) { vditor.wysiwyg.popover.innerHTML = ""; genClose(footnotesElement, vditor); setPopoverPosition(vditor, footnotesElement); return; } // 工具栏高亮和禁用 const liElement = hasClosestByMatchTag(typeElement, "LI"); if (liElement) { if (liElement.classList.contains("vditor-task")) { setCurrentToolbar(vditor.toolbar.elements, ["check"]); } else if (liElement.parentElement.tagName === "OL") { setCurrentToolbar(vditor.toolbar.elements, ["ordered-list"]); } else if (liElement.parentElement.tagName === "UL") { setCurrentToolbar(vditor.toolbar.elements, ["list"]); } enableToolbar(vditor.toolbar.elements, ["outdent", "indent"]); } else { disableToolbar(vditor.toolbar.elements, ["outdent", "indent"]); } if (hasClosestByMatchTag(typeElement, "BLOCKQUOTE")) { setCurrentToolbar(vditor.toolbar.elements, ["quote"]); } if (hasClosestByMatchTag(typeElement, "B") || hasClosestByMatchTag(typeElement, "STRONG")) { setCurrentToolbar(vditor.toolbar.elements, ["bold"]); } if (hasClosestByMatchTag(typeElement, "I") || hasClosestByMatchTag(typeElement, "EM")) { setCurrentToolbar(vditor.toolbar.elements, ["italic"]); } if (hasClosestByMatchTag(typeElement, "STRIKE") || hasClosestByMatchTag(typeElement, "S")) { setCurrentToolbar(vditor.toolbar.elements, ["strike"]); } // comments vditor.wysiwyg.element.querySelectorAll(".vditor-comment--focus").forEach((item) => { item.classList.remove("vditor-comment--focus"); }); const commentElement = hasClosestByClassName(typeElement, "vditor-comment"); if (commentElement) { let ids = commentElement.getAttribute("data-cmtids").split(" "); if (ids.length > 1 && commentElement.nextSibling.isSameNode(commentElement.nextElementSibling)) { const nextIds = commentElement.nextElementSibling.getAttribute("data-cmtids").split(" "); ids.find((id) => { if (nextIds.includes(id)) { ids = [id]; return true; } }); } vditor.wysiwyg.element.querySelectorAll(".vditor-comment").forEach((item) => { if (item.getAttribute("data-cmtids").indexOf(ids[0]) > -1) { item.classList.add("vditor-comment--focus"); } }); } const aElement = hasClosestByMatchTag(typeElement, "A"); if (aElement) { setCurrentToolbar(vditor.toolbar.elements, ["link"]); } const tableElement = hasClosestByMatchTag(typeElement, "TABLE") as HTMLTableElement; const headingElement = hasClosestByHeadings(typeElement) as HTMLElement; if (hasClosestByMatchTag(typeElement, "CODE")) { if (hasClosestByMatchTag(typeElement, "PRE")) { disableToolbar(vditor.toolbar.elements, ["headings", "bold", "italic", "strike", "line", "quote", "list", "ordered-list", "check", "code", "inline-code", "upload", "link", "table", "record"]); setCurrentToolbar(vditor.toolbar.elements, ["code"]); } else { disableToolbar(vditor.toolbar.elements, ["headings", "bold", "italic", "strike", "line", "quote", "list", "ordered-list", "check", "code", "upload", "link", "table", "record"]); setCurrentToolbar(vditor.toolbar.elements, ["inline-code"]); } } else if (headingElement) { disableToolbar(vditor.toolbar.elements, ["bold"]); setCurrentToolbar(vditor.toolbar.elements, ["headings"]); } else if (tableElement) { disableToolbar(vditor.toolbar.elements, ["table"]); } // toc popover const tocElement = hasClosestByClassName(typeElement, "vditor-toc") as HTMLElement; if (tocElement) { vditor.wysiwyg.popover.innerHTML = ""; genClose(tocElement, vditor); setPopoverPosition(vditor, tocElement); return; } // quote popover const blockquoteElement = hasClosestByTag(typeElement, "BLOCKQUOTE") as HTMLTableElement; if (blockquoteElement) { vditor.wysiwyg.popover.innerHTML = ""; genUp(range, blockquoteElement, vditor); genDown(range, blockquoteElement, vditor); genClose(blockquoteElement, vditor); setPopoverPosition(vditor, blockquoteElement); } // list item popover if (liElement) { vditor.wysiwyg.popover.innerHTML = ""; genUp(range, liElement, vditor); genDown(range, liElement, vditor); genClose(liElement, vditor); setPopoverPosition(vditor, liElement); } // table popover if (tableElement) { vditor.wysiwyg.popover.innerHTML = ""; const updateTable = () => { const oldRow = tableElement.rows.length; const oldColumn = tableElement.rows[0].cells.length; const row = parseInt(input.value, 10) || oldRow; const column = parseInt(input2.value, 10) || oldColumn; if (row === oldRow && oldColumn === column) { return; } if (oldColumn !== column) { const columnDiff = column - oldColumn; for (let i = 0; i < tableElement.rows.length; i++) { if (columnDiff > 0) { for (let j = 0; j < columnDiff; j++) { if (i === 0) { tableElement.rows[i].lastElementChild.insertAdjacentHTML("afterend", " "); } else { tableElement.rows[i].lastElementChild.insertAdjacentHTML("afterend", " "); } } } else { for (let k = oldColumn - 1; k >= column; k--) { tableElement.rows[i].cells[k].remove(); } } } } if (oldRow !== row) { const rowDiff = row - oldRow; if (rowDiff > 0) { let rowHTML = ""; for (let m = 0; m < column; m++) { rowHTML += " "; } for (let l = 0; l < rowDiff; l++) { if (tableElement.querySelector("tbody")) { tableElement.querySelector("tbody").insertAdjacentHTML("beforeend", rowHTML); } else { tableElement.querySelector("thead").insertAdjacentHTML("afterend", rowHTML + ""); } } } else { for (let m = oldRow - 1; m >= row; m--) { tableElement.rows[m].remove(); if (tableElement.rows.length === 1) { tableElement.querySelector("tbody").remove(); } } } } }; const setAlign = (type: string) => { setTableAlign(tableElement, type); if (type === "right") { left.classList.remove("vditor-icon--current"); center.classList.remove("vditor-icon--current"); right.classList.add("vditor-icon--current"); } else if (type === "center") { left.classList.remove("vditor-icon--current"); right.classList.remove("vditor-icon--current"); center.classList.add("vditor-icon--current"); } else { center.classList.remove("vditor-icon--current"); right.classList.remove("vditor-icon--current"); left.classList.add("vditor-icon--current"); } setSelectionFocus(range); afterRenderEvent(vditor); }; const td = hasClosestByMatchTag(typeElement, "TD"); const th = hasClosestByMatchTag(typeElement, "TH"); let alignType = "left"; if (td) { alignType = td.getAttribute("align") || "left"; } else if (th) { alignType = th.getAttribute("align") || "center"; } const left = document.createElement("button"); left.setAttribute("type", "button"); left.setAttribute("aria-label", i18n[vditor.options.lang].alignLeft + "<" + updateHotkeyTip("⇧⌘L") + ">"); left.setAttribute("data-type", "left"); left.innerHTML = ''; left.className = "vditor-icon vditor-tooltipped vditor-tooltipped__n" + (alignType === "left" ? " vditor-icon--current" : ""); left.onclick = () => { setAlign("left"); }; const center = document.createElement("button"); center.setAttribute("type", "button"); center.setAttribute("aria-label", i18n[vditor.options.lang].alignCenter + "<" + updateHotkeyTip("⇧⌘C") + ">"); center.setAttribute("data-type", "center"); center.innerHTML = ''; center.className = "vditor-icon vditor-tooltipped vditor-tooltipped__n" + (alignType === "center" ? " vditor-icon--current" : ""); center.onclick = () => { setAlign("center"); }; const right = document.createElement("button"); right.setAttribute("type", "button"); right.setAttribute("aria-label", i18n[vditor.options.lang].alignRight + "<" + updateHotkeyTip("⇧⌘R") + ">"); right.setAttribute("data-type", "right"); right.innerHTML = ''; right.className = "vditor-icon vditor-tooltipped vditor-tooltipped__n" + (alignType === "right" ? " vditor-icon--current" : ""); right.onclick = () => { setAlign("right"); }; const insertRowElement = document.createElement("button"); insertRowElement.setAttribute("type", "button"); insertRowElement.setAttribute("aria-label", i18n[vditor.options.lang].insertRowBelow + "<" + updateHotkeyTip("⌘=") + ">"); insertRowElement.setAttribute("data-type", "insertRow"); insertRowElement.innerHTML = ''; insertRowElement.className = "vditor-icon vditor-tooltipped vditor-tooltipped__n"; insertRowElement.onclick = () => { const startContainer = getSelection().getRangeAt(0).startContainer; const cellElement = hasClosestByMatchTag(startContainer, "TD") || hasClosestByMatchTag(startContainer, "TH"); if (cellElement) { insertRow(vditor, range, cellElement); } }; const insertRowBElement = document.createElement("button"); insertRowBElement.setAttribute("type", "button"); insertRowBElement.setAttribute("aria-label", i18n[vditor.options.lang].insertRowAbove + "<" + updateHotkeyTip("⇧⌘F") + ">"); insertRowBElement.setAttribute("data-type", "insertRow"); insertRowBElement.innerHTML = ''; insertRowBElement.className = "vditor-icon vditor-tooltipped vditor-tooltipped__n"; insertRowBElement.onclick = () => { const startContainer = getSelection().getRangeAt(0).startContainer; const cellElement = hasClosestByMatchTag(startContainer, "TD") || hasClosestByMatchTag(startContainer, "TH"); if (cellElement) { insertRowAbove(vditor, range, cellElement); } }; const insertColumnElement = document.createElement("button"); insertColumnElement.setAttribute("type", "button"); insertColumnElement.setAttribute("aria-label", i18n[vditor.options.lang].insertColumnRight + "<" + updateHotkeyTip("⇧⌘=") + ">"); insertColumnElement.setAttribute("data-type", "insertColumn"); insertColumnElement.innerHTML = ''; insertColumnElement.className = "vditor-icon vditor-tooltipped vditor-tooltipped__n"; insertColumnElement.onclick = () => { const startContainer = getSelection().getRangeAt(0).startContainer; const cellElement = hasClosestByMatchTag(startContainer, "TD") || hasClosestByMatchTag(startContainer, "TH"); if (cellElement) { insertColumn(vditor, tableElement, cellElement); } }; const insertColumnBElement = document.createElement("button"); insertColumnBElement.setAttribute("type", "button"); insertColumnBElement.setAttribute("aria-label", i18n[vditor.options.lang].insertColumnLeft + "<" + updateHotkeyTip("⇧⌘G") + ">"); insertColumnBElement.setAttribute("data-type", "insertColumn"); insertColumnBElement.innerHTML = ''; insertColumnBElement.className = "vditor-icon vditor-tooltipped vditor-tooltipped__n"; insertColumnBElement.onclick = () => { const startContainer = getSelection().getRangeAt(0).startContainer; const cellElement = hasClosestByMatchTag(startContainer, "TD") || hasClosestByMatchTag(startContainer, "TH"); if (cellElement) { insertColumn(vditor, tableElement, cellElement, "beforebegin"); } }; const deleteRowElement = document.createElement("button"); deleteRowElement.setAttribute("type", "button"); deleteRowElement.setAttribute("aria-label", i18n[vditor.options.lang]["delete-row"] + "<" + updateHotkeyTip("⌘-") + ">"); deleteRowElement.setAttribute("data-type", "deleteRow"); deleteRowElement.innerHTML = ''; deleteRowElement.className = "vditor-icon vditor-tooltipped vditor-tooltipped__n"; deleteRowElement.onclick = () => { const startContainer = getSelection().getRangeAt(0).startContainer; const cellElement = hasClosestByMatchTag(startContainer, "TD") || hasClosestByMatchTag(startContainer, "TH"); if (cellElement) { deleteRow(vditor, range, cellElement); } }; const deleteColumnElement = document.createElement("button"); deleteColumnElement.setAttribute("type", "button"); deleteColumnElement.setAttribute("aria-label", i18n[vditor.options.lang]["delete-column"] + "<" + updateHotkeyTip("⇧⌘-") + ">"); deleteColumnElement.setAttribute("data-type", "deleteColumn"); deleteColumnElement.innerHTML = ''; deleteColumnElement.className = "vditor-icon vditor-tooltipped vditor-tooltipped__n"; deleteColumnElement.onclick = () => { const startContainer = getSelection().getRangeAt(0).startContainer; const cellElement = hasClosestByMatchTag(startContainer, "TD") || hasClosestByMatchTag(startContainer, "TH"); if (cellElement) { deleteColumn(vditor, range, tableElement, cellElement); } }; const inputWrap = document.createElement("span"); inputWrap.setAttribute("aria-label", i18n[vditor.options.lang].row); inputWrap.className = "vditor-tooltipped vditor-tooltipped__n"; const input = document.createElement("input"); inputWrap.appendChild(input); input.type = "number"; input.min = "1"; input.className = "vditor-input"; input.style.width = "42px"; input.style.textAlign = "center"; input.setAttribute("placeholder", i18n[vditor.options.lang].row); input.value = tableElement.rows.length.toString(); input.oninput = () => { updateTable(); }; input.onkeydown = (event) => { if (event.isComposing) { return; } if (event.key === "Tab") { input2.focus(); input2.select(); event.preventDefault(); return; } removeBlockElement(vditor, event); }; const input2Wrap = document.createElement("span"); input2Wrap.setAttribute("aria-label", i18n[vditor.options.lang].column); input2Wrap.className = "vditor-tooltipped vditor-tooltipped__n"; const input2 = document.createElement("input"); input2Wrap.appendChild(input2); input2.type = "number"; input2.min = "1"; input2.className = "vditor-input"; input2.style.width = "42px"; input2.style.textAlign = "center"; input2.setAttribute("placeholder", i18n[vditor.options.lang].column); input2.value = tableElement.rows[0].cells.length.toString(); input2.oninput = () => { updateTable(); }; input2.onkeydown = (event) => { if (event.isComposing) { return; } if (event.key === "Tab") { input.focus(); input.select(); event.preventDefault(); return; } removeBlockElement(vditor, event); }; genUp(range, tableElement, vditor); genDown(range, tableElement, vditor); genClose(tableElement, vditor); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", left); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", center); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", right); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", insertRowBElement); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", insertRowElement); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", insertColumnBElement); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", insertColumnElement); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", deleteRowElement); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", deleteColumnElement); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", inputWrap); vditor.wysiwyg.popover.insertAdjacentHTML("beforeend", " x "); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", input2Wrap); setPopoverPosition(vditor, tableElement); } // link ref popover const linkRefElement = hasClosestByAttribute(typeElement, "data-type", "link-ref"); if (linkRefElement) { genLinkRefPopover(vditor, linkRefElement); } // footnote popover const footnotesRefElement = hasClosestByAttribute(typeElement, "data-type", "footnotes-ref"); if (footnotesRefElement) { vditor.wysiwyg.popover.innerHTML = ""; const inputWrap = document.createElement("span"); inputWrap.setAttribute("aria-label", i18n[vditor.options.lang].footnoteRef + "<" + updateHotkeyTip("⌥Enter") + ">"); inputWrap.className = "vditor-tooltipped vditor-tooltipped__n"; const input = document.createElement("input"); inputWrap.appendChild(input); input.className = "vditor-input"; input.setAttribute("placeholder", i18n[vditor.options.lang].footnoteRef + "<" + updateHotkeyTip("⌥Enter") + ">"); input.style.width = "120px"; input.value = footnotesRefElement.getAttribute("data-footnotes-label"); input.oninput = () => { if (input.value.trim() !== "") { footnotesRefElement.setAttribute("data-footnotes-label", input.value); } }; input.onkeydown = (event) => { if (event.isComposing) { return; } if (!isCtrl(event) && !event.shiftKey && event.altKey && event.key === "Enter") { range.selectNodeContents(footnotesRefElement); range.collapse(false); setSelectionFocus(range); event.preventDefault(); return; } removeBlockElement(vditor, event); }; genClose(footnotesRefElement, vditor); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", inputWrap); setPopoverPosition(vditor, footnotesRefElement); } let blockRenderElement = hasClosestByClassName(typeElement, "vditor-wysiwyg__block") as HTMLElement; // block popover: math-inline, math-block, html-block, html-inline, code-block, html-entity if (blockRenderElement && blockRenderElement.getAttribute("data-type").indexOf("block") > -1) { vditor.wysiwyg.popover.innerHTML = ""; genUp(range, blockRenderElement, vditor); genDown(range, blockRenderElement, vditor); genClose(blockRenderElement, vditor); if (blockRenderElement.getAttribute("data-type") === "code-block") { const languageWrap = document.createElement("span"); languageWrap.setAttribute("aria-label", i18n[vditor.options.lang].language + "<" + updateHotkeyTip("⌥Enter") + ">"); languageWrap.className = "vditor-tooltipped vditor-tooltipped__n"; const language = document.createElement("input"); languageWrap.appendChild(language); const codeElement = blockRenderElement.firstElementChild.firstElementChild; language.className = "vditor-input"; language.setAttribute("placeholder", i18n[vditor.options.lang].language + "<" + updateHotkeyTip("⌥Enter") + ">"); language.value = codeElement.className.indexOf("language-") > -1 ? codeElement.className.split("-")[1].split(" ")[0] : ""; language.oninput = () => { if (language.value.trim() !== "") { codeElement.className = `language-${language.value}`; } else { codeElement.className = ""; vditor.hint.recentLanguage = ""; } if (blockRenderElement.lastElementChild.classList.contains("vditor-wysiwyg__preview")) { blockRenderElement.lastElementChild.innerHTML = blockRenderElement.firstElementChild.innerHTML; processCodeRender(blockRenderElement.lastElementChild as HTMLElement, vditor); } afterRenderEvent(vditor); }; language.onkeydown = (event: KeyboardEvent) => { if (event.isComposing) { return; } if (removeBlockElement(vditor, event)) { return; } if (event.key === "Escape" && vditor.hint.element.style.display === "block") { vditor.hint.element.style.display = "none"; event.preventDefault(); return; } if (!isCtrl(event) && !event.shiftKey && event.altKey && event.key === "Enter") { range.setStart(codeElement.firstChild, 0); range.collapse(true); setSelectionFocus(range); } vditor.hint.select(event, vditor); }; language.onkeyup = (event: KeyboardEvent) => { if (event.isComposing || event.key === "Enter" || event.key === "ArrowUp" || event.key === "Escape" || event.key === "ArrowDown") { return; } const matchLangData: IHintData[] = []; const key = language.value.substring(0, language.selectionStart); Constants.CODE_LANGUAGES.forEach((keyName) => { if (keyName.indexOf(key.toLowerCase()) > -1) { matchLangData.push({ html: keyName, value: keyName, }); } }); vditor.hint.genHTML(matchLangData, key, vditor); event.preventDefault(); }; vditor.wysiwyg.popover.insertAdjacentElement("beforeend", languageWrap); } setPopoverPosition(vditor, blockRenderElement); } else { if (!blockRenderElement) { vditor.wysiwyg.element.querySelectorAll(".vditor-wysiwyg__preview").forEach((itemElement) => { const previousElement = itemElement.previousElementSibling as HTMLElement; previousElement.style.display = "none"; }); } blockRenderElement = undefined; } if (headingElement) { vditor.wysiwyg.popover.innerHTML = ""; const inputWrap = document.createElement("span"); inputWrap.setAttribute("aria-label", "ID" + "<" + updateHotkeyTip("⌥Enter") + ">"); inputWrap.className = "vditor-tooltipped vditor-tooltipped__n"; const input = document.createElement("input"); inputWrap.appendChild(input); input.className = "vditor-input"; input.setAttribute("placeholder", "ID" + "<" + updateHotkeyTip("⌥Enter") + ">"); input.style.width = "120px"; input.value = headingElement.getAttribute("data-id") || ""; input.oninput = () => { headingElement.setAttribute("data-id", input.value); }; input.onkeydown = (event) => { if (event.isComposing) { return; } if (!isCtrl(event) && !event.shiftKey && event.altKey && event.key === "Enter") { range.selectNodeContents(headingElement); range.collapse(false); setSelectionFocus(range); event.preventDefault(); return; } removeBlockElement(vditor, event); }; genUp(range, headingElement, vditor); genDown(range, headingElement, vditor); genClose(headingElement, vditor); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", inputWrap); setPopoverPosition(vditor, headingElement); } // a popover if (aElement) { genAPopover(vditor, aElement); } if (!blockquoteElement && !liElement && !tableElement && !blockRenderElement && !aElement && !linkRefElement && !footnotesRefElement && !headingElement && !tocElement) { const blockElement = hasClosestByAttribute(typeElement, "data-block", "0"); if (blockElement && blockElement.parentElement.isEqualNode(vditor.wysiwyg.element)) { vditor.wysiwyg.popover.innerHTML = ""; genUp(range, blockElement, vditor); genDown(range, blockElement, vditor); genClose(blockElement, vditor); setPopoverPosition(vditor, blockElement); } else { vditor.wysiwyg.popover.style.display = "none"; } } // 反斜杠特殊处理 vditor.wysiwyg.element.querySelectorAll('span[data-type="backslash"] > span').forEach((item: HTMLElement) => { item.style.display = "none"; }); const backslashElement = hasClosestByAttribute(range.startContainer, "data-type", "backslash"); if (backslashElement) { backslashElement.querySelector("span").style.display = "inline"; } }, 200); }; const setPopoverPosition = (vditor: IVditor, element: HTMLElement) => { let targetElement = element; const tableElement = hasClosestByMatchTag(element, "TABLE"); if (tableElement) { targetElement = tableElement; } vditor.wysiwyg.popover.style.left = "0"; vditor.wysiwyg.popover.style.display = "block"; vditor.wysiwyg.popover.style.top = Math.max(-8, targetElement.offsetTop - 21 - vditor.wysiwyg.element.scrollTop) + "px"; vditor.wysiwyg.popover.style.left = Math.min(targetElement.offsetLeft, vditor.wysiwyg.element.clientWidth - vditor.wysiwyg.popover.clientWidth) + "px"; vditor.wysiwyg.popover.setAttribute("data-top", (targetElement.offsetTop - 21).toString()); }; export const genLinkRefPopover = (vditor: IVditor, linkRefElement: HTMLElement) => { vditor.wysiwyg.popover.innerHTML = ""; const updateLinkRef = () => { if (input.value.trim() !== "") { if (linkRefElement.tagName === "IMG") { linkRefElement.setAttribute("alt", input.value); } else { linkRefElement.textContent = input.value; } } // data-link-label if (input1.value.trim() !== "") { linkRefElement.setAttribute("data-link-label", input1.value); } }; const inputWrap = document.createElement("span"); inputWrap.setAttribute("aria-label", i18n[vditor.options.lang].textIsNotEmpty); inputWrap.className = "vditor-tooltipped vditor-tooltipped__n"; const input = document.createElement("input"); inputWrap.appendChild(input); input.className = "vditor-input"; input.setAttribute("placeholder", i18n[vditor.options.lang].textIsNotEmpty); input.style.width = "120px"; input.value = linkRefElement.getAttribute("alt") || linkRefElement.textContent; input.oninput = () => { updateLinkRef(); }; input.onkeydown = (event) => { if (removeBlockElement(vditor, event)) { return; } linkHotkey(vditor, linkRefElement, event, input1); }; const input1Wrap = document.createElement("span"); input1Wrap.setAttribute("aria-label", i18n[vditor.options.lang].linkRef); input1Wrap.className = "vditor-tooltipped vditor-tooltipped__n"; const input1 = document.createElement("input"); input1Wrap.appendChild(input1); input1.className = "vditor-input"; input1.setAttribute("placeholder", i18n[vditor.options.lang].linkRef); input1.value = linkRefElement.getAttribute("data-link-label"); input1.oninput = () => { updateLinkRef(); }; input1.onkeydown = (event) => { if (removeBlockElement(vditor, event)) { return; } linkHotkey(vditor, linkRefElement, event, input); }; genClose(linkRefElement, vditor); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", inputWrap); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", input1Wrap); setPopoverPosition(vditor, linkRefElement); }; // 去掉focus之后的向上向下和删除按钮的显示 const genUp = (range: Range, element: HTMLElement, vditor: IVditor) => { // const previousElement = element.previousElementSibling; // if (!previousElement || (!element.parentElement.isEqualNode(vditor.wysiwyg.element) && element.tagName !== "LI")) { // return; // } // const upElement = document.createElement("button"); // upElement.setAttribute("type", "button"); // upElement.setAttribute("data-type", "up"); // upElement.setAttribute("aria-label", i18n[vditor.options.lang].up + // "<" + updateHotkeyTip("⇧⌘U") + ">"); // upElement.innerHTML = ''; // upElement.className = "vditor-icon vditor-tooltipped vditor-tooltipped__n"; // upElement.onclick = () => { // range.insertNode(document.createElement("wbr")); // previousElement.insertAdjacentElement("beforebegin", element); // setRangeByWbr(vditor.wysiwyg.element, range); // afterRenderEvent(vditor); // highlightToolbarWYSIWYG(vditor); // scrollCenter(vditor); // }; // vditor.wysiwyg.popover.insertAdjacentElement("beforeend", upElement); }; const genDown = (range: Range, element: HTMLElement, vditor: IVditor) => { // const nextElement = element.nextElementSibling; // if (!nextElement || (!element.parentElement.isEqualNode(vditor.wysiwyg.element) && element.tagName !== "LI")) { // return; // } // const downElement = document.createElement("button"); // downElement.setAttribute("type", "button"); // downElement.setAttribute("data-type", "down"); // downElement.setAttribute("aria-label", i18n[vditor.options.lang].down + // "<" + updateHotkeyTip("⇧⌘D") + ">"); // downElement.innerHTML = ''; // downElement.className = "vditor-icon vditor-tooltipped vditor-tooltipped__n"; // downElement.onclick = () => { // range.insertNode(document.createElement("wbr")); // nextElement.insertAdjacentElement("afterend", element); // setRangeByWbr(vditor.wysiwyg.element, range); // afterRenderEvent(vditor); // highlightToolbarWYSIWYG(vditor); // scrollCenter(vditor); // }; // vditor.wysiwyg.popover.insertAdjacentElement("beforeend", downElement); }; const genClose = (element: HTMLElement, vditor: IVditor) => { // const close = document.createElement("button"); // close.setAttribute("type", "button"); // close.setAttribute("data-type", "remove"); // close.setAttribute("aria-label", i18n[vditor.options.lang].remove + // "<" + updateHotkeyTip("⇧⌘X") + ">"); // close.innerHTML = ''; // close.className = "vditor-icon vditor-tooltipped vditor-tooltipped__n"; // close.onclick = () => { // const range = getEditorRange(vditor); // range.setStartAfter(element); // setSelectionFocus(range); // element.remove(); // afterRenderEvent(vditor); // highlightToolbarWYSIWYG(vditor); // }; // vditor.wysiwyg.popover.insertAdjacentElement("beforeend", close); }; const linkHotkey = (vditor: IVditor, element: HTMLElement, event: KeyboardEvent, nextInputElement: HTMLInputElement) => { if (event.isComposing) { return; } if (event.key === "Tab") { nextInputElement.focus(); nextInputElement.select(); event.preventDefault(); return; } if (!isCtrl(event) && !event.shiftKey && event.altKey && event.key === "Enter") { const range = getEditorRange(vditor); // firefox 不会打断 link https://github.com/Vanessa219/vditor/issues/193 element.insertAdjacentHTML("afterend", Constants.ZWSP); range.setStartAfter(element.nextSibling); range.collapse(true); setSelectionFocus(range); event.preventDefault(); } }; export const genAPopover = (vditor: IVditor, aElement: HTMLElement) => { vditor.wysiwyg.popover.innerHTML = ""; const updateA = () => { if (input.value.trim() !== "") { aElement.innerHTML = input.value; } aElement.setAttribute("href", input1.value); aElement.setAttribute("title", input2.value); }; aElement.querySelectorAll("[data-marker]").forEach((item: HTMLElement) => { item.removeAttribute("data-marker"); }); const inputWrap = document.createElement("span"); inputWrap.setAttribute("aria-label", i18n[vditor.options.lang].textIsNotEmpty); inputWrap.className = "vditor-tooltipped vditor-tooltipped__n"; const input = document.createElement("input"); inputWrap.appendChild(input); input.className = "vditor-input"; input.setAttribute("placeholder", i18n[vditor.options.lang].textIsNotEmpty); input.style.width = "120px"; input.value = aElement.innerHTML || ""; input.oninput = () => { updateA(); }; input.onkeydown = (event) => { if (removeBlockElement(vditor, event)) { return; } linkHotkey(vditor, aElement, event, input1); }; const input1Wrap = document.createElement("span"); input1Wrap.setAttribute("aria-label", i18n[vditor.options.lang].link); input1Wrap.className = "vditor-tooltipped vditor-tooltipped__n"; const input1 = document.createElement("input"); input1Wrap.appendChild(input1); input1.className = "vditor-input"; input1.setAttribute("placeholder", i18n[vditor.options.lang].link); input1.value = aElement.getAttribute("href") || ""; input1.oninput = () => { updateA(); }; input1.onkeydown = (event) => { if (removeBlockElement(vditor, event)) { return; } linkHotkey(vditor, aElement, event, input2); }; const input2Wrap = document.createElement("span"); input2Wrap.setAttribute("aria-label", i18n[vditor.options.lang].tooltipText); input2Wrap.className = "vditor-tooltipped vditor-tooltipped__n"; const input2 = document.createElement("input"); input2Wrap.appendChild(input2); input2.className = "vditor-input"; input2.setAttribute("placeholder", i18n[vditor.options.lang].tooltipText); input2.style.width = "60px"; input2.value = aElement.getAttribute("title") || ""; input2.oninput = () => { updateA(); }; input2.onkeydown = (event) => { if (removeBlockElement(vditor, event)) { return; } linkHotkey(vditor, aElement, event, input); }; genClose(aElement, vditor); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", inputWrap); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", input1Wrap); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", input2Wrap); setPopoverPosition(vditor, aElement); }; export const genImagePopover = (event: Event, vditor: IVditor) => { const imgElement = event.target as HTMLImageElement; vditor.wysiwyg.popover.innerHTML = ""; const updateImg = () => { imgElement.setAttribute("src", inputElement.value); imgElement.setAttribute("alt", alt.value); imgElement.setAttribute("title", title.value); }; const inputWrap = document.createElement("span"); inputWrap.setAttribute("aria-label", i18n[vditor.options.lang].imageURL); inputWrap.className = "vditor-tooltipped vditor-tooltipped__n"; const inputElement = document.createElement("input"); inputWrap.appendChild(inputElement); inputElement.className = "vditor-input"; inputElement.setAttribute("placeholder", i18n[vditor.options.lang].imageURL); inputElement.value = imgElement.getAttribute("src") || ""; inputElement.oninput = () => { updateImg(); }; inputElement.onkeydown = (elementEvent) => { removeBlockElement(vditor, elementEvent); }; const altWrap = document.createElement("span"); altWrap.setAttribute("aria-label", i18n[vditor.options.lang].alternateText); altWrap.className = "vditor-tooltipped vditor-tooltipped__n"; const alt = document.createElement("input"); altWrap.appendChild(alt); alt.className = "vditor-input"; alt.setAttribute("placeholder", i18n[vditor.options.lang].alternateText); alt.style.width = "52px"; alt.value = imgElement.getAttribute("alt") || ""; alt.oninput = () => { updateImg(); }; alt.onkeydown = (elementEvent) => { removeBlockElement(vditor, elementEvent); }; const titleWrap = document.createElement("span"); titleWrap.setAttribute("aria-label", i18n[vditor.options.lang].title); titleWrap.className = "vditor-tooltipped vditor-tooltipped__n"; const title = document.createElement("input"); titleWrap.appendChild(title); title.className = "vditor-input"; title.setAttribute("placeholder", i18n[vditor.options.lang].title); title.value = imgElement.getAttribute("title") || ""; title.oninput = () => { updateImg(); }; title.onkeydown = (elementEvent) => { removeBlockElement(vditor, elementEvent); }; genClose(imgElement, vditor); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", inputWrap); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", altWrap); vditor.wysiwyg.popover.insertAdjacentElement("beforeend", titleWrap); setPopoverPosition(vditor, imgElement); };