appContext is now component

This commit is contained in:
zadam 2020-02-16 19:21:17 +01:00
parent 22c042e21f
commit e000fb4579
23 changed files with 70 additions and 103 deletions

View File

@ -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);

View File

@ -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';

View File

@ -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() {

View File

@ -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() {

View File

@ -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

View File

@ -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() {

View File

@ -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());

View File

@ -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
});

View File

@ -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();
}

View File

@ -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);

View File

@ -169,7 +169,7 @@ function getTemplates(treeWidget) {
return false;
},
"editNoteTitle": node => {
appContext.trigger('focusOnTitle');
appContext.triggerEvent('focusOnTitle');
return false;
},

View File

@ -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 {

View File

@ -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);

View File

@ -51,6 +51,6 @@ export default class NoteActionsWidget extends TabAwareWidget {
return;
}
this.trigger(eventName);
this.triggerEvent(eventName);
}
}

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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() {

View File

@ -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');
}
}
}

View File

@ -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() {

View File

@ -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);

View File

@ -16,11 +16,11 @@ export default class TabCachingWidget extends TabAwareWidget {
return this.$widget = $(`<div class="marker" style="display: none;">`);
}
async triggerChildren(name, data) {
async handleEventInChildren(name, data) {
// stop propagation of the event to the children, individual tab widget should not know about tab switching
// since they are per-tab
if (name !== 'activeTabChanged') {
await super.triggerChildren(name, data);
await super.handleEventInChildren(name, data);
}
}
@ -42,7 +42,7 @@ export default class TabCachingWidget extends TabAwareWidget {
this.children.push(widget);
this.$widget.after(widget.render());
widget.eventReceived('setTabContext', {tabContext: this.tabContext});
widget.handleEvent('setTabContext', {tabContext: this.tabContext});
}
widget.toggle(widget.isEnabled());

View File

@ -262,7 +262,7 @@ export default class TabRowWidget extends BasicWidget {
];
},
selectContextMenuItem: (e, cmd) => {
this.trigger(cmd, {tabId});
this.triggerEvent(cmd, {tabId});
}
});
});
@ -543,7 +543,7 @@ export default class TabRowWidget extends BasicWidget {
tabEl.parentNode.insertBefore(tabEl, beforeEl);
}
this.trigger('tabReorder', {tabIdsInOrder: this.getTabIdsInOrder()});
this.triggerEvent('tabReorder', {tabIdsInOrder: this.getTabIdsInOrder()});
this.layoutTabs();
}
@ -552,7 +552,7 @@ export default class TabRowWidget extends BasicWidget {
this.$tabContainer.append(this.$newTab);
this.$newTab.on('click', _ => this.trigger('openNewTab'));
this.$newTab.on('click', _ => this.triggerEvent('openNewTab'));
}
setupFiller() {

View File

@ -202,7 +202,7 @@ export default class BookTypeWidget extends TypeWidget {
const $addTextLink = $('<a href="javascript:">here</a>').on('click', () => {
this.tabContext.autoBookDisabled = true;
this.trigger('autoBookDisabled');
this.triggerEvent('autoBookDisabled');
});
this.$content.append($('<div class="note-book-auto-message"></div>')