diff --git a/src/public/javascripts/dialogs/markdown_import.js b/src/public/javascripts/dialogs/markdown_import.js index a8df0a15a..05d7d245a 100644 --- a/src/public/javascripts/dialogs/markdown_import.js +++ b/src/public/javascripts/dialogs/markdown_import.js @@ -16,7 +16,7 @@ async function convertMarkdownToHtml(text) { const result = writer.render(parsed); - appContext.trigger('executeInActiveEditor', { + appContext.triggerEvent('executeInActiveEditor', { callback: textEditor => { const viewFragment = textEditor.data.processor.toView(result); const modelFragment = textEditor.data.toModel(viewFragment); diff --git a/src/public/javascripts/dialogs/options/appearance.js b/src/public/javascripts/dialogs/options/appearance.js index c1f73f27f..372ed1e1f 100644 --- a/src/public/javascripts/dialogs/options/appearance.js +++ b/src/public/javascripts/dialogs/options/appearance.js @@ -106,7 +106,7 @@ export default class ApperanceOptions { server.put('options/theme/' + newTheme); }); - this.$zoomFactorSelect.on('change', () => { appContext.trigger('setZoomFactorAndSave', {zoomFactor: this.$zoomFactorSelect.val()}); }); + this.$zoomFactorSelect.on('change', () => { appContext.triggerEvent('setZoomFactorAndSave', {zoomFactor: this.$zoomFactorSelect.val()}); }); this.$nativeTitleBarSelect.on('change', () => { const nativeTitleBarVisible = this.$nativeTitleBarSelect.val() === 'show' ? 'true' : 'false'; diff --git a/src/public/javascripts/services/app_context.js b/src/public/javascripts/services/app_context.js index 8c57f08c9..79349981a 100644 --- a/src/public/javascripts/services/app_context.js +++ b/src/public/javascripts/services/app_context.js @@ -9,14 +9,15 @@ import ZoomService from "./zoom.js"; import Layout from "../widgets/layout.js"; import TabManager from "./tab_manager.js"; import treeService from "./tree.js"; +import Component from "../widgets/component.js"; -class AppContext { +class AppContext extends Component { constructor(layout) { + super(null); + this.layout = layout; this.tabManager = new TabManager(this); - this.components = []; this.executors = []; - this.idToComponent = {}; } async start() { @@ -30,72 +31,38 @@ class AppContext { } showWidgets() { - const rootContainer = this.layout.getRootWidget(this); - const $renderedWidget = rootContainer.render(); + const rootWidget = this.layout.getRootWidget(this); + const $renderedWidget = rootWidget.render(); $("body").append($renderedWidget); $renderedWidget.on('click', "[data-trigger-event]", e => { const eventName = $(e.target).attr('data-trigger-event'); - this.trigger(eventName); + this.triggerEvent(eventName); }); - this.components = [ + this.children = [ this.tabManager, - rootContainer, + rootWidget, new Entrypoints(this) ]; this.executors = [ - new DialogCommandExecutor(this, this) + new DialogCommandExecutor(this) ]; if (utils.isElectron()) { - this.components.push(new ZoomService(this, this)); + this.children.push(new ZoomService(this)); import("./spell_check.js").then(spellCheckService => spellCheckService.initSpellCheck()); } - this.trigger('initialRenderComplete'); + this.triggerEvent('initialRenderComplete'); } - registerComponent(componentId, component) { - this.idToComponent[componentId] = component; - } - - findComponentById(componentId) { - return this.idToComponent[componentId]; - } - - getComponentByEl(el) { - return $(el).closest(".component").prop('component'); - } - - async trigger(name, data) { - this.eventReceived(name, data); - - const promises = []; - - for (const component of this.components) { - promises.push(component.eventReceived(name, data)); - } - - await Promise.all(promises); - } - - async eventReceived(name, data) { - const fun = this[name + 'Listener']; - - if (typeof fun === 'function') { - await fun.call(this, data); - } - } - - async protectedSessionStartedListener() { - await treeCache.loadInitialTree(); - - this.trigger('treeCacheReloaded'); + async triggerEvent(name, data) { + await this.handleEvent(name, data); } async triggerCommand(name, data = {}) { @@ -112,14 +79,14 @@ class AppContext { console.error(`Unhandled command ${name}`); } - async callMethod(thiz, fun, data) { - if (typeof fun !== 'function') { - return false; - } + getComponentByEl(el) { + return $(el).closest(".component").prop('component'); + } - await fun.call(thiz, data); + async protectedSessionStartedListener() { + await treeCache.loadInitialTree(); - return true; + this.triggerEvent('treeCacheReloaded'); } } @@ -129,7 +96,7 @@ const appContext = new AppContext(layout); // we should save all outstanding changes before the page/app is closed $(window).on('beforeunload', () => { - appContext.trigger('beforeUnload'); + appContext.triggerEvent('beforeUnload'); }); function isNotePathInAddress() { diff --git a/src/public/javascripts/services/entrypoints.js b/src/public/javascripts/services/entrypoints.js index 1d986fa0b..0206884fb 100644 --- a/src/public/javascripts/services/entrypoints.js +++ b/src/public/javascripts/services/entrypoints.js @@ -74,7 +74,7 @@ export default class Entrypoints extends Component { appContext.tabManager.activateTab(tabContext.tabId); await tabContext.setNote(note.noteId); - appContext.trigger('focusAndSelectTitle'); + appContext.triggerEvent('focusAndSelectTitle'); } async toggleNoteHoistingListener() { diff --git a/src/public/javascripts/services/frontend_script_api.js b/src/public/javascripts/services/frontend_script_api.js index d9f7386d4..7c2704790 100644 --- a/src/public/javascripts/services/frontend_script_api.js +++ b/src/public/javascripts/services/frontend_script_api.js @@ -61,7 +61,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte await ws.waitForMaxKnownSyncId(); await appContext.tabManager.getActiveTabContext().setNote(notePath); - appContext.trigger('focusAndSelectTitle'); + appContext.triggerEvent('focusAndSelectTitle'); }; /** @@ -279,7 +279,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte * @param {string} text - this must be clear text, HTML is not supported. * @method */ - this.addTextToActiveTabEditor = text => appContext.trigger('addTextToActiveEditor', {text}); + this.addTextToActiveTabEditor = text => appContext.triggerEvent('addTextToActiveEditor', {text}); /** * @method @@ -293,7 +293,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte * @method * @param callback - method receiving "textEditor" instance */ - this.getActiveTabTextEditor = callback => appContext.trigger('executeInActiveEditor', {callback}); + this.getActiveTabTextEditor = callback => appContext.triggerEvent('executeInActiveEditor', {callback}); /** * @method diff --git a/src/public/javascripts/services/hoisted_note.js b/src/public/javascripts/services/hoisted_note.js index cbc444cf7..6c2aebc78 100644 --- a/src/public/javascripts/services/hoisted_note.js +++ b/src/public/javascripts/services/hoisted_note.js @@ -10,7 +10,7 @@ async function setHoistedNoteId(noteId) { await options.save('hoistedNoteId', noteId); // FIXME - just use option load event - appContext.trigger('hoistedNoteChanged', {noteId}); + appContext.triggerEvent('hoistedNoteChanged', {noteId}); } async function unhoist() { diff --git a/src/public/javascripts/services/protected_session.js b/src/public/javascripts/services/protected_session.js index a8c1c911e..918533eb7 100644 --- a/src/public/javascripts/services/protected_session.js +++ b/src/public/javascripts/services/protected_session.js @@ -47,7 +47,7 @@ async function setupProtectedSession(password) { protectedSessionHolder.setProtectedSessionId(response.protectedSessionId); protectedSessionHolder.touchProtectedSession(); - appContext.trigger('protectedSessionStarted'); + appContext.triggerEvent('protectedSessionStarted'); if (protectedSessionDeferred !== null) { import("../dialogs/protected_session.js").then(dialog => dialog.close()); diff --git a/src/public/javascripts/services/tab_context.js b/src/public/javascripts/services/tab_context.js index edff6f6fd..20bf8bfb2 100644 --- a/src/public/javascripts/services/tab_context.js +++ b/src/public/javascripts/services/tab_context.js @@ -17,7 +17,7 @@ class TabContext extends Component { this.tabId = tabId || utils.randomString(4); - this.trigger('newTabOpened', {tabId: this.tabId}); + this.triggerEvent('newTabOpened', {tabId: this.tabId}); } async setNote(inputNotePath) { @@ -36,7 +36,7 @@ class TabContext extends Component { return; // note is outside of hoisted subtree and user chose not to unhoist } - await this.trigger('beforeNoteSwitch', {tabId: this.tabId}); + await this.triggerEvent('beforeNoteSwitch', {tabId: this.tabId}); utils.closeActiveDialog(); @@ -62,7 +62,7 @@ class TabContext extends Component { protectedSessionHolder.touchProtectedSession(); } - this.trigger('tabNoteSwitched', { + this.triggerEvent('tabNoteSwitched', { tabId: this.tabId, notePath: this.notePath }); @@ -106,7 +106,7 @@ class TabContext extends Component { this.noteId = null; this.notePath = null; - this.trigger('tabNoteSwitched', { + this.triggerEvent('tabNoteSwitched', { tabId: this.tabId, notePath: this.notePath }); diff --git a/src/public/javascripts/services/tab_manager.js b/src/public/javascripts/services/tab_manager.js index 655e74c0a..c4264849c 100644 --- a/src/public/javascripts/services/tab_manager.js +++ b/src/public/javascripts/services/tab_manager.js @@ -6,10 +6,11 @@ import treeCache from "./tree_cache.js"; import treeService from "./tree.js"; import utils from "./utils.js"; import TabContext from "./tab_context.js"; +import appContext from "./app_context.js"; export default class TabManager extends Component { - constructor(appContext, parent) { - super(appContext, parent); + constructor(parent) { + super(parent); this.activeTabId = null; @@ -181,7 +182,7 @@ export default class TabManager extends Component { } openEmptyTab(tabId) { - const tabContext = new TabContext(this.appContext, tabId); + const tabContext = new TabContext(appContext, tabId); this.children.push(tabContext); return tabContext; } @@ -207,7 +208,7 @@ export default class TabManager extends Component { this.activeTabId = tabId; - this.trigger('activeTabChanged'); + this.triggerEvent('activeTabChanged'); this.tabsUpdate.scheduleUpdate(); @@ -221,7 +222,7 @@ export default class TabManager extends Component { return; } - await this.trigger('beforeTabRemove', {tabId}, true); + await this.triggerEvent('beforeTabRemove', {tabId}, true); if (this.tabContexts.length <= 1) { this.openAndActivateEmptyTab(); @@ -232,7 +233,7 @@ export default class TabManager extends Component { this.children = this.children.filter(tc => tc.tabId !== tabId); - this.trigger('tabRemoved', {tabId}); + this.triggerEvent('tabRemoved', {tabId}); this.tabsUpdate.scheduleUpdate(); } diff --git a/src/public/javascripts/services/tree_context_menu.js b/src/public/javascripts/services/tree_context_menu.js index 9ba209dc0..8a36793b6 100644 --- a/src/public/javascripts/services/tree_context_menu.js +++ b/src/public/javascripts/services/tree_context_menu.js @@ -189,7 +189,7 @@ class TreeContextMenu { noteCreateService.duplicateNote(noteId, branch.parentNoteId); } else if (cmd === "searchInSubtree") { - appContext.trigger("searchInSubtree", {noteId}); + appContext.triggerEvent("searchInSubtree", {noteId}); } else { ws.logError("Unknown command: " + cmd); diff --git a/src/public/javascripts/services/tree_keybindings.js b/src/public/javascripts/services/tree_keybindings.js index db89d1b10..820e79be3 100644 --- a/src/public/javascripts/services/tree_keybindings.js +++ b/src/public/javascripts/services/tree_keybindings.js @@ -169,7 +169,7 @@ function getTemplates(treeWidget) { return false; }, "editNoteTitle": node => { - appContext.trigger('focusOnTitle'); + appContext.triggerEvent('focusOnTitle'); return false; }, diff --git a/src/public/javascripts/services/ws.js b/src/public/javascripts/services/ws.js index 3ac74abc9..91c4a5f43 100644 --- a/src/public/javascripts/services/ws.js +++ b/src/public/javascripts/services/ws.js @@ -328,7 +328,7 @@ async function processSyncRows(syncRows) { }); const appContext = (await import("./app_context.js")).default; - appContext.trigger('entitiesReloaded', {loadResults}); + appContext.triggerEvent('entitiesReloaded', {loadResults}); } export default { diff --git a/src/public/javascripts/widgets/component.js b/src/public/javascripts/widgets/component.js index 3b05a9bc1..6e208e70c 100644 --- a/src/public/javascripts/widgets/component.js +++ b/src/public/javascripts/widgets/component.js @@ -1,6 +1,5 @@ import utils from '../services/utils.js'; import Mutex from "../services/mutex.js"; -import appContext from "../services/app_context.js"; export default class Component { /** @@ -16,7 +15,7 @@ export default class Component { this.mutex = new Mutex(); } - async eventReceived(name, data) { + async handleEvent(name, data) { await this.initialized; const fun = this[name + 'Listener']; @@ -31,18 +30,18 @@ export default class Component { console.log(`Event ${name} in component ${this.componentId} took ${end-start}ms`); } - await this.triggerChildren(name, data); + await this.handleEventInChildren(name, data); } - async trigger(name, data) { - await appContext.trigger(name, data); + async triggerEvent(name, data) { + await this.parent.triggerEvent(name, data); } - async triggerChildren(name, data) { + async handleEventInChildren(name, data) { const promises = []; for (const child of this.children) { - promises.push(child.eventReceived(name, data)); + promises.push(child.handleEvent(name, data)); } await Promise.all(promises); diff --git a/src/public/javascripts/widgets/note_actions.js b/src/public/javascripts/widgets/note_actions.js index 62cf491e5..98e5496e6 100644 --- a/src/public/javascripts/widgets/note_actions.js +++ b/src/public/javascripts/widgets/note_actions.js @@ -51,6 +51,6 @@ export default class NoteActionsWidget extends TabAwareWidget { return; } - this.trigger(eventName); + this.triggerEvent(eventName); } } \ No newline at end of file diff --git a/src/public/javascripts/widgets/note_detail.js b/src/public/javascripts/widgets/note_detail.js index f42708091..7d2f5e02f 100644 --- a/src/public/javascripts/widgets/note_detail.js +++ b/src/public/javascripts/widgets/note_detail.js @@ -105,7 +105,7 @@ export default class NoteDetailWidget extends TabAwareWidget { this.children.push(typeWidget); this.$widget.append(typeWidget.render()); - typeWidget.eventReceived('setTabContext', {tabContext: this.tabContext}); + typeWidget.handleEvent('setTabContext', {tabContext: this.tabContext}); } this.setupClasses(); @@ -223,10 +223,10 @@ export default class NoteDetailWidget extends TabAwareWidget { this.refresh(); } - async triggerChildren(name, data) { + async handleEventInChildren(name, data) { // done manually in refresh() if (name !== 'setTabContext') { - await super.triggerChildren(name, data); + await super.handleEventInChildren(name, data); } } } \ No newline at end of file diff --git a/src/public/javascripts/widgets/note_title.js b/src/public/javascripts/widgets/note_title.js index d614a845d..03d9f5b0a 100644 --- a/src/public/javascripts/widgets/note_title.js +++ b/src/public/javascripts/widgets/note_title.js @@ -42,7 +42,7 @@ export default class NoteTitleWidget extends TabAwareWidget { this.$noteTitle.on('input', () => this.spacedUpdate.scheduleUpdate()); utils.bindElShortcut(this.$noteTitle, 'return', () => { - this.trigger('focusOnDetail', {tabId: this.tabContext.tabId}); + this.triggerEvent('focusOnDetail', {tabId: this.tabContext.tabId}); }); return this.$widget; diff --git a/src/public/javascripts/widgets/search_box.js b/src/public/javascripts/widgets/search_box.js index 622afde2a..db2823a7a 100644 --- a/src/public/javascripts/widgets/search_box.js +++ b/src/public/javascripts/widgets/search_box.js @@ -70,7 +70,7 @@ export default class SearchBoxWidget extends BasicWidget { this.$saveSearchButton.on('click', () => this.saveSearch()); - this.$closeSearchButton.on('click', () => this.trigger('hideSearch')); + this.$closeSearchButton.on('click', () => this.triggerEvent('hideSearch')); return this.$widget; } @@ -91,7 +91,7 @@ export default class SearchBoxWidget extends BasicWidget { return; } - this.trigger('searchForResults', { + this.triggerEvent('searchForResults', { searchText: this.$searchInput.val() }); @@ -147,7 +147,7 @@ export default class SearchBoxWidget extends BasicWidget { this.$searchBox.slideUp(); - this.trigger('hideSearchResults'); + this.triggerEvent('hideSearchResults'); } toggleSearchListener() { diff --git a/src/public/javascripts/widgets/side_pane_container.js b/src/public/javascripts/widgets/side_pane_container.js index 7227d55a9..c3db27faa 100644 --- a/src/public/javascripts/widgets/side_pane_container.js +++ b/src/public/javascripts/widgets/side_pane_container.js @@ -12,9 +12,9 @@ export default class SidePaneContainer extends FlexContainer { return super.isEnabled() && options.is(this.side + 'PaneVisible'); } - eventReceived(name, data) { + handleEvent(name, data) { if (options.is(this.side + 'PaneVisible')) { - super.eventReceived(name, data); + super.handleEvent(name, data); } } @@ -22,7 +22,7 @@ export default class SidePaneContainer extends FlexContainer { if (this.side === side) { this.toggle(show); - this.eventReceived('lazyLoaded'); + this.handleEvent('lazyLoaded'); } } } \ No newline at end of file diff --git a/src/public/javascripts/widgets/side_pane_toggles.js b/src/public/javascripts/widgets/side_pane_toggles.js index 9fe070c86..b4e47592b 100644 --- a/src/public/javascripts/widgets/side_pane_toggles.js +++ b/src/public/javascripts/widgets/side_pane_toggles.js @@ -65,7 +65,7 @@ export default class SidePaneToggles extends BasicWidget { splitService.setupSplit(this.paneVisible.left, this.paneVisible.right); - this.trigger('sidebarVisibilityChanged', {side, show}); + this.triggerEvent('sidebarVisibilityChanged', {side, show}); } initialRenderCompleteListener() { diff --git a/src/public/javascripts/widgets/standard_top_widget.js b/src/public/javascripts/widgets/standard_top_widget.js index 5f6979437..4b48646d9 100644 --- a/src/public/javascripts/widgets/standard_top_widget.js +++ b/src/public/javascripts/widgets/standard_top_widget.js @@ -70,8 +70,8 @@ export default class StandardTopWidget extends BasicWidget { this.$widget.prepend(historyNavigationWidget.render()); - this.$widget.find(".jump-to-note-dialog-button").on('click', () => this.trigger('jumpToNote')); - this.$widget.find(".recent-changes-button").on('click', () => this.trigger('showRecentChanges')); + this.$widget.find(".jump-to-note-dialog-button").on('click', () => this.triggerEvent('jumpToNote')); + this.$widget.find(".recent-changes-button").on('click', () => this.triggerEvent('showRecentChanges')); this.$widget.find(".enter-protected-session-button").on('click', protectedSessionService.enterProtectedSession); this.$widget.find(".leave-protected-session-button").on('click', protectedSessionService.leaveProtectedSession); diff --git a/src/public/javascripts/widgets/tab_caching_widget.js b/src/public/javascripts/widgets/tab_caching_widget.js index 6dcc37f90..0e3dd6b0c 100644 --- a/src/public/javascripts/widgets/tab_caching_widget.js +++ b/src/public/javascripts/widgets/tab_caching_widget.js @@ -16,11 +16,11 @@ export default class TabCachingWidget extends TabAwareWidget { return this.$widget = $(`