Browse Source

:art: https://github.com/siyuan-note/siyuan/issues/13343

Vanessa 7 months ago
parent
commit
0f027ed714

+ 1 - 1
app/src/history/history.ts

@@ -712,7 +712,7 @@ const bindEvent = (app: App, element: Element, dialog?: Dialog) => {
                                 protyle: historyEditor.protyle,
                                 action: [Constants.CB_GET_HISTORY, Constants.CB_GET_HTML],
                             });
-                            searchMarkRender(historyEditor.protyle, ["TODO"]);
+                            searchMarkRender(historyEditor.protyle, ["TODO"], false);
                         }
                     });
                 }

+ 1 - 1
app/src/layout/dock/Backlink.ts

@@ -458,7 +458,7 @@ export class Backlink extends Model {
                     }
                 });
                 editor.protyle.notebookId = liElement.getAttribute("data-notebook-id");
-                searchMarkRender(editor.protyle, ["TODO"]);
+                searchMarkRender(editor.protyle, ["TODO"], false);
                 this.editors.push(editor);
             });
         }

+ 71 - 23
app/src/protyle/render/searchMarkRender.ts

@@ -1,31 +1,79 @@
-export const searchMarkRender = (protyle: IProtyle, keys: string[]) => {
+import {Constants} from "../../constants";
+
+export const searchMarkRender = (protyle: IProtyle, keys: string[], isHL:boolean) => {
     if (!isSupportCSSHL()) {
         return;
     }
-    protyle.highlight.markHL.clear();
-    protyle.highlight.markHL.clear();
-    protyle.highlight.ranges = [];
-    matchElements.forEach((item, index) => {
-        const range = new Range();
-        if (item.getAttribute("data-type") === "search-mark") {
-            const contentElement = item.firstChild;
-            item.replaceWith(contentElement);
-            range.selectNodeContents(contentElement);
-        } else {
-            item.setAttribute("data-type", item.getAttribute("data-type").replace(" search-mark", "").replace("search-mark ", ""));
-            range.selectNodeContents(item);
+    setTimeout(() => {
+        protyle.highlight.markHL.clear();
+        protyle.highlight.markHL.clear();
+        protyle.highlight.ranges = [];
+
+
+        // 准备一个数组来保存所有文本节点
+        const textNodes: Node[] = [];
+        const textNodesSize: number[] = [];
+        let currentSize = 0;
+
+        const treeWalker = document.createTreeWalker(protyle.wysiwyg.element, NodeFilter.SHOW_TEXT);
+        let currentNode = treeWalker.nextNode();
+        while (currentNode) {
+            textNodes.push(currentNode);
+            currentSize += currentNode.textContent.length
+            textNodesSize.push(currentSize);
+            currentNode = treeWalker.nextNode();
         }
-        if (index === protyle.highlight.rangeIndex && !protyle.options.backlinkData) {
-            protyle.highlight.markHL.add(range);
-        } else {
-            protyle.highlight.mark.add(range);
+
+        const text = protyle.wysiwyg.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) => {
+            if (index === protyle.highlight.rangeIndex && isHL) {
+                protyle.highlight.markHL.add(item.range);
+            } else {
+                protyle.highlight.mark.add(item.range);
+            }
+            protyle.highlight.ranges.push(item.range);
+        });
+        CSS.highlights.set("search-mark-" + protyle.highlight.styleElement.dataset.uuid, protyle.highlight.mark);
+        if (!protyle.options.backlinkData) {
+            CSS.highlights.set("search-mark-hl-" + protyle.highlight.styleElement.dataset.uuid, protyle.highlight.markHL);
         }
-        protyle.highlight.ranges.push(range);
-    });
-    CSS.highlights.set("search-mark-" + protyle.highlight.styleElement.dataset.uuid, protyle.highlight.mark);
-    if (!protyle.options.backlinkData) {
-        CSS.highlights.set("search-mark-hl-" + protyle.highlight.styleElement.dataset.uuid, protyle.highlight.markHL);
-    }
+    }, protyle.wysiwyg.element.querySelector(".hljs") ? Constants.TIMEOUT_TRANSITION : 0);
 };
 
 

+ 2 - 2
app/src/protyle/util/reload.ts

@@ -45,7 +45,7 @@ export const reloadProtyle = (protyle: IProtyle, focus: boolean, updateReadonly?
             }, response => {
                 protyle.options.backlinkData = isMention ? response.data.backmentions : response.data.backlinks;
                 renderBacklink(protyle, protyle.options.backlinkData);
-                searchMarkRender(protyle, ["TODO"]);
+                searchMarkRender(protyle, ["TODO"], false);
             });
         }
     } else {
@@ -57,7 +57,7 @@ export const reloadProtyle = (protyle: IProtyle, focus: boolean, updateReadonly?
             updateReadonly,
             cb() {
                 if (protyle.query?.key) {
-                    searchMarkRender(protyle, ["TODO"]);
+                    searchMarkRender(protyle, ["TODO"], true);
                 }
             }
         });

+ 1 - 1
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"]);
+                    searchMarkRender(options.edit.protyle, ["TODO", "得到"], true);
                     matchRectTop = options.edit.protyle.highlight.ranges[0].getBoundingClientRect().top;
                 } else {
                     const matchElements = options.edit.protyle.wysiwyg.element.querySelectorAll('span[data-type~="search-mark"]');