converting sidebar widgets to normal widgets

This commit is contained in:
zadam 2020-01-14 21:23:32 +01:00
parent 23701219e1
commit c9770573b2
14 changed files with 99 additions and 126 deletions

View File

@ -12,6 +12,12 @@ import NoteTitleWidget from "../widgets/note_title.js";
import PromotedAttributesWidget from "../widgets/promoted_attributes.js"; import PromotedAttributesWidget from "../widgets/promoted_attributes.js";
import NoteDetailWidget from "../widgets/note_detail.js"; import NoteDetailWidget from "../widgets/note_detail.js";
import TabCachingWidget from "../widgets/tab_caching_widget.js"; import TabCachingWidget from "../widgets/tab_caching_widget.js";
import NoteInfoWidget from "../widgets/note_info.js";
import NoteRevisionsWidget from "../widgets/note_revisions.js";
import LinkMapWidget from "../widgets/link_map.js";
import SimilarNotesWidget from "../widgets/similar_notes.js";
import WhatLinksHereWidget from "../widgets/what_links_here.js";
import AttributesWidget from "../widgets/attributes.js";
class AppContext { class AppContext {
constructor() { constructor() {
@ -56,10 +62,26 @@ class AppContext {
widget.renderTo($centerPane); widget.renderTo($centerPane);
} }
const $rightPane = $("#right-pane");
const rightPaneWidgets = [
new NoteInfoWidget(this),
new TabCachingWidget(this, () => new AttributesWidget(this)),
new TabCachingWidget(this, () => new LinkMapWidget(this)),
new TabCachingWidget(this, () => new NoteRevisionsWidget(this)),
new TabCachingWidget(this, () => new SimilarNotesWidget(this)),
new TabCachingWidget(this, () => new WhatLinksHereWidget(this)),
];
for (const widget of rightPaneWidgets) {
widget.renderTo($rightPane);
}
this.widgets = [ this.widgets = [
this.tabRow, this.tabRow,
...leftPaneWidgets, ...leftPaneWidgets,
...centerPaneWidgets ...centerPaneWidgets,
...rightPaneWidgets
]; ];
} }

View File

@ -5,7 +5,6 @@ import bundleService from "./bundle.js";
import Attributes from "./attributes.js"; import Attributes from "./attributes.js";
import utils from "./utils.js"; import utils from "./utils.js";
import optionsService from "./options.js"; import optionsService from "./options.js";
import Sidebar from "./sidebar.js";
import appContext from "./app_context.js"; import appContext from "./app_context.js";
let showSidebarInNewTab = true; let showSidebarInNewTab = true;
@ -39,14 +38,6 @@ class TabContext {
this.noteChangeDisabled = false; this.noteChangeDisabled = false;
this.isNoteChanged = false; this.isNoteChanged = false;
this.attributes = new Attributes(this); this.attributes = new Attributes(this);
if (utils.isDesktop()) {
const sidebarState = this.state.sidebar || {
visible: showSidebarInNewTab
};
this.sidebar = new Sidebar(this, sidebarState);
}
} }
async setNote(note, notePath) { async setNote(note, notePath) {
@ -70,10 +61,6 @@ class TabContext {
this.setCurrentNotePathToHash(); this.setCurrentNotePathToHash();
if (this.sidebar) {
this.sidebar.noteLoaded(); // load async
}
this.noteChangeDisabled = true; this.noteChangeDisabled = true;
try { try {
@ -118,10 +105,6 @@ class TabContext {
} }
} }
if (this.sidebar) {
this.sidebar.show();
}
this.setCurrentNotePathToHash(); this.setCurrentNotePathToHash();
this.setTitleBar(); this.setTitleBar();
} }
@ -254,10 +237,6 @@ class TabContext {
await this.saveNoteIfChanged(); await this.saveNoteIfChanged();
this.$tabContent.remove(); this.$tabContent.remove();
} }
if (this.sidebar) {
this.sidebar.remove();
}
} }
cleanup() { cleanup() {
@ -274,10 +253,6 @@ class TabContext {
} }
this.attributes.eventReceived(name, data); this.attributes.eventReceived(name, data);
if (this.sidebar) {
this.sidebar.eventReceived(name, data);
}
} }
getTabState() { getTabState() {
@ -288,8 +263,7 @@ class TabContext {
return { return {
tabId: this.tabId, tabId: this.tabId,
notePath: this.notePath, notePath: this.notePath,
active: this.tabRow.activeTabEl === this.$tab[0], active: this.tabRow.activeTabEl === this.$tab[0]
sidebar: this.sidebar && this.sidebar.getSidebarState()
} }
} }

View File

@ -23,9 +23,9 @@ class AttributesWidget extends StandardWidget {
return [$showFullButton]; return [$showFullButton];
} }
async doRenderBody() { async activeTabChanged() {
const attributes = await this.ctx.attributes.getAttributes(); const attributes = await this.tabContext.attributes.getAttributes();
const ownedAttributes = attributes.filter(attr => attr.noteId === this.ctx.note.noteId); const ownedAttributes = attributes.filter(attr => attr.noteId === this.tabContext.note.noteId);
if (attributes.length === 0) { if (attributes.length === 0) {
this.$body.text("No attributes yet..."); this.$body.text("No attributes yet...");
@ -36,7 +36,7 @@ class AttributesWidget extends StandardWidget {
await this.renderAttributes(ownedAttributes, $attributesContainer); await this.renderAttributes(ownedAttributes, $attributesContainer);
const inheritedAttributes = attributes.filter(attr => attr.noteId !== this.ctx.note.noteId); const inheritedAttributes = attributes.filter(attr => attr.noteId !== this.tabContext.note.noteId);
if (inheritedAttributes.length > 0) { if (inheritedAttributes.length > 0) {
const $inheritedAttrs = $("<span>").append($("<strong>").text("Inherited: ")); const $inheritedAttrs = $("<span>").append($("<strong>").text("Inherited: "));
@ -88,15 +88,13 @@ class AttributesWidget extends StandardWidget {
} }
} }
eventReceived(name, data) { syncDataListener({data}) {
if (name === 'syncData') { if (data.find(sd => sd.entityName === 'attributes' && sd.noteId === this.tabContext.note.noteId)) {
if (data.find(sd => sd.entityName === 'attributes' && sd.noteId === this.ctx.note.noteId)) {
// no need to invalidate attributes since the Attribute class listens to this as well // no need to invalidate attributes since the Attribute class listens to this as well
// (and is guaranteed to run first) // (and is guaranteed to run first)
this.doRenderBody(); this.doRenderBody();
} }
} }
}
} }
export default AttributesWidget; export default AttributesWidget;

View File

@ -26,6 +26,8 @@ class BasicWidget {
doRender() {} doRender() {}
eventReceived(name, data) { eventReceived(name, data) {
console.log("received", name, "to", this.widgetId);
const fun = this[name + 'Listener']; const fun = this[name + 'Listener'];
if (typeof fun === 'function') { if (typeof fun === 'function') {

View File

@ -29,15 +29,17 @@ class CalendarWidget extends StandardWidget {
async isEnabled() { async isEnabled() {
return await super.isEnabled() return await super.isEnabled()
&& await this.ctx.note.hasLabel("dateNote"); && await this.tabContext.note.hasLabel("dateNote");
} }
async doRenderBody() { async doRenderBody() {
await libraryLoader.requireLibrary(libraryLoader.CALENDAR_WIDGET); await libraryLoader.requireLibrary(libraryLoader.CALENDAR_WIDGET);
this.$body.html(TPL); this.$body.html(TPL);
}
this.init(this.$body, await this.ctx.note.getLabelValue("dateNote")); async activeTabChanged() {
this.init(this.$body, await this.tabContext.note.getLabelValue("dateNote"));
} }
init($el, activeDate) { init($el, activeDate) {

View File

@ -16,23 +16,23 @@ class EditedNotesWidget extends StandardWidget {
async isEnabled() { async isEnabled() {
return await super.isEnabled() return await super.isEnabled()
&& await this.ctx.note.hasLabel("dateNote"); && await this.tabContext.note.hasLabel("dateNote");
} }
async doRenderBody() { async doRenderBody() {
const note = this.tabContext.note;
// remember which title was when we found the similar notes // remember which title was when we found the similar notes
this.title = this.ctx.note.title; this.title = note.title;
let editedNotes = await server.get('edited-notes/' + await note.getLabelValue("dateNote"));
let editedNotes = await server.get('edited-notes/' + await this.ctx.note.getLabelValue("dateNote")); editedNotes = editedNotes.filter(n => n.noteId !== note.noteId);
editedNotes = editedNotes.filter(note => note.noteId !== this.ctx.note.noteId);
if (editedNotes.length === 0) { if (editedNotes.length === 0) {
this.$body.text("No edited notes on this day yet ..."); this.$body.text("No edited notes on this day yet ...");
return; return;
} }
const noteIds = editedNotes.flatMap(note => note.noteId); const noteIds = editedNotes.flatMap(n => n.noteId);
await treeCache.getNotes(noteIds, true); // preload all at once await treeCache.getNotes(noteIds, true); // preload all at once

View File

@ -28,7 +28,7 @@ class LinkMapWidget extends StandardWidget {
return [$showFullButton]; return [$showFullButton];
} }
async doRenderBody() { async activeTabChanged() {
this.$body.css('opacity', 0); this.$body.css('opacity', 0);
this.$body.html(TPL); this.$body.html(TPL);
@ -38,7 +38,7 @@ class LinkMapWidget extends StandardWidget {
const LinkMapServiceClass = (await import('../services/link_map.js')).default; const LinkMapServiceClass = (await import('../services/link_map.js')).default;
this.linkMapService = new LinkMapServiceClass(this.ctx.note, $linkMapContainer, { this.linkMapService = new LinkMapServiceClass(this.tabContext.note, $linkMapContainer, {
maxDepth: 1, maxDepth: 1,
zoom: 0.6 zoom: 0.6
}); });
@ -54,9 +54,8 @@ class LinkMapWidget extends StandardWidget {
} }
} }
eventReceived(name, data) { syncDataListener({data}) {
if (name === 'syncData') { if (data.find(sd => sd.entityName === 'attributes' && sd.noteId === this.tabContext.note.noteId)) {
if (data.find(sd => sd.entityName === 'attributes' && sd.noteId === this.ctx.note.noteId)) {
// no need to invalidate attributes since the Attribute class listens to this as well // no need to invalidate attributes since the Attribute class listens to this as well
// (and is guaranteed to run first) // (and is guaranteed to run first)
if (this.linkMapService) { if (this.linkMapService) {
@ -64,7 +63,6 @@ class LinkMapWidget extends StandardWidget {
} }
} }
} }
}
} }
export default LinkMapWidget; export default LinkMapWidget;

View File

@ -27,16 +27,18 @@ const TPL = `
class NoteInfoWidget extends StandardWidget { class NoteInfoWidget extends StandardWidget {
getWidgetTitle() { return "Note info"; } getWidgetTitle() { return "Note info"; }
async doRenderBody() { doRenderBody() {
this.$body.html(TPL); this.$body.html(TPL);
}
activeTabChanged() {
const $noteId = this.$body.find(".note-info-note-id"); const $noteId = this.$body.find(".note-info-note-id");
const $dateCreated = this.$body.find(".note-info-date-created"); const $dateCreated = this.$body.find(".note-info-date-created");
const $dateModified = this.$body.find(".note-info-date-modified"); const $dateModified = this.$body.find(".note-info-date-modified");
const $type = this.$body.find(".note-info-type"); const $type = this.$body.find(".note-info-type");
const $mime = this.$body.find(".note-info-mime"); const $mime = this.$body.find(".note-info-mime");
const note = this.ctx.note; const note = this.tabContext.note;
$noteId.text(note.noteId); $noteId.text(note.noteId);
$dateCreated $dateCreated
@ -54,11 +56,9 @@ class NoteInfoWidget extends StandardWidget {
.attr("title", note.mime); .attr("title", note.mime);
} }
eventReceived(name, data) { syncDataListener({data}) {
if (name === 'syncData') { if (data.find(sd => sd.entityName === 'notes' && sd.entityId === this.tabContext.note.noteId)) {
if (data.find(sd => sd.entityName === 'notes' && sd.entityId === this.ctx.note.noteId)) { this.activeTabChanged();
this.doRenderBody();
}
} }
} }
} }

View File

@ -26,8 +26,9 @@ class NoteRevisionsWidget extends StandardWidget {
return [$showFullButton]; return [$showFullButton];
} }
async doRenderBody() { async activeTabChanged() {
const revisionItems = await server.get(`notes/${this.ctx.note.noteId}/revisions`); const note = this.tabContext.note;
const revisionItems = await server.get(`notes/${note.noteId}/revisions`);
if (revisionItems.length === 0) { if (revisionItems.length === 0) {
this.$body.text("No revisions yet..."); this.$body.text("No revisions yet...");
@ -41,7 +42,7 @@ class NoteRevisionsWidget extends StandardWidget {
for (const item of revisionItems) { for (const item of revisionItems) {
const $listItem = $('<li>').append($("<a>", { const $listItem = $('<li>').append($("<a>", {
'data-action': 'note-revision', 'data-action': 'note-revision',
'data-note-path': this.ctx.note.noteId, 'data-note-path': note.noteId,
'data-note-revision-id': item.noteRevisionId, 'data-note-revision-id': item.noteRevisionId,
href: 'javascript:' href: 'javascript:'
}).text(item.dateLastEdited.substr(0, 16))); }).text(item.dateLastEdited.substr(0, 16)));
@ -54,11 +55,9 @@ class NoteRevisionsWidget extends StandardWidget {
} }
} }
eventReceived(name, data) { syncDataListener({data}) {
if (name === 'syncData') { if (data.find(sd => sd.entityName === 'note_revisions' && sd.noteId === this.tabContext.note.noteId)) {
if (data.find(sd => sd.entityName === 'note_revisions' && sd.noteId === this.ctx.note.noteId)) { this.activeTabChanged();
this.doRenderBody();
}
} }
} }
} }

View File

@ -14,11 +14,11 @@ class SimilarNotesWidget extends StandardWidget {
getMaxHeight() { return "200px"; } getMaxHeight() { return "200px"; }
async doRenderBody() { async activeTabChanged() {
// remember which title was when we found the similar notes // remember which title was when we found the similar notes
this.title = this.ctx.note.title; this.title = this.tabContext.note.title;
const similarNotes = await server.get('similar-notes/' + this.ctx.note.noteId); const similarNotes = await server.get('similar-notes/' + this.tabContext.note.noteId);
if (similarNotes.length === 0) { if (similarNotes.length === 0) {
this.$body.text("No similar notes found ..."); this.$body.text("No similar notes found ...");
@ -47,15 +47,13 @@ class SimilarNotesWidget extends StandardWidget {
this.$body.empty().append($list); this.$body.empty().append($list);
} }
eventReceived(name, data) { noteSavedListener({data}) {
if (name === 'noteSaved') { if (this.title !== this.tabContext.note.title) {
if (this.title !== this.ctx.note.title) {
this.rendered = false; this.rendered = false;
this.renderBody(); this.renderBody();
} }
} }
}
} }
export default SimilarNotesWidget; export default SimilarNotesWidget;

View File

@ -1,4 +1,5 @@
import optionsService from "../services/options.js"; import utils from "../services/utils.js";
import TabAwareWidget from "./tab_aware_widget.js";
const WIDGET_TPL = ` const WIDGET_TPL = `
<div class="card widget"> <div class="card widget">
@ -20,25 +21,7 @@ const WIDGET_TPL = `
</div> </div>
`; `;
class StandardWidget { class StandardWidget extends TabAwareWidget {
/**
* @param {TabContext} ctx
* @param {Options} options
* @param {object} sidebarState
*/
constructor(ctx, options, sidebarState) {
this.ctx = ctx;
// construct in camelCase
this.widgetName = this.constructor.name.substr(0, 1).toLowerCase() + this.constructor.name.substr(1);
this.widgetOptions = options.getJson(this.widgetName) || {
expanded: true
};
this.state = sidebarState.widgets.find(s => s.name === this.widgetName) || {
expanded: this.widgetOptions.expanded
};
}
getWidgetTitle() { return "Untitled widget"; } getWidgetTitle() { return "Untitled widget"; }
getHeaderActions() { return []; } getHeaderActions() { return []; }
@ -47,20 +30,20 @@ class StandardWidget {
getMaxHeight() { return null; } getMaxHeight() { return null; }
getPosition() { return this.widgetOptions.position; } //getPosition() { return this.widgetOptions.position; }
render() { render() {
const widgetId = `tab-${this.ctx.tabId}-widget-${this.widgetName}`; const widgetInstanceId = this.widgetId + "-" + utils.randomString(10);
this.$widget = $(WIDGET_TPL); this.$widget = $(WIDGET_TPL);
this.$widget.find('[data-target]').attr('data-target', "#" + widgetId); this.$widget.find('[data-target]').attr('data-target', "#" + widgetInstanceId);
this.$bodyWrapper = this.$widget.find('.body-wrapper'); this.$bodyWrapper = this.$widget.find('.body-wrapper');
this.$bodyWrapper.attr('id', widgetId); this.$bodyWrapper.attr('id', widgetInstanceId);
if (this.state.expanded) { // if (this.state.expanded) {
this.$bodyWrapper.collapse("show"); this.$bodyWrapper.collapse("show");
} // }
this.$body = this.$bodyWrapper.find('.card-body'); this.$body = this.$bodyWrapper.find('.card-body');
@ -71,9 +54,9 @@ class StandardWidget {
this.$body.css("overflow", "auto"); this.$body.css("overflow", "auto");
} }
this.$widget.on('shown.bs.collapse', () => this.renderBody()); // this.$widget.on('shown.bs.collapse', () => this.renderBody());
this.$widget.on('shown.bs.collapse', () => this.ctx.stateChanged()); // this.$widget.on('shown.bs.collapse', () => this.ctx.stateChanged());
this.$widget.on('hidden.bs.collapse', () => this.ctx.stateChanged()); // this.$widget.on('hidden.bs.collapse', () => this.ctx.stateChanged());
this.$title = this.$widget.find('.widget-title'); this.$title = this.$widget.find('.widget-title');
this.$title.text(this.getWidgetTitle()); this.$title.text(this.getWidgetTitle());
@ -103,11 +86,11 @@ class StandardWidget {
} }
async renderBody() { async renderBody() {
if (!this.isExpanded() || this.rendered) { // if (!this.isExpanded() || this.rendered) {
return; // return;
} // }
//
this.rendered = true; // this.rendered = true;
await this.doRenderBody(); await this.doRenderBody();
} }
@ -139,8 +122,6 @@ class StandardWidget {
}; };
} }
eventReceived(name, data) {}
cleanup() {} cleanup() {}
} }

View File

@ -22,8 +22,8 @@ class WhatLinksHereWidget extends StandardWidget {
return [$showFullButton]; return [$showFullButton];
} }
async doRenderBody() { async activeTabChanged() {
const targetRelations = await this.ctx.note.getTargetRelations(); const targetRelations = await this.tabContext.note.getTargetRelations();
if (targetRelations.length === 0) { if (targetRelations.length === 0) {
this.$body.text("Nothing links here yet ..."); this.$body.text("Nothing links here yet ...");

View File

@ -138,7 +138,12 @@
<div id="center-pane"></div> <div id="center-pane"></div>
<% include sidebar.ejs %> <button id="hide-sidebar-button" class="btn btn-sm icon-button bx bx-chevrons-right hide-in-zen-mode" title="Hide sidebar"></button>
<button id="show-sidebar-button" class="btn btn-sm icon-button bx bx-chevrons-left hide-in-zen-mode" title="Show sidebar"></button>
<div id="right-pane" class="hide-in-zen-mode">
<div id="sidebar-container"></div>
</div>
</div> </div>
<div class="dropdown-menu dropdown-menu-sm" id="context-menu-container"></div> <div class="dropdown-menu dropdown-menu-sm" id="context-menu-container"></div>

View File

@ -1,6 +0,0 @@
<button id="hide-sidebar-button" class="btn btn-sm icon-button bx bx-chevrons-right hide-in-zen-mode" title="Hide sidebar"></button>
<button id="show-sidebar-button" class="btn btn-sm icon-button bx bx-chevrons-left hide-in-zen-mode" title="Show sidebar"></button>
<div id="right-pane" class="hide-in-zen-mode">
<div id="sidebar-container"></div>
</div>