mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 18:08:33 +02:00
refactored tab activation
This commit is contained in:
parent
1098d75ce0
commit
0760dc742b
@ -30,6 +30,7 @@ import ProtectedNoteSwitchWidget from "../widgets/protected_note_switch.js";
|
|||||||
import NoteTypeWidget from "../widgets/note_type.js";
|
import NoteTypeWidget from "../widgets/note_type.js";
|
||||||
import NoteActionsWidget from "../widgets/note_actions.js";
|
import NoteActionsWidget from "../widgets/note_actions.js";
|
||||||
import protectedSessionHolder from "./protected_session_holder.js";
|
import protectedSessionHolder from "./protected_session_holder.js";
|
||||||
|
import bundleService from "./bundle.js";
|
||||||
|
|
||||||
class AppContext {
|
class AppContext {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -39,6 +40,7 @@ class AppContext {
|
|||||||
this.tabsChangedTaskId = null;
|
this.tabsChangedTaskId = null;
|
||||||
/** @type {TabRowWidget} */
|
/** @type {TabRowWidget} */
|
||||||
this.tabRow = null;
|
this.tabRow = null;
|
||||||
|
this.activeTabId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
showWidgets() {
|
showWidgets() {
|
||||||
@ -180,9 +182,7 @@ class AppContext {
|
|||||||
|
|
||||||
/** @returns {TabContext} */
|
/** @returns {TabContext} */
|
||||||
getActiveTabContext() {
|
getActiveTabContext() {
|
||||||
const tabId = this.tabRow.activeTabId;
|
return this.tabContexts.find(tc => tc.tabId === this.activeTabId);
|
||||||
|
|
||||||
return this.tabContexts.find(tc => tc.tabId === tabId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @returns {string|null} */
|
/** @returns {string|null} */
|
||||||
@ -268,10 +268,10 @@ class AppContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async openEmptyTab() {
|
async openEmptyTab() {
|
||||||
const ctx = new TabContext(this, this.tabRow);
|
const tabContext = new TabContext(this, this.tabRow);
|
||||||
this.tabContexts.push(ctx);
|
this.tabContexts.push(tabContext);
|
||||||
|
|
||||||
await this.tabRow.activateTab(ctx.$tab[0]);
|
await this.activateTab(tabContext.tabId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async filterTabs(noteId) {
|
async filterTabs(noteId) {
|
||||||
@ -291,8 +291,7 @@ class AppContext {
|
|||||||
async saveOpenTabs() {
|
async saveOpenTabs() {
|
||||||
const openTabs = [];
|
const openTabs = [];
|
||||||
|
|
||||||
for (const tabEl of this.tabRow.tabEls) {
|
for (const tabId of this.tabRow.getTabIdsInOrder()) {
|
||||||
const tabId = tabEl.getAttribute('data-tab-id');
|
|
||||||
const tabContext = appContext.getTabContexts().find(tc => tc.tabId === tabId);
|
const tabContext = appContext.getTabContexts().find(tc => tc.tabId === tabId);
|
||||||
|
|
||||||
if (tabContext) {
|
if (tabContext) {
|
||||||
@ -324,23 +323,42 @@ class AppContext {
|
|||||||
this.tabsChangedTaskId = setTimeout(() => this.saveOpenTabs(), 1000);
|
this.tabsChangedTaskId = setTimeout(() => this.saveOpenTabs(), 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
async activateTab(tabContext) {
|
async activateTab(tabId) {
|
||||||
return this.tabRow.activateTab(tabContext.$tab[0]);
|
this.activeTabId = tabId;
|
||||||
|
|
||||||
|
this.trigger('activeTabChanged', { tabId: this.activeTabId });
|
||||||
}
|
}
|
||||||
|
|
||||||
newTabListener() {
|
newTabListener() {
|
||||||
this.openEmptyTab();
|
this.openEmptyTab();
|
||||||
}
|
}
|
||||||
|
|
||||||
async tabRemoveListener({tabId}) {
|
async removeTab(tabId) {
|
||||||
this.tabContexts.filter(nc => nc.tabId === tabId)
|
const tabContextToRemove = this.tabContexts.find(tc => tc.tabId === tabId);
|
||||||
.forEach(tc => tc.remove());
|
const tabIdsInOrder = this.tabRow.getTabIdsInOrder();
|
||||||
|
|
||||||
this.tabContexts = this.tabContexts.filter(nc => nc.tabId !== tabId);
|
if (!tabContextToRemove) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.tabContexts.length === 0) {
|
if (this.tabContexts.length === 0) {
|
||||||
this.openEmptyTab();
|
this.openEmptyTab();
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
const oldIdx = tabIdsInOrder.findIndex(tid => tid === tabId);
|
||||||
|
const newActiveTabId = tabIdsInOrder[oldIdx === tabIdsInOrder.length ? oldIdx - 1 : oldIdx + 1];
|
||||||
|
|
||||||
|
if (newActiveTabId) {
|
||||||
|
this.activateTab(newActiveTabId);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log("Failed to find next tabcontext to activate");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await tabContextToRemove.remove();
|
||||||
|
|
||||||
|
this.tabContexts = this.tabContexts.filter(tc => tc.tabId === tabId);
|
||||||
|
|
||||||
this.openTabsChanged();
|
this.openTabsChanged();
|
||||||
}
|
}
|
||||||
@ -359,6 +377,9 @@ class AppContext {
|
|||||||
if (activeTabContext.note.isProtected && protectedSessionHolder.isProtectedSessionAvailable()) {
|
if (activeTabContext.note.isProtected && protectedSessionHolder.isProtectedSessionAvailable()) {
|
||||||
protectedSessionHolder.touchProtectedSession();
|
protectedSessionHolder.touchProtectedSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// run async
|
||||||
|
bundleService.executeRelationBundles(activeTabContext.note, 'runOnNoteChange', activeTabContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,6 +399,7 @@ keyboardActionService.setGlobalActionHandler('ActivateNextTab', () => {
|
|||||||
const nextTab = this.tabRow.nextTabEl;
|
const nextTab = this.tabRow.nextTabEl;
|
||||||
|
|
||||||
if (nextTab) {
|
if (nextTab) {
|
||||||
|
// FIXME
|
||||||
this.tabRow.activateTab(nextTab);
|
this.tabRow.activateTab(nextTab);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -386,6 +408,7 @@ keyboardActionService.setGlobalActionHandler('ActivatePreviousTab', () => {
|
|||||||
const prevTab = this.tabRow.previousTabEl;
|
const prevTab = this.tabRow.previousTabEl;
|
||||||
|
|
||||||
if (prevTab) {
|
if (prevTab) {
|
||||||
|
// FIXME
|
||||||
this.tabRow.activateTab(prevTab);
|
this.tabRow.activateTab(prevTab);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -113,7 +113,7 @@ async function loadNoteDetail(origNotePath, options = {}) {
|
|||||||
|
|
||||||
const loadPromise = loadNoteDetailToContext(ctx, notePath).then(() => {
|
const loadPromise = loadNoteDetailToContext(ctx, notePath).then(() => {
|
||||||
if (activate) {
|
if (activate) {
|
||||||
return appContext.activateTab(ctx);
|
return appContext.activateTab(ctx.tabId);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
|
@ -81,6 +81,12 @@ class TabContext extends Component {
|
|||||||
return this.tabId === this.tabRow.activeTabId;
|
return this.tabId === this.tabRow.activeTabId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async remove() {
|
||||||
|
await this.trigger('beforeTabRemove', {tabId: this.tabId}, true);
|
||||||
|
|
||||||
|
this.trigger('tabRemoved', {tabId: this.tabId});
|
||||||
|
}
|
||||||
|
|
||||||
setupClasses() {
|
setupClasses() {
|
||||||
for (const clazz of Array.from(this.$tab[0].classList)) { // create copy to safely iterate over while removing classes
|
for (const clazz of Array.from(this.$tab[0].classList)) { // create copy to safely iterate over while removing classes
|
||||||
if (clazz !== 'note-tab') {
|
if (clazz !== 'note-tab') {
|
||||||
@ -123,8 +129,7 @@ class TabContext extends Component {
|
|||||||
// FIXME trigger "noteSaved" event so that title indicator is triggered
|
// FIXME trigger "noteSaved" event so that title indicator is triggered
|
||||||
this.eventReceived('noteSaved');
|
this.eventReceived('noteSaved');
|
||||||
|
|
||||||
// run async
|
|
||||||
bundleService.executeRelationBundles(this.note, 'runOnNoteChange', this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveNoteIfChanged() {
|
async saveNoteIfChanged() {
|
||||||
|
@ -18,6 +18,12 @@ class BasicWidget extends Component {
|
|||||||
this.$widget.toggle(show);
|
this.$widget.toggle(show);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
remove() {
|
||||||
|
if (this.$widget) {
|
||||||
|
this.$widget.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cleanup() {}
|
cleanup() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +132,13 @@ export default class NoteTitleWidget extends TabAwareWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async beforeNoteSwitch({tabId}) {
|
async beforeNoteSwitchListener({tabId}) {
|
||||||
|
if (this.isTab(tabId)) {
|
||||||
|
await this.spacedUpdate.updateNowIfNecessary();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async beforeTabRemoveListener({tabId}) {
|
||||||
if (this.isTab(tabId)) {
|
if (this.isTab(tabId)) {
|
||||||
await this.spacedUpdate.updateNowIfNecessary();
|
await this.spacedUpdate.updateNowIfNecessary();
|
||||||
}
|
}
|
||||||
|
@ -408,6 +408,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
|||||||
|
|
||||||
if (oldActiveNode) {
|
if (oldActiveNode) {
|
||||||
oldActiveNode.setActive(false);
|
oldActiveNode.setActive(false);
|
||||||
|
oldActiveNode.setFocus(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.tabContext && this.tabContext.notePath) {
|
if (this.tabContext && this.tabContext.notePath) {
|
||||||
|
@ -35,6 +35,14 @@ export default class TabCachingWidget extends TabAwareWidget {
|
|||||||
return false; // stop propagation to children
|
return false; // stop propagation to children
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tabRemovedListener({tabId}) {
|
||||||
|
const widget = this.widgets[tabId];
|
||||||
|
|
||||||
|
if (widget) {
|
||||||
|
widget.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
toggle(show) {
|
toggle(show) {
|
||||||
for (const tabId in this.widgets) {
|
for (const tabId in this.widgets) {
|
||||||
this.widgets[tabId].toggle(show && this.tabContext && tabId === this.tabContext.tabId);
|
this.widgets[tabId].toggle(show && this.tabContext && tabId === this.tabContext.tabId);
|
||||||
|
@ -399,11 +399,11 @@ export default class TabRowWidget extends BasicWidget {
|
|||||||
|
|
||||||
setTabCloseEventListener(tabEl) {
|
setTabCloseEventListener(tabEl) {
|
||||||
tabEl.querySelector('.note-tab-close')
|
tabEl.querySelector('.note-tab-close')
|
||||||
.addEventListener('click', _ => this.removeTab(tabEl.getAttribute('data-tab-id')));
|
.addEventListener('click', _ => this.appContext.removeTab(tabEl.getAttribute('data-tab-id')));
|
||||||
|
|
||||||
tabEl.addEventListener('mousedown', e => {
|
tabEl.addEventListener('mousedown', e => {
|
||||||
if (e.which === 2) {
|
if (e.which === 2) {
|
||||||
this.removeTab(tabEl.getAttribute('data-tab-id'));
|
this.appContext.removeTab(tabEl.getAttribute('data-tab-id'));
|
||||||
|
|
||||||
return true; // event has been handled
|
return true; // event has been handled
|
||||||
}
|
}
|
||||||
@ -464,44 +464,26 @@ export default class TabRowWidget extends BasicWidget {
|
|||||||
return !!this.activeTabEl;
|
return !!this.activeTabEl;
|
||||||
}
|
}
|
||||||
|
|
||||||
activateTab(tabEl) {
|
activeTabChangedListener({tabId}) {
|
||||||
|
const tabEl = this.getTabById(tabId)[0];
|
||||||
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.trigger('activeTabChanged', { tabId: tabEl.getAttribute('data-tab-id') });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
removeTab(tabId) {
|
removeTab(tabId) {
|
||||||
const tabEl = this.$widget.find(`[data-tab-id='${tabId}']`)[0];
|
const tabEl = this.getTabById(tabId)[0];
|
||||||
|
|
||||||
if (tabEl === this.activeTabEl) {
|
|
||||||
if (tabEl.nextElementSibling && tabEl.nextElementSibling.classList.contains("note-tab")) {
|
|
||||||
this.activateTab(tabEl.nextElementSibling)
|
|
||||||
} else if (tabEl.previousElementSibling && tabEl.previousElementSibling.classList.contains("note-tab")) {
|
|
||||||
this.activateTab(tabEl.previousElementSibling)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tabEl.parentNode.removeChild(tabEl);
|
tabEl.parentNode.removeChild(tabEl);
|
||||||
this.trigger('tabRemove', { tabId: tabEl.getAttribute('data-tab-id') });
|
|
||||||
this.cleanUpPreviouslyDraggedTabs();
|
this.cleanUpPreviouslyDraggedTabs();
|
||||||
this.layoutTabs();
|
this.layoutTabs();
|
||||||
this.setupDraggabilly();
|
this.setupDraggabilly();
|
||||||
this.setVisibility();
|
this.setVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
removeAllTabs() {
|
getTabIdsInOrder() {
|
||||||
for (const tabEl of this.tabEls) {
|
return this.tabEls.map(el => el.getAttribute('data-tab-id'));
|
||||||
this.removeTab(tabEl.getAttribute('data-tab-id'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
removeAllTabsExceptForThis(remainingTabEl) {
|
|
||||||
for (const tabEl of this.tabEls) {
|
|
||||||
if (remainingTabEl !== tabEl) {
|
|
||||||
this.removeTab(tabEl.getAttribute('data-tab-id'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTab(tabEl, tabProperties) {
|
updateTab(tabEl, tabProperties) {
|
||||||
@ -519,6 +501,10 @@ export default class TabRowWidget extends BasicWidget {
|
|||||||
.forEach($el => $el.find('.note-tab-title').text(title));
|
.forEach($el => $el.find('.note-tab-title').text(title));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tabRemovedListener({tabId}) {
|
||||||
|
this.removeTab(tabId);
|
||||||
|
}
|
||||||
|
|
||||||
cleanUpPreviouslyDraggedTabs() {
|
cleanUpPreviouslyDraggedTabs() {
|
||||||
this.tabEls.forEach((tabEl) => tabEl.classList.remove('note-tab-was-just-dragged'));
|
this.tabEls.forEach((tabEl) => tabEl.classList.remove('note-tab-was-just-dragged'));
|
||||||
}
|
}
|
||||||
@ -552,7 +538,7 @@ export default class TabRowWidget extends BasicWidget {
|
|||||||
this.draggabillies.push(draggabilly);
|
this.draggabillies.push(draggabilly);
|
||||||
|
|
||||||
draggabilly.on('pointerDown', _ => {
|
draggabilly.on('pointerDown', _ => {
|
||||||
this.activateTab(tabEl)
|
this.appContext.activateTab(tabEl.getAttribute('data-tab-id'));
|
||||||
});
|
});
|
||||||
|
|
||||||
draggabilly.on('dragStart', _ => {
|
draggabilly.on('dragStart', _ => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user