hoisting note now seems to work correctly in relation to tabs

This commit is contained in:
zadam 2019-05-11 21:27:27 +02:00
parent bd97df5ee9
commit 2dec8f1ad6
7 changed files with 84 additions and 53 deletions

View File

@ -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();

View File

@ -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();

View File

@ -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

View File

@ -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);

View File

@ -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();
} }
} }

View File

@ -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
}; };

View File

@ -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;