@@ -215,7 +216,11 @@ class NoteListRenderer {
if (highlightedTokens.length > 0) {
await libraryLoader.requireLibrary(libraryLoader.MARKJS);
- this.highlightRegex = new RegExp(highlightedTokens.join("|"), 'gi');
+ const regex = highlightedTokens
+ .map(token => utils.escapeRegExp(token))
+ .join("|");
+
+ this.highlightRegex = new RegExp(regex, 'gi');
} else {
this.highlightRegex = null;
}
diff --git a/src/public/app/widgets/type_widgets/canvas.js b/src/public/app/widgets/type_widgets/canvas.js
index 628b6116a..b0be9f845 100644
--- a/src/public/app/widgets/type_widgets/canvas.js
+++ b/src/public/app/widgets/type_widgets/canvas.js
@@ -1,10 +1,8 @@
-import libraryLoader from "../../services/library_loader.js";
-import TypeWidget from "./type_widget.js";
+import libraryLoader from '../../services/library_loader.js';
+import TypeWidget from './type_widget.js';
import utils from '../../services/utils.js';
import linkService from '../../services/link.js';
-import debounce from "../../services/debounce.js";
-
-const {sleep} = utils;
+import debounce from '../../services/debounce.js';
const TPL = `
@@ -115,7 +113,6 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
this.currentSceneVersion = this.SCENE_VERSION_INITIAL;
// will be overwritten
- this.excalidrawRef;
this.$render;
this.$widget;
this.reactHandlers; // used to control react state
@@ -155,7 +152,8 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
const renderElement = this.$render.get(0);
ReactDOM.unmountComponentAtNode(renderElement);
- ReactDOM.render(React.createElement(this.createExcalidrawReactApp), renderElement);
+ const root = ReactDOM.createRoot(renderElement);
+ root.render(React.createElement(this.createExcalidrawReactApp));
});
return this.$widget;
@@ -179,9 +177,9 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
const blob = await note.getBlob();
// before we load content into excalidraw, make sure excalidraw has loaded
- while (!this.excalidrawRef?.current) {
- console.log("excalidrawRef not yet loaded, sleep 200ms...");
- await sleep(200);
+ while (!this.excalidrawApi) {
+ console.log("excalidrawApi not yet loaded, sleep 200ms...");
+ await utils.sleep(200);
}
/**
@@ -199,7 +197,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
collaborators: []
};
- this.excalidrawRef.current.updateScene(sceneData);
+ this.excalidrawApi.updateScene(sceneData);
}
else if (blob.content) {
// load saved content into excalidraw canvas
@@ -246,9 +244,9 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
fileArray.push(file);
}
- this.excalidrawRef.current.updateScene(sceneData);
- this.excalidrawRef.current.addFiles(fileArray);
- this.excalidrawRef.current.history.clear();
+ this.excalidrawApi.updateScene(sceneData);
+ this.excalidrawApi.addFiles(fileArray);
+ this.excalidrawApi.history.clear();
}
Promise.all(
@@ -261,7 +259,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
}
const libraryItems = blobs.map(blob => blob.getJsonContentSafely()).filter(item => !!item);
- this.excalidrawRef.current.updateLibrary({libraryItems, merge: false});
+ this.excalidrawApi.updateLibrary({libraryItems, merge: false});
});
// set initial scene version
@@ -275,17 +273,17 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
* this is automatically called after this.saveData();
*/
async getData() {
- const elements = this.excalidrawRef.current.getSceneElements();
- const appState = this.excalidrawRef.current.getAppState();
+ const elements = this.excalidrawApi.getSceneElements();
+ const appState = this.excalidrawApi.getAppState();
/**
* A file is not deleted, even though removed from canvas. Therefore, we only keep
* files that are referenced by an element. Maybe this will change with a new excalidraw version?
*/
- const files = this.excalidrawRef.current.getFiles();
+ const files = this.excalidrawApi.getFiles();
// parallel svg export to combat bitrot and enable rendering image for note inclusion, preview, and share
- const svg = await window.ExcalidrawLib.exportToSvg({
+ const svg = await ExcalidrawLib.exportToSvg({
elements,
appState,
exportPadding: 5, // 5 px padding
@@ -321,7 +319,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
// this.libraryChanged is unset in dataSaved()
// there's no separate method to get library items, so have to abuse this one
- const libraryItems = await this.excalidrawRef.current.updateLibrary({merge: true});
+ const libraryItems = await this.excalidrawApi.updateLibrary({merge: true});
let position = 10;
@@ -379,9 +377,6 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
createExcalidrawReactApp() {
const React = window.React;
const { Excalidraw } = window.ExcalidrawLib;
-
- const excalidrawRef = React.useRef(null);
- this.excalidrawRef = excalidrawRef;
const excalidrawWrapperRef = React.useRef(null);
this.excalidrawWrapperRef = excalidrawWrapperRef;
const [dimensions, setDimensions] = React.useState({
@@ -439,7 +434,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
React.createElement(Excalidraw, {
// this makes sure that 1) manual theme switch button is hidden 2) theme stays as it should after opening menu
theme: this.themeStyle,
- ref: excalidrawRef,
+ excalidrawAPI: api => { this.excalidrawApi = api; },
width: dimensions.width,
height: dimensions.height,
onPaste: (data, event) => {
@@ -483,8 +478,8 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
}
getSceneVersion() {
- if (this.excalidrawRef) {
- const elements = this.excalidrawRef.current.getSceneElements();
+ if (this.excalidrawApi) {
+ const elements = this.excalidrawApi.getSceneElements();
return window.ExcalidrawLib.getSceneVersion(elements);
} else {
return this.SCENE_VERSION_ERROR;
diff --git a/src/public/stylesheets/theme-dark.css b/src/public/stylesheets/theme-dark.css
index 7d948d169..3391eaa44 100644
--- a/src/public/stylesheets/theme-dark.css
+++ b/src/public/stylesheets/theme-dark.css
@@ -88,3 +88,7 @@ body .CodeMirror {
.excalidraw.theme--dark {
--theme-filter: invert(80%) hue-rotate(180deg) !important;
}
+
+body .todo-list input[type="checkbox"]:not(:checked):before {
+ border-color: var(--muted-text-color) !important;
+}
diff --git a/src/services/build.js b/src/services/build.js
index f42c6d8df..7818202a8 100644
--- a/src/services/build.js
+++ b/src/services/build.js
@@ -1 +1 @@
-module.exports = { buildDate:"2024-01-21T23:49:23+01:00", buildRevision: "4f8073daa7cff1b8b6737ae45792b2e87c2adf33" };
+module.exports = { buildDate:"2024-03-03T06:58:18+01:00", buildRevision: "0ad337c8e806ba84d48d7b97aa46df52d9f236a8" };
diff --git a/src/services/search/expressions/note_content_fulltext.js b/src/services/search/expressions/note_content_fulltext.js
index 6a5466a3e..98b8a804f 100644
--- a/src/services/search/expressions/note_content_fulltext.js
+++ b/src/services/search/expressions/note_content_fulltext.js
@@ -111,11 +111,7 @@ class NoteContentFulltextExp extends Expression {
if (type === 'text' && mime === 'text/html') {
if (!this.raw && content.length < 20000) { // striptags is slow for very large notes
- // allow link to preserve URLs: https://github.com/zadam/trilium/issues/2412
- content = striptags(content, ['a'], ' ');
-
- // at least the closing tag can be easily stripped
- content = content.replace(/<\/a>/ig, "");
+ content = this.stripTags(content);
}
content = content.replace(/ /g, ' ');
@@ -123,6 +119,23 @@ class NoteContentFulltextExp extends Expression {
return content.trim();
}
+
+ stripTags(content) {
+ // we want to allow link to preserve URLs: https://github.com/zadam/trilium/issues/2412
+ // we want to insert space in place of block tags (because they imply text separation)
+ // but we don't want to insert text for typical formatting inline tags which can occur within one word
+ const linkTag = 'a';
+ const inlineFormattingTags = ['b', 'strong', 'em', 'i', 'span', 'big', 'small', 'font', 'sub', 'sup'];
+
+ // replace tags which imply text separation with a space
+ content = striptags(content, [linkTag, ...inlineFormattingTags], ' ');
+
+ // replace the inline formatting tags (but not links) without a space
+ content = striptags(content, [linkTag], '');
+
+ // at least the closing link tag can be easily stripped
+ return content.replace(/<\/a>/ig, "");
+ }
}
module.exports = NoteContentFulltextExp;