| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  | import Component from "../widgets/component.js"; | 
					
						
							|  |  |  | import SpacedUpdate from "./spaced_update.js"; | 
					
						
							|  |  |  | import server from "./server.js"; | 
					
						
							|  |  |  | import options from "./options.js"; | 
					
						
							| 
									
										
										
										
											2021-04-16 23:01:56 +02:00
										 |  |  | import froca from "./froca.js"; | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  | import treeService from "./tree.js"; | 
					
						
							|  |  |  | import utils from "./utils.js"; | 
					
						
							|  |  |  | import TabContext from "./tab_context.js"; | 
					
						
							| 
									
										
										
										
											2020-04-25 23:52:13 +02:00
										 |  |  | import appContext from "./app_context.js"; | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | export default class TabManager extends Component { | 
					
						
							| 
									
										
										
										
											2020-02-27 10:03:14 +01:00
										 |  |  |     constructor() { | 
					
						
							|  |  |  |         super(); | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.activeTabId = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.tabsUpdate = new SpacedUpdate(async () => { | 
					
						
							| 
									
										
										
										
											2020-04-25 23:52:13 +02:00
										 |  |  |             if (!appContext.isMainWindow) { | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |             const openTabs = this.tabContexts | 
					
						
							|  |  |  |                 .map(tc => tc.getTabState()) | 
					
						
							|  |  |  |                 .filter(t => !!t); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             await server.put('options', { | 
					
						
							|  |  |  |                 openTabs: JSON.stringify(openTabs) | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2021-02-27 23:39:02 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         appContext.addBeforeUnloadListener(this); | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-09 21:13:05 +01:00
										 |  |  |     /** @type {TabContext[]} */ | 
					
						
							|  |  |  |     get tabContexts() { | 
					
						
							|  |  |  |         return this.children; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-20 23:13:34 +02:00
										 |  |  |     /** @type {TabContext[]} */ | 
					
						
							|  |  |  |     get mainTabContexts() { | 
					
						
							|  |  |  |         return this.tabContexts.filter(tc => !tc.parentTabId) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-25 23:52:13 +02:00
										 |  |  |     async loadTabs() { | 
					
						
							|  |  |  |         const tabsToOpen = appContext.isMainWindow | 
					
						
							| 
									
										
										
										
											2020-04-23 23:08:15 +02:00
										 |  |  |             ? (options.getJson('openTabs') || []) | 
					
						
							|  |  |  |             : []; | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // if there's notePath in the URL, make sure it's open and active
 | 
					
						
							|  |  |  |         // (useful, among others, for opening clipped notes from clipper)
 | 
					
						
							|  |  |  |         if (window.location.hash) { | 
					
						
							|  |  |  |             const notePath = window.location.hash.substr(1); | 
					
						
							|  |  |  |             const noteId = treeService.getNoteIdFromNotePath(notePath); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-16 22:57:37 +02:00
										 |  |  |             if (noteId && await froca.noteExists(noteId)) { | 
					
						
							| 
									
										
										
										
											2020-04-25 23:52:13 +02:00
										 |  |  |                 for (const tab of tabsToOpen) { | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |                     tab.active = false; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-25 23:52:13 +02:00
										 |  |  |                 const foundTab = tabsToOpen.find(tab => noteId === treeService.getNoteIdFromNotePath(tab.notePath)); | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 if (foundTab) { | 
					
						
							|  |  |  |                     foundTab.active = true; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else { | 
					
						
							| 
									
										
										
										
											2020-04-25 23:52:13 +02:00
										 |  |  |                     tabsToOpen.push({ | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |                         notePath: notePath, | 
					
						
							| 
									
										
										
										
											2021-02-07 21:27:09 +01:00
										 |  |  |                         active: true, | 
					
						
							|  |  |  |                         hoistedNoteId: glob.extraHoistedNoteId || 'root' | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |                     }); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let filteredTabs = []; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-25 23:52:13 +02:00
										 |  |  |         for (const openTab of tabsToOpen) { | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |             const noteId = treeService.getNoteIdFromNotePath(openTab.notePath); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-16 22:57:37 +02:00
										 |  |  |             if (await froca.noteExists(noteId)) { | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |                 // note doesn't exist so don't try to open tab for it
 | 
					
						
							|  |  |  |                 filteredTabs.push(openTab); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (utils.isMobile()) { | 
					
						
							|  |  |  |             // mobile frontend doesn't have tabs so show only the active tab
 | 
					
						
							|  |  |  |             filteredTabs = filteredTabs.filter(tab => tab.active); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (filteredTabs.length === 0) { | 
					
						
							|  |  |  |             filteredTabs.push({ | 
					
						
							| 
									
										
										
										
											2020-05-05 19:30:03 +02:00
										 |  |  |                 notePath: this.isMainWindow ? 'root' : '', | 
					
						
							| 
									
										
										
										
											2021-02-07 21:27:09 +01:00
										 |  |  |                 active: true, | 
					
						
							|  |  |  |                 extraHoistedNoteId: glob.extraHoistedNoteId || 'root' | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |             }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!filteredTabs.find(tab => tab.active)) { | 
					
						
							|  |  |  |             filteredTabs[0].active = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-21 22:34:40 +02:00
										 |  |  |         console.log("filteredTabs", filteredTabs); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-08 21:23:42 +01:00
										 |  |  |         await this.tabsUpdate.allowUpdateWithoutChange(async () => { | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |             for (const tab of filteredTabs) { | 
					
						
							| 
									
										
										
										
											2021-05-20 23:13:34 +02:00
										 |  |  |                 await this.openTabWithNote(tab.notePath, tab.active, tab.tabId, tab.hoistedNoteId, tab.parentTabId); | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 13:40:46 +01:00
										 |  |  |     tabNoteSwitchedEvent({tabContext}) { | 
					
						
							|  |  |  |         if (tabContext.isActive()) { | 
					
						
							| 
									
										
										
										
											2020-02-08 21:23:42 +01:00
										 |  |  |             this.setCurrentNotePathToHash(); | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-02-08 21:23:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.tabsUpdate.scheduleUpdate(); | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-08 21:23:42 +01:00
										 |  |  |     setCurrentNotePathToHash() { | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |         const activeTabContext = this.getActiveTabContext(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-08 17:17:18 +01:00
										 |  |  |         if (window.history.length === 0 // first history entry
 | 
					
						
							|  |  |  |             || (activeTabContext && activeTabContext.notePath !== treeService.getHashValueFromAddress()[0])) { | 
					
						
							| 
									
										
										
										
											2020-02-09 21:13:05 +01:00
										 |  |  |             const url = '#' + (activeTabContext.notePath || "") + "-" + activeTabContext.tabId; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // using pushState instead of directly modifying document.location because it does not trigger hashchange
 | 
					
						
							|  |  |  |             window.history.pushState(null, "", url); | 
					
						
							| 
									
										
										
										
											2020-10-26 20:11:43 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-02-09 21:13:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-26 20:11:43 +01:00
										 |  |  |         document.title = "Trilium Notes"; | 
					
						
							| 
									
										
										
										
											2020-02-09 21:13:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-26 20:11:43 +01:00
										 |  |  |         if (activeTabContext.note) { | 
					
						
							|  |  |  |             // it helps navigating in history if note title is included in the title
 | 
					
						
							|  |  |  |             document.title += " - " + activeTabContext.note.title; | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-03-08 17:17:18 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.triggerEvent('activeNoteChanged'); // trigger this even in on popstate event
 | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** @return {TabContext[]} */ | 
					
						
							|  |  |  |     getTabContexts() { | 
					
						
							|  |  |  |         return this.tabContexts; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** @returns {TabContext} */ | 
					
						
							|  |  |  |     getTabContextById(tabId) { | 
					
						
							| 
									
										
										
										
											2021-05-20 23:13:34 +02:00
										 |  |  |         const tabContext = this.tabContexts.find(tc => tc.tabId === tabId); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!tabContext) { | 
					
						
							|  |  |  |             throw new Error(`Cannot find tabContext id='${tabId}'`); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return tabContext; | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** @returns {TabContext} */ | 
					
						
							|  |  |  |     getActiveTabContext() { | 
					
						
							| 
									
										
										
										
											2021-05-20 23:13:34 +02:00
										 |  |  |         return this.activeTabId | 
					
						
							|  |  |  |             ? this.getTabContextById(this.activeTabId) | 
					
						
							|  |  |  |             : null; | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** @returns {string|null} */ | 
					
						
							|  |  |  |     getActiveTabNotePath() { | 
					
						
							|  |  |  |         const activeContext = this.getActiveTabContext(); | 
					
						
							|  |  |  |         return activeContext ? activeContext.notePath : null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** @return {NoteShort} */ | 
					
						
							|  |  |  |     getActiveTabNote() { | 
					
						
							|  |  |  |         const activeContext = this.getActiveTabContext(); | 
					
						
							|  |  |  |         return activeContext ? activeContext.note : null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** @return {string|null} */ | 
					
						
							|  |  |  |     getActiveTabNoteId() { | 
					
						
							|  |  |  |         const activeNote = this.getActiveTabNote(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return activeNote ? activeNote.noteId : null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** @return {string|null} */ | 
					
						
							|  |  |  |     getActiveTabNoteType() { | 
					
						
							|  |  |  |         const activeNote = this.getActiveTabNote(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return activeNote ? activeNote.type : null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async switchToTab(tabId, notePath) { | 
					
						
							|  |  |  |         const tabContext = this.tabContexts.find(tc => tc.tabId === tabId) | 
					
						
							| 
									
										
										
										
											2020-02-29 16:26:46 +01:00
										 |  |  |             || await this.openEmptyTab(); | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.activateTab(tabContext.tabId); | 
					
						
							|  |  |  |         await tabContext.setNote(notePath); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async openAndActivateEmptyTab() { | 
					
						
							| 
									
										
										
										
											2020-02-29 16:26:46 +01:00
										 |  |  |         const tabContext = await this.openEmptyTab(); | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         await this.activateTab(tabContext.tabId); | 
					
						
							| 
									
										
										
										
											2020-02-28 11:46:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         await tabContext.setEmpty(); | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-21 22:34:40 +02:00
										 |  |  |     async openEmptyTab(tabId, hoistedNoteId = 'root', parentTabId = null) { | 
					
						
							| 
									
										
										
										
											2021-05-20 23:13:34 +02:00
										 |  |  |         const tabContext = new TabContext(tabId, hoistedNoteId, parentTabId); | 
					
						
							| 
									
										
										
										
											2021-05-21 22:34:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         const existingTabContext = this.children.find(tc => tc.tabId === tabContext.tabId); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (existingTabContext) { | 
					
						
							|  |  |  |             return existingTabContext; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-27 10:03:14 +01:00
										 |  |  |         this.child(tabContext); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-06 22:17:07 +01:00
										 |  |  |         await this.triggerEvent('newTabOpened', {tabContext}); | 
					
						
							| 
									
										
										
										
											2020-02-27 10:03:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |         return tabContext; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-24 23:24:05 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * If the requested notePath is within current note hoisting scope then keep the note hoisting also for the new tab. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     async openTabWithNoteWithHoisting(notePath) { | 
					
						
							|  |  |  |         const tabContext = this.getActiveTabContext(); | 
					
						
							|  |  |  |         let hoistedNoteId = 'root'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (tabContext) { | 
					
						
							| 
									
										
										
										
											2021-03-03 21:49:57 +01:00
										 |  |  |             const resolvedNotePath = await treeService.resolveNotePath(notePath, tabContext.hoistedNoteId); | 
					
						
							| 
									
										
										
										
											2020-11-24 23:24:05 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if (resolvedNotePath.includes(tabContext.hoistedNoteId)) { | 
					
						
							|  |  |  |                 hoistedNoteId = tabContext.hoistedNoteId; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return this.openTabWithNote(notePath, false, null, hoistedNoteId); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-21 22:34:40 +02:00
										 |  |  |     async openTabWithNote(notePath, activate, tabId, hoistedNoteId = 'root', parentTabId = null) { | 
					
						
							| 
									
										
										
										
											2021-05-20 23:13:34 +02:00
										 |  |  |         const tabContext = await this.openEmptyTab(tabId, hoistedNoteId, parentTabId); | 
					
						
							| 
									
										
										
										
											2020-02-27 12:26:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-05 19:30:03 +02:00
										 |  |  |         if (notePath) { | 
					
						
							|  |  |  |             await tabContext.setNote(notePath, !activate); // if activate is false then send normal noteSwitched event
 | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-02-27 12:26:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (activate) { | 
					
						
							|  |  |  |             this.activateTab(tabContext.tabId, false); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 21:44:34 +02:00
										 |  |  |             await this.triggerEvent('tabNoteSwitchedAndActivated', { | 
					
						
							| 
									
										
										
										
											2020-03-07 13:40:46 +01:00
										 |  |  |                 tabContext, | 
					
						
							| 
									
										
										
										
											2020-03-18 10:08:16 +01:00
										 |  |  |                 notePath: tabContext.notePath // resolved note path
 | 
					
						
							| 
									
										
										
										
											2020-02-28 00:31:12 +01:00
										 |  |  |             }); | 
					
						
							| 
									
										
										
										
											2020-02-27 12:26:42 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-05-08 23:39:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return tabContext; | 
					
						
							| 
									
										
										
										
											2020-02-27 12:26:42 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |     async activateOrOpenNote(noteId) { | 
					
						
							|  |  |  |         for (const tabContext of this.getTabContexts()) { | 
					
						
							|  |  |  |             if (tabContext.note && tabContext.note.noteId === noteId) { | 
					
						
							| 
									
										
										
										
											2020-04-05 15:35:01 +02:00
										 |  |  |                 this.activateTab(tabContext.tabId); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // if no tab with this note has been found we'll create new tab
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-18 10:08:16 +01:00
										 |  |  |         await this.openTabWithNote(noteId, true); | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-27 12:26:42 +01:00
										 |  |  |     activateTab(tabId, triggerEvent = true) { | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |         if (tabId === this.activeTabId) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.activeTabId = tabId; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-27 12:26:42 +01:00
										 |  |  |         if (triggerEvent) { | 
					
						
							| 
									
										
										
										
											2020-03-07 13:40:46 +01:00
										 |  |  |             this.triggerEvent('activeTabChanged', { | 
					
						
							|  |  |  |                 tabContext: this.getTabContextById(tabId) | 
					
						
							|  |  |  |             }); | 
					
						
							| 
									
										
										
										
											2020-02-27 12:26:42 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-02-08 21:23:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.tabsUpdate.scheduleUpdate(); | 
					
						
							| 
									
										
										
										
											2020-05-22 19:30:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-08 21:23:42 +01:00
										 |  |  |         this.setCurrentNotePathToHash(); | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async removeTab(tabId) { | 
					
						
							| 
									
										
										
										
											2021-05-21 22:34:40 +02:00
										 |  |  |         const mainTabContextToRemove = this.getTabContextById(tabId).getMainTabContext(); | 
					
						
							| 
									
										
										
										
											2021-05-20 23:13:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-22 19:30:21 +02:00
										 |  |  |         // close dangling autocompletes after closing the tab
 | 
					
						
							|  |  |  |         $(".aa-input").autocomplete("close"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-20 23:13:34 +02:00
										 |  |  |         const tabIdsToRemove = mainTabContextToRemove.getAllSubTabContexts().map(tc => tc.tabId); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         await this.triggerEvent('beforeTabRemove', { tabIds: tabIdsToRemove }); | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-20 23:13:34 +02:00
										 |  |  |         if (this.mainTabContexts.length <= 1) { | 
					
						
							|  |  |  |             await this.openAndActivateEmptyTab(); | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-05-20 23:13:34 +02:00
										 |  |  |         else if (tabIdsToRemove.includes(this.activeTabId)) { | 
					
						
							|  |  |  |             const idx = this.mainTabContexts.findIndex(tc => tc.tabId === mainTabContextToRemove.tabId); | 
					
						
							| 
									
										
										
										
											2020-03-07 13:57:31 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-20 23:13:34 +02:00
										 |  |  |             if (idx === this.mainTabContexts.length - 1) { | 
					
						
							| 
									
										
										
										
											2020-03-07 13:57:31 +01:00
										 |  |  |                 this.activatePreviousTabCommand(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else { | 
					
						
							|  |  |  |                 this.activateNextTabCommand(); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-20 23:13:34 +02:00
										 |  |  |         this.children = this.children.filter(tc => !tabIdsToRemove.includes(tc.tabId)); | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-20 23:13:34 +02:00
										 |  |  |         this.triggerEvent('tabRemoved', {tabIds: tabIdsToRemove}); | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-08 21:23:42 +01:00
										 |  |  |         this.tabsUpdate.scheduleUpdate(); | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 19:23:49 +01:00
										 |  |  |     tabReorderEvent({tabIdsInOrder}) { | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |         const order = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const i in tabIdsInOrder) { | 
					
						
							|  |  |  |             order[tabIdsInOrder[i]] = i; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-09 21:13:05 +01:00
										 |  |  |         this.children.sort((a, b) => order[a.tabId] < order[b.tabId] ? -1 : 1); | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-08 21:23:42 +01:00
										 |  |  |         this.tabsUpdate.scheduleUpdate(); | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 19:54:11 +01:00
										 |  |  |     activateNextTabCommand() { | 
					
						
							| 
									
										
										
										
											2021-05-20 23:13:34 +02:00
										 |  |  |         const oldIdx = this.mainTabContexts.findIndex(tc => tc.tabId === this.activeTabId); | 
					
						
							|  |  |  |         const newActiveTabId = this.mainTabContexts[oldIdx === this.tabContexts.length - 1 ? 0 : oldIdx + 1].tabId; | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.activateTab(newActiveTabId); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 19:54:11 +01:00
										 |  |  |     activatePreviousTabCommand() { | 
					
						
							| 
									
										
										
										
											2021-05-20 23:13:34 +02:00
										 |  |  |         const oldIdx = this.mainTabContexts.findIndex(tc => tc.tabId === this.activeTabId); | 
					
						
							|  |  |  |         const newActiveTabId = this.mainTabContexts[oldIdx === 0 ? this.tabContexts.length - 1 : oldIdx - 1].tabId; | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.activateTab(newActiveTabId); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 19:54:11 +01:00
										 |  |  |     closeActiveTabCommand() { | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |         this.removeTab(this.activeTabId); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 19:23:49 +01:00
										 |  |  |     beforeUnloadEvent() { | 
					
						
							| 
									
										
										
										
											2020-02-08 20:53:07 +01:00
										 |  |  |         this.tabsUpdate.updateNowIfNecessary(); | 
					
						
							| 
									
										
										
										
											2021-02-27 23:39:02 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return true; // don't block closing the tab, this metadata is not that important
 | 
					
						
							| 
									
										
										
										
											2020-02-08 20:53:07 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 19:54:11 +01:00
										 |  |  |     openNewTabCommand() { | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |         this.openAndActivateEmptyTab(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 19:54:11 +01:00
										 |  |  |     async removeAllTabsCommand() { | 
					
						
							| 
									
										
										
										
											2020-02-09 21:13:05 +01:00
										 |  |  |         for (const tabIdToRemove of this.tabContexts.map(tc => tc.tabId)) { | 
					
						
							|  |  |  |             await this.removeTab(tabIdToRemove); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-02-07 21:08:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 19:54:11 +01:00
										 |  |  |     async removeAllTabsExceptForThisCommand({tabId}) { | 
					
						
							| 
									
										
										
										
											2020-02-09 21:13:05 +01:00
										 |  |  |         for (const tabIdToRemove of this.tabContexts.map(tc => tc.tabId)) { | 
					
						
							|  |  |  |             if (tabIdToRemove !== tabId) { | 
					
						
							|  |  |  |                 await this.removeTab(tabIdToRemove); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-26 23:11:52 +02:00
										 |  |  |     moveTabToNewWindowCommand({tabId}) { | 
					
						
							| 
									
										
										
										
											2021-02-07 21:27:09 +01:00
										 |  |  |         const {notePath, hoistedNoteId} = this.getTabContextById(tabId); | 
					
						
							| 
									
										
										
										
											2020-04-26 23:11:52 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.removeTab(tabId); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-07 21:27:09 +01:00
										 |  |  |         this.triggerCommand('openInWindow', {notePath, hoistedNoteId}); | 
					
						
							| 
									
										
										
										
											2020-04-26 23:11:52 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-11-24 22:32:22 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     hoistedNoteChangedEvent() { | 
					
						
							|  |  |  |         this.tabsUpdate.scheduleUpdate(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-05-22 19:30:21 +02:00
										 |  |  | } |