shaca now loads attributes, added favicon and shareJs

This commit is contained in:
zadam 2022-01-01 13:23:09 +01:00
parent dad82ea4e8
commit 1fed71a92e
8 changed files with 86 additions and 34 deletions

21
src/public/app/share.js Normal file
View File

@ -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);

View File

@ -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', "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", "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.", "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'.",
} }
}; };

View File

@ -67,6 +67,8 @@ const BUILTIN_ATTRIBUTES = [
{ type: 'relation', name: 'widget', isDangerous: true }, { type: 'relation', name: 'widget', isDangerous: true },
{ type: 'relation', name: 'renderNote', isDangerous: true }, { type: 'relation', name: 'renderNote', isDangerous: true },
{ type: 'relation', name: 'shareCss', isDangerous: false }, { type: 'relation', name: 'shareCss', isDangerous: false },
{ type: 'relation', name: 'shareJs', isDangerous: false },
{ type: 'relation', name: 'shareFavicon', isDangerous: false },
]; ];
/** @returns {Note[]} */ /** @returns {Note[]} */

View File

@ -46,19 +46,15 @@ function register(router) {
} }
}); });
router.get('/share/api/images/:noteId/:filename', (req, res, next) => { router.get('/share/api/notes/:noteId', (req, res, next) => {
const image = shaca.getNote(req.params.noteId); const {noteId} = req.params;
const note = shaca.getNote(noteId);
if (!image) { if (!note) {
return res.status(404).send("Not found"); 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.json(note.getPojoWithAttributes());
res.send(image.getContent());
}); });
router.get('/share/api/notes/:noteId/download', (req, res, next) => { router.get('/share/api/notes/:noteId/download', (req, res, next) => {
@ -66,7 +62,7 @@ function register(router) {
const note = shaca.getNote(noteId); const note = shaca.getNote(noteId);
if (!note) { if (!note) {
return res.status(404).send(`Not found`); return res.status(404).send(`Note ${noteId} not found`);
} }
const utils = require("../services/utils"); const utils = require("../services/utils");
@ -81,20 +77,30 @@ function register(router) {
res.send(note.getContent()); 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) => { router.get('/share/api/notes/:noteId/view', (req, res, next) => {
const {noteId} = req.params; const {noteId} = req.params;
const note = shaca.getNote(noteId); const note = shaca.getNote(noteId);
if (!note) { 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("Cache-Control", "no-cache, no-store, must-revalidate");
res.setHeader('Content-Type', note.mime); res.setHeader('Content-Type', note.mime);

View File

@ -89,6 +89,18 @@ class Attribute extends AbstractEntity {
return this.shaca.getNote(this.value); 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; module.exports = Attribute;

View File

@ -410,6 +410,19 @@ class Note extends AbstractEntity {
return sharedAlias || this.noteId; 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; module.exports = Note;

View File

@ -59,11 +59,7 @@ function load() {
SELECT attributeId, noteId, type, name, value, isInheritable, position, utcDateModified SELECT attributeId, noteId, type, name, value, isInheritable, position, utcDateModified
FROM attributes FROM attributes
WHERE isDeleted = 0 WHERE isDeleted = 0
AND noteId IN (${noteIdStr}) AND noteId IN (${noteIdStr})`);
AND (
(type = 'label' AND name IN ('archived', 'shareHiddenFromTree', 'shareAlias', 'shareOmitDefaultCss'))
OR (type = 'relation' AND name IN ('imageLink', 'template', 'shareCss'))
)`, []);
for (const row of rawAttributeRows) { for (const row of rawAttributeRows) {
new Attribute(row); new Attribute(row);

View File

@ -2,7 +2,12 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<% if (note.hasRelation("shareFavicon")) { %>
<link rel="shortcut icon" href="api/notes/<%= note.getRelation("shareFavicon").value %>/download">
<% } else { %>
<link rel="shortcut icon" href="../favicon.ico"> <link rel="shortcut icon" href="../favicon.ico">
<% } %>
<script src="app/share.js"></script>
<% if (!note.hasLabel("shareOmitDefaultCss")) { %> <% if (!note.hasLabel("shareOmitDefaultCss")) { %>
<link href="../libraries/normalize.min.css" rel="stylesheet"> <link href="../libraries/normalize.min.css" rel="stylesheet">
<link href="../stylesheets/share.css" rel="stylesheet"> <link href="../stylesheets/share.css" rel="stylesheet">
@ -13,15 +18,19 @@
<% for (const cssRelation of note.getRelations("shareCss")) { %> <% for (const cssRelation of note.getRelations("shareCss")) { %>
<link href="api/notes/<%= cssRelation.value %>/download" rel="stylesheet"> <link href="api/notes/<%= cssRelation.value %>/download" rel="stylesheet">
<% } %> <% } %>
<% for (const jsRelation of note.getRelations("shareJs")) { %>
<script src="api/notes/<%= jsRelation.value %>/download"></script>
<% } %>
<%- header %> <%- header %>
<title><%= note.title %></title> <title><%= note.title %></title>
</head> </head>
<body> <body data-note-id="<%= note.noteId %>">
<div id="layout"> <div id="layout">
<div id="main"> <div id="main">
<% if (note.parents[0].noteId !== 'share' && note.parents.length !== 0) { %> <% if (note.parents[0].noteId !== 'share' && note.parents.length !== 0) { %>
<nav id="parentLink"> <nav id="parentLink">
parent: <a href="<%= note.parents[0].noteId %>" class="type-<%= note.parents[0].type %>"><%= note.parents[0].title %></a> parent: <a href="<%= note.parents[0].noteId %>"
class="type-<%= note.parents[0].type %>"><%= note.parents[0].title %></a>
</nav> </nav>
<% } %> <% } %>
@ -63,14 +72,5 @@
</nav> </nav>
<% } %> <% } %>
</div> </div>
<script>
(function () {
const toggleMenuButton = document.getElementById('toggleMenuButton');
const layout = document.getElementById('layout');
toggleMenuButton.addEventListener('click', () => layout.classList.toggle('showMenu'));
}());
</script>
</body> </body>
</html> </html>