Vanessa 2024-11-28 22:59:21 +08:00
parent c800731c0a
commit f7fea18b3b
7 changed files with 110 additions and 12 deletions

View file

@ -18,6 +18,16 @@
outline: none;
}
&::highlight(search-mark) {
background-color: var(--b3-protyle-inline-mark-background);
color: var(--b3-protyle-inline-mark-color);
}
&::highlight(search-mark-hl) {
background-color: var(--b3-theme-primary-lighter);
box-shadow: 0 0 0 .5px var(--b3-theme-on-background);
}
[data-node-id] {
position: relative;

View file

@ -72,6 +72,12 @@ export class Protyle {
element: id,
options: mergedOptions,
block: {},
highlight: {
mark: new Highlight(),
markHL: new Highlight(),
ranges: [],
rangeIndex: 0,
}
};
this.protyle.hint = new Hint(this.protyle);

View file

@ -5,6 +5,10 @@ export const destroy = (protyle: IProtyle) => {
return;
}
hideElements(["util"], protyle);
protyle.highlight.markHL.clear();
protyle.highlight.mark.clear();
protyle.highlight.ranges = [];
protyle.highlight.rangeIndex = 0;
protyle.observer?.disconnect();
protyle.observerLoad?.disconnect();
protyle.element.classList.remove("protyle");

View file

@ -4,6 +4,7 @@ import {getDocByScroll, saveScroll} from "../scroll/saveScroll";
import {renderBacklink} from "../wysiwyg/renderBacklink";
import {hasClosestByClassName} from "./hasClosest";
import {preventScroll} from "../scroll/preventScroll";
import {highlightMark} from "../../search/util";
export const reloadProtyle = (protyle: IProtyle, focus: boolean, updateReadonly?: boolean) => {
if (!protyle.preview.element.classList.contains("fn__none")) {
@ -56,7 +57,12 @@ export const reloadProtyle = (protyle: IProtyle, focus: boolean, updateReadonly?
protyle,
focus,
scrollAttr: saveScroll(protyle, true) as IScrollAttr,
updateReadonly
updateReadonly,
cb () {
if (protyle.query?.key) {
highlightMark(protyle, protyle.wysiwyg.element.querySelectorAll(`span[data-type~="search-mark"]`));
}
}
});
}
};

View file

@ -1159,6 +1159,28 @@ const renderNextSearchMark = (options: {
edit: Protyle,
target: Element,
}) => {
const contentRect = options.edit.protyle.contentElement.getBoundingClientRect();
if (CSS.highlights) {
options.edit.protyle.highlight.markHL.clear();
options.edit.protyle.highlight.mark.clear();
options.edit.protyle.highlight.rangeIndex++;
if (options.edit.protyle.highlight.rangeIndex >= options.edit.protyle.highlight.ranges.length) {
options.edit.protyle.highlight.rangeIndex = 0;
}
let rangeTop
options.edit.protyle.highlight.ranges.forEach((item, index) => {
if (options.edit.protyle.highlight.rangeIndex === index) {
options.edit.protyle.highlight.markHL.add(item);
rangeTop = item.getBoundingClientRect().top
} else {
options.edit.protyle.highlight.mark.add(item);
}
});
if (typeof rangeTop === "number") {
options.edit.protyle.contentElement.scrollTop = options.edit.protyle.contentElement.scrollTop + rangeTop - contentRect.top - contentRect.height / 2;
}
return;
}
let matchElement;
const allMatchElements = Array.from(options.edit.protyle.wysiwyg.element.querySelectorAll(`div[data-node-id="${options.id}"] span[data-type~="search-mark"]`));
allMatchElements.find((item, itemIndex) => {
@ -1173,7 +1195,6 @@ const renderNextSearchMark = (options: {
}
if (matchElement) {
matchElement.classList.add("search-mark--hl");
const contentRect = options.edit.protyle.contentElement.getBoundingClientRect();
options.edit.protyle.contentElement.scrollTop = options.edit.protyle.contentElement.scrollTop + matchElement.getBoundingClientRect().top - contentRect.top - contentRect.height / 2;
}
};
@ -1209,18 +1230,23 @@ export const getArticle = (options: {
updateReadonly: true,
data: getResponse,
protyle: options.edit.protyle,
action: zoomIn ? [Constants.CB_GET_ALL, Constants.CB_GET_HTML] : [Constants.CB_GET_HL, Constants.CB_GET_HTML],
action: zoomIn ? [Constants.CB_GET_ALL, Constants.CB_GET_HTML] : [Constants.CB_GET_HTML],
});
const matchElement = options.edit.protyle.wysiwyg.element.querySelector(`div[data-node-id="${options.id}"] span[data-type~="search-mark"]`);
if (matchElement) {
matchElement.classList.add("search-mark--hl");
const contentRect = options.edit.protyle.contentElement.getBoundingClientRect();
const matchRectTop = matchElement.getBoundingClientRect().top; // 需前置,否则代码高亮后会移除该元素
setTimeout(() => {
// 等待 scrollCenter 定位后再滚动
options.edit.protyle.contentElement.scrollTop = options.edit.protyle.contentElement.scrollTop + matchRectTop - contentRect.top - contentRect.height / 2;
});
const matchElements = options.edit.protyle.wysiwyg.element.querySelectorAll(`div[data-node-id="${options.id}"] span[data-type~="search-mark"]`);
if (matchElements.length === 0) {
return;
}
const contentRect = options.edit.protyle.contentElement.getBoundingClientRect();
let matchRectTop: number
if (CSS.highlights) {
options.edit.protyle.highlight.rangeIndex = 0;
highlightMark(options.edit.protyle, matchElements);
matchRectTop = options.edit.protyle.highlight.ranges[0].getBoundingClientRect().top;
} else {
matchElements[0].classList.add("search-mark--hl");
matchRectTop = matchElements[0].getBoundingClientRect().top;
}
options.edit.protyle.contentElement.scrollTop = options.edit.protyle.contentElement.scrollTop + matchRectTop - contentRect.top - contentRect.height / 2;
});
});
});
@ -1476,3 +1502,28 @@ ${item.tag ? `<span class="b3-list-item__meta b3-list-item__meta--ellipsis">${it
</span>
</div>`);
};
export const highlightMark = (protyle: IProtyle, matchElements: NodeListOf<Element>) => {
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);
}
if (index === protyle.highlight.rangeIndex) {
protyle.highlight.markHL.add(range);
} else {
protyle.highlight.mark.add(range);
}
protyle.highlight.ranges.push(range)
})
CSS.highlights.set("search-mark", protyle.highlight.mark);
CSS.highlights.set("search-mark-hl", protyle.highlight.markHL);
}

View file

@ -107,8 +107,23 @@ type TAVFilterOperator =
| "Is relative to today"
| "Is true"
| "Is false"
declare module "blueimp-md5"
declare class Highlight {
constructor(...range: Range[]);
add(range: Range): void
clear(): void
forEach(callbackfn: (value: Range, key: number) => void): void;
}
declare namespace CSS {
const highlights: Map<string, Highlight>;
}
interface Window {
echarts: {
init(element: HTMLElement, theme?: string, options?: {

View file

@ -482,6 +482,12 @@ interface IProtyleOptions {
}
interface IProtyle {
highlight: {
mark: Highlight
markHL: Highlight
ranges: Range[]
rangeIndex: 0
}
getInstance: () => import("../protyle").Protyle,
observerLoad?: ResizeObserver,
observer?: ResizeObserver,