').append($svgHtml));
} catch(err) {
console.error("error parsing fullNoteRevision.content as JSON", fullNoteRevision.content, err);
$content.html($("
").text("Error parsing content. Please check console.error() for more details."));
diff --git a/src/public/app/widgets/type_widgets/canvas_note.js b/src/public/app/widgets/type_widgets/canvas_note.js
index fa8cb1b37..f56f98ceb 100644
--- a/src/public/app/widgets/type_widgets/canvas_note.js
+++ b/src/public/app/widgets/type_widgets/canvas_note.js
@@ -70,7 +70,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
// will be overwritten
this.excalidrawRef;
this.$render;
- this.$renderElement;
+ this.renderElement;
this.$widget;
this.reactHandlers; // used to control react state
@@ -114,7 +114,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
// this.contentSized();
this.$widget.toggleClass("full-height", true); // only add
this.$render = this.$widget.find('.canvas-note-render');
- this.$renderElement = this.$render.get(0);
+ this.renderElement = this.$render.get(0);
// this.log("doRender", this.$widget);
libraryLoader
@@ -125,8 +125,8 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
const React = window.React;
const ReactDOM = window.ReactDOM;
- ReactDOM.unmountComponentAtNode(this.$renderElement);
- ReactDOM.render(React.createElement(this.ExcalidrawReactApp), this.$renderElement);
+ ReactDOM.unmountComponentAtNode(this.renderElement);
+ ReactDOM.render(React.createElement(this.ExcalidrawReactApp), this.renderElement);
})
return this.$widget;
From 2394fe6ed958f6d915aaefa53177b621731b10b1 Mon Sep 17 00:00:00 2001
From: Tom <7283497+thfrei@users.noreply.github.com>
Date: Mon, 9 May 2022 15:16:12 +0200
Subject: [PATCH 63/86] reduce redundant package version to simplify upgrade
---
src/public/app/services/library_loader.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/public/app/services/library_loader.js b/src/public/app/services/library_loader.js
index 7411b0dc9..a80ac1cbf 100644
--- a/src/public/app/services/library_loader.js
+++ b/src/public/app/services/library_loader.js
@@ -58,9 +58,9 @@ const MERMAID = {
const EXCALIDRAW = {
js: [
- "node_modules/react/umd/react.production.min.js", //v17.0.2
- "node_modules/react-dom/umd/react-dom.production.min.js", //v17.0.2
- "node_modules/@excalidraw/excalidraw/dist/excalidraw.production.min.js", //v.0.11.0
+ "node_modules/react/umd/react.production.min.js",
+ "node_modules/react-dom/umd/react-dom.production.min.js",
+ "node_modules/@excalidraw/excalidraw/dist/excalidraw.production.min.js",
],
// css: [
// "stylesheets/somestyle.css"
From dfa30358c560a958edae00304e4de343efedafe8 Mon Sep 17 00:00:00 2001
From: Tom <7283497+thfrei@users.noreply.github.com>
Date: Mon, 9 May 2022 16:08:56 +0200
Subject: [PATCH 64/86] ensure external assets in excalidraw are avoided
---
libraries/excalidraw/canvas_note_share.js | 3 ++-
src/app.js | 7 +++++--
src/public/app/dialogs/note_revisions.js | 1 -
.../canvas-note-utils/replaceExternalAssets.js | 16 ++++++++++++++++
.../app/widgets/type_widgets/canvas_note.js | 10 ++++++----
src/share/content_renderer.js | 3 +++
6 files changed, 32 insertions(+), 8 deletions(-)
create mode 100644 src/public/app/widgets/type_widgets/canvas-note-utils/replaceExternalAssets.js
diff --git a/libraries/excalidraw/canvas_note_share.js b/libraries/excalidraw/canvas_note_share.js
index a0c47fc65..3662f81b3 100644
--- a/libraries/excalidraw/canvas_note_share.js
+++ b/libraries/excalidraw/canvas_note_share.js
@@ -9,7 +9,8 @@ const App = () => {
height: appState.height,
});
const [viewModeEnabled, setViewModeEnabled] = React.useState(false);
- console.log("no render?");
+
+ // ensure that assets are loaded from trilium
/**
* resizing
diff --git a/src/app.js b/src/app.js
index c024e15c0..abc3c2451 100644
--- a/src/app.js
+++ b/src/app.js
@@ -30,8 +30,11 @@ app.use(express.urlencoded({extended: false}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/libraries', express.static(path.join(__dirname, '..', 'libraries')));
-// node_modules required for excalidraw-view mode in shared notes
-app.use('/node_modules', express.static(path.join(__dirname, '..', 'node_modules')));
+// excalidraw-view mode in shared notes
+app.use('/node_modules/react/umd/react.production.min.js', express.static(path.join(__dirname, '..', 'node_modules/react/umd/react.production.min.js')));
+app.use('/node_modules/react-dom/umd/react-dom.production.min.js', express.static(path.join(__dirname, '..', 'node_modules/react-dom/umd/react-dom.production.min.js')));
+// expose whole dist folder since complete assets are needed in edit and share
+app.use('/node_modules/@excalidraw/excalidraw/dist/', express.static(path.join(__dirname, '..', 'node_modules/@excalidraw/excalidraw/dist/')));
app.use('/images', express.static(path.join(__dirname, '..', 'images')));
const sessionParser = session({
secret: sessionSecret,
diff --git a/src/public/app/dialogs/note_revisions.js b/src/public/app/dialogs/note_revisions.js
index c0333b525..19e5f8b81 100644
--- a/src/public/app/dialogs/note_revisions.js
+++ b/src/public/app/dialogs/note_revisions.js
@@ -183,7 +183,6 @@ async function setContentPane() {
const svg = data.svg || "no svg present."
/**
- * Debatable
* maxWidth: 100% use full width of container but do not enlarge!
* height:auto to ensure that height scales with width
*/
diff --git a/src/public/app/widgets/type_widgets/canvas-note-utils/replaceExternalAssets.js b/src/public/app/widgets/type_widgets/canvas-note-utils/replaceExternalAssets.js
new file mode 100644
index 000000000..d2ecfced8
--- /dev/null
+++ b/src/public/app/widgets/type_widgets/canvas-note-utils/replaceExternalAssets.js
@@ -0,0 +1,16 @@
+/**
+ * replaces exlicraw.com and unpkg.com with own assets
+ *
+ * workaround until https://github.com/excalidraw/excalidraw/pull/5065 is merged and published
+ *
+ * @param {string} string
+ * @returns
+ */
+const replaceExternalAssets = (string) => {
+ let result = string;
+ // exlidraw.com asset in react usage
+ result = result.replaceAll("https://excalidraw.com/", window.EXCALIDRAW_ASSET_PATH+"excalidraw-assets/");
+ return result;
+}
+
+export default replaceExternalAssets;
\ No newline at end of file
diff --git a/src/public/app/widgets/type_widgets/canvas_note.js b/src/public/app/widgets/type_widgets/canvas_note.js
index f56f98ceb..001429a5f 100644
--- a/src/public/app/widgets/type_widgets/canvas_note.js
+++ b/src/public/app/widgets/type_widgets/canvas_note.js
@@ -5,6 +5,7 @@ import sleep from './canvas-note-utils/sleep.js';
import froca from "../../services/froca.js";
import debounce from "./canvas-note-utils/lodash.debounce.js";
import uniqueId from "./canvas-note-utils/lodash.uniqueId.js";
+import replaceExternalAssets from "./canvas-note-utils/replaceExternalAssets.js";
const TPL = `
@@ -156,7 +157,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
/**
* before we load content into excalidraw, make sure excalidraw has loaded
*/
- while (!this.excalidrawRef) {
+ while (!this.excalidrawRef || !this.excalidrawRef.current) {
this.log("doRefresh! excalidrawref not yet loeaded, sleep 200ms...");
await sleep(200);
}
@@ -259,10 +260,11 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
files
});
const svgString = svg.outerHTML;
+
/**
- * workaround until https://github.com/excalidraw/excalidraw/pull/5065 is merged
+ * workaround until https://github.com/excalidraw/excalidraw/pull/5065 is merged and published
*/
- const svgSafeString =svgString.replaceAll("https://excalidraw.com/", window.EXCALIDRAW_ASSET_PATH+"excalidraw-assets/");
+ const svgSafeString = replaceExternalAssets(svgString);
const activeFiles = {};
elements.forEach((element) => {
@@ -276,7 +278,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
elements, // excalidraw
appState, // excalidraw
files: activeFiles, // excalidraw
- svg: svgSafeString, // rendered on every save, not needed for excalidraw
+ svg: svgSafeString, // not needed for excalidraw, used for note_short, content, and image api
};
const contentString = JSON.stringify(content);
diff --git a/src/share/content_renderer.js b/src/share/content_renderer.js
index 399c74136..230f97fd4 100644
--- a/src/share/content_renderer.js
+++ b/src/share/content_renderer.js
@@ -86,6 +86,9 @@ document.addEventListener("DOMContentLoaded", function() {
isEmpty = true;
}
else if (note.type === 'canvas-note') {
+ header += ``;
header += ``;
header += ``;
header += ``;
From 65c725c21eae355c72b5cf1104740ada22afe33d Mon Sep 17 00:00:00 2001
From: Tom <7283497+thfrei@users.noreply.github.com>
Date: Mon, 9 May 2022 16:14:03 +0200
Subject: [PATCH 65/86] add jsdoc to indicate possibility to use getContent
async
---
src/public/app/widgets/type_widgets/type_widget.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/public/app/widgets/type_widgets/type_widget.js b/src/public/app/widgets/type_widgets/type_widget.js
index faa1ff98a..f3dd88317 100644
--- a/src/public/app/widgets/type_widgets/type_widget.js
+++ b/src/public/app/widgets/type_widgets/type_widget.js
@@ -39,8 +39,8 @@ export default class TypeWidget extends NoteContextAwareWidget {
}
/**
- * FIXME: add async here to indicate promise?
- */
+ * @returns {Promise|*} promise resolving content or directly the content
+ */
getContent() {}
focus() {}
From f0f9274a3c9a18bc1b01a6970aba305a0b05e8ef Mon Sep 17 00:00:00 2001
From: Tom <7283497+thfrei@users.noreply.github.com>
Date: Mon, 9 May 2022 16:17:14 +0200
Subject: [PATCH 66/86] remove route without filename
---
src/routes/routes.js | 3 ++-
src/share/routes.js | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/routes/routes.js b/src/routes/routes.js
index 0cd2460c9..eb4308318 100644
--- a/src/routes/routes.js
+++ b/src/routes/routes.js
@@ -285,7 +285,8 @@ function register(app) {
apiRoute(POST, '/api/special-notes/search-note', specialNotesRoute.createSearchNote);
apiRoute(POST, '/api/special-notes/save-search-note', specialNotesRoute.saveSearchNote);
- route(GET, ['/api/images/:noteId/:filename', '/api/images/:noteId'], [auth.checkApiAuthOrElectron], imageRoute.returnImage);
+ // :filename is not used by trilium, but instead used for "save as" to assign a human readable filename
+ route(GET, '/api/images/:noteId/:filename', [auth.checkApiAuthOrElectron], imageRoute.returnImage);
route(POST, '/api/images', [auth.checkApiAuthOrElectron, uploadMiddleware, csrfMiddleware], imageRoute.uploadImage, apiResultHandler);
route(PUT, '/api/images/:noteId', [auth.checkApiAuthOrElectron, uploadMiddleware, csrfMiddleware], imageRoute.updateImage, apiResultHandler);
diff --git a/src/share/routes.js b/src/share/routes.js
index 684dde3e0..edda89e95 100644
--- a/src/share/routes.js
+++ b/src/share/routes.js
@@ -110,6 +110,7 @@ function register(router) {
res.send(note.getContent());
});
+ // :filename is not used by trilium, but instead used for "save as" to assign a human readable filename
router.get('/share/api/images/:noteId/:filename', (req, res, next) => {
shacaLoader.ensureLoad();
From 9c7f8cf5d8219d443ee694c7cbf52d0a15a94de1 Mon Sep 17 00:00:00 2001
From: Tom <7283497+thfrei@users.noreply.github.com>
Date: Mon, 9 May 2022 16:17:37 +0200
Subject: [PATCH 67/86] extract errorSvg
---
src/public/app/services/note_content_renderer.js | 5 +++--
.../type_widgets/canvas-note-utils/errorSvg.js | 11 +++++++++++
2 files changed, 14 insertions(+), 2 deletions(-)
create mode 100644 src/public/app/widgets/type_widgets/canvas-note-utils/errorSvg.js
diff --git a/src/public/app/services/note_content_renderer.js b/src/public/app/services/note_content_renderer.js
index 12c094cf4..a1d06ed92 100644
--- a/src/public/app/services/note_content_renderer.js
+++ b/src/public/app/services/note_content_renderer.js
@@ -7,6 +7,7 @@ import openService from "./open.js";
import froca from "./froca.js";
import utils from "./utils.js";
import linkService from "./link.js";
+import errorSvg from "../widgets/type_widgets/canvas-note-utils/errorSvg";
let idCounter = 1;
@@ -149,9 +150,9 @@ async function getRenderedContent(note, options = {}) {
const content = noteComplement.content || "";
try {
- const errorSvg = `
`;
+ const placeHolderSVG = errorSvg;
const data = JSON.parse(content)
- const svg = data.svg || errorSvg;
+ const svg = data.svg || placeHolderSVG;
/**
* maxWidth: size down to 100% (full) width of container but do not enlarge!
* height:auto to ensure that height scales with width
diff --git a/src/public/app/widgets/type_widgets/canvas-note-utils/errorSvg.js b/src/public/app/widgets/type_widgets/canvas-note-utils/errorSvg.js
new file mode 100644
index 000000000..80b40dae9
--- /dev/null
+++ b/src/public/app/widgets/type_widgets/canvas-note-utils/errorSvg.js
@@ -0,0 +1,11 @@
+/**
+ * used a placeholder, when svg parsing fails
+ */
+const erorrSvg = `
`;
+
+export default erorrSvg;
From 552e5d7d060f1266b9a81bd26627fbe1c33f7d88 Mon Sep 17 00:00:00 2001
From: Tom <7283497+thfrei@users.noreply.github.com>
Date: Mon, 9 May 2022 16:18:06 +0200
Subject: [PATCH 68/86] typo in note.type
---
src/services/export/single.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/services/export/single.js b/src/services/export/single.js
index f7ab87dc4..d3fe2144c 100644
--- a/src/services/export/single.js
+++ b/src/services/export/single.js
@@ -41,7 +41,7 @@ function exportSingleNote(taskContext, branch, format, res) {
extension = mimeTypes.extension(note.mime) || 'code';
mime = note.mime;
}
- else if (note.type === 'relation-map' || note.type === 'canas-note' || note.type === 'search') {
+ else if (note.type === 'relation-map' || note.type === 'canvas-note' || note.type === 'search') {
payload = content;
extension = 'json';
mime = 'application/json';
From 83f1a68bfd5b9c72fb300e4fce6767fb083f324e Mon Sep 17 00:00:00 2001
From: Tom <7283497+thfrei@users.noreply.github.com>
Date: Mon, 9 May 2022 16:26:30 +0200
Subject: [PATCH 69/86] fix errorSvg.js path
---
src/public/app/services/note_content_renderer.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/public/app/services/note_content_renderer.js b/src/public/app/services/note_content_renderer.js
index a1d06ed92..7b446c7aa 100644
--- a/src/public/app/services/note_content_renderer.js
+++ b/src/public/app/services/note_content_renderer.js
@@ -7,7 +7,7 @@ import openService from "./open.js";
import froca from "./froca.js";
import utils from "./utils.js";
import linkService from "./link.js";
-import errorSvg from "../widgets/type_widgets/canvas-note-utils/errorSvg";
+import errorSvg from "../widgets/type_widgets/canvas-note-utils/errorSvg.js";
let idCounter = 1;
From f85ed672cc3b64a3408a900b573d62a20b67a8fa Mon Sep 17 00:00:00 2001
From: Tom <7283497+thfrei@users.noreply.github.com>
Date: Mon, 9 May 2022 16:38:23 +0200
Subject: [PATCH 70/86] moving canvas_note_share to src/share and add routes
---
{libraries/excalidraw => src/share}/canvas_note_share.js | 8 +++++++-
src/share/content_renderer.js | 2 +-
src/share/routes.js | 5 +++++
3 files changed, 13 insertions(+), 2 deletions(-)
rename {libraries/excalidraw => src/share}/canvas_note_share.js (94%)
diff --git a/libraries/excalidraw/canvas_note_share.js b/src/share/canvas_note_share.js
similarity index 94%
rename from libraries/excalidraw/canvas_note_share.js
rename to src/share/canvas_note_share.js
index 3662f81b3..70da159a0 100644
--- a/libraries/excalidraw/canvas_note_share.js
+++ b/src/share/canvas_note_share.js
@@ -1,4 +1,10 @@
-// const {elements, appState, files} = window.triliumExcalidraw;
+/**
+ * this is used as a "standalone js" file and required by a shared note directly via script-tags
+ *
+ * data input comes via window variable as follow
+ * const {elements, appState, files} = window.triliumExcalidraw;
+ */
+
document.getElementById("excalidraw-app").style.height = appState.height+"px";
const App = () => {
diff --git a/src/share/content_renderer.js b/src/share/content_renderer.js
index 230f97fd4..b2731a53d 100644
--- a/src/share/content_renderer.js
+++ b/src/share/content_renderer.js
@@ -114,7 +114,7 @@ document.addEventListener("DOMContentLoaded", function() {
Get Image Link
-
+
`;
}
else {
diff --git a/src/share/routes.js b/src/share/routes.js
index edda89e95..8d55cb9d8 100644
--- a/src/share/routes.js
+++ b/src/share/routes.js
@@ -1,3 +1,6 @@
+const express = require('express');
+const path = require('path');
+
const shaca = require("./shaca/shaca");
const shacaLoader = require("./shaca/shaca_loader");
const shareRoot = require("./share_root");
@@ -55,6 +58,8 @@ function register(router) {
});
}
+ router.use('/share/canvas_note_share.js', express.static(path.join(__dirname, 'canvas_note_share.js')));
+
router.get(['/share', '/share/'], (req, res, next) => {
shacaLoader.ensureLoad();
From 358e8c548cd0778e67a789cda48e166444541992 Mon Sep 17 00:00:00 2001
From: Tom <7283497+thfrei@users.noreply.github.com>
Date: Mon, 9 May 2022 16:47:28 +0200
Subject: [PATCH 71/86] remove branch bugfix
---
src/share/shaca/entities/attribute.js | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/src/share/shaca/entities/attribute.js b/src/share/shaca/entities/attribute.js
index 9898a5f3b..1696312ab 100644
--- a/src/share/shaca/entities/attribute.js
+++ b/src/share/shaca/entities/attribute.js
@@ -36,14 +36,7 @@ class Attribute extends AbstractEntity {
if (linkedChildNote) {
const branch = this.shaca.getBranchFromChildAndParent(linkedChildNote.noteId, this.noteId);
- /**
- * FIXME: why can we have branch is undefined? issue when
- * sharing and not sharing notes? canvas-note specific?
- * This error occured during development.
- */
- if(branch) {
- branch.isHidden = true;
- }
+ branch.isHidden = true;
}
}
From d2975bbd21212d5244449a61141e028b88032925 Mon Sep 17 00:00:00 2001
From: Tom <7283497+thfrei@users.noreply.github.com>
Date: Mon, 9 May 2022 16:47:40 +0200
Subject: [PATCH 72/86] remove obsolete comments
---
src/public/app/widgets/type_widgets/canvas_note.js | 3 ---
1 file changed, 3 deletions(-)
diff --git a/src/public/app/widgets/type_widgets/canvas_note.js b/src/public/app/widgets/type_widgets/canvas_note.js
index 001429a5f..b102ee1dd 100644
--- a/src/public/app/widgets/type_widgets/canvas_note.js
+++ b/src/public/app/widgets/type_widgets/canvas_note.js
@@ -110,9 +110,6 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
doRender() {
this.$widget = $(TPL);
- // leads to contain: none
- // https://developer.mozilla.org/en-US/docs/Web/CSS/contain
- // this.contentSized();
this.$widget.toggleClass("full-height", true); // only add
this.$render = this.$widget.find('.canvas-note-render');
this.renderElement = this.$render.get(0);
From a168edb1686e08d335de5a4f099effbe2fba813b Mon Sep 17 00:00:00 2001
From: Tom <7283497+thfrei@users.noreply.github.com>
Date: Mon, 9 May 2022 16:50:06 +0200
Subject: [PATCH 73/86] move sleep to general utisl function
---
src/public/app/services/utils.js | 9 ++++++++-
.../app/widgets/type_widgets/canvas-note-utils/sleep.js | 7 -------
src/public/app/widgets/type_widgets/canvas_note.js | 5 +++--
3 files changed, 11 insertions(+), 10 deletions(-)
delete mode 100644 src/public/app/widgets/type_widgets/canvas-note-utils/sleep.js
diff --git a/src/public/app/services/utils.js b/src/public/app/services/utils.js
index 213787b10..27db3e5a4 100644
--- a/src/public/app/services/utils.js
+++ b/src/public/app/services/utils.js
@@ -359,6 +359,12 @@ function isValidAttributeName(name) {
return ATTR_NAME_MATCHER.test(name);
}
+function sleep(time_ms) {
+ return new Promise((resolve) => {
+ setTimeout(resolve, time_ms);
+ });
+};
+
export default {
reloadFrontendApp,
parseDate,
@@ -402,5 +408,6 @@ export default {
initHelpButtons,
openHelp,
filterAttributeName,
- isValidAttributeName
+ isValidAttributeName,
+ sleep,
};
diff --git a/src/public/app/widgets/type_widgets/canvas-note-utils/sleep.js b/src/public/app/widgets/type_widgets/canvas-note-utils/sleep.js
deleted file mode 100644
index 40c777f13..000000000
--- a/src/public/app/widgets/type_widgets/canvas-note-utils/sleep.js
+++ /dev/null
@@ -1,7 +0,0 @@
-export const sleep = (time_ms) => {
- return new Promise((resolve) => {
- setTimeout(resolve, time_ms);
- });
-};
-
-export default sleep;
\ No newline at end of file
diff --git a/src/public/app/widgets/type_widgets/canvas_note.js b/src/public/app/widgets/type_widgets/canvas_note.js
index b102ee1dd..700889dd6 100644
--- a/src/public/app/widgets/type_widgets/canvas_note.js
+++ b/src/public/app/widgets/type_widgets/canvas_note.js
@@ -1,12 +1,13 @@
import libraryLoader from "../../services/library_loader.js";
import TypeWidget from "./type_widget.js";
-import appContext from "../../services/app_context.js";
-import sleep from './canvas-note-utils/sleep.js';
+import utils from '../../services/utils.js';
import froca from "../../services/froca.js";
import debounce from "./canvas-note-utils/lodash.debounce.js";
import uniqueId from "./canvas-note-utils/lodash.uniqueId.js";
import replaceExternalAssets from "./canvas-note-utils/replaceExternalAssets.js";
+const {sleep} = utils;
+
const TPL = `
`;
@@ -85,10 +85,10 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
/**
* (trilium)
- * @returns {string} "canvas-note"
+ * @returns {string} "canvas"
*/
static getType() {
- return "canvas-note";
+ return "canvas";
}
/**
@@ -99,7 +99,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
this.$widget = $(TPL);
this.$widget.toggleClass("full-height", true); // only add
- this.$render = this.$widget.find('.canvas-note-render');
+ this.$render = this.$widget.find('.canvas-render');
this.renderElement = this.$render.get(0);
libraryLoader
@@ -249,7 +249,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
})
const content = {
- _meta: "This note has type `canvas-note`. It uses excalidraw and stores an exported svg alongside.",
+ _meta: "This note has type `canvas`. It uses excalidraw and stores an exported svg alongside.",
elements, // excalidraw
appState, // excalidraw
files: activeFiles, // excalidraw
diff --git a/src/routes/api/image.js b/src/routes/api/image.js
index 30e7b9899..7807f1fb9 100644
--- a/src/routes/api/image.js
+++ b/src/routes/api/image.js
@@ -11,7 +11,7 @@ function returnImage(req, res) {
if (!image) {
return res.sendStatus(404);
}
- else if (!["image", "canvas-note"].includes(image.type)){
+ else if (!["image", "canvas"].includes(image.type)){
return res.sendStatus(400);
}
else if (image.isDeleted || image.data === null) {
@@ -20,10 +20,10 @@ function returnImage(req, res) {
}
/**
- * special "image" type. the canvas-note is actually type application/json
+ * special "image" type. the canvas is actually type application/json
* to avoid bitrot and enable usage as referenced image the svg is included.
*/
- if (image.type === 'canvas-note') {
+ if (image.type === 'canvas') {
const content = image.getContent();
try {
const data = JSON.parse(content);
diff --git a/src/services/backend_script_api.js b/src/services/backend_script_api.js
index 305a39c94..dadc40c6a 100644
--- a/src/services/backend_script_api.js
+++ b/src/services/backend_script_api.js
@@ -210,7 +210,7 @@ function BackendScriptApi(currentNote, apiParams) {
* @property {string} parentNoteId - MANDATORY
* @property {string} title - MANDATORY
* @property {string|buffer} content - MANDATORY
- * @property {string} type - text, code, file, image, search, book, relation-map, canvas-note - MANDATORY
+ * @property {string} type - text, code, file, image, search, book, relation-map, canvas - MANDATORY
* @property {string} mime - value is derived from default mimes for type
* @property {boolean} isProtected - default is false
* @property {boolean} isExpanded - default is false
diff --git a/src/services/export/single.js b/src/services/export/single.js
index d3fe2144c..881bb394b 100644
--- a/src/services/export/single.js
+++ b/src/services/export/single.js
@@ -41,7 +41,7 @@ function exportSingleNote(taskContext, branch, format, res) {
extension = mimeTypes.extension(note.mime) || 'code';
mime = note.mime;
}
- else if (note.type === 'relation-map' || note.type === 'canvas-note' || note.type === 'search') {
+ else if (note.type === 'relation-map' || note.type === 'canvas' || note.type === 'search') {
payload = content;
extension = 'json';
mime = 'application/json';
diff --git a/src/services/note_types.js b/src/services/note_types.js
index 2b488424d..cdc890162 100644
--- a/src/services/note_types.js
+++ b/src/services/note_types.js
@@ -9,5 +9,5 @@ module.exports = [
'book',
'note-map',
'mermaid',
- 'canvas-note'
+ 'canvas'
];
\ No newline at end of file
diff --git a/src/services/notes.js b/src/services/notes.js
index 41ad60d09..9accb08d8 100644
--- a/src/services/notes.js
+++ b/src/services/notes.js
@@ -53,7 +53,7 @@ function deriveMime(type, mime) {
mime = 'text/html';
} else if (type === 'code' || type === 'mermaid') {
mime = 'text/plain';
- } else if (['relation-map', 'search', 'canvas-note'].includes(type)) {
+ } else if (['relation-map', 'search', 'canvas'].includes(type)) {
mime = 'application/json';
} else if (['render', 'book'].includes(type)) {
mime = '';
@@ -84,7 +84,7 @@ function copyChildAttributes(parentNote, childNote) {
* - {string} parentNoteId
* - {string} title
* - {*} content
- * - {string} type - text, code, file, image, search, book, relation-map, canvas-note, render
+ * - {string} type - text, code, file, image, search, book, relation-map, canvas, render
*
* Following are optional (have defaults)
* - {string} mime - value is derived from default mimes for type
diff --git a/src/services/utils.js b/src/services/utils.js
index d50716381..85b719d01 100644
--- a/src/services/utils.js
+++ b/src/services/utils.js
@@ -168,7 +168,7 @@ const STRING_MIME_TYPES = [
function isStringNote(type, mime) {
// render and book are string note in the sense that they are expected to contain empty string
- return ["text", "code", "relation-map", "search", "render", "book", "mermaid", "canvas-note"].includes(type)
+ return ["text", "code", "relation-map", "search", "render", "book", "mermaid", "canvas"].includes(type)
|| mime.startsWith('text/')
|| STRING_MIME_TYPES.includes(mime);
}
@@ -192,7 +192,7 @@ function formatDownloadTitle(filename, type, mime) {
if (type === 'text') {
return filename + '.html';
- } else if (['relation-map', 'canvas-note', 'search'].includes(type)) {
+ } else if (['relation-map', 'canvas', 'search'].includes(type)) {
return filename + '.json';
} else {
if (!mime) {
diff --git a/src/share/content_renderer.js b/src/share/content_renderer.js
index b2731a53d..9eb9f5803 100644
--- a/src/share/content_renderer.js
+++ b/src/share/content_renderer.js
@@ -85,7 +85,7 @@ document.addEventListener("DOMContentLoaded", function() {
else if (note.type === 'book') {
isEmpty = true;
}
- else if (note.type === 'canvas-note') {
+ else if (note.type === 'canvas') {
header += ``;
diff --git a/src/share/routes.js b/src/share/routes.js
index 8d55cb9d8..80f2b20d5 100644
--- a/src/share/routes.js
+++ b/src/share/routes.js
@@ -124,11 +124,11 @@ function register(router) {
if (!image) {
return res.status(404).send(`Note '${req.params.noteId}' not found`);
}
- else if (!["image", "canvas-note"].includes(image.type)) {
+ else if (!["image", "canvas"].includes(image.type)) {
return res.status(400).send("Requested note is not a shareable image");
- } else if (image.type === "canvas-note") {
+ } else if (image.type === "canvas") {
/**
- * special "image" type. the canvas-note is actually type application/json
+ * special "image" type. the canvas is actually type application/json
* to avoid bitrot and enable usage as referenced image the svg is included.
*/
const content = image.getContent();
From c85f70e1979e8b9858546110c3522c00e892c10b Mon Sep 17 00:00:00 2001
From: Tom <7283497+thfrei@users.noreply.github.com>
Date: Tue, 10 May 2022 13:47:43 +0200
Subject: [PATCH 83/86] remove obsolete errorSvg
---
src/public/app/services/note_content_renderer.js | 3 +--
.../app/widgets/type_widgets/canvas-utils/errorSvg.js | 11 -----------
2 files changed, 1 insertion(+), 13 deletions(-)
delete mode 100644 src/public/app/widgets/type_widgets/canvas-utils/errorSvg.js
diff --git a/src/public/app/services/note_content_renderer.js b/src/public/app/services/note_content_renderer.js
index 07bd6a8b3..771f860b7 100644
--- a/src/public/app/services/note_content_renderer.js
+++ b/src/public/app/services/note_content_renderer.js
@@ -7,7 +7,6 @@ import openService from "./open.js";
import froca from "./froca.js";
import utils from "./utils.js";
import linkService from "./link.js";
-import errorSvg from "../widgets/type_widgets/canvas-utils/errorSvg.js";
let idCounter = 1;
@@ -150,7 +149,7 @@ async function getRenderedContent(note, options = {}) {
const content = noteComplement.content || "";
try {
- const placeHolderSVG = errorSvg;
+ const placeHolderSVG = "
";
const data = JSON.parse(content)
const svg = data.svg || placeHolderSVG;
/**
diff --git a/src/public/app/widgets/type_widgets/canvas-utils/errorSvg.js b/src/public/app/widgets/type_widgets/canvas-utils/errorSvg.js
deleted file mode 100644
index 80b40dae9..000000000
--- a/src/public/app/widgets/type_widgets/canvas-utils/errorSvg.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * used a placeholder, when svg parsing fails
- */
-const erorrSvg = `
`;
-
-export default erorrSvg;
From 3491e71084fc8d7be0d13cb6611a83f9b6191bdf Mon Sep 17 00:00:00 2001
From: Tom <7283497+thfrei@users.noreply.github.com>
Date: Tue, 10 May 2022 13:53:50 +0200
Subject: [PATCH 84/86] handle note.type changing
---
src/public/app/widgets/type_widgets/canvas.js | 84 ++++++++++---------
1 file changed, 46 insertions(+), 38 deletions(-)
diff --git a/src/public/app/widgets/type_widgets/canvas.js b/src/public/app/widgets/type_widgets/canvas.js
index 85215686a..10785ce9e 100644
--- a/src/public/app/widgets/type_widgets/canvas.js
+++ b/src/public/app/widgets/type_widgets/canvas.js
@@ -159,47 +159,55 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
* load saved content into excalidraw canvas
*/
else if (this.excalidrawRef.current && noteComplement.content) {
+ let content ={
+ elements: [],
+ appState: [],
+ files: [],
+ };
+
try {
- const content = JSON.parse(noteComplement.content || "");
-
- const {elements, appState, files} = content;
-
- /**
- * use widths and offsets of current view, since stored appState has the state from
- * previous edit. using the stored state would lead to pointer mismatch.
- */
- const boundingClientRect = this.excalidrawWrapperRef.current.getBoundingClientRect();
- appState.width = boundingClientRect.width;
- appState.height = boundingClientRect.height;
- appState.offsetLeft = boundingClientRect.left;
- appState.offsetTop = boundingClientRect.top;
-
- const sceneData = {
- elements,
- appState,
- collaborators: []
- };
-
- // files are expected in an array when loading. they are stored as an key-index object
- // see example for loading here:
- // https://github.com/excalidraw/excalidraw/blob/c5a7723185f6ca05e0ceb0b0d45c4e3fbcb81b2a/src/packages/excalidraw/example/App.js#L68
- const fileArray = [];
- for (const fileId in files) {
- const file = files[fileId];
- // TODO: dataURL is replaceable with a trilium image url
- // maybe we can save normal images (pasted) with base64 data url, and trilium images
- // with their respective url! nice
- // file.dataURL = "http://localhost:8080/api/images/ltjOiU8nwoZx/start.png";
- fileArray.push(file);
- }
-
- this.sceneVersion = window.Excalidraw.getSceneVersion(elements);
-
- this.excalidrawRef.current.updateScene(sceneData);
- this.excalidrawRef.current.addFiles(fileArray);
+ content = JSON.parse(noteComplement.content || "");
} catch(err) {
- console.error("Error (note, noteComplement, err)", note, noteComplement, err);
+ console.error("Error parsing content. Probably note.type changed",
+ "Starting with empty canvas"
+ , note, noteComplement, err);
}
+
+ const {elements, appState, files} = content;
+
+ /**
+ * use widths and offsets of current view, since stored appState has the state from
+ * previous edit. using the stored state would lead to pointer mismatch.
+ */
+ const boundingClientRect = this.excalidrawWrapperRef.current.getBoundingClientRect();
+ appState.width = boundingClientRect.width;
+ appState.height = boundingClientRect.height;
+ appState.offsetLeft = boundingClientRect.left;
+ appState.offsetTop = boundingClientRect.top;
+
+ const sceneData = {
+ elements,
+ appState,
+ collaborators: []
+ };
+
+ // files are expected in an array when loading. they are stored as an key-index object
+ // see example for loading here:
+ // https://github.com/excalidraw/excalidraw/blob/c5a7723185f6ca05e0ceb0b0d45c4e3fbcb81b2a/src/packages/excalidraw/example/App.js#L68
+ const fileArray = [];
+ for (const fileId in files) {
+ const file = files[fileId];
+ // TODO: dataURL is replaceable with a trilium image url
+ // maybe we can save normal images (pasted) with base64 data url, and trilium images
+ // with their respective url! nice
+ // file.dataURL = "http://localhost:8080/api/images/ltjOiU8nwoZx/start.png";
+ fileArray.push(file);
+ }
+
+ this.sceneVersion = window.Excalidraw.getSceneVersion(elements);
+
+ this.excalidrawRef.current.updateScene(sceneData);
+ this.excalidrawRef.current.addFiles(fileArray);
}
// set initial scene version
From 26f3c1d45381610fa9a9b4e78d49f9953566aa4b Mon Sep 17 00:00:00 2001
From: Tom <7283497+thfrei@users.noreply.github.com>
Date: Wed, 11 May 2022 09:06:30 +0200
Subject: [PATCH 85/86] rename canvas_note_share to canvas_share to align witih
refactor
---
src/share/{canvas_note_share.js => canvas_share.js} | 0
src/share/content_renderer.js | 2 +-
src/share/routes.js | 2 +-
3 files changed, 2 insertions(+), 2 deletions(-)
rename src/share/{canvas_note_share.js => canvas_share.js} (100%)
diff --git a/src/share/canvas_note_share.js b/src/share/canvas_share.js
similarity index 100%
rename from src/share/canvas_note_share.js
rename to src/share/canvas_share.js
diff --git a/src/share/content_renderer.js b/src/share/content_renderer.js
index 9eb9f5803..6584b4b23 100644
--- a/src/share/content_renderer.js
+++ b/src/share/content_renderer.js
@@ -114,7 +114,7 @@ document.addEventListener("DOMContentLoaded", function() {
Get Image Link
-
+
`;
}
else {
diff --git a/src/share/routes.js b/src/share/routes.js
index 80f2b20d5..ce858ad6b 100644
--- a/src/share/routes.js
+++ b/src/share/routes.js
@@ -58,7 +58,7 @@ function register(router) {
});
}
- router.use('/share/canvas_note_share.js', express.static(path.join(__dirname, 'canvas_note_share.js')));
+ router.use('/share/canvas_share.js', express.static(path.join(__dirname, 'canvas_share.js')));
router.get(['/share', '/share/'], (req, res, next) => {
shacaLoader.ensureLoad();
From 1cbf918024da27dffbace549a17011225638cfb1 Mon Sep 17 00:00:00 2001
From: Tom <7283497+thfrei@users.noreply.github.com>
Date: Wed, 11 May 2022 09:29:54 +0200
Subject: [PATCH 86/86] update comment and discussion about canvas note
---
src/public/app/widgets/type_widgets/canvas.js | 49 +++++++++++++------
1 file changed, 35 insertions(+), 14 deletions(-)
diff --git a/src/public/app/widgets/type_widgets/canvas.js b/src/public/app/widgets/type_widgets/canvas.js
index 10785ce9e..483baa572 100644
--- a/src/public/app/widgets/type_widgets/canvas.js
+++ b/src/public/app/widgets/type_widgets/canvas.js
@@ -31,28 +31,49 @@ const TPL = `
`;
/**
- * ## Excalidraw and SVG
- * 2022-04-16 - @thfrei
+ * # Canvas note with excalidraw
+ * @author thfrei 2022-05-11
*
- * Known issues:
- * - excalidraw-to-svg (node.js) does not render any hand drawn (freedraw) paths. There is an issue with
- * Path2D object not present in node-canvas library used by jsdom. (See Trilium PR for samples and other issues
- * in respective library. Link will be added later). Related links:
+ * Background:
+ * excalidraw gives great support for hand drawn notes. It also allows to include images and support
+ * for sketching. Excalidraw has a vibrant and active community.
+ *
+ * Functionality:
+ * We store the excalidraw assets (elements, appState, files) in the note. In addition to that, we
+ * export the SVG from the canvas on every update. The SVG is also saved in the note. It is used
+ * for displaying any canvas note inside of a text note as an image.
+ *
+ * Paths not taken.
+ * - excalidraw-to-svg (node.js) could be used to avoid storing the svg in the backend.
+ * We could render the SVG on the fly. However, as of now, it does not render any hand drawn
+ * (freedraw) paths. There is an issue with Path2D object not present in node-canvas library
+ * used by jsdom. (See Trilium PR for samples and other issues in respective library.
+ * Link will be added later). Related links:
* - https://github.com/Automattic/node-canvas/pull/2013
* - https://github.com/google/canvas-5-polyfill
* - https://github.com/Automattic/node-canvas/issues/1116
* - https://www.npmjs.com/package/path2d-polyfill
* - excalidraw-to-svg (node.js) takes quite some time to load an image (1-2s)
- * - excalidraw-utils (browser) does render freedraw, however NOT freedraw with background
+ * - excalidraw-utils (browser) does render freedraw, however NOT freedraw with background. It is not
+ * used, since it is a big dependency, and has the same functionality as react + excalidraw.
+ * - infinite-drawing-canvas with fabric.js. This library lacked a lot of feature, excalidraw already
+ * has.
*
- * Due to this issues, we opt to use **only excalidraw in the frontend**. Upon saving, we will also get the SVG
- * output from the live excalidraw instance. We will save this **SVG side by side the native excalidraw format
- * in the trilium note**.
+ * Known issues:
+ * - v0.11.0 of excalidraw does not render freedraw backgrounds in the svg
+ * - the 3 excalidraw fonts should be included in the share and everywhere, so that it is shown
+ * when requiring svg.
*
- * Pro: we will combat bit-rot. Showing the SVG will be very fast, since it is already rendered.
- * Con: The note will get bigger (maybe +30%?), we will generate more bandwith.
- * (However, using trilium desktop instance, does not care too much about bandwidth. Size increase is probably
- * acceptable, as a trade off.)
+ * Discussion of storing svg in the note:
+ * - Pro: we will combat bit-rot. Showing the SVG will be very fast and easy, since it is already there.
+ * - Con: The note will get bigger (~40-50%?), we will generate more bandwith. However, using trilium
+ * desktop instance mitigates that issue.
+ *
+ * Roadmap:
+ * - Support image-notes as reference in excalidraw
+ * - Support canvas note as reference (svg) in other canvas notes.
+ * - Make it easy to include a canvas note inside a text note
+ * - Support for excalidraw libraries. Maybe special code notes with a tag.
*/
export default class ExcalidrawTypeWidget extends TypeWidget {
constructor() {