| 
									
										
										
										
											2020-01-12 12:30:30 +01:00
										 |  |  | import TabContext from "./tab_context.js"; | 
					
						
							| 
									
										
										
										
											2020-01-12 12:48:17 +01:00
										 |  |  | import server from "./server.js"; | 
					
						
							| 
									
										
										
										
											2020-01-15 21:36:01 +01:00
										 |  |  | import treeCache from "./tree_cache.js"; | 
					
						
							| 
									
										
										
										
											2020-01-19 21:12:53 +01:00
										 |  |  | import bundleService from "./bundle.js"; | 
					
						
							| 
									
										
										
										
											2020-01-20 22:35:52 +01:00
										 |  |  | import DialogEventComponent from "./dialog_events.js"; | 
					
						
							| 
									
										
										
										
											2020-01-21 22:54:16 +01:00
										 |  |  | import Entrypoints from "./entrypoints.js"; | 
					
						
							| 
									
										
										
										
											2020-02-05 22:08:45 +01:00
										 |  |  | import options from "./options.js"; | 
					
						
							| 
									
										
										
										
											2020-02-02 22:32:44 +01:00
										 |  |  | import utils from "./utils.js"; | 
					
						
							|  |  |  | import treeService from "./tree.js"; | 
					
						
							| 
									
										
										
										
											2020-02-05 22:08:45 +01:00
										 |  |  | import ZoomService from "./zoom.js"; | 
					
						
							| 
									
										
										
										
											2020-02-06 21:47:31 +01:00
										 |  |  | import Layout from "../widgets/layout.js"; | 
					
						
							| 
									
										
										
										
											2020-02-07 20:56:49 +01:00
										 |  |  | import SpacedUpdate from "./spaced_update.js"; | 
					
						
							| 
									
										
										
										
											2020-01-11 21:19:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-12 09:57:28 +01:00
										 |  |  | class AppContext { | 
					
						
							| 
									
										
										
										
											2020-02-06 21:47:31 +01:00
										 |  |  |     constructor(layout) { | 
					
						
							|  |  |  |         this.layout = layout; | 
					
						
							| 
									
										
										
										
											2020-01-20 22:35:52 +01:00
										 |  |  |         this.components = []; | 
					
						
							| 
									
										
										
										
											2020-01-12 12:30:30 +01:00
										 |  |  |         /** @type {TabContext[]} */ | 
					
						
							|  |  |  |         this.tabContexts = []; | 
					
						
							| 
									
										
										
										
											2020-01-19 21:12:53 +01:00
										 |  |  |         this.activeTabId = null; | 
					
						
							| 
									
										
										
										
											2020-02-07 20:56:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.tabsUpdate = new SpacedUpdate(async () => { | 
					
						
							|  |  |  |             const openTabs = this.tabContexts | 
					
						
							|  |  |  |                 .map(tc => tc.getTabState()) | 
					
						
							|  |  |  |                 .filter(t => !!t); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             await server.put('options', { | 
					
						
							|  |  |  |                 openTabs: JSON.stringify(openTabs) | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2020-01-12 19:05:09 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-05 22:08:45 +01:00
										 |  |  |     async start() { | 
					
						
							|  |  |  |         options.load(await server.get('options')); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 22:04:28 +01:00
										 |  |  |         this.showWidgets(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 22:32:44 +01:00
										 |  |  |         this.loadTabs(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 22:04:28 +01:00
										 |  |  |         bundleService.executeStartupBundles(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-01-12 19:05:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 22:32:44 +01:00
										 |  |  |     async loadTabs() { | 
					
						
							|  |  |  |         const openTabs = options.getJson('openTabs') || []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         await treeCache.initializedPromise; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // 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); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (noteId && await treeCache.noteExists(noteId)) { | 
					
						
							|  |  |  |                 for (const tab of openTabs) { | 
					
						
							|  |  |  |                     tab.active = false; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 const foundTab = openTabs.find(tab => noteId === treeService.getNoteIdFromNotePath(tab.notePath)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (foundTab) { | 
					
						
							|  |  |  |                     foundTab.active = true; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else { | 
					
						
							|  |  |  |                     openTabs.push({ | 
					
						
							|  |  |  |                         notePath: notePath, | 
					
						
							|  |  |  |                         active: true | 
					
						
							|  |  |  |                     }); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let filteredTabs = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const openTab of openTabs) { | 
					
						
							|  |  |  |             const noteId = treeService.getNoteIdFromNotePath(openTab.notePath); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (await treeCache.noteExists(noteId)) { | 
					
						
							|  |  |  |                 // 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({ | 
					
						
							|  |  |  |                 notePath: 'root', | 
					
						
							|  |  |  |                 active: true | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!filteredTabs.find(tab => tab.active)) { | 
					
						
							|  |  |  |             filteredTabs[0].active = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-07 20:56:49 +01:00
										 |  |  |         this.tabsUpdate.allowUpdateWithoutChange(() => { | 
					
						
							|  |  |  |             for (const tab of filteredTabs) { | 
					
						
							|  |  |  |                 const tabContext = this.openEmptyTab(); | 
					
						
							|  |  |  |                 tabContext.setNote(tab.notePath); | 
					
						
							| 
									
										
										
										
											2020-02-02 22:32:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-07 20:56:49 +01:00
										 |  |  |                 if (tab.active) { | 
					
						
							|  |  |  |                     this.activateTab(tabContext.tabId); | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2020-02-02 22:32:44 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-02-07 20:56:49 +01:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2020-02-02 22:32:44 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 22:04:28 +01:00
										 |  |  |     showWidgets() { | 
					
						
							| 
									
										
										
										
											2020-02-06 21:47:31 +01:00
										 |  |  |         const rootContainer = this.layout.getRootWidget(this); | 
					
						
							| 
									
										
										
										
											2020-01-14 21:23:32 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-06 21:16:02 +01:00
										 |  |  |         $("body").append(rootContainer.render()); | 
					
						
							| 
									
										
										
										
											2020-02-05 22:08:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-20 22:35:52 +01:00
										 |  |  |         this.components = [ | 
					
						
							| 
									
										
										
										
											2020-02-06 21:16:02 +01:00
										 |  |  |             rootContainer, | 
					
						
							| 
									
										
										
										
											2020-01-21 22:54:16 +01:00
										 |  |  |             new Entrypoints(), | 
					
						
							| 
									
										
										
										
											2020-02-06 21:16:02 +01:00
										 |  |  |             new DialogEventComponent(this) | 
					
						
							| 
									
										
										
										
											2020-01-13 21:48:44 +01:00
										 |  |  |         ]; | 
					
						
							| 
									
										
										
										
											2020-02-05 22:08:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (utils.isElectron()) { | 
					
						
							|  |  |  |             this.components.push(new ZoomService(this)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             import("./spell_check.js").then(spellCheckService => spellCheckService.initSpellCheck()); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-02-06 21:16:02 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.trigger('initialRenderComplete'); | 
					
						
							| 
									
										
										
										
											2020-01-11 21:19:56 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-19 20:18:02 +01:00
										 |  |  |     trigger(name, data, sync = false) { | 
					
						
							| 
									
										
										
										
											2020-01-12 23:03:55 +01:00
										 |  |  |         this.eventReceived(name, data); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-21 22:54:16 +01:00
										 |  |  |         for (const component of this.components) { | 
					
						
							|  |  |  |             component.eventReceived(name, data, sync); | 
					
						
							| 
									
										
										
										
											2020-01-15 21:36:01 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-01-11 21:19:56 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-19 20:18:02 +01:00
										 |  |  |     async eventReceived(name, data, sync) { | 
					
						
							| 
									
										
										
										
											2020-01-12 23:03:55 +01:00
										 |  |  |         const fun = this[name + 'Listener']; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (typeof fun === 'function') { | 
					
						
							| 
									
										
										
										
											2020-01-19 20:18:02 +01:00
										 |  |  |             await fun.call(this, data, sync); | 
					
						
							| 
									
										
										
										
											2020-01-12 23:03:55 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 21:15:40 +01:00
										 |  |  |     tabNoteSwitchedListener({tabId}) { | 
					
						
							|  |  |  |         if (tabId === this.activeTabId) { | 
					
						
							|  |  |  |             this._setCurrentNotePathToHash(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-01-15 21:36:01 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _setCurrentNotePathToHash() { | 
					
						
							|  |  |  |         const activeTabContext = this.getActiveTabContext(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (activeTabContext && activeTabContext.notePath) { | 
					
						
							|  |  |  |             document.location.hash = (activeTabContext.notePath || "") + "-" + activeTabContext.tabId; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-12 12:30:30 +01:00
										 |  |  |     /** @return {TabContext[]} */ | 
					
						
							|  |  |  |     getTabContexts() { | 
					
						
							|  |  |  |         return this.tabContexts; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-19 21:24:14 +01:00
										 |  |  |     /** @returns {TabContext} */ | 
					
						
							|  |  |  |     getTabContextById(tabId) { | 
					
						
							|  |  |  |         return this.tabContexts.find(tc => tc.tabId === tabId); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-12 12:30:30 +01:00
										 |  |  |     /** @returns {TabContext} */ | 
					
						
							|  |  |  |     getActiveTabContext() { | 
					
						
							| 
									
										
										
										
											2020-01-19 21:24:14 +01:00
										 |  |  |         return this.getTabContextById(this.activeTabId); | 
					
						
							| 
									
										
										
										
											2020-01-12 12:30:30 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** @returns {string|null} */ | 
					
						
							|  |  |  |     getActiveTabNotePath() { | 
					
						
							|  |  |  |         const activeContext = this.getActiveTabContext(); | 
					
						
							|  |  |  |         return activeContext ? activeContext.notePath : null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-01 11:15:58 +01:00
										 |  |  |     /** @return {NoteShort} */ | 
					
						
							| 
									
										
										
										
											2020-01-12 12:30:30 +01:00
										 |  |  |     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) { | 
					
						
							| 
									
										
										
										
											2020-01-24 17:54:47 +01:00
										 |  |  |         const tabContext = this.tabContexts.find(tc => tc.tabId === tabId) | 
					
						
							|  |  |  |                          || this.openEmptyTab(); | 
					
						
							| 
									
										
										
										
											2020-01-12 12:30:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 17:54:47 +01:00
										 |  |  |         this.activateTab(tabContext.tabId); | 
					
						
							|  |  |  |         await tabContext.setNote(notePath); | 
					
						
							| 
									
										
										
										
											2020-01-12 12:30:30 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     getTab(newTab, state) { | 
					
						
							|  |  |  |         if (!this.getActiveTabContext() || newTab) { | 
					
						
							|  |  |  |             // if it's a new tab explicitly by user then it's in background
 | 
					
						
							| 
									
										
										
										
											2020-02-06 22:39:31 +01:00
										 |  |  |             const ctx = new TabContext(this, state); | 
					
						
							| 
									
										
										
										
											2020-01-12 12:30:30 +01:00
										 |  |  |             this.tabContexts.push(ctx); | 
					
						
							| 
									
										
										
										
											2020-01-20 22:35:52 +01:00
										 |  |  |             this.components.push(ctx); | 
					
						
							| 
									
										
										
										
											2020-01-12 12:30:30 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             return ctx; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             return this.getActiveTabContext(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-20 20:51:22 +01:00
										 |  |  |     async openAndActivateEmptyTab() { | 
					
						
							|  |  |  |         const tabContext = this.openEmptyTab(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         await this.activateTab(tabContext.tabId); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     openEmptyTab() { | 
					
						
							| 
									
										
										
										
											2020-02-06 22:39:31 +01:00
										 |  |  |         const tabContext = new TabContext(this); | 
					
						
							| 
									
										
										
										
											2020-01-19 21:12:53 +01:00
										 |  |  |         this.tabContexts.push(tabContext); | 
					
						
							| 
									
										
										
										
											2020-01-20 22:35:52 +01:00
										 |  |  |         this.components.push(tabContext); | 
					
						
							| 
									
										
										
										
											2020-01-20 20:51:22 +01:00
										 |  |  |         return tabContext; | 
					
						
							| 
									
										
										
										
											2020-01-12 12:30:30 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-01-12 12:48:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 17:54:47 +01:00
										 |  |  |     async activateOrOpenNote(noteId) { | 
					
						
							|  |  |  |         for (const tabContext of this.getTabContexts()) { | 
					
						
							|  |  |  |             if (tabContext.note && tabContext.note.noteId === noteId) { | 
					
						
							|  |  |  |                 await tabContext.activate(); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // if no tab with this note has been found we'll create new tab
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const tabContext = this.openEmptyTab(); | 
					
						
							|  |  |  |         await tabContext.setNote(noteId); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 22:04:28 +01:00
										 |  |  |     hoistedNoteChangedListener({hoistedNoteId}) { | 
					
						
							|  |  |  |         if (hoistedNoteId === 'root') { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-12 12:48:17 +01:00
										 |  |  |         for (const tc of this.tabContexts) { | 
					
						
							| 
									
										
										
										
											2020-02-02 22:04:28 +01:00
										 |  |  |             if (tc.notePath && !tc.notePath.split("/").includes(hoistedNoteId)) { | 
					
						
							| 
									
										
										
										
											2020-02-06 22:39:31 +01:00
										 |  |  |                 this.removeTab(tc.tabId); | 
					
						
							| 
									
										
										
										
											2020-01-12 12:48:17 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (this.tabContexts.length === 0) { | 
					
						
							| 
									
										
										
										
											2020-02-02 22:04:28 +01:00
										 |  |  |             this.openAndActivateEmptyTab(); | 
					
						
							| 
									
										
										
										
											2020-01-12 12:48:17 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 22:04:28 +01:00
										 |  |  |         this.saveOpenTabs(); | 
					
						
							| 
									
										
										
										
											2020-01-12 12:48:17 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 17:54:47 +01:00
										 |  |  |     openTabsChangedListener() { | 
					
						
							| 
									
										
										
										
											2020-02-07 20:56:49 +01:00
										 |  |  |         this.tabsUpdate.scheduleUpdate(); | 
					
						
							| 
									
										
										
										
											2020-01-12 12:48:17 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-01-12 09:57:28 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 17:54:47 +01:00
										 |  |  |     activateTab(tabId) { | 
					
						
							| 
									
										
										
										
											2020-01-25 10:25:06 +01:00
										 |  |  |         if (tabId === this.activeTabId) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 20:15:53 +01:00
										 |  |  |         const oldActiveTabId = this.activeTabId; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-19 21:12:53 +01:00
										 |  |  |         this.activeTabId = tabId; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 22:30:17 +01:00
										 |  |  |         this.trigger('activeTabChanged', { oldActiveTabId, newActiveTabId: tabId }); | 
					
						
							| 
									
										
										
										
											2020-01-12 20:15:05 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-12 19:05:09 +01:00
										 |  |  |     newTabListener() { | 
					
						
							| 
									
										
										
										
											2020-01-20 20:51:22 +01:00
										 |  |  |         this.openAndActivateEmptyTab(); | 
					
						
							| 
									
										
										
										
											2020-01-12 19:05:09 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-01-12 09:57:28 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-19 21:12:53 +01:00
										 |  |  |     async removeTab(tabId) { | 
					
						
							|  |  |  |         const tabContextToRemove = this.tabContexts.find(tc => tc.tabId === tabId); | 
					
						
							| 
									
										
										
										
											2020-01-12 12:30:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-19 21:12:53 +01:00
										 |  |  |         if (!tabContextToRemove) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-01-12 12:30:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-06 22:39:31 +01:00
										 |  |  |         await this.trigger('beforeTabRemove', {tabId}, true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (this.tabContexts.length === 1) { | 
					
						
							| 
									
										
										
										
											2020-01-20 20:51:22 +01:00
										 |  |  |             this.openAndActivateEmptyTab(); | 
					
						
							| 
									
										
										
										
											2020-01-12 19:05:09 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-01-19 21:12:53 +01:00
										 |  |  |         else { | 
					
						
							| 
									
										
										
										
											2020-02-06 22:39:31 +01:00
										 |  |  |             this.activateNextTabListener(); | 
					
						
							| 
									
										
										
										
											2020-01-19 21:12:53 +01:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.tabContexts = this.tabContexts.filter(tc => tc.tabId === tabId); | 
					
						
							| 
									
										
										
										
											2020-01-12 12:30:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-06 22:39:31 +01:00
										 |  |  |         this.trigger('tabRemoved', {tabId}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 17:54:47 +01:00
										 |  |  |         this.openTabsChangedListener(); | 
					
						
							| 
									
										
										
										
											2020-01-12 12:30:30 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-06 22:39:31 +01:00
										 |  |  |     tabReorderListener({tabIdsInOrder}) { | 
					
						
							|  |  |  |         const order = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const i in tabIdsInOrder) { | 
					
						
							|  |  |  |             order[tabIdsInOrder[i]] = i; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.tabContexts.sort((a, b) => order[a.tabId] < order[b.tabId] ? -1 : 1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-24 17:54:47 +01:00
										 |  |  |         this.openTabsChangedListener(); | 
					
						
							| 
									
										
										
										
											2020-01-12 19:05:09 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-01-19 20:18:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-20 20:51:22 +01:00
										 |  |  |     activateNextTabListener() { | 
					
						
							| 
									
										
										
										
											2020-02-06 22:39:31 +01:00
										 |  |  |         const oldIdx = this.tabContexts.findIndex(tc => tc.tabId === this.activeTabId); | 
					
						
							|  |  |  |         const newActiveTabId = this.tabContexts[oldIdx === this.tabContexts.length - 1 ? 0 : oldIdx + 1].tabId; | 
					
						
							| 
									
										
										
										
											2020-01-20 20:51:22 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.activateTab(newActiveTabId); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     activatePreviousTabListener() { | 
					
						
							| 
									
										
										
										
											2020-02-06 22:39:31 +01:00
										 |  |  |         const oldIdx = this.tabContexts.findIndex(tc => tc.tabId === this.activeTabId); | 
					
						
							|  |  |  |         const newActiveTabId = this.tabContexts[oldIdx === 0 ? this.tabContexts.length - 1 : oldIdx - 1].tabId; | 
					
						
							| 
									
										
										
										
											2020-01-20 20:51:22 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.activateTab(newActiveTabId); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     closeActiveTabListener() { | 
					
						
							|  |  |  |         this.removeTab(this.activeTabId); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     openNewTabListener() { | 
					
						
							|  |  |  |         this.openAndActivateEmptyTab(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-01-20 22:35:52 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     removeAllTabsListener() { | 
					
						
							|  |  |  |         // TODO
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     removeAllTabsExceptForThis() { | 
					
						
							|  |  |  |         // TODO
 | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-02-01 22:29:32 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     async protectedSessionStartedListener() { | 
					
						
							|  |  |  |         await treeCache.loadInitialTree(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.trigger('treeCacheReloaded'); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-01-12 19:05:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-06 21:47:31 +01:00
										 |  |  | const layout = new Layout(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const appContext = new AppContext(layout); | 
					
						
							| 
									
										
										
										
											2020-01-12 12:48:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 10:41:43 +01:00
										 |  |  | // we should save all outstanding changes before the page/app is closed
 | 
					
						
							|  |  |  | $(window).on('beforeunload', () => { | 
					
						
							|  |  |  |     appContext.trigger('beforeUnload'); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-03 20:07:34 +01:00
										 |  |  | function isNotePathInAddress() { | 
					
						
							|  |  |  |     const [notePath, tabId] = getHashValueFromAddress(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return notePath.startsWith("root") | 
					
						
							|  |  |  |         // empty string is for empty/uninitialized tab
 | 
					
						
							|  |  |  |         || (notePath === '' && !!tabId); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function getHashValueFromAddress() { | 
					
						
							|  |  |  |     const str = document.location.hash ? document.location.hash.substr(1) : ""; // strip initial #
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return str.split("-"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | $(window).on('hashchange', function() { | 
					
						
							|  |  |  |     if (isNotePathInAddress()) { | 
					
						
							|  |  |  |         const [notePath, tabId] = getHashValueFromAddress(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         appContext.switchToTab(tabId, notePath); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-12 09:57:28 +01:00
										 |  |  | export default appContext; |