mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 11:39:01 +01:00 
			
		
		
		
	further tab management moved to app context
This commit is contained in:
		
							parent
							
								
									4d16018f6c
								
							
						
					
					
						commit
						f25d735b9d
					
				| @ -6,12 +6,16 @@ import tabRow from "./tab_row.js"; | |||||||
| import treeService from "./tree.js"; | import treeService from "./tree.js"; | ||||||
| import noteDetailService from "./note_detail.js"; | import noteDetailService from "./note_detail.js"; | ||||||
| import TabContext from "./tab_context.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 { | class AppContext { | ||||||
|     constructor() { |     constructor() { | ||||||
|         this.widgets = []; |         this.widgets = []; | ||||||
|         /** @type {TabContext[]} */ |         /** @type {TabContext[]} */ | ||||||
|         this.tabContexts = []; |         this.tabContexts = []; | ||||||
|  |         this.tabsChangedTaskId = null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     trigger(name, data) { |     trigger(name, data) { | ||||||
| @ -175,6 +179,56 @@ class AppContext { | |||||||
| 
 | 
 | ||||||
|         await tabRow.activateTab(ctx.$tab[0]); |         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(); | 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; | export default appContext; | ||||||
| @ -21,7 +21,7 @@ async function getHoistedNoteId() { | |||||||
| 
 | 
 | ||||||
| async function setHoistedNoteId(noteId) { | async function setHoistedNoteId(noteId) { | ||||||
|     if (noteId !== 'root') { |     if (noteId !== 'root') { | ||||||
|         await noteDetailService.filterTabs(noteId); |         await appContext.filterTabs(noteId); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     hoistedNoteId = noteId; |     hoistedNoteId = noteId; | ||||||
|  | |||||||
| @ -36,7 +36,7 @@ async function switchToNote(notePath) { | |||||||
| 
 | 
 | ||||||
|     await loadNoteDetail(notePath); |     await loadNoteDetail(notePath); | ||||||
| 
 | 
 | ||||||
|     openTabsChanged(); |     appContext.openTabsChanged(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function onNoteChange(func) { | function onNoteChange(func) { | ||||||
| @ -87,7 +87,7 @@ async function activateOrOpenNote(noteId) { | |||||||
| async function loadNoteDetailToContext(ctx, note, notePath) { | async function loadNoteDetailToContext(ctx, note, notePath) { | ||||||
|     await ctx.setNote(note, notePath); |     await ctx.setNote(note, notePath); | ||||||
| 
 | 
 | ||||||
|     openTabsChanged(); |     appContext.openTabsChanged(); | ||||||
| 
 | 
 | ||||||
|     fireDetailLoaded(); |     fireDetailLoaded(); | ||||||
| } | } | ||||||
| @ -141,23 +141,6 @@ async function loadNote(noteId) { | |||||||
|     return new NoteFull(treeCache, row, noteShort); |     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) { | async function noteDeleted(noteId) { | ||||||
|     for (const tc of appContext.getTabContexts()) { |     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)
 |         // 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() { | function noteChanged() { | ||||||
|     const activeTabContext = appContext.getActiveTabContext(); |     const activeTabContext = appContext.getActiveTabContext(); | ||||||
| 
 | 
 | ||||||
| @ -367,10 +260,7 @@ export default { | |||||||
|     addDetailLoadedListener, |     addDetailLoadedListener, | ||||||
|     getActiveEditor, |     getActiveEditor, | ||||||
|     activateOrOpenNote, |     activateOrOpenNote, | ||||||
|     clearOpenTabsTask, |  | ||||||
|     filterTabs, |  | ||||||
|     noteDeleted, |     noteDeleted, | ||||||
|     noteChanged, |     noteChanged, | ||||||
|     openTabsChanged, |  | ||||||
|     reloadNote |     reloadNote | ||||||
| }; | }; | ||||||
| @ -479,7 +479,7 @@ class TabContext { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     stateChanged() { |     stateChanged() { | ||||||
|         noteDetailService.openTabsChanged(); |         appContext.openTabsChanged(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -287,7 +287,7 @@ async function treeInitialized() { | |||||||
| 
 | 
 | ||||||
|     // previous opening triggered task to save tab changes but these are bogus changes (this is init)
 |     // previous opening triggered task to save tab changes but these are bogus changes (this is init)
 | ||||||
|     // so we'll cancel it
 |     // so we'll cancel it
 | ||||||
|     noteDetailService.clearOpenTabsTask(); |     appContext.clearOpenTabsTask(); | ||||||
| 
 | 
 | ||||||
|     setFrontendAsLoaded(); |     setFrontendAsLoaded(); | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 zadam
						zadam