From f25d735b9db6a556007fc0fddf8f4d248b4cf8ec Mon Sep 17 00:00:00 2001 From: zadam Date: Sun, 12 Jan 2020 12:48:17 +0100 Subject: [PATCH] further tab management moved to app context --- .../javascripts/services/app_context.js | 106 ++++++++++++++++ .../javascripts/services/hoisted_note.js | 2 +- .../javascripts/services/note_detail.js | 114 +----------------- .../javascripts/services/tab_context.js | 2 +- src/public/javascripts/services/tree.js | 2 +- 5 files changed, 111 insertions(+), 115 deletions(-) diff --git a/src/public/javascripts/services/app_context.js b/src/public/javascripts/services/app_context.js index 3c1bcadd7..c24173698 100644 --- a/src/public/javascripts/services/app_context.js +++ b/src/public/javascripts/services/app_context.js @@ -6,12 +6,16 @@ import tabRow from "./tab_row.js"; import treeService from "./tree.js"; import noteDetailService from "./note_detail.js"; import TabContext from "./tab_context.js"; +import server from "./server.js"; +import keyboardActionService from "./keyboard_actions.js"; +import contextMenuService from "./context_menu.js"; class AppContext { constructor() { this.widgets = []; /** @type {TabContext[]} */ this.tabContexts = []; + this.tabsChangedTaskId = null; } trigger(name, data) { @@ -175,6 +179,56 @@ class AppContext { await tabRow.activateTab(ctx.$tab[0]); } + + async filterTabs(noteId) { + for (const tc of this.tabContexts) { + if (tc.notePath && !tc.notePath.split("/").includes(noteId)) { + await tabRow.removeTab(tc.$tab[0]); + } + } + + if (this.tabContexts.length === 0) { + this.openEmptyTab() + } + + await this.saveOpenTabs(); + } + + async saveOpenTabs() { + const openTabs = []; + + for (const tabEl of tabRow.tabEls) { + const tabId = tabEl.getAttribute('data-tab-id'); + const tabContext = appContext.getTabContexts().find(tc => tc.tabId === tabId); + + if (tabContext) { + const tabState = tabContext.getTabState(); + + if (tabState) { + openTabs.push(tabState); + } + } + } + + await server.put('options', { + openTabs: JSON.stringify(openTabs) + }); + } + + clearOpenTabsTask() { + if (this.tabsChangedTaskId) { + clearTimeout(this.tabsChangedTaskId); + } + } + + openTabsChanged() { + // we don't want to send too many requests with tab changes so we always schedule task to do this in 1 seconds, + // but if there's any change in between, we cancel the old one and schedule new one + // so effectively we kind of wait until user stopped e.g. quickly switching tabs + this.clearOpenTabsTask(); + + this.tabsChangedTaskId = setTimeout(() => this.saveOpenTabs(), 1000); + } } const appContext = new AppContext(); @@ -200,4 +254,56 @@ tabRow.addListener('tabRemove', async ({ detail }) => { } }); +tabRow.addListener('activeTabChange', () => appContext.openTabsChanged()); +tabRow.addListener('tabRemove', () => appContext.openTabsChanged()); +tabRow.addListener('tabReorder', () => appContext.openTabsChanged()); + +keyboardActionService.setGlobalActionHandler('OpenNewTab', () => { + appContext.openEmptyTab(); +}); + +keyboardActionService.setGlobalActionHandler('CloseActiveTab', () => { + if (tabRow.activeTabEl) { + tabRow.removeTab(tabRow.activeTabEl); + } +}); + +keyboardActionService.setGlobalActionHandler('ActivateNextTab', () => { + const nextTab = tabRow.nextTabEl; + + if (nextTab) { + tabRow.activateTab(nextTab); + } +}); + +keyboardActionService.setGlobalActionHandler('ActivatePreviousTab', () => { + const prevTab = tabRow.previousTabEl; + + if (prevTab) { + tabRow.activateTab(prevTab); + } +}); + +$(tabRow.el).on('contextmenu', '.note-tab', e => { + e.preventDefault(); + + const tab = $(e.target).closest(".note-tab"); + + contextMenuService.initContextMenu(e, { + getContextMenuItems: () => { + return [ + {title: "Close all tabs", cmd: "removeAllTabs", uiIcon: "empty"}, + {title: "Close all tabs except for this", cmd: "removeAllTabsExceptForThis", uiIcon: "empty"} + ]; + }, + selectContextMenuItem: (e, cmd) => { + if (cmd === 'removeAllTabs') { + tabRow.removeAllTabs(); + } else if (cmd === 'removeAllTabsExceptForThis') { + tabRow.removeAllTabsExceptForThis(tab[0]); + } + } + }); +}); + export default appContext; \ No newline at end of file diff --git a/src/public/javascripts/services/hoisted_note.js b/src/public/javascripts/services/hoisted_note.js index 7b5265459..fc2617de6 100644 --- a/src/public/javascripts/services/hoisted_note.js +++ b/src/public/javascripts/services/hoisted_note.js @@ -21,7 +21,7 @@ async function getHoistedNoteId() { async function setHoistedNoteId(noteId) { if (noteId !== 'root') { - await noteDetailService.filterTabs(noteId); + await appContext.filterTabs(noteId); } hoistedNoteId = noteId; diff --git a/src/public/javascripts/services/note_detail.js b/src/public/javascripts/services/note_detail.js index 5914add37..4f7af4d60 100644 --- a/src/public/javascripts/services/note_detail.js +++ b/src/public/javascripts/services/note_detail.js @@ -36,7 +36,7 @@ async function switchToNote(notePath) { await loadNoteDetail(notePath); - openTabsChanged(); + appContext.openTabsChanged(); } function onNoteChange(func) { @@ -87,7 +87,7 @@ async function activateOrOpenNote(noteId) { async function loadNoteDetailToContext(ctx, note, notePath) { await ctx.setNote(note, notePath); - openTabsChanged(); + appContext.openTabsChanged(); fireDetailLoaded(); } @@ -141,23 +141,6 @@ async function loadNote(noteId) { return new NoteFull(treeCache, row, noteShort); } -async function filterTabs(noteId) { - for (const tc of appContext.getTabContexts()) { - if (tc.notePath && !tc.notePath.split("/").includes(noteId)) { - await tabRow.removeTab(tc.$tab[0]); - } - } - - if (appContext.getTabContexts().length === 0) { - await loadNoteDetail(noteId, { - newTab: true, - activate: true - }); - } - - await saveOpenTabs(); -} - async function noteDeleted(noteId) { for (const tc of appContext.getTabContexts()) { // not removing active even if it contains deleted note since that one will move to another note (handled by deletion logic) @@ -250,96 +233,6 @@ $tabContentsContainer.on("drop", async e => { }); }); -$(tabRow.el).on('contextmenu', '.note-tab', e => { - e.preventDefault(); - - const tab = $(e.target).closest(".note-tab"); - - contextMenuService.initContextMenu(e, { - getContextMenuItems: () => { - return [ - {title: "Close all tabs", cmd: "removeAllTabs", uiIcon: "empty"}, - {title: "Close all tabs except for this", cmd: "removeAllTabsExceptForThis", uiIcon: "empty"} - ]; - }, - selectContextMenuItem: (e, cmd) => { - if (cmd === 'removeAllTabs') { - tabRow.removeAllTabs(); - } else if (cmd === 'removeAllTabsExceptForThis') { - tabRow.removeAllTabsExceptForThis(tab[0]); - } - } - }); -}); - -keyboardActionService.setGlobalActionHandler('OpenNewTab', () => { - openEmptyTab(); -}); - -keyboardActionService.setGlobalActionHandler('CloseActiveTab', () => { - if (tabRow.activeTabEl) { - tabRow.removeTab(tabRow.activeTabEl); - } -}); - -keyboardActionService.setGlobalActionHandler('ActivateNextTab', () => { - const nextTab = tabRow.nextTabEl; - - if (nextTab) { - tabRow.activateTab(nextTab); - } -}); - -keyboardActionService.setGlobalActionHandler('ActivatePreviousTab', () => { - const prevTab = tabRow.previousTabEl; - - if (prevTab) { - tabRow.activateTab(prevTab); - } -}); - -tabRow.addListener('activeTabChange', openTabsChanged); -tabRow.addListener('tabRemove', openTabsChanged); -tabRow.addListener('tabReorder', openTabsChanged); - -let tabsChangedTaskId = null; - -function clearOpenTabsTask() { - if (tabsChangedTaskId) { - clearTimeout(tabsChangedTaskId); - } -} - -function openTabsChanged() { - // we don't want to send too many requests with tab changes so we always schedule task to do this in 1 seconds, - // but if there's any change in between, we cancel the old one and schedule new one - // so effectively we kind of wait until user stopped e.g. quickly switching tabs - clearOpenTabsTask(); - - tabsChangedTaskId = setTimeout(saveOpenTabs, 1000); -} - -async function saveOpenTabs() { - const openTabs = []; - - for (const tabEl of tabRow.tabEls) { - const tabId = tabEl.getAttribute('data-tab-id'); - const tabContext = appContext.getTabContexts().find(tc => tc.tabId === tabId); - - if (tabContext) { - const tabState = tabContext.getTabState(); - - if (tabState) { - openTabs.push(tabState); - } - } - } - - await server.put('options', { - openTabs: JSON.stringify(openTabs) - }); -} - function noteChanged() { const activeTabContext = appContext.getActiveTabContext(); @@ -367,10 +260,7 @@ export default { addDetailLoadedListener, getActiveEditor, activateOrOpenNote, - clearOpenTabsTask, - filterTabs, noteDeleted, noteChanged, - openTabsChanged, reloadNote }; \ No newline at end of file diff --git a/src/public/javascripts/services/tab_context.js b/src/public/javascripts/services/tab_context.js index 1c52f8d2b..794e8f80a 100644 --- a/src/public/javascripts/services/tab_context.js +++ b/src/public/javascripts/services/tab_context.js @@ -479,7 +479,7 @@ class TabContext { } stateChanged() { - noteDetailService.openTabsChanged(); + appContext.openTabsChanged(); } } diff --git a/src/public/javascripts/services/tree.js b/src/public/javascripts/services/tree.js index 2414ec6d7..a21b1f40f 100644 --- a/src/public/javascripts/services/tree.js +++ b/src/public/javascripts/services/tree.js @@ -287,7 +287,7 @@ async function treeInitialized() { // previous opening triggered task to save tab changes but these are bogus changes (this is init) // so we'll cancel it - noteDetailService.clearOpenTabsTask(); + appContext.clearOpenTabsTask(); setFrontendAsLoaded(); }