Notes/src/public/app/widgets/find_in_html.ts

98 lines
3.4 KiB
TypeScript
Raw Normal View History

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 libraryLoader from "../services/library_loader.js";
import utils from "../services/utils.js";
2022-12-01 13:07:23 +01:00
import appContext from "../components/app_context.js";
2025-03-17 22:46:00 +02:00
import type FindWidget 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) {
2022-05-25 23:38:06 +02:00
await libraryLoader.requireLibrary(libraryLoader.MARKJS);
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-01-09 18:07:02 +02:00
return new Promise((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 () => {
this.$results = $content.find(`.${FIND_RESULT_CSS_CLASSNAME}`);
2022-05-26 16:29:54 +02:00
this.currentIndex = 0;
await this.jumpTo();
res({
totalFound: this.$results.length,
2023-09-05 21:00:24 +02:00
currentFound: Math.min(1, this.$results.length)
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();
if ($content) {
$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 offsetTop = 100;
const $current = this.$results.eq(this.currentIndex);
this.$results.removeClass(FIND_RESULT_SELECTED_CSS_CLASSNAME);
if ($current.length) {
$current.addClass(FIND_RESULT_SELECTED_CSS_CLASSNAME);
const position = $current.position().top - offsetTop;
2025-03-17 22:46:00 +02:00
const $content = await this.parent.noteContext?.getContentElement();
if ($content) {
const $contentWidget = appContext.getComponentByEl($content[0]);
$contentWidget.triggerCommand("scrollContainerTo", { position });
}
2022-05-26 16:29:54 +02:00
}
}
2022-05-25 23:38:06 +02:00
}
}