This commit is contained in:
parent
c800731c0a
commit
f7fea18b3b
7 changed files with 110 additions and 12 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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"]`));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
15
app/src/types/index.d.ts
vendored
15
app/src/types/index.d.ts
vendored
|
@ -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?: {
|
||||
|
|
6
app/src/types/protyle.d.ts
vendored
6
app/src/types/protyle.d.ts
vendored
|
@ -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,
|
||||
|
|
Loading…
Add table
Reference in a new issue