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 NoteDetailWidget from "../widgets/note_detail.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 {
constructor() {
@ -56,10 +62,26 @@ class AppContext {
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.tabRow,
...leftPaneWidgets,
...centerPaneWidgets
...centerPaneWidgets,
...rightPaneWidgets
];
}

View File

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

View File

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

View File

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

View File

@ -29,15 +29,17 @@ class CalendarWidget extends StandardWidget {
async isEnabled() {
return await super.isEnabled()
&& await this.ctx.note.hasLabel("dateNote");
&& await this.tabContext.note.hasLabel("dateNote");
}
async doRenderBody() {
await libraryLoader.requireLibrary(libraryLoader.CALENDAR_WIDGET);
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) {

View File

@ -16,23 +16,23 @@ class EditedNotesWidget extends StandardWidget {
async isEnabled() {
return await super.isEnabled()
&& await this.ctx.note.hasLabel("dateNote");
&& await this.tabContext.note.hasLabel("dateNote");
}
async doRenderBody() {
const note = this.tabContext.note;
// 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(note => note.noteId !== this.ctx.note.noteId);
editedNotes = editedNotes.filter(n => n.noteId !== note.noteId);
if (editedNotes.length === 0) {
this.$body.text("No edited notes on this day yet ...");
return;
}
const noteIds = editedNotes.flatMap(note => note.noteId);
const noteIds = editedNotes.flatMap(n => n.noteId);
await treeCache.getNotes(noteIds, true); // preload all at once

View File

@ -28,7 +28,7 @@ class LinkMapWidget extends StandardWidget {
return [$showFullButton];
}
async doRenderBody() {
async activeTabChanged() {
this.$body.css('opacity', 0);
this.$body.html(TPL);
@ -38,7 +38,7 @@ class LinkMapWidget extends StandardWidget {
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,
zoom: 0.6
});
@ -54,14 +54,12 @@ class LinkMapWidget extends StandardWidget {
}
}
eventReceived(name, data) {
if (name === 'syncData') {
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
// (and is guaranteed to run first)
if (this.linkMapService) {
this.linkMapService.loadNotesAndRelations();
}
syncDataListener({data}) {
if (data.find(sd => sd.entityName === 'attributes' && sd.noteId === this.tabContext.note.noteId)) {
// no need to invalidate attributes since the Attribute class listens to this as well
// (and is guaranteed to run first)
if (this.linkMapService) {
this.linkMapService.loadNotesAndRelations();
}
}
}

View File

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

View File

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

View File

@ -14,11 +14,11 @@ class SimilarNotesWidget extends StandardWidget {
getMaxHeight() { return "200px"; }
async doRenderBody() {
async activeTabChanged() {
// 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) {
this.$body.text("No similar notes found ...");
@ -47,13 +47,11 @@ class SimilarNotesWidget extends StandardWidget {
this.$body.empty().append($list);
}
eventReceived(name, data) {
if (name === 'noteSaved') {
if (this.title !== this.ctx.note.title) {
this.rendered = false;
noteSavedListener({data}) {
if (this.title !== this.tabContext.note.title) {
this.rendered = false;
this.renderBody();
}
this.renderBody();
}
}
}

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 = `
<div class="card widget">
@ -20,25 +21,7 @@ const WIDGET_TPL = `
</div>
`;
class StandardWidget {
/**
* @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
};
}
class StandardWidget extends TabAwareWidget {
getWidgetTitle() { return "Untitled widget"; }
getHeaderActions() { return []; }
@ -47,20 +30,20 @@ class StandardWidget {
getMaxHeight() { return null; }
getPosition() { return this.widgetOptions.position; }
//getPosition() { return this.widgetOptions.position; }
render() {
const widgetId = `tab-${this.ctx.tabId}-widget-${this.widgetName}`;
const widgetInstanceId = this.widgetId + "-" + utils.randomString(10);
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.attr('id', widgetId);
this.$bodyWrapper.attr('id', widgetInstanceId);
if (this.state.expanded) {
// if (this.state.expanded) {
this.$bodyWrapper.collapse("show");
}
// }
this.$body = this.$bodyWrapper.find('.card-body');
@ -71,9 +54,9 @@ class StandardWidget {
this.$body.css("overflow", "auto");
}
this.$widget.on('shown.bs.collapse', () => this.renderBody());
this.$widget.on('shown.bs.collapse', () => this.ctx.stateChanged());
this.$widget.on('hidden.bs.collapse', () => this.ctx.stateChanged());
// this.$widget.on('shown.bs.collapse', () => this.renderBody());
// this.$widget.on('shown.bs.collapse', () => this.ctx.stateChanged());
// this.$widget.on('hidden.bs.collapse', () => this.ctx.stateChanged());
this.$title = this.$widget.find('.widget-title');
this.$title.text(this.getWidgetTitle());
@ -103,11 +86,11 @@ class StandardWidget {
}
async renderBody() {
if (!this.isExpanded() || this.rendered) {
return;
}
this.rendered = true;
// if (!this.isExpanded() || this.rendered) {
// return;
// }
//
// this.rendered = true;
await this.doRenderBody();
}
@ -139,8 +122,6 @@ class StandardWidget {
};
}
eventReceived(name, data) {}
cleanup() {}
}

View File

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

View File

@ -138,7 +138,12 @@
<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 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>