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