mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
basic separation of note list renderer from book type
This commit is contained in:
parent
99f35b2588
commit
761912c3bd
File diff suppressed because one or more lines are too long
4664
package-lock.json
generated
4664
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
@ -32,7 +32,7 @@
|
||||
"commonmark": "0.29.2",
|
||||
"cookie-parser": "1.4.5",
|
||||
"csurf": "1.11.0",
|
||||
"dayjs": "1.8.36",
|
||||
"dayjs": "1.9.1",
|
||||
"ejs": "3.1.5",
|
||||
"electron-debug": "3.1.0",
|
||||
"electron-dl": "3.0.2",
|
||||
@ -55,17 +55,17 @@
|
||||
"mime-types": "2.1.27",
|
||||
"multer": "1.4.2",
|
||||
"node-abi": "2.19.1",
|
||||
"open": "7.2.1",
|
||||
"open": "7.3.0",
|
||||
"portscanner": "2.2.0",
|
||||
"rand-token": "1.0.1",
|
||||
"request": "^2.88.2",
|
||||
"rimraf": "3.0.2",
|
||||
"sanitize-filename": "1.6.3",
|
||||
"sanitize-html": "1.27.4",
|
||||
"sanitize-html": "2.1.0",
|
||||
"sax": "1.2.4",
|
||||
"semver": "7.3.2",
|
||||
"serve-favicon": "2.5.0",
|
||||
"session-file-store": "1.4.0",
|
||||
"session-file-store": "1.5.0",
|
||||
"striptags": "3.1.1",
|
||||
"turndown": "6.0.0",
|
||||
"turndown-plugin-gfm": "1.0.2",
|
||||
@ -79,14 +79,14 @@
|
||||
"electron": "9.3.2",
|
||||
"electron-builder": "22.8.1",
|
||||
"electron-packager": "15.1.0",
|
||||
"electron-rebuild": "2.0.3",
|
||||
"electron-rebuild": "2.2.0",
|
||||
"esm": "3.2.25",
|
||||
"jasmine": "3.6.1",
|
||||
"jsdoc": "3.6.6",
|
||||
"lorem-ipsum": "2.0.3",
|
||||
"rcedit": "2.2.0",
|
||||
"webpack": "5.0.0-beta.32",
|
||||
"webpack-cli": "4.0.0-beta.8"
|
||||
"webpack": "5.0.0-rc.4",
|
||||
"webpack-cli": "4.0.0-rc.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"electron-installer-debian": "2.0.1"
|
||||
|
201
src/public/app/services/note_list_renderer.js
Normal file
201
src/public/app/services/note_list_renderer.js
Normal file
@ -0,0 +1,201 @@
|
||||
import linkService from "./link.js";
|
||||
import noteContentRenderer from "./note_content_renderer.js";
|
||||
import treeCache from "./tree_cache.js";
|
||||
|
||||
const ZOOMS = {
|
||||
1: {
|
||||
width: "100%",
|
||||
height: "100%"
|
||||
},
|
||||
2: {
|
||||
width: "49%",
|
||||
height: "350px"
|
||||
},
|
||||
3: {
|
||||
width: "32%",
|
||||
height: "250px"
|
||||
},
|
||||
4: {
|
||||
width: "24%",
|
||||
height: "200px"
|
||||
},
|
||||
5: {
|
||||
width: "19%",
|
||||
height: "175px"
|
||||
},
|
||||
6: {
|
||||
width: "16%",
|
||||
height: "150px"
|
||||
}
|
||||
};
|
||||
|
||||
const zoomLevel = 2;
|
||||
|
||||
const TPL = `
|
||||
<div class="note-list">
|
||||
<style>
|
||||
.note-list {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.note-book-card {
|
||||
border-radius: 10px;
|
||||
background-color: var(--accented-background-color);
|
||||
padding: 15px;
|
||||
padding-bottom: 5px;
|
||||
margin: 5px;
|
||||
margin-left: 0;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.note-book-card .note-book-card {
|
||||
border: 1px solid var(--main-border-color);
|
||||
}
|
||||
|
||||
.note-book-card.type-image .note-book-content, .note-book-card.type-file .note-book-content, .note-book-card.type-protected-session .note-book-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.note-book-card.type-image .note-book-content img, .note-book-card.type-text .note-book-content img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.note-book-title {
|
||||
flex-grow: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="note-list-container"></div>
|
||||
</div>`;
|
||||
|
||||
async function renderList(notes, parentNote = null) {
|
||||
const $noteList = $(TPL);
|
||||
|
||||
// $zoomInButton.on('click', () => this.setZoom(this.zoomLevel - 1));
|
||||
// $zoomOutButton.on('click', () => this.setZoom(this.zoomLevel + 1));
|
||||
//
|
||||
// $expandChildrenButton.on('click', async () => {
|
||||
// for (let i = 1; i < 30; i++) { // protection against infinite cycle
|
||||
// const $unexpandedLinks = this.$content.find('.note-book-open-children-button:visible');
|
||||
//
|
||||
// if ($unexpandedLinks.length === 0) {
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// for (const link of $unexpandedLinks) {
|
||||
// const $card = $(link).closest(".note-book-card");
|
||||
//
|
||||
// await this.expandCard($card);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
$noteList.on('click', '.note-book-open-children-button', async ev => {
|
||||
const $card = $(ev.target).closest('.note-book-card');
|
||||
|
||||
await expandCard($card);
|
||||
});
|
||||
|
||||
$noteList.on('click', '.note-book-hide-children-button', async ev => {
|
||||
const $card = $(ev.target).closest('.note-book-card');
|
||||
|
||||
$card.find('.note-book-open-children-button').show();
|
||||
$card.find('.note-book-hide-children-button').hide();
|
||||
|
||||
$card.find('.note-book-children-content').empty();
|
||||
});
|
||||
|
||||
const $container = $noteList.find('.note-list-container');
|
||||
|
||||
const imageLinks = parentNote ? parentNote.getRelations('imageLink') : [];
|
||||
|
||||
for (const note of notes) {
|
||||
// image is already visible in the parent note so no need to display it separately in the book
|
||||
if (imageLinks.find(rel => rel.value === note.noteId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const $card = await renderNote(note);
|
||||
|
||||
$container.append($card);
|
||||
}
|
||||
|
||||
return $noteList;
|
||||
}
|
||||
|
||||
async function renderNote(note) {
|
||||
const notePath = /*this.notePath + '/' + */ note.noteId;
|
||||
|
||||
const $content = $('<div class="note-book-content">')
|
||||
.css("max-height", ZOOMS[zoomLevel].height);
|
||||
|
||||
const $card = $('<div class="note-book-card">')
|
||||
.attr('data-note-id', note.noteId)
|
||||
.css("flex-basis", ZOOMS[zoomLevel].width)
|
||||
.append($('<h5 class="note-book-title">').append(await linkService.createNoteLink(notePath, {showTooltip: false})))
|
||||
.append($content);
|
||||
|
||||
try {
|
||||
const {type, renderedContent} = await noteContentRenderer.getRenderedContent(note);
|
||||
|
||||
$card.addClass("type-" + type);
|
||||
$content.append(renderedContent);
|
||||
} catch (e) {
|
||||
console.log(`Caught error while rendering note ${note.noteId} of type ${note.type}: ${e.message}, stack: ${e.stack}`);
|
||||
|
||||
$content.append("rendering error");
|
||||
}
|
||||
|
||||
const imageLinks = note.getRelations('imageLink');
|
||||
|
||||
const childCount = note.getChildNoteIds()
|
||||
.filter(childNoteId => !imageLinks.find(rel => rel.value === childNoteId))
|
||||
.length;
|
||||
|
||||
if (childCount > 0) {
|
||||
const label = `${childCount} child${childCount > 1 ? 'ren' : ''}`;
|
||||
|
||||
$card.append($('<div class="note-book-children">')
|
||||
.append($(`<a class="note-book-open-children-button no-print" href="javascript:">+ Show ${label}</a>`))
|
||||
.append($(`<a class="note-book-hide-children-button no-print" href="javascript:">- Hide ${label}</a>`).hide())
|
||||
.append($('<div class="note-book-children-content">'))
|
||||
);
|
||||
}
|
||||
|
||||
return $card;
|
||||
}
|
||||
|
||||
async function expandCard($card) {
|
||||
const noteId = $card.attr('data-note-id');
|
||||
const note = await treeCache.getNote(noteId);
|
||||
|
||||
$card.find('.note-book-open-children-button').hide();
|
||||
$card.find('.note-book-hide-children-button').show();
|
||||
|
||||
$card.find('.note-book-children-content').append(await renderList(await note.getChildNotes(), note));
|
||||
}
|
||||
|
||||
function setZoom(zoomLevel) {
|
||||
if (!(zoomLevel in ZOOMS)) {
|
||||
zoomLevel = this.getDefaultZoomLevel();
|
||||
}
|
||||
|
||||
this.zoomLevel = zoomLevel;
|
||||
|
||||
this.$zoomInButton.prop("disabled", zoomLevel === MIN_ZOOM_LEVEL);
|
||||
this.$zoomOutButton.prop("disabled", zoomLevel === MAX_ZOOM_LEVEL);
|
||||
|
||||
this.$content.find('.note-book-card').css("flex-basis", ZOOMS[zoomLevel].width);
|
||||
this.$content.find('.note-book-content').css("max-height", ZOOMS[zoomLevel].height);
|
||||
}
|
||||
|
||||
export default {
|
||||
renderList
|
||||
};
|
@ -1,100 +1,15 @@
|
||||
import linkService from "../../services/link.js";
|
||||
import treeCache from "../../services/tree_cache.js";
|
||||
import noteContentRenderer from "../../services/note_content_renderer.js";
|
||||
import noteListRenderer from "../../services/note_list_renderer.js";
|
||||
import TypeWidget from "./type_widget.js";
|
||||
|
||||
const MIN_ZOOM_LEVEL = 1;
|
||||
const MAX_ZOOM_LEVEL = 6;
|
||||
|
||||
const ZOOMS = {
|
||||
1: {
|
||||
width: "100%",
|
||||
height: "100%"
|
||||
},
|
||||
2: {
|
||||
width: "49%",
|
||||
height: "350px"
|
||||
},
|
||||
3: {
|
||||
width: "32%",
|
||||
height: "250px"
|
||||
},
|
||||
4: {
|
||||
width: "24%",
|
||||
height: "200px"
|
||||
},
|
||||
5: {
|
||||
width: "19%",
|
||||
height: "175px"
|
||||
},
|
||||
6: {
|
||||
width: "16%",
|
||||
height: "150px"
|
||||
}
|
||||
};
|
||||
|
||||
const TPL = `
|
||||
<div class="note-detail-book note-detail-printable">
|
||||
<style>
|
||||
/*
|
||||
* We have specific CSS file here instead of being part of the respective widgets to also include this in the printing process
|
||||
*/
|
||||
|
||||
.note-detail-book {
|
||||
height: 100%;
|
||||
padding: 0 10px 10px 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.note-detail-book-content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
align-content: start;
|
||||
}
|
||||
|
||||
.note-book-card {
|
||||
border-radius: 10px;
|
||||
background-color: var(--accented-background-color);
|
||||
padding: 15px;
|
||||
padding-bottom: 5px;
|
||||
margin: 5px;
|
||||
margin-left: 0;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.note-book-card .note-book-card {
|
||||
border: 1px solid var(--main-border-color);
|
||||
}
|
||||
|
||||
.note-book-content {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.note-book-card.type-image .note-book-content, .note-book-card.type-file .note-book-content, .note-book-card.type-protected-session .note-book-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.note-book-card.type-image .note-book-content img, .note-book-card.type-text .note-book-content img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.note-book-title {
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.note-book-content {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.note-book-auto-message {
|
||||
background-color: var(--accented-background-color);
|
||||
text-align: center;
|
||||
@ -103,22 +18,12 @@ const TPL = `
|
||||
padding: 5px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.note-book-content {
|
||||
flex-grow: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="btn-group floating-button" style="right: 20px; top: 20px;">
|
||||
<button type="button"
|
||||
class="expand-children-button btn icon-button bx bx-move-vertical"
|
||||
title="Expand all children"></button>
|
||||
|
||||
<button type="button"
|
||||
class="book-zoom-in-button btn icon-button bx bx-zoom-in"
|
||||
title="Zoom In"></button>
|
||||
|
||||
<button type="button"
|
||||
class="book-zoom-out-button btn icon-button bx bx-zoom-out"
|
||||
title="Zoom Out"></button>
|
||||
</div>
|
||||
|
||||
<div class="note-detail-book-help alert alert-warning" style="margin: 50px; padding: 20px;">
|
||||
This note of type Book doesn't have any child notes so there's nothing to display. See <a href="https://github.com/zadam/trilium/wiki/Book-note">wiki</a> for details.
|
||||
</div>
|
||||
@ -132,68 +37,7 @@ export default class BookTypeWidget extends TypeWidget {
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
this.$content = this.$widget.find('.note-detail-book-content');
|
||||
this.$zoomInButton = this.$widget.find('.book-zoom-in-button');
|
||||
this.$zoomOutButton = this.$widget.find('.book-zoom-out-button');
|
||||
this.$expandChildrenButton = this.$widget.find('.expand-children-button');
|
||||
this.$help = this.$widget.find('.note-detail-book-help');
|
||||
|
||||
this.$zoomInButton.on('click', () => this.setZoom(this.zoomLevel - 1));
|
||||
this.$zoomOutButton.on('click', () => this.setZoom(this.zoomLevel + 1));
|
||||
|
||||
this.$expandChildrenButton.on('click', async () => {
|
||||
for (let i = 1; i < 30; i++) { // protection against infinite cycle
|
||||
const $unexpandedLinks = this.$content.find('.note-book-open-children-button:visible');
|
||||
|
||||
if ($unexpandedLinks.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (const link of $unexpandedLinks) {
|
||||
const $card = $(link).closest(".note-book-card");
|
||||
|
||||
await this.expandCard($card);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.$content.on('click', '.note-book-open-children-button', async ev => {
|
||||
const $card = $(ev.target).closest('.note-book-card');
|
||||
|
||||
await this.expandCard($card);
|
||||
});
|
||||
|
||||
this.$content.on('click', '.note-book-hide-children-button', async ev => {
|
||||
const $card = $(ev.target).closest('.note-book-card');
|
||||
|
||||
$card.find('.note-book-open-children-button').show();
|
||||
$card.find('.note-book-hide-children-button').hide();
|
||||
|
||||
$card.find('.note-book-children-content').empty();
|
||||
});
|
||||
}
|
||||
|
||||
async expandCard($card) {
|
||||
const noteId = $card.attr('data-note-id');
|
||||
const note = await treeCache.getNote(noteId);
|
||||
|
||||
$card.find('.note-book-open-children-button').hide();
|
||||
$card.find('.note-book-hide-children-button').show();
|
||||
|
||||
await this.renderIntoElement(note, $card.find('.note-book-children-content'));
|
||||
}
|
||||
|
||||
setZoom(zoomLevel) {
|
||||
if (!(zoomLevel in ZOOMS)) {
|
||||
zoomLevel = this.getDefaultZoomLevel();
|
||||
}
|
||||
|
||||
this.zoomLevel = zoomLevel;
|
||||
|
||||
this.$zoomInButton.prop("disabled", zoomLevel === MIN_ZOOM_LEVEL);
|
||||
this.$zoomOutButton.prop("disabled", zoomLevel === MAX_ZOOM_LEVEL);
|
||||
|
||||
this.$content.find('.note-book-card').css("flex-basis", ZOOMS[zoomLevel].width);
|
||||
this.$content.find('.note-book-content').css("max-height", ZOOMS[zoomLevel].height);
|
||||
}
|
||||
|
||||
async doRefresh(note) {
|
||||
@ -213,73 +57,10 @@ export default class BookTypeWidget extends TypeWidget {
|
||||
.append(' if you want to add some text.'));
|
||||
}
|
||||
|
||||
const zoomLevel = parseInt(note.getLabelValue('bookZoomLevel')) || this.getDefaultZoomLevel();
|
||||
this.setZoom(zoomLevel);
|
||||
// const zoomLevel = parseInt(note.getLabelValue('bookZoomLevel')) || this.getDefaultZoomLevel();
|
||||
// this.setZoom(zoomLevel);
|
||||
|
||||
await this.renderIntoElement(note, this.$content);
|
||||
}
|
||||
|
||||
async renderIntoElement(note, $container) {
|
||||
const childNotes = await note.getChildNotes();
|
||||
|
||||
if (childNotes.length === 0) {
|
||||
this.$help.show();
|
||||
}
|
||||
|
||||
const imageLinks = note.getRelations('imageLink');
|
||||
|
||||
for (const childNote of childNotes) {
|
||||
// image is already visible in the parent note so no need to display it separately in the book
|
||||
if (imageLinks.find(rel => rel.value === childNote.noteId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const $card = await this.renderNote(childNote);
|
||||
|
||||
$container.append($card);
|
||||
}
|
||||
}
|
||||
|
||||
async renderNote(note) {
|
||||
const notePath = this.notePath + '/' + note.noteId;
|
||||
|
||||
const $content = $('<div class="note-book-content">')
|
||||
.css("max-height", ZOOMS[this.zoomLevel].height);
|
||||
|
||||
const $card = $('<div class="note-book-card">')
|
||||
.attr('data-note-id', note.noteId)
|
||||
.css("flex-basis", ZOOMS[this.zoomLevel].width)
|
||||
.append($('<h5 class="note-book-title">').append(await linkService.createNoteLink(notePath, {showTooltip: false})))
|
||||
.append($content);
|
||||
|
||||
try {
|
||||
const {type, renderedContent} = await noteContentRenderer.getRenderedContent(note);
|
||||
|
||||
$card.addClass("type-" + type);
|
||||
$content.append(renderedContent);
|
||||
} catch (e) {
|
||||
console.log(`Caught error while rendering note ${note.noteId} of type ${note.type}: ${e.message}, stack: ${e.stack}`);
|
||||
|
||||
$content.append("rendering error");
|
||||
}
|
||||
|
||||
const imageLinks = note.getRelations('imageLink');
|
||||
|
||||
const childCount = note.getChildNoteIds()
|
||||
.filter(childNoteId => !imageLinks.find(rel => rel.value === childNoteId))
|
||||
.length;
|
||||
|
||||
if (childCount > 0) {
|
||||
const label = `${childCount} child${childCount > 1 ? 'ren' : ''}`;
|
||||
|
||||
$card.append($('<div class="note-book-children">')
|
||||
.append($(`<a class="note-book-open-children-button no-print" href="javascript:">+ Show ${label}</a>`))
|
||||
.append($(`<a class="note-book-hide-children-button no-print" href="javascript:">- Hide ${label}</a>`).hide())
|
||||
.append($('<div class="note-book-children-content">'))
|
||||
);
|
||||
}
|
||||
|
||||
return $card;
|
||||
this.$content.append(await noteListRenderer.renderList(await note.getChildNotes()));
|
||||
}
|
||||
|
||||
/** @return {boolean} true if this is "auto book" activated (empty text note) and not explicit book note */
|
||||
|
@ -650,6 +650,7 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
|
||||
|
||||
.component {
|
||||
contain: size;
|
||||
content-visibility: auto;
|
||||
}
|
||||
|
||||
.toast {
|
||||
|
Loading…
x
Reference in New Issue
Block a user