From f9abea83f3618d3e655b3b61b88114626c6769b3 Mon Sep 17 00:00:00 2001 From: zadam Date: Thu, 22 Aug 2019 23:31:02 +0200 Subject: [PATCH] refactoring of access to options in frontend --- .../0139__show_sidebar_in_new_tab.sql | 2 +- .../javascripts/dialogs/options/appearance.js | 2 +- .../dialogs/options/protected_session.js | 2 +- .../javascripts/dialogs/options/sidebar.js | 6 +- .../javascripts/services/hoisted_note.js | 6 +- .../javascripts/services/options_init.js | 70 ++++++++++++------- .../services/protected_session_holder.js | 2 +- src/public/javascripts/services/sidebar.js | 9 ++- .../javascripts/services/tab_context.js | 2 +- src/public/javascripts/services/tab_row.js | 2 +- src/public/javascripts/services/tree.js | 11 +-- src/public/javascripts/services/zoom.js | 2 +- .../javascripts/widgets/standard_widget.js | 39 +++++++---- 13 files changed, 93 insertions(+), 62 deletions(-) diff --git a/db/migrations/0139__show_sidebar_in_new_tab.sql b/db/migrations/0139__show_sidebar_in_new_tab.sql index 83a878384..5150630dc 100644 --- a/db/migrations/0139__show_sidebar_in_new_tab.sql +++ b/db/migrations/0139__show_sidebar_in_new_tab.sql @@ -1,2 +1,2 @@ INSERT INTO options (name, value, utcDateCreated, utcDateModified, isSynced) -VALUES ('showSidebarInNewTab', '1', '2018-07-29T18:31:00.874Z', '2018-07-29T18:31:00.874Z', 0); \ No newline at end of file +VALUES ('showSidebarInNewTab', 'true', '2018-07-29T18:31:00.874Z', '2018-07-29T18:31:00.874Z', 0); \ No newline at end of file diff --git a/src/public/javascripts/dialogs/options/appearance.js b/src/public/javascripts/dialogs/options/appearance.js index 2f89d6175..430668904 100644 --- a/src/public/javascripts/dialogs/options/appearance.js +++ b/src/public/javascripts/dialogs/options/appearance.js @@ -45,7 +45,7 @@ export default class ApperanceOptions { const hideTabRowForOneTab = this.$oneTabDisplaySelect.val() === 'hide' ? 'true' : 'false'; server.put('options/hideTabRowForOneTab/' + hideTabRowForOneTab) - .then(optionsInit.loadOptions); + .then(optionsInit.reloadOptions); }); this.$leftPaneMinWidth.change(async () => { diff --git a/src/public/javascripts/dialogs/options/protected_session.js b/src/public/javascripts/dialogs/options/protected_session.js index db25f5e1b..7fcc194d1 100644 --- a/src/public/javascripts/dialogs/options/protected_session.js +++ b/src/public/javascripts/dialogs/options/protected_session.js @@ -18,7 +18,7 @@ export default class ProtectedSessionOptions { const protectedSessionTimeout = this.$protectedSessionTimeout.val(); server.put('options', { 'protectedSessionTimeout': protectedSessionTimeout }).then(() => { - optionsInit.loadOptions(); + optionsInit.reloadOptions(); infoService.showMessage("Options change have been saved."); }); diff --git a/src/public/javascripts/dialogs/options/sidebar.js b/src/public/javascripts/dialogs/options/sidebar.js index 96a1ca063..a8eab44ca 100644 --- a/src/public/javascripts/dialogs/options/sidebar.js +++ b/src/public/javascripts/dialogs/options/sidebar.js @@ -24,11 +24,11 @@ export default class SidebarOptions { }); this.$showSidebarInNewTab.change(async () => { - const flag = this.$showSidebarInNewTab.is(":checked") ? 1 : 0; + const flag = this.$showSidebarInNewTab.is(":checked") ? 'true' : 'false'; await server.put('options/showSidebarInNewTab/' + flag); - optionsInit.loadOptions(); + optionsInit.reloadOptions(); }); } @@ -116,6 +116,8 @@ export default class SidebarOptions { }); await server.put('options', opts); + + optionsInit.reloadOptions(); } parseJsonSafely(str) { diff --git a/src/public/javascripts/services/hoisted_note.js b/src/public/javascripts/services/hoisted_note.js index 80b0fc12e..420c54c46 100644 --- a/src/public/javascripts/services/hoisted_note.js +++ b/src/public/javascripts/services/hoisted_note.js @@ -5,12 +5,12 @@ import noteDetailService from "./note_detail.js"; let hoistedNoteId; -optionsInit.optionsReady.then(options => { - hoistedNoteId = options['hoistedNoteId']; +optionsInit.waitForOptions().then(options => { + hoistedNoteId = options.get('hoistedNoteId'); }); async function getHoistedNoteId() { - await optionsInit.optionsReady; + await optionsInit.waitForOptions(); return hoistedNoteId; } diff --git a/src/public/javascripts/services/options_init.js b/src/public/javascripts/services/options_init.js index d68b260cd..11e34efbf 100644 --- a/src/public/javascripts/services/options_init.js +++ b/src/public/javascripts/services/options_init.js @@ -4,9 +4,42 @@ let optionsReady; const loadListeners = []; -function loadOptions() { +class Options { + constructor(arr) { + this.arr = arr; + } + + get(key) { + return this.arr[key]; + } + + getJson(key) { + try { + return JSON.parse(this.arr[key]); + } + catch (e) { + return null; + } + } + + getInt(key) { + return parseInt(this.arr[key]); + } + + getFloat(key) { + return parseFloat(this.arr[key]); + } + + is(key) { + return this.arr[key] === 'true'; + } +} + +function reloadOptions() { optionsReady = new Promise((resolve, reject) => { - server.get('options').then(options => { + server.get('options').then(optionArr => { + const options = new Options(optionArr); + resolve(options); for (const listener of loadListeners) { @@ -14,9 +47,16 @@ function loadOptions() { } }); }); + + return optionsReady; } -loadOptions(); // initial load +/** just waits for some options without triggering reload */ +async function waitForOptions() { + return await optionsReady; +} + +reloadOptions(); // initial load function addLoadListener(listener) { loadListeners.push(listener); @@ -26,28 +66,8 @@ function addLoadListener(listener) { optionsReady.then(listener); } -async function getOption(name) { - const options = await optionsReady; - - return options[name]; -} - -async function getJsonOption(name) { - const option = await getOption(name); - - try { - return JSON.parse(option); - } - catch (e) { - return null; - } -} - export default { - // use addLoadListener() which will be called also on refreshes - optionsReady, addLoadListener, - loadOptions, - getOption, - getJsonOption + reloadOptions, + waitForOptions } \ No newline at end of file diff --git a/src/public/javascripts/services/protected_session_holder.js b/src/public/javascripts/services/protected_session_holder.js index f9b97beb2..18169470f 100644 --- a/src/public/javascripts/services/protected_session_holder.js +++ b/src/public/javascripts/services/protected_session_holder.js @@ -6,7 +6,7 @@ const PROTECTED_SESSION_ID_KEY = 'protectedSessionId'; let lastProtectedSessionOperationDate = null; let protectedSessionTimeout = null; -optionsInitService.addLoadListener(options => setProtectedSessionTimeout(options.protectedSessionTimeout)); +optionsInitService.addLoadListener(options => setProtectedSessionTimeout(options.getInt('protectedSessionTimeout'))); setInterval(() => { if (lastProtectedSessionOperationDate !== null && Date.now() - lastProtectedSessionOperationDate.getTime() > protectedSessionTimeout * 1000) { diff --git a/src/public/javascripts/services/sidebar.js b/src/public/javascripts/services/sidebar.js index 91bf00fab..f0a529845 100644 --- a/src/public/javascripts/services/sidebar.js +++ b/src/public/javascripts/services/sidebar.js @@ -74,10 +74,13 @@ class Sidebar { try { const widget = new widgetClass(this.ctx, state); - await widget.renderBody(); - this.widgets.push(widget); - this.$widgetContainer.append(widget.getWidgetElement()); + if (await widget.isEnabled()) { + const $el = await widget.render(); + + this.widgets.push(widget); + this.$widgetContainer.append($el); + } } catch (e) { messagingService.logError(`Error while loading widget ${widgetClass.name}: ${e.message}`); diff --git a/src/public/javascripts/services/tab_context.js b/src/public/javascripts/services/tab_context.js index ae431dee3..57da7e2c7 100644 --- a/src/public/javascripts/services/tab_context.js +++ b/src/public/javascripts/services/tab_context.js @@ -38,7 +38,7 @@ const componentClasses = { let showSidebarInNewTab = true; optionsInitService.addLoadListener(options => { - showSidebarInNewTab = options.showSidebarInNewTab === '1'; + showSidebarInNewTab = options.is('showSidebarInNewTab'); }); class TabContext { diff --git a/src/public/javascripts/services/tab_row.js b/src/public/javascripts/services/tab_row.js index 9ade26e2e..03694075d 100644 --- a/src/public/javascripts/services/tab_row.js +++ b/src/public/javascripts/services/tab_row.js @@ -410,6 +410,6 @@ class TabRow { const noteTabRowEl = document.querySelector('.note-tab-row'); const tabRow = new TabRow(noteTabRowEl); -optionsInit.addLoadListener(options => tabRow.setHideTabRowForOneTab(options.hideTabRowForOneTab === 'true')); +optionsInit.addLoadListener(options => tabRow.setHideTabRowForOneTab(options.is('hideTabRowForOneTab'))); export default tabRow; \ No newline at end of file diff --git a/src/public/javascripts/services/tree.js b/src/public/javascripts/services/tree.js index b720652b4..71e616469 100644 --- a/src/public/javascripts/services/tree.js +++ b/src/public/javascripts/services/tree.js @@ -331,16 +331,9 @@ async function treeInitialized() { return; } - let openTabs = []; + const options = await optionsInit.waitForOptions(); - try { - const options = await optionsInit.optionsReady; - - openTabs = JSON.parse(options.openTabs); - } - catch (e) { - messagingService.logError("Cannot retrieve open tabs: " + e.stack); - } + const openTabs = options.getJson('openTabs') || []; // if there's notePath in the URL, make sure it's open and active // (useful, among others, for opening clipped notes from clipper) diff --git a/src/public/javascripts/services/zoom.js b/src/public/javascripts/services/zoom.js index 6900779be..28b75e726 100644 --- a/src/public/javascripts/services/zoom.js +++ b/src/public/javascripts/services/zoom.js @@ -40,7 +40,7 @@ function getCurrentZoom() { } if (utils.isElectron()) { - optionsInitService.addLoadListener(options => setZoomFactor(options.zoomFactor)) + optionsInitService.addLoadListener(options => setZoomFactor(options.getFloat('zoomFactor'))) } export default { diff --git a/src/public/javascripts/widgets/standard_widget.js b/src/public/javascripts/widgets/standard_widget.js index a90d702d0..6070fba7d 100644 --- a/src/public/javascripts/widgets/standard_widget.js +++ b/src/public/javascripts/widgets/standard_widget.js @@ -1,3 +1,5 @@ +import optionsInit from "../services/options_init.js"; + const WIDGET_TPL = `
@@ -21,9 +23,20 @@ class StandardWidget { */ constructor(ctx, state) { this.ctx = ctx; - this.widgetName = this.constructor.name; + this.state = state; + // construct in camelCase + this.widgetName = this.constructor.name.substr(0, 1).toLowerCase() + this.constructor.name.substr(1); - const widgetId = `tab-${ctx.tabId}-widget-${this.widgetName}`; + } + + getWidgetTitle() { return "Untitled widget"; } + + getHeaderActions() { return []; } + + getMaxHeight() { return null; } + + async render() { + const widgetId = `tab-${this.ctx.tabId}-widget-${this.widgetName}`; this.$widget = $(WIDGET_TPL); this.$widget.find('[data-target]').attr('data-target', "#" + widgetId); @@ -31,7 +44,7 @@ class StandardWidget { this.$bodyWrapper = this.$widget.find('.body-wrapper'); this.$bodyWrapper.attr('id', widgetId); - if (state && state.expanded) { + if (this.state && this.state.expanded) { this.$bodyWrapper.collapse("show"); } @@ -51,14 +64,12 @@ class StandardWidget { this.$title.text(this.getWidgetTitle()); this.$headerActions = this.$widget.find('.widget-header-actions'); this.$headerActions.append(...this.getHeaderActions()); + + await this.renderBody(); + + return this.$widget; } - getWidgetTitle() { return "Untitled widget"; } - - getHeaderActions() { return []; } - - getMaxHeight() { return null; } - async renderBody() { if (!this.isExpanded() || this.rendered) { return; @@ -72,6 +83,12 @@ class StandardWidget { /** for overriding */ async doRenderBody() {} + async isEnabled() { + const option = await optionsInit.getJsonOption(this.widgetName + 'Widget'); + + return option ? option.enabled : true; + } + isExpanded() { return this.$bodyWrapper.hasClass("show"); } @@ -83,10 +100,6 @@ class StandardWidget { }; } - getWidgetElement() { - return this.$widget; - } - syncDataReceived(syncData) {} }