2022-05-25 23:38:06 +02:00
|
|
|
// ck-find-result and ck-find-result_selected are the styles ck-editor
|
|
|
|
// uses for highlighting matches, use the same one on CodeMirror
|
|
|
|
// for consistency
|
|
|
|
import utils from "../services/utils.js";
|
2025-03-17 22:46:00 +02:00
|
|
|
import type FindWidget from "./find.js";
|
2025-03-19 22:00:41 +02:00
|
|
|
import type { FindResult } from "./find.js";
|
2022-05-25 23:38:06 +02:00
|
|
|
|
|
|
|
const FIND_RESULT_SELECTED_CSS_CLASSNAME = "ck-find-result_selected";
|
|
|
|
const FIND_RESULT_CSS_CLASSNAME = "ck-find-result";
|
|
|
|
|
|
|
|
export default class FindInHtml {
|
2025-03-17 22:46:00 +02:00
|
|
|
|
|
|
|
private parent: FindWidget;
|
|
|
|
private currentIndex: number;
|
|
|
|
private $results: JQuery<HTMLElement> | null;
|
|
|
|
|
|
|
|
constructor(parent: FindWidget) {
|
2022-05-25 23:38:06 +02:00
|
|
|
this.parent = parent;
|
2022-05-26 16:29:54 +02:00
|
|
|
this.currentIndex = 0;
|
|
|
|
this.$results = null;
|
2022-05-25 23:38:06 +02:00
|
|
|
}
|
|
|
|
|
2025-03-17 22:46:00 +02:00
|
|
|
async performFind(searchTerm: string, matchCase: boolean, wholeWord: boolean) {
|
2025-03-29 00:51:36 +01:00
|
|
|
await import("script-loader!mark.js/dist/jquery.mark.min.js");
|
|
|
|
|
2025-03-17 22:46:00 +02:00
|
|
|
const $content = await this.parent?.noteContext?.getContentElement();
|
2022-05-25 23:38:06 +02:00
|
|
|
|
2022-05-26 16:29:54 +02:00
|
|
|
const wholeWordChar = wholeWord ? "\\b" : "";
|
|
|
|
const regExp = new RegExp(wholeWordChar + utils.escapeRegExp(searchTerm) + wholeWordChar, matchCase ? "g" : "gi");
|
|
|
|
|
2025-03-19 22:00:41 +02:00
|
|
|
return new Promise<FindResult>((res) => {
|
2025-03-17 22:46:00 +02:00
|
|
|
$content?.unmark({
|
2022-05-26 16:29:54 +02:00
|
|
|
done: () => {
|
|
|
|
$content.markRegExp(regExp, {
|
|
|
|
element: "span",
|
|
|
|
className: FIND_RESULT_CSS_CLASSNAME,
|
|
|
|
separateWordSearch: false,
|
|
|
|
caseSensitive: matchCase,
|
|
|
|
done: async () => {
|
2022-12-21 15:19:05 +01:00
|
|
|
this.$results = $content.find(`.${FIND_RESULT_CSS_CLASSNAME}`);
|
2025-05-08 16:25:44 +08:00
|
|
|
let closestIndex = 0;
|
|
|
|
let minTop = Infinity;
|
|
|
|
|
|
|
|
this.$results.each((i, el) => {
|
|
|
|
const rect = el.getBoundingClientRect();
|
|
|
|
const top = rect.top;
|
|
|
|
|
|
|
|
if (top >= 0 && top < minTop) {
|
|
|
|
minTop = top;
|
|
|
|
closestIndex = i;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
this.currentIndex = closestIndex;
|
2022-05-26 16:29:54 +02:00
|
|
|
await this.jumpTo();
|
|
|
|
|
|
|
|
res({
|
|
|
|
totalFound: this.$results.length,
|
2025-05-08 16:25:44 +08:00
|
|
|
currentFound: this.$results.length > 0 ? closestIndex + 1 : 0
|
2022-05-26 16:29:54 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2022-05-25 23:38:06 +02:00
|
|
|
}
|
|
|
|
|
2025-03-17 22:46:00 +02:00
|
|
|
async findNext(direction: -1 | 1, currentFound: number, nextFound: number) {
|
|
|
|
if (this.$results?.length) {
|
2022-05-26 16:29:54 +02:00
|
|
|
this.currentIndex += direction;
|
|
|
|
|
|
|
|
if (this.currentIndex < 0) {
|
|
|
|
this.currentIndex = this.$results.length - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.currentIndex > this.$results.length - 1) {
|
|
|
|
this.currentIndex = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
await this.jumpTo();
|
|
|
|
}
|
2022-05-25 23:38:06 +02:00
|
|
|
}
|
|
|
|
|
2025-03-17 22:46:00 +02:00
|
|
|
async findBoxClosed(totalFound: number, currentFound: number) {
|
|
|
|
const $content = await this.parent?.noteContext?.getContentElement();
|
2025-05-09 10:00:12 +08:00
|
|
|
if (typeof $content?.unmark === 'function') {
|
2025-03-17 22:46:00 +02:00
|
|
|
$content.unmark();
|
|
|
|
}
|
2022-05-25 23:38:06 +02:00
|
|
|
}
|
|
|
|
|
2022-05-26 16:29:54 +02:00
|
|
|
async jumpTo() {
|
2025-03-17 22:46:00 +02:00
|
|
|
if (this.$results?.length) {
|
2022-05-26 16:29:54 +02:00
|
|
|
const $current = this.$results.eq(this.currentIndex);
|
|
|
|
this.$results.removeClass(FIND_RESULT_SELECTED_CSS_CLASSNAME);
|
2025-05-08 16:25:44 +08:00
|
|
|
$current[0].scrollIntoView();
|
|
|
|
$current.addClass(FIND_RESULT_SELECTED_CSS_CLASSNAME);
|
2022-05-26 16:29:54 +02:00
|
|
|
}
|
2022-05-25 23:38:06 +02:00
|
|
|
}
|
|
|
|
}
|