diff --git a/app/src/history/history.ts b/app/src/history/history.ts index 2bd651f95..2edde5efe 100644 --- a/app/src/history/history.ts +++ b/app/src/history/history.ts @@ -15,7 +15,7 @@ import {openModel} from "../mobile/menu/model"; import {closeModel} from "../mobile/util/closePanel"; import {App} from "../index"; import {resizeSide} from "./resizeSide"; -import {isSupportCSSHL, searchMarkRender, searchTextMarkRender} from "../protyle/render/searchMarkRender"; +import {isSupportCSSHL, searchMarkRender} from "../protyle/render/searchMarkRender"; let historyEditor: Protyle; @@ -39,6 +39,7 @@ const renderDoc = (element: HTMLElement, currentPage: number) => { const assetElement = element.querySelector('.history__text[data-type="assetPanel"]'); const mdElement = element.querySelector('.history__text[data-type="mdPanel"]') as HTMLTextAreaElement; const listElement = element.querySelector(".b3-list"); + element.querySelector(".protyle-title__input").classList.add("fn__none"); assetElement.classList.add("fn__none"); mdElement.classList.add("fn__none"); docElement.classList.add("fn__none"); @@ -399,7 +400,7 @@ export const openHistory = (app: App) => {
-
+
@@ -693,16 +694,16 @@ const bindEvent = (app: App, element: Element, dialog?: Dialog) => { assetElement.classList.remove("fn__none"); assetElement.innerHTML = renderAssetsPreview(dataPath); } else if (type === "doc") { + const k = (firstPanelElement.querySelector(".b3-text-field") as HTMLInputElement).value fetchPost("/api/history/getDocHistoryContent", { historyPath: dataPath, highlight: !isSupportCSSHL(), - k: (firstPanelElement.querySelector(".b3-text-field") as HTMLInputElement).value + k }, (response) => { if (response.data.isLargeDoc) { mdElement.value = response.data.content; mdElement.classList.remove("fn__none"); docElement.classList.add("fn__none"); - searchTextMarkRender(historyEditor.protyle, ["TODO"], mdElement); } else { mdElement.classList.add("fn__none"); docElement.classList.remove("fn__none"); @@ -712,10 +713,11 @@ const bindEvent = (app: App, element: Element, dialog?: Dialog) => { protyle: historyEditor.protyle, action: [Constants.CB_GET_HISTORY, Constants.CB_GET_HTML], }); - searchMarkRender(historyEditor.protyle, ["TODO"], false); + searchMarkRender(historyEditor.protyle, k.split(" "), false); } }); } + titleElement.classList.remove("fn__none") titleElement.textContent = target.querySelector(".b3-list-item__text").textContent; let currentItem = hasClosestByClassName(target, "b3-list") as HTMLElement; if (currentItem) { diff --git a/app/src/layout/dock/Backlink.ts b/app/src/layout/dock/Backlink.ts index d06b6f7a9..b088b6753 100644 --- a/app/src/layout/dock/Backlink.ts +++ b/app/src/layout/dock/Backlink.ts @@ -434,11 +434,12 @@ export class Backlink extends Model { }); svgElement.removeAttribute("disabled"); } else { + const keyword = isMention ? this.inputsElement[1].value : this.inputsElement[0].value fetchPost(isMention ? "/api/ref/getBackmentionDoc" : "/api/ref/getBacklinkDoc", { defID: this.blockId, refTreeID: docId, highlight: !isSupportCSSHL(), - keyword: isMention ? this.inputsElement[1].value : this.inputsElement[0].value, + keyword, }, (response) => { svgElement.removeAttribute("disabled"); svgElement.classList.add("b3-list-item__arrow--open"); @@ -458,7 +459,7 @@ export class Backlink extends Model { } }); editor.protyle.notebookId = liElement.getAttribute("data-notebook-id"); - searchMarkRender(editor.protyle, ["TODO"], false); + searchMarkRender(editor.protyle, keyword.split(" "), false); this.editors.push(editor); }); } diff --git a/app/src/protyle/render/searchMarkRender.ts b/app/src/protyle/render/searchMarkRender.ts index a172cd026..e7aeec82d 100644 --- a/app/src/protyle/render/searchMarkRender.ts +++ b/app/src/protyle/render/searchMarkRender.ts @@ -28,6 +28,9 @@ export const searchMarkRender = (protyle: IProtyle, keys: string[], isHL: boolea const rangeIndexes: { range: Range, startIndex: number }[] = []; keys.forEach(key => { + if (!key) { + return; + } let startIndex = 0; let endIndex = 0; let currentNodeIndex = 0; @@ -76,72 +79,6 @@ export const searchMarkRender = (protyle: IProtyle, keys: string[], isHL: boolea }, protyle.wysiwyg.element.querySelector(".hljs") ? Constants.TIMEOUT_TRANSITION : 0); }; - -export const searchTextMarkRender = (protyle: IProtyle, keys: string[], element: HTMLElement,) => { - if (!isSupportCSSHL()) { - return; - } - protyle.highlight.markHL.clear(); - protyle.highlight.mark.clear(); - - - // 准备一个数组来保存所有文本节点 - const textNodes: Node[] = []; - const textNodesSize: number[] = []; - let currentSize = 0; - - const treeWalker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT); - let currentNode = treeWalker.nextNode(); - while (currentNode) { - textNodes.push(currentNode); - currentSize += currentNode.textContent.length - textNodesSize.push(currentSize); - currentNode = treeWalker.nextNode(); - } - - const text = element.textContent; - const rangeIndexes: { range: Range, startIndex: number }[] = []; - - keys.forEach(key => { - let startIndex = 0; - let endIndex = 0; - let currentNodeIndex = 0; - while ((startIndex = text.indexOf(key, startIndex)) !== -1) { - const range = new Range(); - endIndex = startIndex + key.length; - try { - while (currentNodeIndex < textNodes.length && textNodesSize[currentNodeIndex] <= startIndex) { - currentNodeIndex++; - } - let currentTextNode = textNodes[currentNodeIndex]; - range.setStart(currentTextNode, startIndex - (currentNodeIndex ? textNodesSize[currentNodeIndex - 1] : 0)); - - while (currentNodeIndex < textNodes.length && textNodesSize[currentNodeIndex] < endIndex) { - currentNodeIndex++ - } - currentTextNode = textNodes[currentNodeIndex] - range.setEnd(currentTextNode, endIndex - (currentNodeIndex ? textNodesSize[currentNodeIndex - 1] : 0)); - - rangeIndexes.push({range, startIndex}); - } catch (e) { - console.error("searchMarkRender error:", e); - } - startIndex = endIndex; - } - }) - - rangeIndexes.sort((b, a) => { - if (a.startIndex > b.startIndex) { - return -1 - } else { - return 0 - } - }).forEach((item, index) => { - protyle.highlight.mark.add(item.range); - }); - CSS.highlights.set("search-mark-" + protyle.highlight.styleElement.dataset.uuid, protyle.highlight.mark); -} - export const isSupportCSSHL = () => { return !!(CSS && CSS.highlights); } diff --git a/app/src/protyle/scroll/saveScroll.ts b/app/src/protyle/scroll/saveScroll.ts index 7b84a105c..d85aaca14 100644 --- a/app/src/protyle/scroll/saveScroll.ts +++ b/app/src/protyle/scroll/saveScroll.ts @@ -53,7 +53,7 @@ export const getDocByScroll = (options: { protyle: IProtyle, scrollAttr?: IScrollAttr, mergedOptions?: IProtyleOptions, - cb?: () => void + cb?: (keys: string[]) => void focus?: boolean, updateReadonly?: boolean }) => { @@ -89,7 +89,9 @@ export const getDocByScroll = (options: { protyle: options.protyle, action: actions, scrollAttr: options.scrollAttr, - afterCB: options.cb, + afterCB: options.cb ? () => { + options.cb(response.data.keywords); + } : undefined, updateReadonly: options.updateReadonly }); }); @@ -100,7 +102,9 @@ export const getDocByScroll = (options: { protyle: options.protyle, action: actions, scrollAttr: options.scrollAttr, - afterCB: options.cb, + afterCB: options.cb ? () => { + options.cb(response.data.keywords); + } : undefined, updateReadonly: options.updateReadonly }); } @@ -121,7 +125,9 @@ export const getDocByScroll = (options: { protyle: options.protyle, action: actions, scrollAttr: options.scrollAttr, - afterCB: options.cb, + afterCB: options.cb ? () => { + options.cb(response.data.keywords); + } : undefined, updateReadonly: options.updateReadonly }); }); diff --git a/app/src/protyle/util/reload.ts b/app/src/protyle/util/reload.ts index 6aa6d0107..21ee812d5 100644 --- a/app/src/protyle/util/reload.ts +++ b/app/src/protyle/util/reload.ts @@ -37,15 +37,16 @@ export const reloadProtyle = (protyle: IProtyle, focus: boolean, updateReadonly? const tabElement = hasClosestByClassName(protyle.element, "sy__backlink"); if (tabElement) { const inputsElement = tabElement.querySelectorAll(".b3-text-field") as NodeListOf; + const keyword = isMention ? inputsElement[1].value : inputsElement[0].value fetchPost(isMention ? "/api/ref/getBackmentionDoc" : "/api/ref/getBacklinkDoc", { defID: protyle.element.getAttribute("data-defid"), refTreeID: protyle.block.rootID, highlight: !isSupportCSSHL(), - keyword: isMention ? inputsElement[1].value : inputsElement[0].value, + keyword, }, response => { protyle.options.backlinkData = isMention ? response.data.backmentions : response.data.backlinks; renderBacklink(protyle, protyle.options.backlinkData); - searchMarkRender(protyle, ["TODO"], false); + searchMarkRender(protyle, keyword.split(" "), false); }); } } else { @@ -55,9 +56,9 @@ export const reloadProtyle = (protyle: IProtyle, focus: boolean, updateReadonly? focus, scrollAttr: saveScroll(protyle, true) as IScrollAttr, updateReadonly, - cb() { + cb(keys) { if (protyle.query?.key) { - searchMarkRender(protyle, ["TODO"], true); + searchMarkRender(protyle, keys, true); } } }); diff --git a/app/src/search/util.ts b/app/src/search/util.ts index e84dbff5d..a13e0596f 100644 --- a/app/src/search/util.ts +++ b/app/src/search/util.ts @@ -1239,7 +1239,7 @@ export const getArticle = (options: { let matchRectTop: number; if (isSupportCSSHL()) { options.edit.protyle.highlight.rangeIndex = 0; - searchMarkRender(options.edit.protyle, ["TODO", "得到"], true); + searchMarkRender(options.edit.protyle, getResponse.data.keywords, true); matchRectTop = options.edit.protyle.highlight.ranges[0].getBoundingClientRect().top; } else { const matchElements = options.edit.protyle.wysiwyg.element.querySelectorAll('span[data-type~="search-mark"]');