import {Constants} from "../../constants"; import {hasClosestBlock, hasClosestByAttribute, hasClosestByClassName, hasClosestByMatchTag} from "../util/hasClosest"; import { focusBlock, focusByRange, focusByWbr, getEditorRange, getSelectionOffset, getSelectionPosition } from "../util/selection"; import {hintEmbed, hintRef, hintSlash} from "./extend"; import {getSavePath} from "../../util/newFile"; import {upDownHint} from "../../util/upDownHint"; import {setPosition} from "../../util/setPosition"; import {getContenteditableElement} from "../wysiwyg/getBlock"; import {transaction, updateTransaction} from "../wysiwyg/transaction"; import {genEmptyBlock} from "../../block/util"; import {insertHTML} from "../util/insertHTML"; import {highlightRender} from "../markdown/highlightRender"; import {imgMenu} from "../../menus/protyle"; import {hideElements} from "../ui/hideElements"; import {fetchPost} from "../../util/fetch"; import {getDisplayName, pathPosix} from "../../util/pathName"; import {addEmoji, filterEmoji, lazyLoadEmoji, unicode2Emoji} from "../../emoji"; import {escapeHtml} from "../../util/escape"; import {blockRender} from "../markdown/blockRender"; import {uploadFiles} from "../upload"; /// #if !MOBILE import {openFileById} from "../../editor/util"; /// #endif import {openMobileFileById} from "../../mobile/editor"; import {getIconByType} from "../../editor/getIcon"; export class Hint { public timeId: number; public element: HTMLDivElement; public enableSlash = true; public enableEmoji = false; public splitChar = ""; public lastIndex = -1; constructor(protyle: IProtyle) { this.element = document.createElement("div"); this.element.setAttribute("data-close", "false"); // height 402 根据 .emojis max-height+8 得来 this.element.setAttribute("style", `z-index: 201;overflow:auto;max-height:402px;width:${Math.max(protyle.element.clientWidth / 2, 320)}px;box-sizing: border-box;`); this.element.className = "b3-menu b3-list b3-list--background fn__none"; this.element.addEventListener("click", (event) => { const eventTarget = event.target as HTMLElement; if (eventTarget.tagName === "INPUT") { event.stopPropagation(); return; } const btnElement = hasClosestByMatchTag(eventTarget, "BUTTON"); if (btnElement && !btnElement.classList.contains("emojis__item")) { if (btnElement.parentElement.classList.contains("b3-list")) { this.fill(decodeURIComponent(btnElement.getAttribute("data-value")), protyle); } else { // 划选引用点击,需先重置 range setTimeout(() => { this.fill(decodeURIComponent(btnElement.getAttribute("data-value")), protyle); }, 148); focusByRange(protyle.toolbar.range); } event.preventDefault(); event.stopPropagation(); // https://github.com/siyuan-note/siyuan/issues/3710 return; } const emojisContentElement = this.element.querySelector(".emojis__panel"); const typeElement = hasClosestByClassName(eventTarget, "emojis__type"); if (typeElement) { const titleElement = emojisContentElement.querySelector(`[data-type="${typeElement.getAttribute("data-type")}"]`) as HTMLElement; if (titleElement) { const index = titleElement.nextElementSibling.getAttribute("data-index"); if (index) { let html = ""; window.siyuan.emojis[parseInt(index)].items.forEach(emoji => { html += ``; }); titleElement.nextElementSibling.innerHTML = html; titleElement.nextElementSibling.removeAttribute("data-index"); } emojisContentElement.scrollTo({ top: titleElement.offsetTop, // behavior: "smooth" 不能使用,否则无法定位 }); } return; } const emojiElement = hasClosestByClassName(eventTarget, "emojis__item"); if (emojiElement) { const unicode = emojiElement.getAttribute("data-unicode"); if (this.element.querySelectorAll(".emojis__title").length > 2) { // /emoji 后会自动添加冒号,导致 range 无法计算,因此不依赖 this.fill const range = getSelection().getRangeAt(0); if (range.endContainer.nodeType !== 3) { range.endContainer.childNodes[range.endOffset - 1]?.remove(); } addEmoji(unicode); let emoji; if (unicode.indexOf(".") > -1) { emoji = `:${unicode.split(".")[0]}: `; } else { emoji = unicode2Emoji(unicode, true) + " "; } insertHTML(protyle.lute.SpinBlockDOM(emoji), protyle); this.element.classList.add("fn__none"); } else { this.fill(unicode, protyle); } } }); } public render(protyle: IProtyle) { if (!window.getSelection().focusNode) { this.element.classList.add("fn__none"); clearTimeout(this.timeId); return; } const range = getSelection().getRangeAt(0); const start = getSelectionOffset(range.startContainer as HTMLElement, protyle.wysiwyg.element).start; const currentLineValue = range.startContainer.textContent.substring(0, start) || ""; const key = this.getKey(currentLineValue, protyle.options.hint.extend); if (typeof key === "undefined" || ( // 除emoji 提示外,其余在 tag/inline math/inline-code 内移动不进行提示 this.splitChar !== ":" && (protyle.toolbar.getCurrentType(range).length > 0 || hasClosestByAttribute(range.startContainer, "data-type", "NodeCodeBlock")) ) ) { this.element.classList.add("fn__none"); clearTimeout(this.timeId); return; } if (this.splitChar === ":") { clearTimeout(this.timeId); if (key) { this.genEmojiHTML(protyle, key); } else { this.element.classList.add("fn__none"); } return; } // https://github.com/siyuan-note/siyuan/issues/5083 if (this.splitChar === "/" || this.splitChar === "、") { clearTimeout(this.timeId); if (this.enableSlash) { this.genHTML(hintSlash(key, protyle), protyle); } return; } protyle.options.hint.extend.forEach((item) => { if (item.key === this.splitChar) { clearTimeout(this.timeId); this.timeId = window.setTimeout(() => { this.genHTML(item.hint(key, protyle), protyle); }, protyle.options.hint.delay); } }); } public genLoading(protyle: IProtyle) { if (this.element.classList.contains("fn__none")) { this.element.innerHTML = "
"; this.element.classList.remove("fn__none"); const textareaPosition = getSelectionPosition(protyle.wysiwyg.element); setPosition(this.element, textareaPosition.left, textareaPosition.top + 26, 30); } else { this.element.insertAdjacentHTML("beforeend", '
'); } } public genHTML(data: IHintData[], protyle: IProtyle, hide = false, hasSearch = false) { if (data.length === 0) { if (!this.element.querySelector(".fn__loading") || hide) { this.element.classList.add("fn__none"); } return; } let hintsHTML = ""; if (hasSearch) { hintsHTML = '
'; this.element.style.display = "flex"; this.element.style.flexDirection = "column"; } else { this.element.style.display = ""; } let hasFocus = false; data.forEach((hintData, i) => { // https://github.com/siyuan-note/siyuan/issues/1229 提示时,新建文件不应默认选中 let focusClass = ""; if (i === 0) { if (hintData.value.startsWith("((newFile ") && hintData.value.endsWith(`${Lute.Caret}'))`) && data.length > 1) { focusClass = ""; } else { focusClass = " b3-list-item--focus"; hasFocus = true; } } else if (i === 1 && !hasFocus) { focusClass = " b3-list-item--focus"; } if (hintData.html === "separator") { hintsHTML += '
'; } else { hintsHTML += ``; } }); if (hasSearch) { hintsHTML = hintsHTML + "
"; } this.element.innerHTML = hintsHTML; this.element.classList.remove("fn__none"); // https://github.com/siyuan-note/siyuan/issues/4575 if (data[0].filter) { this.element.classList.add("hint--menu"); } else { this.element.classList.remove("hint--menu"); } this.element.style.width = Math.max(protyle.element.clientWidth / 2, 320) + "px"; const textareaPosition = getSelectionPosition(protyle.wysiwyg.element); setPosition(this.element, textareaPosition.left, textareaPosition.top + 26, 30); this.element.scrollTop = 0; const uploadElement = this.element.querySelector('input[type="file"]'); if (uploadElement) { uploadElement.addEventListener("change", (event: InputEvent & { target: HTMLInputElement }) => { if (event.target.files.length === 0) { return; } const range = getEditorRange(protyle.wysiwyg.element); if (this.lastIndex > -1) { range.setStart(range.startContainer, this.lastIndex); } range.deleteContents(); uploadFiles(protyle, event.target.files, event.target); hideElements(["hint", "toolbar"], protyle); }); } if (hasSearch) { const searchElement = this.element.querySelector("input.b3-text-field") as HTMLInputElement; const oldValue = this.element.querySelector("mark").textContent; searchElement.value = oldValue; searchElement.select(); searchElement.addEventListener("keydown", (event: KeyboardEvent) => { event.stopPropagation(); if (event.isComposing) { return; } upDownHint(this.element.lastElementChild, event); if (event.key === "Enter") { setTimeout(() => { this.fill(decodeURIComponent(this.element.querySelector(".b3-list-item--focus").getAttribute("data-value")), protyle); }, 148); focusByRange(protyle.toolbar.range); event.preventDefault(); } else if (event.key === "Escape") { this.element.classList.add("fn__none"); focusByRange(protyle.toolbar.range); } }); const nodeElement = hasClosestBlock(protyle.toolbar.range.startContainer); searchElement.addEventListener("input", (event: InputEvent) => { if (event.isComposing) { return; } event.stopPropagation(); this.genSearchHTML(protyle, searchElement, nodeElement, oldValue); }); searchElement.addEventListener("compositionend", (event: InputEvent) => { event.stopPropagation(); this.genSearchHTML(protyle, searchElement, nodeElement, oldValue); }); } } private genSearchHTML(protyle: IProtyle, searchElement: HTMLInputElement, nodeElement: false | HTMLElement, oldValue: string) { this.element.lastElementChild.innerHTML = '
'; fetchPost("/api/search/searchRefBlock", { k: searchElement.value, id: nodeElement ? nodeElement.getAttribute("data-node-id") : protyle.block.parentID, beforeLen: Math.floor((Math.max(protyle.element.clientWidth / 2, 320) - 58) / 28.8), rootID: protyle.block.rootID, }, (response) => { let searchHTML = ""; if (response.data.newDoc) { const blockRefText = `((newFile "${oldValue}"${Constants.ZWSP}'${response.data.k}${Lute.Caret}'))`; searchHTML += ``; } response.data.blocks.forEach((item: IBlock, index: number) => { const iconName = getIconByType(item.type); let attrHTML = ""; if (item.name) { attrHTML += ` ${escapeHtml(item.name)}`; } if (item.alias) { attrHTML += ` ${escapeHtml(item.alias)}`; } if (item.memo) { attrHTML += ` ${escapeHtml(item.memo)}`; } if (attrHTML) { attrHTML = `
${attrHTML}
`; } const blockRefHTML = `${oldValue}`; searchHTML += ``; }); if (searchHTML === "") { searchHTML = ``; } this.element.lastElementChild.innerHTML = searchHTML; }); } private genEmojiHTML(protyle: IProtyle, value = "") { if (value && !this.enableEmoji) { return; } const panelElement = this.element.querySelector(".emojis__panel"); if (panelElement) { panelElement.innerHTML = filterEmoji(value, 256, true); if (value) { panelElement.nextElementSibling.classList.add("fn__none"); } else { panelElement.nextElementSibling.classList.remove("fn__none"); } } else { this.element.innerHTML = `
${filterEmoji(value, 256, true)}
${unicode2Emoji("2b50", true)}
${unicode2Emoji("1f527", true)}
${unicode2Emoji("1f60d", true)}
${unicode2Emoji("1f433", true)}
${unicode2Emoji("1f96a", true)}
${unicode2Emoji("1f3a8", true)}
${unicode2Emoji("1f3dd", true)}
${unicode2Emoji("1f52e", true)}
${unicode2Emoji("267e", true)}
${unicode2Emoji("1f6a9", true)}
`; lazyLoadEmoji(this.element, true); } const firstEmojiElement = this.element.querySelector(".emojis__item"); if (firstEmojiElement) { firstEmojiElement.classList.add("emojis__item--current"); this.element.classList.remove("fn__none"); this.element.style.width = Math.max(protyle.element.clientWidth / 2, 320) + "px"; const textareaPosition = getSelectionPosition(protyle.wysiwyg.element); setPosition(this.element, textareaPosition.left, textareaPosition.top + 26, 30); this.element.querySelector(".emojis__panel").scrollTop = 0; } else { this.element.classList.add("fn__none"); } } public fill(value: string, protyle: IProtyle) { hideElements(["hint", "toolbar"], protyle); const range: Range = getEditorRange(protyle.wysiwyg.element); let nodeElement = hasClosestBlock(range.startContainer) as HTMLElement; if (!nodeElement) { return; } let id = ""; if (nodeElement) { id = nodeElement.getAttribute("data-node-id"); } let html = nodeElement.outerHTML; // 自顶向下法新建文档后光标定位问题 https://github.com/siyuan-note/siyuan/issues/299 // QQ 拼音输入法自动补全需移除补全内容 https://github.com/siyuan-note/siyuan/issues/320 // 前后有标记符的情况 https://github.com/siyuan-note/siyuan/issues/2511 const endSplit = Constants.BLOCK_HINT_CLOSE_KEYS[this.splitChar]; if (Constants.BLOCK_HINT_KEYS.includes(this.splitChar) && endSplit && range.startContainer.nodeType === 3 && (range.startContainer as Text).wholeText.indexOf(endSplit) > -1) { let matchEndChar = 0; let textNode = range.startContainer; while (textNode && matchEndChar < 2) { const index = textNode.textContent.indexOf(endSplit); const startIndex = textNode.textContent.indexOf(this.splitChar); if (index > -1 && (index < startIndex || startIndex < 0)) { matchEndChar = 2; range.setEnd(textNode, index + 2); break; } const indexOne = textNode.textContent.indexOf(endSplit.substr(1)); if (indexOne > -1) { matchEndChar += 1; } if (matchEndChar === 2) { range.setEnd(textNode, indexOne + 1); break; } textNode = textNode.nextSibling; } } if (this.lastIndex > -1) { range.setStart(range.startContainer, this.lastIndex); } range.deleteContents(); // 新建文件 if (Constants.BLOCK_HINT_KEYS.includes(this.splitChar) && value.startsWith("((newFile ") && value.endsWith(`${Lute.Caret}'))`)) { focusByRange(range); const fileNames = value.substring(11, value.length - 4).split(`"${Constants.ZWSP}'`); const realFileName = fileNames.length === 1 ? fileNames[0] : fileNames[1]; getSavePath(protyle.path, protyle.notebookId, (pathString) => { fetchPost("/api/filetree/createDocWithMd", { notebook: protyle.notebookId, path: pathPosix().join(pathString, realFileName), markdown: "" }, response => { let blockRefHTML = `${escapeHtml(realFileName)}`; if (fileNames.length === 2) { blockRefHTML = `${escapeHtml(fileNames[0])}`; } insertHTML(genEmptyBlock(false, false, blockRefHTML), protyle); }); }); return; } if (Constants.BLOCK_HINT_KEYS.includes(this.splitChar)) { if (value === "") { const editElement = getContenteditableElement(nodeElement); if (editElement.textContent === "") { editElement.innerHTML = ""; focusByWbr(editElement, range); } return; } range.insertNode(document.createElement("wbr")); html = nodeElement.outerHTML; const tempElement = document.createElement("template"); tempElement.innerHTML = value.replace(//g, "").replace(/<\/mark>/g, ""); range.insertNode(tempElement.content.cloneNode(true)); updateTransaction(protyle, id, nodeElement.outerHTML, html); focusByWbr(nodeElement, range); return; } else if (this.splitChar === ":") { addEmoji(value); let emoji; if (value.indexOf(".") > -1) { emoji = `:${value.split(".")[0]}: `; } else { emoji = unicode2Emoji(value, true) + " "; } insertHTML(protyle.lute.SpinBlockDOM(emoji), protyle); } else if (["「「", "{{"].includes(this.splitChar) || this.splitChar === "#" || this.splitChar === ":") { if (value === "") { const editElement = getContenteditableElement(nodeElement); if (editElement.textContent === "") { editElement.innerHTML = ""; focusByWbr(editElement, range); } return; } insertHTML(protyle.lute.SpinBlockDOM(value), protyle); blockRender(protyle, protyle.wysiwyg.element); return; } else if (this.splitChar === "/" || this.splitChar === "、") { if (value === "((" || value === "{{") { if (value === "((") { hintRef("", protyle); } else { hintEmbed("", protyle); } this.splitChar = value; this.lastIndex = 0; const textNode = document.createTextNode(value); range.insertNode(textNode); range.setEnd(textNode, value.length); range.collapse(false); return; } else if (value === Constants.ZWSP) { protyle.toolbar.showTpl(protyle, nodeElement, range); updateTransaction(protyle, id, nodeElement.outerHTML, html); return; } else if (value === Constants.ZWSP + 1) { protyle.toolbar.showWidget(protyle, nodeElement, range); updateTransaction(protyle, id, nodeElement.outerHTML, html); return; } else if (value === Constants.ZWSP + 2) { protyle.toolbar.showAssets(protyle, nodeElement, range); updateTransaction(protyle, id, nodeElement.outerHTML, html); return; } else if (value === Constants.ZWSP + 3) { return; } else if (value === Constants.ZWSP + 4) { const newSubDocId = Lute.NewNodeID(); fetchPost("/api/filetree/createDoc", { notebook: protyle.notebookId, path: pathPosix().join(getDisplayName(protyle.path, false, true), newSubDocId + ".sy"), title: "Untitled", md: "" }, () => { insertHTML(genEmptyBlock(false, false, `Untitled`), protyle); /// #if MOBILE openMobileFileById(newSubDocId, [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT]); /// #else openFileById({ id: newSubDocId, action: [Constants.CB_GET_HL, Constants.CB_GET_CONTEXT] }); /// #endif }); return; } else if (Constants.INLINE_TYPE.includes(value)) { focusByRange(range); protyle.toolbar.range = range; protyle.toolbar.setInlineMark(protyle, value, "add"); return; } else if (value === "emoji") { range.insertNode(document.createTextNode(":")); range.collapse(false); this.enableEmoji = true; this.genEmojiHTML(protyle); return; } else if (value.indexOf("style") > -1) { nodeElement.setAttribute("style", value.split(Constants.ZWSP)[1] || ""); updateTransaction(protyle, id, nodeElement.outerHTML, html); return; } else { let textContent = value; if (value === "```") { textContent = value + (localStorage.getItem(Constants.LOCAL_CODELANG) || "") + Lute.Caret + "\n```"; } const editableElement = getContenteditableElement(nodeElement); if (value === "![]()") { // https://github.com/siyuan-note/siyuan/issues/4586 1 let newHTML = ""; range.insertNode(document.createElement("wbr")); range.insertNode(document.createTextNode(value)); newHTML = protyle.lute.SpinBlockDOM(nodeElement.outerHTML); nodeElement.outerHTML = newHTML; nodeElement = protyle.wysiwyg.element.querySelector(`[data-node-id="${id}"]`); focusByWbr(nodeElement, range); updateTransaction(protyle, id, nodeElement.outerHTML, html); let imgElement: HTMLElement = range.startContainer.childNodes[range.startOffset - 1] as HTMLElement || range.startContainer as HTMLElement; if (imgElement && imgElement.nodeType !== 3 && imgElement.classList.contains("img")) { // 已经找到图片 } else { imgElement = nodeElement.querySelector(".img"); } const rect = imgElement.getBoundingClientRect(); imgMenu(protyle, range, imgElement, { clientX: rect.left, clientY: rect.top }); return; } else if (editableElement.textContent === "" && nodeElement.getAttribute("data-type") === "NodeParagraph") { let newHTML = ""; if (value === "
") { newHTML = `
${Constants.ZWSP}
`; } else { editableElement.textContent = textContent; newHTML = protyle.lute.SpinBlockDOM(nodeElement.outerHTML); } nodeElement.outerHTML = newHTML; nodeElement = protyle.wysiwyg.element.querySelector(`[data-node-id="${id}"]`); updateTransaction(protyle, id, newHTML, html); } else { let newHTML = protyle.lute.SpinBlockDOM(textContent); if (value === "
") { newHTML = `
${Constants.ZWSP}
`; } nodeElement.insertAdjacentHTML("afterend", newHTML); const newId = newHTML.substr(newHTML.indexOf('data-node-id="') + 14, 22); transaction(protyle, [{ data: nodeElement.outerHTML, id, action: "update" }, { data: newHTML, id: newId, previousID: id, action: "insert" }], [{ id: newId, action: "delete" }, { data: html, id, action: "update" }]); nodeElement = protyle.wysiwyg.element.querySelector(`[data-node-id="${newId}"]`); } if (value === "
" || value === "$$" || (value.indexOf("```") > -1 && value.length > 3)) { protyle.toolbar.showRender(protyle, nodeElement); } else if (value.startsWith("```")) { highlightRender(nodeElement); } else if (value.startsWith(" 2) { // /emoji 后会自动添加冒号,导致 range 无法计算,因此不依赖 this.fill const range = getSelection().getRangeAt(0); if (range.endContainer.nodeType !== 3) { range.endContainer.childNodes[range.endOffset - 1]?.remove(); } addEmoji(unicode); let emoji; if (unicode.indexOf(".") > -1) { emoji = `:${unicode.split(".")[0]}: `; } else { emoji = unicode2Emoji(unicode, true) + " "; } insertHTML(protyle.lute.SpinBlockDOM(emoji), protyle); this.element.classList.add("fn__none"); } else { this.fill(unicode, protyle); } } else { const mark = decodeURIComponent(this.element.querySelector(".b3-list-item--focus").getAttribute("data-value")); if (mark === Constants.ZWSP + 3) { (this.element.querySelector(".b3-list-item--focus input") as HTMLElement).click(); } else { this.fill(mark, protyle); } } event.preventDefault(); event.stopPropagation(); return true; } if (isEmojiPanel) { const currentElement = this.element.querySelector(".emojis__item--current"); if (!currentElement) { return false; } let newCurrentElement: HTMLElement; if (event.key === "ArrowLeft" || event.key === "ArrowUp") { if (currentElement.previousElementSibling) { currentElement.classList.remove("emojis__item--current"); newCurrentElement = currentElement.previousElementSibling as HTMLElement; } else if (currentElement.parentElement.previousElementSibling?.previousElementSibling) { currentElement.classList.remove("emojis__item--current"); newCurrentElement = currentElement.parentElement.previousElementSibling.previousElementSibling.lastElementChild as HTMLElement; } } else if (event.key === "ArrowRight" || event.key === "ArrowDown") { if (currentElement.nextElementSibling) { currentElement.classList.remove("emojis__item--current"); newCurrentElement = currentElement.nextElementSibling as HTMLElement; } else if (currentElement.parentElement.nextElementSibling?.nextElementSibling) { currentElement.classList.remove("emojis__item--current"); newCurrentElement = currentElement.parentElement.nextElementSibling.nextElementSibling.firstElementChild as HTMLElement; } } if (newCurrentElement) { newCurrentElement.classList.add("emojis__item--current"); const topHeight = 4; const emojisContentElement = this.element.querySelector(".emojis__panel"); if (newCurrentElement.offsetTop - topHeight < emojisContentElement.scrollTop) { emojisContentElement.scrollTop = newCurrentElement.offsetTop - topHeight; } else if (newCurrentElement.offsetTop - topHeight - emojisContentElement.clientHeight + newCurrentElement.clientHeight > emojisContentElement.scrollTop) { emojisContentElement.scrollTop = newCurrentElement.offsetTop - topHeight - emojisContentElement.clientHeight + newCurrentElement.clientHeight; } } event.preventDefault(); event.stopPropagation(); return true; } else if (event.key === "ArrowDown" || event.key === "ArrowUp") { upDownHint(this.element, event); event.preventDefault(); event.stopPropagation(); return true; } return false; } private getKey(currentLineValue: string, extend: IHintExtend[]) { this.lastIndex = -1; this.splitChar = ""; extend.forEach((item) => { const currentLastIndex = currentLineValue.lastIndexOf(item.key); if (this.lastIndex < currentLastIndex) { if (Constants.BLOCK_HINT_KEYS.includes(this.splitChar) && (item.key === ":" || item.key === "#" || item.key === "/" || item.key === "、")) { // 块搜索中忽略以上符号 } else if (this.splitChar === "#" && (item.key === "/" || item.key === "、")) { // 标签中忽略以上符号 } else { this.splitChar = item.key; this.lastIndex = currentLastIndex; } } }); if (this.lastIndex === -1) { return undefined; } // 冒号前为数字或冒号不进行emoji提示 if (this.splitChar === ":" && ( /\d/.test(currentLineValue.substr(this.lastIndex - 1, 1)) || currentLineValue.substr(this.lastIndex - 1, 2) === "::" )) { this.enableEmoji = false; } const lineArray = currentLineValue.split(this.splitChar); const lastItem = lineArray[lineArray.length - 1]; if (lineArray.length > 1 && lastItem.trim() === lastItem && lastItem.length < Constants.SIZE_TITLE) { // 输入法自动补全 https://github.com/siyuan-note/insider/issues/100 if (this.splitChar === "【【" && currentLineValue.endsWith("【【】")) { return ""; } return lastItem; } return undefined; } }