From 49398f5374bd064f90eab4ad6314b550e42a1e3e Mon Sep 17 00:00:00 2001 From: zadam Date: Sat, 29 Feb 2020 19:43:19 +0100 Subject: [PATCH] refactoring of component event system + little docs --- .../javascripts/services/app_context.js | 16 ++--- src/public/javascripts/widgets/component.js | 62 ++++++++++--------- src/public/javascripts/widgets/note_info.js | 2 +- .../javascripts/widgets/tab_caching_widget.js | 8 ++- 4 files changed, 47 insertions(+), 41 deletions(-) diff --git a/src/public/javascripts/services/app_context.js b/src/public/javascripts/services/app_context.js index f0cd5b2d1..f759a60f4 100644 --- a/src/public/javascripts/services/app_context.js +++ b/src/public/javascripts/services/app_context.js @@ -65,22 +65,24 @@ class AppContext extends Component { this.triggerEvent('initialRenderComplete'); } - async triggerEvent(name, data) { - await this.handleEvent(name, data); + /** @return {Promise} */ + triggerEvent(name, data) { + return this.handleEvent(name, data); } - async triggerCommand(name, data = {}) { + /** @return {Promise} */ + triggerCommand(name, data = {}) { for (const executor of this.executors) { - const called = await executor.handleCommand(name, data); + const fun = executor[name + "Command"]; - if (called) { - return; + if (fun) { + return executor.callMethod(fun, data); } } console.debug(`Unhandled command ${name}, converting to event.`); - await this.triggerEvent(name, data); + return this.triggerEvent(name, data); } getComponentByEl(el) { diff --git a/src/public/javascripts/widgets/component.js b/src/public/javascripts/widgets/component.js index de1f70bee..f951ce8c1 100644 --- a/src/public/javascripts/widgets/component.js +++ b/src/public/javascripts/widgets/component.js @@ -1,6 +1,18 @@ import utils from '../services/utils.js'; import Mutex from "../services/mutex.js"; +/** + * Abstract class for all components in the Trilium's frontend. + * + * Contains also event implementation with following properties: + * - event / command distribution is synchronous which among others mean that events are well ordered - event + * which was sent out first will also be processed first by the component since it was added to the mutex queue + * as the first one + * - execution of the event / command is asynchronous - each component executes the event on its own without regard for + * other components. + * - although the execution is async, we are collecting all the promises and therefore it is possible to wait until the + * event / command is executed in all components - by simply awaiting the `triggerEvent()`. + */ export default class Component { constructor() { this.componentId = `comp-${this.constructor.name}-` + utils.randomString(6); @@ -24,50 +36,40 @@ export default class Component { return this; } - async handleEvent(name, data) { - await this.initialized; - - const fun = this[name + 'Event']; - - const start = Date.now(); - - await this.callMethod(fun, data); - - const end = Date.now(); - - if (end - start > 10 && glob.PROFILING_LOG) { - console.log(`Event ${name} in component ${this.componentId} took ${end-start}ms`); - } - - await this.handleEventInChildren(name, data); + /** @return {Promise} */ + handleEvent(name, data) { + return Promise.all([ + this.initialized.then(() => this.callMethod(this[name + 'Event'], data)), + this.handleEventInChildren(name, data) + ]); } - async triggerEvent(name, data) { - await this.parent.triggerEvent(name, data); + /** @return {Promise} */ + triggerEvent(name, data) { + return this.parent.triggerEvent(name, data); } - async handleEventInChildren(name, data) { + /** @return {Promise} */ + handleEventInChildren(name, data) { const promises = []; for (const child of this.children) { promises.push(child.handleEvent(name, data)); } - await Promise.all(promises); + return Promise.all(promises); } - async triggerCommand(name, data = {}) { - const called = await this.handleCommand(name, data); - - if (!called) { - await this.parent.triggerCommand(name, data); - } - } - - async handleCommand(name, data) { + /** @return {Promise} */ + triggerCommand(name, data = {}) { const fun = this[name + 'Command']; - return await this.callMethod(fun, data); + if (fun) { + return this.callMethod(fun, data); + } + else { + return this.parent.triggerCommand(name, data); + } } async callMethod(fun, data) { diff --git a/src/public/javascripts/widgets/note_info.js b/src/public/javascripts/widgets/note_info.js index 7eac5f9ff..cf0fa5dd0 100644 --- a/src/public/javascripts/widgets/note_info.js +++ b/src/public/javascripts/widgets/note_info.js @@ -38,7 +38,7 @@ const TPL = ` export default class NoteInfoWidget extends CollapsibleWidget { getWidgetTitle() { return "Note info"; } - doRenderBody() { + async doRenderBody() { this.$body.html(TPL); this.$noteId = this.$body.find(".note-info-note-id"); diff --git a/src/public/javascripts/widgets/tab_caching_widget.js b/src/public/javascripts/widgets/tab_caching_widget.js index 9731bf9f8..3fe808c90 100644 --- a/src/public/javascripts/widgets/tab_caching_widget.js +++ b/src/public/javascripts/widgets/tab_caching_widget.js @@ -17,15 +17,17 @@ export default class TabCachingWidget extends TabAwareWidget { return this.$widget = $(`