mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 18:08:33 +02: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