mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
findwidget in read only notes WIP
This commit is contained in:
parent
37cb5f5e9a
commit
f250b72563
7
libraries/jquery.mark.es6.min.js
vendored
Normal file
7
libraries/jquery.mark.es6.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -16,7 +16,7 @@ async function convertMarkdownToHtml(text) {
|
|||||||
|
|
||||||
const result = writer.render(parsed);
|
const result = writer.render(parsed);
|
||||||
|
|
||||||
appContext.triggerCommand('executeInTextEditor', {
|
appContext.triggerCommand('executeWithTextEditor', {
|
||||||
callback: textEditor => {
|
callback: textEditor => {
|
||||||
const viewFragment = textEditor.data.processor.toView(result);
|
const viewFragment = textEditor.data.processor.toView(result);
|
||||||
const modelFragment = textEditor.data.toModel(viewFragment);
|
const modelFragment = textEditor.data.toModel(viewFragment);
|
||||||
|
@ -61,10 +61,13 @@ const EXCALIDRAW = {
|
|||||||
"node_modules/react/umd/react.production.min.js",
|
"node_modules/react/umd/react.production.min.js",
|
||||||
"node_modules/react-dom/umd/react-dom.production.min.js",
|
"node_modules/react-dom/umd/react-dom.production.min.js",
|
||||||
"node_modules/@excalidraw/excalidraw/dist/excalidraw.production.min.js",
|
"node_modules/@excalidraw/excalidraw/dist/excalidraw.production.min.js",
|
||||||
],
|
]
|
||||||
// css: [
|
};
|
||||||
// "stylesheets/somestyle.css"
|
|
||||||
// ]
|
const MARKJS = {
|
||||||
|
js: [
|
||||||
|
"libraries/jquery.mark.es6.min.js"
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
async function requireLibrary(library) {
|
async function requireLibrary(library) {
|
||||||
@ -118,5 +121,6 @@ export default {
|
|||||||
WHEEL_ZOOM,
|
WHEEL_ZOOM,
|
||||||
FORCE_GRAPH,
|
FORCE_GRAPH,
|
||||||
MERMAID,
|
MERMAID,
|
||||||
EXCALIDRAW
|
EXCALIDRAW,
|
||||||
|
MARKJS
|
||||||
}
|
}
|
||||||
|
@ -228,7 +228,7 @@ class NoteContext extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getTextEditor(callback) {
|
async getTextEditor(callback) {
|
||||||
return new Promise(resolve => appContext.triggerCommand('executeInTextEditor', {
|
return new Promise(resolve => appContext.triggerCommand('executeWithTextEditor', {
|
||||||
callback,
|
callback,
|
||||||
resolve,
|
resolve,
|
||||||
ntxId: this.ntxId
|
ntxId: this.ntxId
|
||||||
@ -236,7 +236,14 @@ class NoteContext extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getCodeEditor() {
|
async getCodeEditor() {
|
||||||
return new Promise(resolve => appContext.triggerCommand('executeInCodeEditor', {
|
return new Promise(resolve => appContext.triggerCommand('executeWithCodeEditor', {
|
||||||
|
resolve,
|
||||||
|
ntxId: this.ntxId
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
async getContentElement() {
|
||||||
|
return new Promise(resolve => appContext.triggerCommand('executeWithContentElement', {
|
||||||
resolve,
|
resolve,
|
||||||
ntxId: this.ntxId
|
ntxId: this.ntxId
|
||||||
}));
|
}));
|
||||||
|
@ -365,6 +365,10 @@ function sleep(time_ms) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function escapeRegExp(str) {
|
||||||
|
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
reloadFrontendApp,
|
reloadFrontendApp,
|
||||||
parseDate,
|
parseDate,
|
||||||
@ -410,4 +414,5 @@ export default {
|
|||||||
filterAttributeName,
|
filterAttributeName,
|
||||||
isValidAttributeName,
|
isValidAttributeName,
|
||||||
sleep,
|
sleep,
|
||||||
|
escapeRegExp
|
||||||
};
|
};
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
import NoteContextAwareWidget from "./note_context_aware_widget.js";
|
import NoteContextAwareWidget from "./note_context_aware_widget.js";
|
||||||
import FindInText from "./find_in_text.js";
|
import FindInText from "./find_in_text.js";
|
||||||
import FindInCode from "./find_in_code.js";
|
import FindInCode from "./find_in_code.js";
|
||||||
|
import FindInHtml from "./find_in_html.js";
|
||||||
|
|
||||||
const findWidgetDelayMillis = 200;
|
const findWidgetDelayMillis = 200;
|
||||||
const waitForEnter = (findWidgetDelayMillis < 0);
|
const waitForEnter = (findWidgetDelayMillis < 0);
|
||||||
@ -86,6 +87,13 @@ export default class FindWidget extends NoteContextAwareWidget {
|
|||||||
|
|
||||||
this.textHandler = new FindInText(this);
|
this.textHandler = new FindInText(this);
|
||||||
this.codeHandler = new FindInCode(this);
|
this.codeHandler = new FindInCode(this);
|
||||||
|
this.htmlHandler = new FindInHtml(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
async noteSwitched() {
|
||||||
|
await super.noteSwitched();
|
||||||
|
|
||||||
|
await this.closeSearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
doRender() {
|
doRender() {
|
||||||
@ -125,6 +133,42 @@ export default class FindWidget extends NoteContextAwareWidget {
|
|||||||
return this.$widget;
|
return this.$widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findInTextEvent() {
|
||||||
|
if (!this.isActiveNoteContext()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!['text', 'code'].includes(this.note.type) || !this.$findBox.is(":hidden")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const readOnly = await this.noteContext.isReadOnly();
|
||||||
|
|
||||||
|
if (readOnly) {
|
||||||
|
this.handler = this.htmlHandler;
|
||||||
|
} else {
|
||||||
|
this.handler = this.note.type === "code"
|
||||||
|
? this.codeHandler
|
||||||
|
: this.textHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$findBox.show();
|
||||||
|
this.$input.focus();
|
||||||
|
this.$totalFound.text(0);
|
||||||
|
this.$currentFound.text(0);
|
||||||
|
|
||||||
|
const searchTerm = await this.handler.getInitialSearchTerm();
|
||||||
|
|
||||||
|
this.$input.val(searchTerm || "");
|
||||||
|
|
||||||
|
// Directly perform the search if there's some text to
|
||||||
|
// find, without delaying or waiting for enter
|
||||||
|
if (searchTerm !== "") {
|
||||||
|
this.$input.select();
|
||||||
|
await this.performFind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
startSearch() {
|
startSearch() {
|
||||||
// XXX This should clear the previous search immediately in all cases
|
// XXX This should clear the previous search immediately in all cases
|
||||||
// (the search is stale when waitforenter but also while the
|
// (the search is stale when waitforenter but also while the
|
||||||
@ -172,35 +216,6 @@ export default class FindWidget extends NoteContextAwareWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async findInTextEvent() {
|
|
||||||
if (!this.isActiveNoteContext()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only writeable text and code supported
|
|
||||||
const readOnly = await this.noteContext.isReadOnly();
|
|
||||||
|
|
||||||
if (readOnly || !['text', 'code'].includes(this.note.type) || !this.$findBox.is(":hidden")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$findBox.show();
|
|
||||||
this.$input.focus();
|
|
||||||
this.$totalFound.text(0);
|
|
||||||
this.$currentFound.text(0);
|
|
||||||
|
|
||||||
const searchTerm = await this.handler.getInitialSearchTerm();
|
|
||||||
|
|
||||||
this.$input.val(searchTerm || "");
|
|
||||||
|
|
||||||
// Directly perform the search if there's some text to
|
|
||||||
// find, without delaying or waiting for enter
|
|
||||||
if (searchTerm !== "") {
|
|
||||||
this.$input.select();
|
|
||||||
await this.performFind();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Perform the find and highlight the find results. */
|
/** Perform the find and highlight the find results. */
|
||||||
async performFind() {
|
async performFind() {
|
||||||
const searchTerm = this.$input.val();
|
const searchTerm = this.$input.val();
|
||||||
@ -216,6 +231,7 @@ export default class FindWidget extends NoteContextAwareWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async closeSearch() {
|
async closeSearch() {
|
||||||
|
if (this.$findBox.is(":visible")) {
|
||||||
this.$findBox.hide();
|
this.$findBox.hide();
|
||||||
|
|
||||||
// Restore any state, if there's a current occurrence clear markers
|
// Restore any state, if there's a current occurrence clear markers
|
||||||
@ -229,20 +245,9 @@ export default class FindWidget extends NoteContextAwareWidget {
|
|||||||
|
|
||||||
this.searchTerm = null;
|
this.searchTerm = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async entitiesReloadedEvent({loadResults}) {
|
|
||||||
if (loadResults.isNoteContentReloaded(this.noteId)) {
|
|
||||||
this.refresh();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isEnabled() {
|
isEnabled() {
|
||||||
return super.isEnabled() && ['text', 'code'].includes(this.note.type);
|
return super.isEnabled() && ['text', 'code'].includes(this.note.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
get handler() {
|
|
||||||
return this.note.type === "code"
|
|
||||||
? this.codeHandler
|
|
||||||
: this.textHandler;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
// ck-find-result and ck-find-result_selected are the styles ck-editor
|
// ck-find-result and ck-find-result_selected are the styles ck-editor
|
||||||
// uses for highlighting matches, use the same one on CodeMirror
|
// uses for highlighting matches, use the same one on CodeMirror
|
||||||
// for consistency
|
// for consistency
|
||||||
|
import utils from "../services/utils.js";
|
||||||
|
|
||||||
const FIND_RESULT_SELECTED_CSS_CLASSNAME = "ck-find-result_selected";
|
const FIND_RESULT_SELECTED_CSS_CLASSNAME = "ck-find-result_selected";
|
||||||
const FIND_RESULT_CSS_CLASSNAME = "ck-find-result";
|
const FIND_RESULT_CSS_CLASSNAME = "ck-find-result";
|
||||||
|
|
||||||
const escapeRegExp = str => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
||||||
|
|
||||||
export default class FindInCode {
|
export default class FindInCode {
|
||||||
constructor(parent) {
|
constructor(parent) {
|
||||||
|
/** @property {FindWidget} */
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +54,7 @@ export default class FindInCode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (searchTerm !== "") {
|
if (searchTerm !== "") {
|
||||||
searchTerm = escapeRegExp(searchTerm);
|
searchTerm = utils.escapeRegExp(searchTerm);
|
||||||
|
|
||||||
// Find and highlight matches
|
// Find and highlight matches
|
||||||
// Find and highlight matches
|
// Find and highlight matches
|
||||||
|
36
src/public/app/widgets/find_in_html.js
Normal file
36
src/public/app/widgets/find_in_html.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// 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";
|
||||||
|
|
||||||
|
const FIND_RESULT_SELECTED_CSS_CLASSNAME = "ck-find-result_selected";
|
||||||
|
const FIND_RESULT_CSS_CLASSNAME = "ck-find-result";
|
||||||
|
|
||||||
|
export default class FindInHtml {
|
||||||
|
constructor(parent) {
|
||||||
|
/** @property {FindWidget} */
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getInitialSearchTerm() {
|
||||||
|
return ""; // FIXME
|
||||||
|
}
|
||||||
|
|
||||||
|
async performFind(searchTerm, matchCase, wholeWord) {
|
||||||
|
await libraryLoader.requireLibrary(libraryLoader.MARKJS);
|
||||||
|
|
||||||
|
const $content = await this.parent.noteContext.getContentElement();
|
||||||
|
|
||||||
|
$content.markRegExp(new RegExp(utils.escapeRegExp(searchTerm), "gi"));
|
||||||
|
}
|
||||||
|
|
||||||
|
async findNext(direction, currentFound, nextFound) {
|
||||||
|
}
|
||||||
|
|
||||||
|
async cleanup(totalFound, currentFound) {
|
||||||
|
}
|
||||||
|
|
||||||
|
async close() {
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
export default class FindInText {
|
export default class FindInText {
|
||||||
constructor(parent) {
|
constructor(parent) {
|
||||||
|
/** @property {FindWidget} */
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ export default class EditableCodeTypeWidget extends TypeWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeInCodeEditorEvent({resolve, ntxId}) {
|
async executeWithCodeEditorEvent({resolve, ntxId}) {
|
||||||
if (!this.isNoteContext(ntxId)) {
|
if (!this.isNoteContext(ntxId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -229,7 +229,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
|||||||
return !selection.isCollapsed;
|
return !selection.isCollapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeInTextEditorEvent({callback, resolve, ntxId}) {
|
async executeWithTextEditorEvent({callback, resolve, ntxId}) {
|
||||||
if (!this.isNoteContext(ntxId)) {
|
if (!this.isNoteContext(ntxId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -30,4 +30,14 @@ export default class ReadOnlyCodeTypeWidget extends TypeWidget {
|
|||||||
|
|
||||||
this.$content.text(noteComplement.content);
|
this.$content.text(noteComplement.content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async executeWithContentElementEvent({resolve, ntxId}) {
|
||||||
|
if (!this.isNoteContext(ntxId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.initialized;
|
||||||
|
|
||||||
|
resolve(this.$content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,4 +114,14 @@ export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget {
|
|||||||
async refreshIncludedNoteEvent({noteId}) {
|
async refreshIncludedNoteEvent({noteId}) {
|
||||||
this.refreshIncludedNote(this.$content, noteId);
|
this.refreshIncludedNote(this.$content, noteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async executeWithContentElementEvent({resolve, ntxId}) {
|
||||||
|
if (!this.isNoteContext(ntxId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.initialized;
|
||||||
|
|
||||||
|
resolve(this.$content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user