From 1fed71a92e528fc9f5e77e7453e3dfc78ed7b15b Mon Sep 17 00:00:00 2001 From: zadam Date: Sat, 1 Jan 2022 13:23:09 +0100 Subject: [PATCH] shaca now loads attributes, added favicon and `shareJs` --- src/public/app/share.js | 21 ++++++++++ .../attribute_widgets/attribute_detail.js | 2 + src/services/attributes.js | 2 + src/share/routes.js | 42 +++++++++++-------- src/share/shaca/entities/attribute.js | 12 ++++++ src/share/shaca/entities/note.js | 13 ++++++ src/share/shaca/shaca_loader.js | 6 +-- src/views/share/page.ejs | 22 +++++----- 8 files changed, 86 insertions(+), 34 deletions(-) create mode 100644 src/public/app/share.js diff --git a/src/public/app/share.js b/src/public/app/share.js new file mode 100644 index 000000000..e7785ba7a --- /dev/null +++ b/src/public/app/share.js @@ -0,0 +1,21 @@ +/** + * Fetch note with given ID from backend + * + * @param noteId of the given note to be fetched. If falsy, fetches current note. + */ +async function fetchNote(noteId = null) { + if (!noteId) { + noteId = document.getElementsByName("body")[0].getAttribute("data-note-id"); + } + + const resp = await fetch(`share/api/notes/${noteId}`); + + return await resp.json(); +} + +document.addEventListener('DOMContentLoaded', () => { + const toggleMenuButton = document.getElementById('toggleMenuButton'); + const layout = document.getElementById('layout'); + + toggleMenuButton.addEventListener('click', () => layout.classList.toggle('showMenu')); +}, false); diff --git a/src/public/app/widgets/attribute_widgets/attribute_detail.js b/src/public/app/widgets/attribute_widgets/attribute_detail.js index 35100e983..a8eb3ba30 100644 --- a/src/public/app/widgets/attribute_widgets/attribute_detail.js +++ b/src/public/app/widgets/attribute_widgets/attribute_detail.js @@ -226,6 +226,8 @@ const ATTR_HELP = { "renderNote": 'notes of type "render HTML note" will be rendered using a code note (HTML or script) and it is necessary to point using this relation to which note should be rendered', "widget": "target of this relation will be executed and rendered as a widget in the sidebar", "shareCss": "CSS note which will be injected into the share page. CSS note must be in the shared sub-tree as well. Consider using 'shareHiddenFromTree' and 'shareOmitDefaultCss' as well.", + "shareJs": "JavaScript note which will be injected into the share page. JS note must be in the shared sub-tree as well. Consider using 'shareHiddenFromTree'.", + "shareFavicon": "Favicon note to be set in the shared page. Typically you want to set it to share root and make it inheritable. Favicon note must be in the shared sub-tree as well. Consider using 'shareHiddenFromTree'.", } }; diff --git a/src/services/attributes.js b/src/services/attributes.js index 5e0fe7b93..89a637e00 100644 --- a/src/services/attributes.js +++ b/src/services/attributes.js @@ -67,6 +67,8 @@ const BUILTIN_ATTRIBUTES = [ { type: 'relation', name: 'widget', isDangerous: true }, { type: 'relation', name: 'renderNote', isDangerous: true }, { type: 'relation', name: 'shareCss', isDangerous: false }, + { type: 'relation', name: 'shareJs', isDangerous: false }, + { type: 'relation', name: 'shareFavicon', isDangerous: false }, ]; /** @returns {Note[]} */ diff --git a/src/share/routes.js b/src/share/routes.js index 985e32737..e40a8222c 100644 --- a/src/share/routes.js +++ b/src/share/routes.js @@ -46,19 +46,15 @@ function register(router) { } }); - router.get('/share/api/images/:noteId/:filename', (req, res, next) => { - const image = shaca.getNote(req.params.noteId); + router.get('/share/api/notes/:noteId', (req, res, next) => { + const {noteId} = req.params; + const note = shaca.getNote(noteId); - if (!image) { - return res.status(404).send("Not found"); - } - else if (image.type !== 'image') { - return res.status(400).send("Requested note is not an image"); + if (!note) { + return res.status(404).send(`Note ${noteId} not found`); } - res.set('Content-Type', image.mime); - - res.send(image.getContent()); + res.json(note.getPojoWithAttributes()); }); router.get('/share/api/notes/:noteId/download', (req, res, next) => { @@ -66,7 +62,7 @@ function register(router) { const note = shaca.getNote(noteId); if (!note) { - return res.status(404).send(`Not found`); + return res.status(404).send(`Note ${noteId} not found`); } const utils = require("../services/utils"); @@ -81,20 +77,30 @@ function register(router) { res.send(note.getContent()); }); + router.get('/share/api/images/:noteId/:filename', (req, res, next) => { + const image = shaca.getNote(req.params.noteId); + + if (!image) { + return res.status(404).send(`Note ${noteId} not found`); + } + else if (image.type !== 'image') { + return res.status(400).send("Requested note is not an image"); + } + + res.set('Content-Type', image.mime); + + res.send(image.getContent()); + }); + + // used for PDF viewing router.get('/share/api/notes/:noteId/view', (req, res, next) => { const {noteId} = req.params; const note = shaca.getNote(noteId); if (!note) { - return res.status(404).send(`Not found`); + return res.status(404).send(`Note ${noteId} not found`); } - const utils = require("../services/utils"); - - const filename = utils.formatDownloadTitle(note.title, note.type, note.mime); - - // res.setHeader('Content-Disposition', utils.getContentDisposition(filename)); - res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); res.setHeader('Content-Type', note.mime); diff --git a/src/share/shaca/entities/attribute.js b/src/share/shaca/entities/attribute.js index cf71258a4..ab8a8583d 100644 --- a/src/share/shaca/entities/attribute.js +++ b/src/share/shaca/entities/attribute.js @@ -89,6 +89,18 @@ class Attribute extends AbstractEntity { return this.shaca.getNote(this.value); } + + getPojo() { + return { + attributeId: this.attributeId, + noteId: this.noteId, + type: this.type, + name: this.name, + position: this.position, + value: this.value, + isInheritable: this.isInheritable + }; + } } module.exports = Attribute; diff --git a/src/share/shaca/entities/note.js b/src/share/shaca/entities/note.js index 2be967c8c..e14f040a1 100644 --- a/src/share/shaca/entities/note.js +++ b/src/share/shaca/entities/note.js @@ -410,6 +410,19 @@ class Note extends AbstractEntity { return sharedAlias || this.noteId; } + + getPojoWithAttributes() { + return { + noteId: this.noteId, + title: this.title, + type: this.type, + mime: this.mime, + utcDateModified: this.utcDateModified, + attributes: this.getAttributes().map(attr => attr.getPojo()), + parentNoteIds: this.parents.map(parentNote => parentNote.noteId), + childNoteIds: this.children.map(child => child.noteId) + }; + } } module.exports = Note; diff --git a/src/share/shaca/shaca_loader.js b/src/share/shaca/shaca_loader.js index 4f849eaf8..8162f674a 100644 --- a/src/share/shaca/shaca_loader.js +++ b/src/share/shaca/shaca_loader.js @@ -59,11 +59,7 @@ function load() { SELECT attributeId, noteId, type, name, value, isInheritable, position, utcDateModified FROM attributes WHERE isDeleted = 0 - AND noteId IN (${noteIdStr}) - AND ( - (type = 'label' AND name IN ('archived', 'shareHiddenFromTree', 'shareAlias', 'shareOmitDefaultCss')) - OR (type = 'relation' AND name IN ('imageLink', 'template', 'shareCss')) - )`, []); + AND noteId IN (${noteIdStr})`); for (const row of rawAttributeRows) { new Attribute(row); diff --git a/src/views/share/page.ejs b/src/views/share/page.ejs index 5e1a479a1..c889bd7f3 100644 --- a/src/views/share/page.ejs +++ b/src/views/share/page.ejs @@ -2,7 +2,12 @@ + <% if (note.hasRelation("shareFavicon")) { %> + /download"> + <% } else { %> + <% } %> + <% if (!note.hasLabel("shareOmitDefaultCss")) { %> @@ -13,15 +18,19 @@ <% for (const cssRelation of note.getRelations("shareCss")) { %> <% } %> + <% for (const jsRelation of note.getRelations("shareJs")) { %> + + <% } %> <%- header %> <%= note.title %> - +
<% if (note.parents[0].noteId !== 'share' && note.parents.length !== 0) { %> <% } %> @@ -63,14 +72,5 @@ <% } %>
- -