mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-30 18:05:55 +01:00 
			
		
		
		
	hoisting note now seems to work correctly in relation to tabs
This commit is contained in:
		| @@ -167,7 +167,7 @@ function AttributesModel() { | ||||
|  | ||||
|         infoService.showMessage("Attributes have been saved."); | ||||
|  | ||||
|         const ctx = noteDetailService.getActiveContext(); | ||||
|         const ctx = noteDetailService.getActiveTabContext(); | ||||
|  | ||||
|         ctx.attributes.refreshAttributes(); | ||||
|  | ||||
|   | ||||
| @@ -16,12 +16,12 @@ async function getHoistedNoteId() { | ||||
| } | ||||
|  | ||||
| async function setHoistedNoteId(noteId) { | ||||
|     hoistedNoteId = noteId; | ||||
|  | ||||
|     if (noteId !== 'root') { | ||||
|         await noteDetailService.filterTabs(noteId); | ||||
|     } | ||||
|  | ||||
|     hoistedNoteId = noteId; | ||||
|  | ||||
|     await server.put('options/hoistedNoteId/' + noteId); | ||||
|  | ||||
|     await tree.reload(); | ||||
|   | ||||
| @@ -19,7 +19,7 @@ let detailLoadedListeners = []; | ||||
|  | ||||
| /** @return {NoteFull} */ | ||||
| function getActiveNote() { | ||||
|     const activeContext = getActiveContext(); | ||||
|     const activeContext = getActiveTabContext(); | ||||
|     return activeContext ? activeContext.note : null; | ||||
| } | ||||
|  | ||||
| @@ -38,7 +38,7 @@ function getActiveNoteType() { | ||||
| async function reload() { | ||||
|     // no saving here | ||||
|  | ||||
|     await loadNoteDetail(getActiveNoteId()); | ||||
|     await loadNoteDetail(getActiveTabContext().notePath); | ||||
| } | ||||
|  | ||||
| async function reloadAllTabs() { | ||||
| @@ -46,12 +46,11 @@ async function reloadAllTabs() { | ||||
|         const note = await loadNote(tabContext.note.noteId); | ||||
|  | ||||
|         await loadNoteDetailToContext(tabContext, note, tabContext.notePath); | ||||
|  | ||||
|     } | ||||
| } | ||||
|  | ||||
| async function openInTab(noteId) { | ||||
|     await loadNoteDetail(noteId, { newTab: true }); | ||||
| async function openInTab(notePath) { | ||||
|     await loadNoteDetail(notePath, { newTab: true }); | ||||
| } | ||||
|  | ||||
| async function switchToNote(notePath) { | ||||
| @@ -63,11 +62,11 @@ async function switchToNote(notePath) { | ||||
| } | ||||
|  | ||||
| function getActiveNoteContent() { | ||||
|     return getActiveContext().getComponent().getContent(); | ||||
|     return getActiveTabContext().getComponent().getContent(); | ||||
| } | ||||
|  | ||||
| function onNoteChange(func) { | ||||
|     return getActiveContext().getComponent().onNoteChange(func); | ||||
|     return getActiveTabContext().getComponent().onNoteChange(func); | ||||
| } | ||||
|  | ||||
| async function saveNotesIfChanged() { | ||||
| @@ -83,11 +82,15 @@ async function saveNotesIfChanged() { | ||||
| let tabContexts = []; | ||||
|  | ||||
| function getActiveComponent() { | ||||
|     return getActiveContext().getComponent(); | ||||
|     return getActiveTabContext().getComponent(); | ||||
| } | ||||
|  | ||||
| function getTabContexts() { | ||||
|     return tabContexts; | ||||
| } | ||||
|  | ||||
| /** @returns {TabContext} */ | ||||
| function getActiveContext() { | ||||
| function getActiveTabContext() { | ||||
|     for (const ctx of tabContexts) { | ||||
|         if (ctx.$tabContent.is(":visible")) { | ||||
|             return ctx; | ||||
| @@ -110,7 +113,7 @@ async function showTab(tabId) { | ||||
|  | ||||
|     treeService.clearSelectedNodes(); | ||||
|  | ||||
|     const newActiveTabContext = getActiveContext(); | ||||
|     const newActiveTabContext = getActiveTabContext(); | ||||
|     const newActiveNode = await treeService.getNodeFromPath(newActiveTabContext.notePath); | ||||
|  | ||||
|     if (newActiveNode && newActiveNode.isVisible()) { | ||||
| @@ -181,6 +184,8 @@ async function loadNoteDetail(notePath, options = {}) { | ||||
|     const newTab = !!options.newTab; | ||||
|     const activate = !!options.activate; | ||||
|  | ||||
|     notePath = await treeService.resolveNotePath(notePath); | ||||
|  | ||||
|     const noteId = treeUtils.getNoteIdFromNotePath(notePath); | ||||
|     const loadedNote = await loadNote(noteId); | ||||
|     let ctx; | ||||
| @@ -191,7 +196,7 @@ async function loadNoteDetail(notePath, options = {}) { | ||||
|         tabContexts.push(ctx); | ||||
|     } | ||||
|     else { | ||||
|         ctx = getActiveContext(); | ||||
|         ctx = getActiveTabContext(); | ||||
|     } | ||||
|  | ||||
|     // we will try to render the new note only if it's still the active one in the tree | ||||
| @@ -219,23 +224,27 @@ async function loadNote(noteId) { | ||||
|  | ||||
| async function filterTabs(noteId) { | ||||
|     for (const tc of tabContexts) { | ||||
|         tabRow.removeTab(tc.tab); | ||||
|         if (tc.notePath && !tc.notePath.split("/").includes(noteId)) { | ||||
|             await tabRow.removeTab(tc.tab); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (tabContexts.length === 0) { | ||||
|         await loadNoteDetail(noteId, { | ||||
|             newTab: true, | ||||
|             activate: true | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     await saveOpenTabs(); | ||||
| } | ||||
|  | ||||
| function focusOnTitle() { | ||||
|     getActiveContext().$noteTitle.focus(); | ||||
|     getActiveTabContext().$noteTitle.focus(); | ||||
| } | ||||
|  | ||||
| function focusAndSelectTitle() { | ||||
|     getActiveContext().$noteTitle.focus().select(); | ||||
|     getActiveTabContext().$noteTitle.focus().select(); | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -284,22 +293,21 @@ $tabContentsContainer.on("drop", e => { | ||||
|     }); | ||||
| }); | ||||
|  | ||||
| tabRow.el.addEventListener('activeTabChange', ({ detail }) => { | ||||
| tabRow.addListener('activeTabChange', async ({ detail }) => { | ||||
|     const tabId = detail.tabEl.getAttribute('data-tab-id'); | ||||
|  | ||||
|     showTab(tabId); | ||||
|     await showTab(tabId); | ||||
|  | ||||
|     console.log(`Activated tab ${tabId}`); | ||||
| }); | ||||
|  | ||||
| tabRow.el.addEventListener('tabRemove', async ({ detail }) => { | ||||
| tabRow.addListener('tabRemove', async ({ detail }) => { | ||||
|     const tabId = parseInt(detail.tabEl.getAttribute('data-tab-id')); | ||||
|  | ||||
|     await saveNotesIfChanged(); | ||||
|  | ||||
|     const tabContentToDelete = tabContexts.find(nc => nc.tabId === tabId); | ||||
|  | ||||
|     if (tabContentToDelete) { | ||||
|         await tabContentToDelete.saveNoteIfChanged(); | ||||
|         tabContentToDelete.$tabContent.remove(); | ||||
|     } | ||||
|  | ||||
| @@ -352,10 +360,9 @@ if (utils.isElectron()) { | ||||
|     }); | ||||
| } | ||||
|  | ||||
| tabRow.el.addEventListener('activeTabChange', openTabsChanged); | ||||
| tabRow.el.addEventListener('tabAdd', openTabsChanged); | ||||
| tabRow.el.addEventListener('tabRemove', openTabsChanged); | ||||
| tabRow.el.addEventListener('tabReorder', openTabsChanged); | ||||
| tabRow.addListener('activeTabChange', openTabsChanged); | ||||
| tabRow.addListener('tabRemove', openTabsChanged); | ||||
| tabRow.addListener('tabReorder', openTabsChanged); | ||||
|  | ||||
| let tabsChangedTaskId = null; | ||||
|  | ||||
| @@ -417,7 +424,8 @@ export default { | ||||
|     saveNotesIfChanged, | ||||
|     onNoteChange, | ||||
|     addDetailLoadedListener, | ||||
|     getActiveContext, | ||||
|     getTabContexts, | ||||
|     getActiveTabContext, | ||||
|     getActiveComponent, | ||||
|     clearOpenTabsTask, | ||||
|     filterTabs | ||||
|   | ||||
| @@ -79,7 +79,7 @@ async function protectNoteAndSendToServer() { | ||||
|     const note = noteDetailService.getActiveNote(); | ||||
|     note.isProtected = true; | ||||
|  | ||||
|     await noteDetailService.getActiveContext().saveNote(); | ||||
|     await noteDetailService.getActiveTabContext().saveNote(); | ||||
|  | ||||
|     treeService.setProtected(note.noteId, note.isProtected); | ||||
|  | ||||
| @@ -106,7 +106,7 @@ async function unprotectNoteAndSendToServer() { | ||||
|  | ||||
|     activeNote.isProtected = false; | ||||
|  | ||||
|     await noteDetailService.getActiveContext().saveNote(); | ||||
|     await noteDetailService.getActiveTabContext().saveNote(); | ||||
|  | ||||
|     treeService.setProtected(activeNote.noteId, activeNote.isProtected); | ||||
|  | ||||
|   | ||||
| @@ -19,8 +19,6 @@ const TAB_SIZE_SMALL = 84; | ||||
| const TAB_SIZE_SMALLER = 60; | ||||
| const TAB_SIZE_MINI = 48; | ||||
|  | ||||
| const noop = _ => {}; | ||||
|  | ||||
| const closest = (value, array) => { | ||||
|     let closest = Infinity; | ||||
|     let closestIndex = -1; | ||||
| @@ -53,7 +51,8 @@ let instanceId = 0; | ||||
|  | ||||
| class TabRow { | ||||
|     constructor() { | ||||
|         this.draggabillies = [] | ||||
|         this.draggabillies = []; | ||||
|         this.eventListeners = {}; | ||||
|     } | ||||
|  | ||||
|     init(el) { | ||||
| @@ -71,8 +70,15 @@ class TabRow { | ||||
|         this.setVisibility(); | ||||
|     } | ||||
|  | ||||
|     emit(eventName, data) { | ||||
|         this.el.dispatchEvent(new CustomEvent(eventName, { detail: data })); | ||||
|     addListener(eventName, callback) { | ||||
|         this.eventListeners[eventName] = this.eventListeners[eventName] || []; | ||||
|         this.eventListeners[eventName].push(callback); | ||||
|     } | ||||
|  | ||||
|     async emit(eventName, data) { | ||||
|         for (const listener of this.eventListeners[eventName]) { | ||||
|             await listener({ detail: data }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     setupCustomProperties() { | ||||
| @@ -194,7 +200,6 @@ class TabRow { | ||||
|         this.setVisibility(); | ||||
|         this.setTabCloseEventListener(tabEl); | ||||
|         this.updateTab(tabEl, tabProperties); | ||||
|         this.emit('tabAdd', { tabEl }); | ||||
|         if (!background) this.setCurrentTab(tabEl); | ||||
|         this.cleanUpPreviouslyDraggedTabs(); | ||||
|         this.layoutTabs(); | ||||
| @@ -255,34 +260,34 @@ class TabRow { | ||||
|         return !!this.activeTabEl; | ||||
|     } | ||||
|  | ||||
|     setCurrentTab(tabEl) { | ||||
|     async setCurrentTab(tabEl) { | ||||
|         const activeTabEl = this.activeTabEl; | ||||
|         if (activeTabEl === tabEl) return; | ||||
|         if (activeTabEl) activeTabEl.removeAttribute('active'); | ||||
|         tabEl.setAttribute('active', ''); | ||||
|         this.emit('activeTabChange', { tabEl }); | ||||
|         await this.emit('activeTabChange', { tabEl }); | ||||
|     } | ||||
|  | ||||
|     removeTab(tabEl) { | ||||
|     async removeTab(tabEl) { | ||||
|         if (tabEl === this.activeTabEl) { | ||||
|             if (tabEl.nextElementSibling) { | ||||
|                 this.setCurrentTab(tabEl.nextElementSibling) | ||||
|                 await this.setCurrentTab(tabEl.nextElementSibling) | ||||
|             } else if (tabEl.previousElementSibling) { | ||||
|                 this.setCurrentTab(tabEl.previousElementSibling) | ||||
|                 await this.setCurrentTab(tabEl.previousElementSibling) | ||||
|             } | ||||
|         } | ||||
|         tabEl.parentNode.removeChild(tabEl); | ||||
|         this.emit('tabRemove', { tabEl }); | ||||
|         await this.emit('tabRemove', { tabEl }); | ||||
|         this.cleanUpPreviouslyDraggedTabs(); | ||||
|         this.layoutTabs(); | ||||
|         this.setupDraggabilly(); | ||||
|         this.setVisibility(); | ||||
|     } | ||||
|  | ||||
|     removeAllTabsExceptForThis(remainingTabEl) { | ||||
|     async removeAllTabsExceptForThis(remainingTabEl) { | ||||
|         for (const tabEl of this.tabEls) { | ||||
|             if (remainingTabEl !== tabEl) { | ||||
|                 this.removeTab(tabEl); | ||||
|                 await this.removeTab(tabEl); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -310,7 +315,7 @@ class TabRow { | ||||
|             this.draggabillyDragging.element.style.transform = ''; | ||||
|             this.draggabillyDragging.dragEnd(); | ||||
|             this.draggabillyDragging.isDragging = false; | ||||
|             this.draggabillyDragging.positionDrag = noop; // Prevent Draggabilly from updating tabEl.style.transform in later frames | ||||
|             this.draggabillyDragging.positionDrag = _ => {}; // Prevent Draggabilly from updating tabEl.style.transform in later frames | ||||
|             this.draggabillyDragging.destroy(); | ||||
|             this.draggabillyDragging = null; | ||||
|         } | ||||
| @@ -380,13 +385,13 @@ class TabRow { | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     animateTabMove(tabEl, originIndex, destinationIndex) { | ||||
|     async animateTabMove(tabEl, originIndex, destinationIndex) { | ||||
|         if (destinationIndex < originIndex) { | ||||
|             tabEl.parentNode.insertBefore(tabEl, this.tabEls[destinationIndex]); | ||||
|         } else { | ||||
|             tabEl.parentNode.insertBefore(tabEl, this.tabEls[destinationIndex + 1]); | ||||
|         } | ||||
|         this.emit('tabReorder', { tabEl, originIndex, destinationIndex }); | ||||
|         await this.emit('tabReorder', { tabEl, originIndex, destinationIndex }); | ||||
|         this.layoutTabs(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -165,6 +165,16 @@ async function activateNote(notePath, noteLoadedListener) { | ||||
|     return node; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Accepts notePath which might or might not be valid and returns an existing path as close to the original | ||||
|  * notePath as possible. | ||||
|  */ | ||||
| async function resolveNotePath(notePath) { | ||||
|     const runPath = await getRunPath(notePath); | ||||
|  | ||||
|     return runPath.join("/"); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Accepts notePath and tries to resolve it. Part of the path might not be valid because of note moving (which causes | ||||
|  * path change) or other corruption, in that case this will try to get some other valid path to the correct note. | ||||
| @@ -358,6 +368,11 @@ function clearSelectedNodes() { | ||||
| } | ||||
|  | ||||
| async function treeInitialized() { | ||||
|     if (noteDetailService.getTabContexts().length > 0) { | ||||
|         // this is just tree reload - tabs are already in place | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     let openTabs = []; | ||||
|  | ||||
|     try { | ||||
| @@ -571,7 +586,7 @@ async function collapseTree(node = null) { | ||||
| } | ||||
|  | ||||
| async function scrollToActiveNote() { | ||||
|     const activeContext = noteDetailService.getActiveContext(); | ||||
|     const activeContext = noteDetailService.getActiveTabContext(); | ||||
|  | ||||
|     if (activeContext) { | ||||
|         const node = await expandToNote(activeContext.notePath); | ||||
| @@ -864,5 +879,6 @@ export default { | ||||
|     reloadNote, | ||||
|     loadTreeCache, | ||||
|     expandToNote, | ||||
|     getNodeFromPath | ||||
|     getNodeFromPath, | ||||
|     resolveNotePath | ||||
| }; | ||||
| @@ -78,7 +78,9 @@ class TreeContextMenu { | ||||
|  | ||||
|     async selectContextMenuItem(event, cmd) { | ||||
|         if (cmd === 'openInTab') { | ||||
|             noteDetailService.openInTab(this.node.data.noteId); | ||||
|             const notePath = treeUtils.getNotePath(this.node); | ||||
|  | ||||
|             noteDetailService.openInTab(notePath); | ||||
|         } | ||||
|         else if (cmd.startsWith("insertNoteAfter")) { | ||||
|             const parentNoteId = this.node.data.parentNoteId; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user