diff --git a/src/public/app/widgets/note_detail.js b/src/public/app/widgets/note_detail.js index f0d696155..106fc8e1e 100644 --- a/src/public/app/widgets/note_detail.js +++ b/src/public/app/widgets/note_detail.js @@ -74,16 +74,16 @@ export default class NoteDetailWidget extends NoteContextAwareWidget { const {note} = this.noteContext; const {noteId} = note; - const content = await this.getTypeWidget().getContent(); + const data = await this.getTypeWidget().getData(); // for read only notes - if (content === undefined) { + if (data === undefined) { return; } protectedSessionHolder.touchProtectedSessionIfNecessary(note); - await server.put(`notes/${noteId}/content`, {content}, this.componentId); + await server.put(`notes/${noteId}/data`, data, this.componentId); }); appContext.addBeforeUnloadListener(this); diff --git a/src/public/app/widgets/type_widgets/canvas.js b/src/public/app/widgets/type_widgets/canvas.js index 5dd8f8f0c..0253e67cc 100644 --- a/src/public/app/widgets/type_widgets/canvas.js +++ b/src/public/app/widgets/type_widgets/canvas.js @@ -246,7 +246,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget { * gets data from widget container that will be sent via spacedUpdate.scheduleUpdate(); * this is automatically called after this.saveData(); */ - async getContent() { + async getData() { const elements = this.excalidrawRef.current.getSceneElements(); const appState = this.excalidrawRef.current.getAppState(); @@ -277,14 +277,21 @@ export default class ExcalidrawTypeWidget extends TypeWidget { }) const content = { - _meta: "This note has type `canvas`. It uses excalidraw and stores an exported svg alongside.", - elements, // excalidraw - appState, // excalidraw - files: activeFiles, // excalidraw - svg: svgString, // not needed for excalidraw, used for note_short, content, and image api + elements, + appState, + files: activeFiles }; - return JSON.stringify(content); + return { + content: JSON.stringify(content), + attachments: [ + { + name: 'canvasSvg', + mime: 'image/svg+xml', + content: svgString + } + ] + }; } /** diff --git a/src/public/app/widgets/type_widgets/editable_code.js b/src/public/app/widgets/type_widgets/editable_code.js index 9948b5d63..144f1392d 100644 --- a/src/public/app/widgets/type_widgets/editable_code.js +++ b/src/public/app/widgets/type_widgets/editable_code.js @@ -96,8 +96,10 @@ export default class EditableCodeTypeWidget extends TypeWidget { } } - getContent() { - return this.codeEditor.getValue(); + getData() { + return { + content: this.codeEditor.getValue() + }; } focus() { diff --git a/src/public/app/widgets/type_widgets/editable_text.js b/src/public/app/widgets/type_widgets/editable_text.js index 74f593d33..9b8b4458e 100644 --- a/src/public/app/widgets/type_widgets/editable_text.js +++ b/src/public/app/widgets/type_widgets/editable_text.js @@ -185,12 +185,14 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { }); } - getContent() { + getData() { const content = this.watchdog.editor.getData(); // if content is only tags/whitespace (typically

 

), then just make it empty // this is important when setting new note to code - return utils.isHtmlEmpty(content) ? '' : content; + return { + content: utils.isHtmlEmpty(content) ? '' : content + }; } focus() { diff --git a/src/public/app/widgets/type_widgets/relation_map.js b/src/public/app/widgets/type_widgets/relation_map.js index 72ad759ad..8df2023ef 100644 --- a/src/public/app/widgets/type_widgets/relation_map.js +++ b/src/public/app/widgets/type_widgets/relation_map.js @@ -586,8 +586,11 @@ export default class RelationMapTypeWidget extends TypeWidget { }; } - getContent() { - return JSON.stringify(this.mapData); + getData() { + // TODO: save also image as attachment + return { + content: JSON.stringify(this.mapData) + }; } async relationMapCreateChildNoteEvent({ntxId}) { diff --git a/src/public/app/widgets/type_widgets/type_widget.js b/src/public/app/widgets/type_widgets/type_widget.js index c38b0a70c..39791e66d 100644 --- a/src/public/app/widgets/type_widgets/type_widget.js +++ b/src/public/app/widgets/type_widgets/type_widget.js @@ -39,9 +39,9 @@ export default class TypeWidget extends NoteContextAwareWidget { } /** - * @returns {Promise|*} promise resolving content or directly the content + * @returns {Promise|*} promise resolving note data. Note data is an object with content and attachments. */ - getContent() {} + getData() {} focus() {} diff --git a/src/routes/api/notes.js b/src/routes/api/notes.js index 5fefc123e..5f62e5ae8 100644 --- a/src/routes/api/notes.js +++ b/src/routes/api/notes.js @@ -53,11 +53,11 @@ function createNote(req) { }; } -function updateNoteContent(req) { - const {content} = req.body; +function updateNoteData(req) { + const {content, attachments} = req.body; const {noteId} = req.params; - return noteService.updateNoteContent(noteId, content); + return noteService.updateNoteData(noteId, content, attachments); } function deleteNote(req) { @@ -327,7 +327,7 @@ function forceSaveNoteRevision(req) { module.exports = { getNote, - updateNoteContent, + updateNoteData, deleteNote, undeleteNote, createNote, diff --git a/src/routes/routes.js b/src/routes/routes.js index 0dc3c9a47..cdca32975 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -118,7 +118,7 @@ function register(app) { apiRoute(GET, '/api/autocomplete', autocompleteApiRoute.getAutocomplete); apiRoute(GET, '/api/notes/:noteId', notesApiRoute.getNote); - apiRoute(PUT, '/api/notes/:noteId/content', notesApiRoute.updateNoteContent); + apiRoute(PUT, '/api/notes/:noteId/data', notesApiRoute.updateNoteData); apiRoute(DELETE, '/api/notes/:noteId', notesApiRoute.deleteNote); apiRoute(PUT, '/api/notes/:noteId/undelete', notesApiRoute.undeleteNote); apiRoute(POST, '/api/notes/:noteId/revision', notesApiRoute.forceSaveNoteRevision); diff --git a/src/services/notes.js b/src/services/notes.js index 1e8d658e9..19bff76a9 100644 --- a/src/services/notes.js +++ b/src/services/notes.js @@ -592,7 +592,7 @@ function saveNoteRevisionIfNeeded(note) { } } -function updateNoteContent(noteId, content) { +function updateNoteData(noteId, content, attachments = []) { const note = becca.getNote(noteId); if (!note.isContentAvailable()) { @@ -604,6 +604,10 @@ function updateNoteContent(noteId, content) { content = saveLinks(note, content); note.setContent(content); + + for (const {name, mime, content} of attachments) { + note.saveNoteAttachment(name, mime, content); + } } /** @@ -998,7 +1002,7 @@ sqlInit.dbReady.then(() => { module.exports = { createNewNote, createNewNoteWithTarget, - updateNoteContent, + updateNoteData, undeleteNote, protectNoteRecursively, scanForLinks,