fixes in closing tabs and elsewhere

This commit is contained in:
zadam 2020-02-09 21:13:05 +01:00
parent 4401a8e1e8
commit 826c434630
15 changed files with 94 additions and 83 deletions

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "trilium", "name": "trilium",
"version": "0.40.2", "version": "0.40.3",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View File

@ -70,6 +70,7 @@ window.glob.refreshTree = treeService.reload;
window.glob.getActiveTabNote = () => appContext.tabManager.getActiveTabNote(); window.glob.getActiveTabNote = () => appContext.tabManager.getActiveTabNote();
window.glob.requireLibrary = libraryLoader.requireLibrary; window.glob.requireLibrary = libraryLoader.requireLibrary;
window.glob.ESLINT = libraryLoader.ESLINT; window.glob.ESLINT = libraryLoader.ESLINT;
window.glob.appContext = appContext; // for debugging
protectedSessionHolder.setProtectedSessionId(null); protectedSessionHolder.setProtectedSessionId(null);

View File

@ -8,6 +8,7 @@ import utils from "./utils.js";
import ZoomService from "./zoom.js"; import ZoomService from "./zoom.js";
import Layout from "../widgets/layout.js"; import Layout from "../widgets/layout.js";
import TabManager from "./tab_manager.js"; import TabManager from "./tab_manager.js";
import treeService from "./tree.js";
class AppContext { class AppContext {
constructor(layout) { constructor(layout) {
@ -63,22 +64,6 @@ class AppContext {
} }
} }
hoistedNoteChangedListener({hoistedNoteId}) {
if (hoistedNoteId === 'root') {
return;
}
for (const tc of this.tabManager.getTabContexts()) {
if (tc.notePath && !tc.notePath.split("/").includes(hoistedNoteId)) {
this.tabManager.removeTab(tc.tabId);
}
}
if (this.tabManager.getTabContexts().length === 0) {
this.tabManager.openAndActivateEmptyTab();
}
}
async protectedSessionStartedListener() { async protectedSessionStartedListener() {
await treeCache.loadInitialTree(); await treeCache.loadInitialTree();
@ -103,15 +88,9 @@ function isNotePathInAddress() {
|| (notePath === '' && !!tabId); || (notePath === '' && !!tabId);
} }
function getHashValueFromAddress() {
const str = document.location.hash ? document.location.hash.substr(1) : ""; // strip initial #
return str.split("-");
}
$(window).on('hashchange', function() { $(window).on('hashchange', function() {
if (isNotePathInAddress()) { if (isNotePathInAddress()) {
const [notePath, tabId] = getHashValueFromAddress(); const [notePath, tabId] = treeService.getHashValueFromAddress();
appContext.tabManager.switchToTab(tabId, notePath); appContext.tabManager.switchToTab(tabId, notePath);
} }

View File

@ -70,7 +70,7 @@ export default class Entrypoints extends Component {
await treeService.expandToNote(note.noteId); await treeService.expandToNote(note.noteId);
const tabContext = appContext.openEmptyTab(); const tabContext = appContext.tabManager.openEmptyTab();
appContext.tabManager.activateTab(tabContext.tabId); appContext.tabManager.activateTab(tabContext.tabId);
await tabContext.setNote(note.noteId); await tabContext.setNote(note.noteId);

View File

@ -77,7 +77,7 @@ function goToLink(e) {
if (notePath) { if (notePath) {
if ((e.which === 1 && e.ctrlKey) || e.which === 2) { if ((e.which === 1 && e.ctrlKey) || e.which === 2) {
const tabContext = appContext.openEmptyTab(); const tabContext = appContext.tabManager.openEmptyTab();
appContext.tabManager.activateTab(tabContext.tabId); appContext.tabManager.activateTab(tabContext.tabId);
tabContext.setNote(notePath); tabContext.setNote(notePath);
} }
@ -119,7 +119,7 @@ function newTabContextMenu(e) {
}, },
selectContextMenuItem: (e, cmd) => { selectContextMenuItem: (e, cmd) => {
if (cmd === 'openNoteInNewTab') { if (cmd === 'openNoteInNewTab') {
const tabContext = appContext.openEmptyTab(); const tabContext = appContext.tabManager.openEmptyTab();
tabContext.setNote(notePath); tabContext.setNote(notePath);
appContext.tabManager.activateTab(tabContext.tabId); appContext.tabManager.activateTab(tabContext.tabId);
} }
@ -141,7 +141,7 @@ $(document).on('mousedown', '.note-detail-text a', function (e) {
e.preventDefault(); e.preventDefault();
if (notePath) { if (notePath) {
const tabContext = appContext.openEmptyTab(); const tabContext = appContext.tabManager.openEmptyTab();
tabContext.setNote(notePath); tabContext.setNote(notePath);
appContext.tabManager.activateTab(tabContext.tabId); appContext.tabManager.activateTab(tabContext.tabId);
} }

View File

@ -12,13 +12,12 @@ import hoistedNoteService from "./hoisted_note.js";
class TabContext extends Component { class TabContext extends Component {
/** /**
* @param {AppContext} appContext * @param {AppContext} appContext
* @param {object} state * @param {string|null} tabId
*/ */
constructor(appContext, state = {}) { constructor(appContext, tabId = null) {
super(appContext); super(appContext);
this.tabId = state.tabId || utils.randomString(4); this.tabId = tabId || utils.randomString(4);
this.state = state;
this.trigger('newTabOpened', {tabId: this.tabId}); this.trigger('newTabOpened', {tabId: this.tabId});
} }

View File

@ -11,8 +11,6 @@ export default class TabManager extends Component {
constructor(appContext) { constructor(appContext) {
super(appContext); super(appContext);
/** @type {TabContext[]} */
this.tabContexts = [];
this.activeTabId = null; this.activeTabId = null;
this.tabsUpdate = new SpacedUpdate(async () => { this.tabsUpdate = new SpacedUpdate(async () => {
@ -26,6 +24,11 @@ export default class TabManager extends Component {
}); });
} }
/** @type {TabContext[]} */
get tabContexts() {
return this.children;
}
async loadTabs() { async loadTabs() {
const openTabs = options.getJson('openTabs') || []; const openTabs = options.getJson('openTabs') || [];
@ -85,7 +88,7 @@ export default class TabManager extends Component {
await this.tabsUpdate.allowUpdateWithoutChange(async () => { await this.tabsUpdate.allowUpdateWithoutChange(async () => {
for (const tab of filteredTabs) { for (const tab of filteredTabs) {
const tabContext = this.openEmptyTab(); const tabContext = this.openEmptyTab(tab.tabId);
await tabContext.setNote(tab.notePath); await tabContext.setNote(tab.notePath);
if (tab.active) { if (tab.active) {
@ -106,8 +109,19 @@ export default class TabManager extends Component {
setCurrentNotePathToHash() { setCurrentNotePathToHash() {
const activeTabContext = this.getActiveTabContext(); const activeTabContext = this.getActiveTabContext();
if (activeTabContext && activeTabContext.notePath) { if (activeTabContext
document.location.hash = (activeTabContext.notePath || "") + "-" + activeTabContext.tabId; && activeTabContext.notePath !== treeService.getHashValueFromAddress()) {
const url = '#' + (activeTabContext.notePath || "") + "-" + activeTabContext.tabId;
// using pushState instead of directly modifying document.location because it does not trigger hashchange
window.history.pushState(null, "", url);
document.title = "Trilium Notes";
if (activeTabContext.note) {
// it helps navigating in history if note title is included in the title
document.title += " - " + activeTabContext.note.title;
}
} }
} }
@ -166,9 +180,8 @@ export default class TabManager extends Component {
await this.activateTab(tabContext.tabId); await this.activateTab(tabContext.tabId);
} }
openEmptyTab() { openEmptyTab(tabId) {
const tabContext = new TabContext(this.appContext); const tabContext = new TabContext(this.appContext, tabId);
this.tabContexts.push(tabContext);
this.children.push(tabContext); this.children.push(tabContext);
return tabContext; return tabContext;
} }
@ -192,11 +205,9 @@ export default class TabManager extends Component {
return; return;
} }
const oldActiveTabId = this.activeTabId;
this.activeTabId = tabId; this.activeTabId = tabId;
this.trigger('activeTabChanged', { oldActiveTabId, newActiveTabId: tabId }); this.trigger('activeTabChanged');
this.tabsUpdate.scheduleUpdate(); this.tabsUpdate.scheduleUpdate();
@ -204,7 +215,7 @@ export default class TabManager extends Component {
} }
async removeTab(tabId) { async removeTab(tabId) {
const tabContextToRemove = this.tabContexts.find(tc => tc.tabId === tabId); const tabContextToRemove = this.getTabContextById(tabId);
if (!tabContextToRemove) { if (!tabContextToRemove) {
return; return;
@ -212,14 +223,14 @@ export default class TabManager extends Component {
await this.trigger('beforeTabRemove', {tabId}, true); await this.trigger('beforeTabRemove', {tabId}, true);
if (this.tabContexts.length === 1) { if (this.tabContexts.length <= 1) {
this.openAndActivateEmptyTab(); this.openAndActivateEmptyTab();
} }
else { else {
this.activateNextTabListener(); this.activateNextTabListener();
} }
this.children = this.tabContexts = this.tabContexts.filter(tc => tc.tabId === tabId); this.children = this.children.filter(tc => tc.tabId !== tabId);
this.trigger('tabRemoved', {tabId}); this.trigger('tabRemoved', {tabId});
@ -233,7 +244,7 @@ export default class TabManager extends Component {
order[tabIdsInOrder[i]] = i; order[tabIdsInOrder[i]] = i;
} }
this.tabContexts.sort((a, b) => order[a.tabId] < order[b.tabId] ? -1 : 1); this.children.sort((a, b) => order[a.tabId] < order[b.tabId] ? -1 : 1);
this.tabsUpdate.scheduleUpdate(); this.tabsUpdate.scheduleUpdate();
} }
@ -264,11 +275,29 @@ export default class TabManager extends Component {
this.openAndActivateEmptyTab(); this.openAndActivateEmptyTab();
} }
removeAllTabsListener() { async removeAllTabsListener() {
// TODO for (const tabIdToRemove of this.tabContexts.map(tc => tc.tabId)) {
await this.removeTab(tabIdToRemove);
}
} }
removeAllTabsExceptForThis() { async removeAllTabsExceptForThisListener({tabId}) {
// TODO for (const tabIdToRemove of this.tabContexts.map(tc => tc.tabId)) {
if (tabIdToRemove !== tabId) {
await this.removeTab(tabIdToRemove);
}
}
}
async hoistedNoteChangedListener({hoistedNoteId}) {
if (hoistedNoteId === 'root') {
return;
}
for (const tc of this.tabContexts.splice()) {
if (tc.notePath && !tc.notePath.split("/").includes(hoistedNoteId)) {
await this.removeTab(tc.tabId);
}
}
} }
} }

View File

@ -1,13 +1,8 @@
import ws from './ws.js'; import ws from './ws.js';
import protectedSessionHolder from './protected_session_holder.js';
import utils from './utils.js'; import utils from './utils.js';
import server from './server.js'; import server from './server.js';
import treeCache from './tree_cache.js'; import treeCache from './tree_cache.js';
import toastService from "./toast.js";
import treeBuilder from "./tree_builder.js";
import hoistedNoteService from '../services/hoisted_note.js'; import hoistedNoteService from '../services/hoisted_note.js';
import optionsService from "../services/options.js";
import bundle from "./bundle.js";
import appContext from "./app_context.js"; import appContext from "./app_context.js";
/** /**
@ -262,6 +257,12 @@ async function getNotePathTitle(notePath) {
return titlePath.join(' / '); return titlePath.join(' / ');
} }
function getHashValueFromAddress() {
const str = document.location.hash ? document.location.hash.substr(1) : ""; // strip initial #
return str.split("-");
}
export default { export default {
sortAlphabetically, sortAlphabetically,
resolveNotePath, resolveNotePath,
@ -272,5 +273,6 @@ export default {
getNoteIdFromNotePath, getNoteIdFromNotePath,
getNoteIdAndParentIdFromNotePath, getNoteIdAndParentIdFromNotePath,
getNoteTitle, getNoteTitle,
getNotePathTitle getNotePathTitle,
getHashValueFromAddress
}; };

View File

@ -102,7 +102,7 @@ class TreeContextMenu {
const notePath = await treeService.getNotePath(this.node); const notePath = await treeService.getNotePath(this.node);
if (cmd === 'openInTab') { if (cmd === 'openInTab') {
const tabContext = appContext.openEmptyTab(); const tabContext = appContext.tabManager.openEmptyTab();
appContext.tabManager.activateTab(tabContext.tabId); appContext.tabManager.activateTab(tabContext.tabId);
tabContext.setNote(notePath); tabContext.setNote(notePath);
} }

View File

@ -32,12 +32,6 @@ export default class CalendarWidget extends CollapsibleWidget {
&& this.note.hasOwnedLabel("dateNote"); && this.note.hasOwnedLabel("dateNote");
} }
setTabContextListener({tabContext}) {
super.setTabContextListener({tabContext});
console.log("set tab context", tabContext.tabId, "to", this.componentId);
}
async doRenderBody() { async doRenderBody() {
await libraryLoader.requireLibrary(libraryLoader.CALENDAR_WIDGET); await libraryLoader.requireLibrary(libraryLoader.CALENDAR_WIDGET);

View File

@ -9,7 +9,6 @@ import treeBuilder from "../services/tree_builder.js";
import TreeContextMenu from "../services/tree_context_menu.js"; import TreeContextMenu from "../services/tree_context_menu.js";
import treeChangesService from "../services/branches.js"; import treeChangesService from "../services/branches.js";
import ws from "../services/ws.js"; import ws from "../services/ws.js";
import appContext from "../services/app_context.js";
import TabAwareWidget from "./tab_aware_widget.js"; import TabAwareWidget from "./tab_aware_widget.js";
import server from "../services/server.js"; import server from "../services/server.js";
import noteCreateService from "../services/note_create.js"; import noteCreateService from "../services/note_create.js";
@ -51,7 +50,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
treeService.getNotePath(node).then(notePath => { treeService.getNotePath(node).then(notePath => {
if (notePath) { if (notePath) {
const tabContext = appContext.openEmptyTab(); const tabContext = this.tabManager.openEmptyTab();
tabContext.setNote(notePath); tabContext.setNote(notePath);
} }
}); });
@ -86,9 +85,9 @@ export default class NoteTreeWidget extends TabAwareWidget {
node.setFocus(true); node.setFocus(true);
} }
else if (event.ctrlKey) { else if (event.ctrlKey) {
const tabContext = appContext.openEmptyTab(); const tabContext = this.tabManager.openEmptyTab();
treeService.getNotePath(node).then(notePath => tabContext.setNote(notePath)); treeService.getNotePath(node).then(notePath => tabContext.setNote(notePath));
appContext.tabManager.activateTab(tabContext.tabId); this.tabManager.activateTab(tabContext.tabId);
} }
else { else {
node.setActive(); node.setActive();
@ -285,7 +284,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
} }
async scrollToActiveNoteListener() { async scrollToActiveNoteListener() {
const activeContext = appContext.tabManager.getActiveTabContext(); const activeContext = this.tabManager.getActiveTabContext();
if (activeContext && activeContext.notePath) { if (activeContext && activeContext.notePath) {
this.tree.setFocus(); this.tree.setFocus();
@ -409,6 +408,10 @@ export default class NoteTreeWidget extends TabAwareWidget {
collapseTreeListener() { this.collapseTree(); } collapseTreeListener() { this.collapseTree(); }
isEnabled() {
return this.tabContext && this.tabContext.isActive();
}
async refresh() { async refresh() {
this.toggle(this.isEnabled()); this.toggle(this.isEnabled());
@ -467,7 +470,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
const notePath = await treeService.getNotePath(newActive); const notePath = await treeService.getNotePath(newActive);
appContext.tabManager.getActiveTabContext().setNote(notePath); this.tabManager.getActiveTabContext().setNote(notePath);
} }
node.remove(); node.remove();
@ -527,7 +530,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
} }
} }
const activateNotePath = appContext.tabManager.getActiveTabNotePath(); const activateNotePath = this.tabManager.getActiveTabNotePath();
if (activateNotePath) { if (activateNotePath) {
const node = await this.getNodeFromPath(activateNotePath); const node = await this.getNodeFromPath(activateNotePath);

View File

@ -4,6 +4,7 @@ import treeCache from "../services/tree_cache.js";
import toastService from "../services/toast.js"; import toastService from "../services/toast.js";
import appContext from "../services/app_context.js"; import appContext from "../services/app_context.js";
import noteCreateService from "../services/note_create.js"; import noteCreateService from "../services/note_create.js";
import utils from "../services/utils.js";
const TPL = ` const TPL = `
<div class="search-box"> <div class="search-box">
@ -126,6 +127,8 @@ export default class SearchBoxWidget extends BasicWidget {
} }
showSearchListener() { showSearchListener() {
utils.saveFocusedElement();
this.$searchBox.slideDown(); this.$searchBox.slideDown();
this.$searchBox.tooltip({ this.$searchBox.tooltip({

View File

@ -53,6 +53,9 @@ export default class TabCachingWidget extends TabAwareWidget {
if (widget) { if (widget) {
widget.remove(); widget.remove();
delete this.widgets[tabId];
this.children = this.children.filter(ch => ch !== widget);
} }
} }

View File

@ -261,11 +261,7 @@ export default class TabRowWidget extends BasicWidget {
]; ];
}, },
selectContextMenuItem: (e, cmd) => { selectContextMenuItem: (e, cmd) => {
if (cmd === 'removeAllTabs') { this.trigger(cmd, {tabId});
this.trigger('removeAllTabs');
} else if (cmd === 'removeAllTabsExceptForThis') {
this.trigger('removeAllTabsExceptForThis', {tabId});
}
} }
}); });
}); });
@ -398,11 +394,11 @@ export default class TabRowWidget extends BasicWidget {
setTabCloseEventListener($tab) { setTabCloseEventListener($tab) {
$tab.find('.note-tab-close') $tab.find('.note-tab-close')
.on('click', _ => this.appContext.removeTab($tab.attr('data-tab-id'))); .on('click', _ => this.tabManager.removeTab($tab.attr('data-tab-id')));
$tab.on('mousedown', e => { $tab.on('mousedown', e => {
if (e.which === 2) { if (e.which === 2) {
this.appContext.removeTab($tab.attr('data-tab-id')); this.tabManager.removeTab($tab.attr('data-tab-id'));
return true; // event has been handled return true; // event has been handled
} }
@ -413,12 +409,14 @@ export default class TabRowWidget extends BasicWidget {
return this.$widget.find('.note-tab[active]')[0]; return this.$widget.find('.note-tab[active]')[0];
} }
activeTabChangedListener({newActiveTabId}) { activeTabChangedListener() {
const newActiveTabId = this.tabManager.activeTabId;
const tabEl = this.getTabById(newActiveTabId)[0]; const tabEl = this.getTabById(newActiveTabId)[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', ''); if (tabEl) tabEl.setAttribute('active', '');
} }
newTabOpenedListener({tabId}) { newTabOpenedListener({tabId}) {
@ -603,7 +601,7 @@ export default class TabRowWidget extends BasicWidget {
} }
async entitiesReloadedListener({loadResults}) { async entitiesReloadedListener({loadResults}) {
for (const tabContext of this.tabManager.getTabContexts()) { for (const tabContext of this.tabManager.tabContexts) {
if (loadResults.isNoteReloaded(tabContext.noteId)) { if (loadResults.isNoteReloaded(tabContext.noteId)) {
const $tab = this.getTabById(tabContext.tabId); const $tab = this.getTabById(tabContext.tabId);
@ -613,7 +611,7 @@ export default class TabRowWidget extends BasicWidget {
} }
treeCacheReloadedListener() { treeCacheReloadedListener() {
for (const tabContext of this.tabManager.getTabContexts()) { for (const tabContext of this.tabManager.tabContexts) {
const $tab = this.getTabById(tabContext.tabId); const $tab = this.getTabById(tabContext.tabId);
this.updateTab($tab, tabContext.note); this.updateTab($tab, tabContext.note);

View File

@ -196,7 +196,7 @@ export default class RelationMapTypeWidget extends TypeWidget {
const noteId = this.idToNoteId($noteBox.prop("id")); const noteId = this.idToNoteId($noteBox.prop("id"));
if (cmd === "open-in-new-tab") { if (cmd === "open-in-new-tab") {
const tabContext = appContext.openEmptyTab(); const tabContext = this.tabManager.openEmptyTab();
tabContext.setNote(noteId); tabContext.setNote(noteId);
} }
else if (cmd === "remove") { else if (cmd === "remove") {