mirror of
https://github.com/zadam/trilium.git
synced 2025-06-05 17:38:47 +02:00
appContext is now component
This commit is contained in:
parent
22c042e21f
commit
e000fb4579
@ -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);
|
||||
|
@ -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';
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
});
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -169,7 +169,7 @@ function getTemplates(treeWidget) {
|
||||
return false;
|
||||
},
|
||||
"editNoteTitle": node => {
|
||||
appContext.trigger('focusOnTitle');
|
||||
appContext.triggerEvent('focusOnTitle');
|
||||
|
||||
return false;
|
||||
},
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -51,6 +51,6 @@ export default class NoteActionsWidget extends TabAwareWidget {
|
||||
return;
|
||||
}
|
||||
|
||||
this.trigger(eventName);
|
||||
this.triggerEvent(eventName);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -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');
|
||||
}
|
||||
}
|
||||
}
|
@ -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() {
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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() {
|
||||
|
@ -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>')
|
||||
|
Loading…
x
Reference in New Issue
Block a user