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",
"version": "0.40.2",
"version": "0.40.3",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

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

View File

@ -8,6 +8,7 @@ import utils from "./utils.js";
import ZoomService from "./zoom.js";
import Layout from "../widgets/layout.js";
import TabManager from "./tab_manager.js";
import treeService from "./tree.js";
class AppContext {
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() {
await treeCache.loadInitialTree();
@ -103,15 +88,9 @@ function isNotePathInAddress() {
|| (notePath === '' && !!tabId);
}
function getHashValueFromAddress() {
const str = document.location.hash ? document.location.hash.substr(1) : ""; // strip initial #
return str.split("-");
}
$(window).on('hashchange', function() {
if (isNotePathInAddress()) {
const [notePath, tabId] = getHashValueFromAddress();
const [notePath, tabId] = treeService.getHashValueFromAddress();
appContext.tabManager.switchToTab(tabId, notePath);
}

View File

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

View File

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

View File

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

View File

@ -11,8 +11,6 @@ export default class TabManager extends Component {
constructor(appContext) {
super(appContext);
/** @type {TabContext[]} */
this.tabContexts = [];
this.activeTabId = null;
this.tabsUpdate = new SpacedUpdate(async () => {
@ -26,6 +24,11 @@ export default class TabManager extends Component {
});
}
/** @type {TabContext[]} */
get tabContexts() {
return this.children;
}
async loadTabs() {
const openTabs = options.getJson('openTabs') || [];
@ -85,7 +88,7 @@ export default class TabManager extends Component {
await this.tabsUpdate.allowUpdateWithoutChange(async () => {
for (const tab of filteredTabs) {
const tabContext = this.openEmptyTab();
const tabContext = this.openEmptyTab(tab.tabId);
await tabContext.setNote(tab.notePath);
if (tab.active) {
@ -106,8 +109,19 @@ export default class TabManager extends Component {
setCurrentNotePathToHash() {
const activeTabContext = this.getActiveTabContext();
if (activeTabContext && activeTabContext.notePath) {
document.location.hash = (activeTabContext.notePath || "") + "-" + activeTabContext.tabId;
if (activeTabContext
&& 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);
}
openEmptyTab() {
const tabContext = new TabContext(this.appContext);
this.tabContexts.push(tabContext);
openEmptyTab(tabId) {
const tabContext = new TabContext(this.appContext, tabId);
this.children.push(tabContext);
return tabContext;
}
@ -192,11 +205,9 @@ export default class TabManager extends Component {
return;
}
const oldActiveTabId = this.activeTabId;
this.activeTabId = tabId;
this.trigger('activeTabChanged', { oldActiveTabId, newActiveTabId: tabId });
this.trigger('activeTabChanged');
this.tabsUpdate.scheduleUpdate();
@ -204,7 +215,7 @@ export default class TabManager extends Component {
}
async removeTab(tabId) {
const tabContextToRemove = this.tabContexts.find(tc => tc.tabId === tabId);
const tabContextToRemove = this.getTabContextById(tabId);
if (!tabContextToRemove) {
return;
@ -212,14 +223,14 @@ export default class TabManager extends Component {
await this.trigger('beforeTabRemove', {tabId}, true);
if (this.tabContexts.length === 1) {
if (this.tabContexts.length <= 1) {
this.openAndActivateEmptyTab();
}
else {
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});
@ -233,7 +244,7 @@ export default class TabManager extends Component {
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();
}
@ -264,11 +275,29 @@ export default class TabManager extends Component {
this.openAndActivateEmptyTab();
}
removeAllTabsListener() {
// TODO
async removeAllTabsListener() {
for (const tabIdToRemove of this.tabContexts.map(tc => tc.tabId)) {
await this.removeTab(tabIdToRemove);
}
}
removeAllTabsExceptForThis() {
// TODO
async removeAllTabsExceptForThisListener({tabId}) {
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 protectedSessionHolder from './protected_session_holder.js';
import utils from './utils.js';
import server from './server.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 optionsService from "../services/options.js";
import bundle from "./bundle.js";
import appContext from "./app_context.js";
/**
@ -262,6 +257,12 @@ async function getNotePathTitle(notePath) {
return titlePath.join(' / ');
}
function getHashValueFromAddress() {
const str = document.location.hash ? document.location.hash.substr(1) : ""; // strip initial #
return str.split("-");
}
export default {
sortAlphabetically,
resolveNotePath,
@ -272,5 +273,6 @@ export default {
getNoteIdFromNotePath,
getNoteIdAndParentIdFromNotePath,
getNoteTitle,
getNotePathTitle
getNotePathTitle,
getHashValueFromAddress
};

View File

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

View File

@ -32,12 +32,6 @@ export default class CalendarWidget extends CollapsibleWidget {
&& this.note.hasOwnedLabel("dateNote");
}
setTabContextListener({tabContext}) {
super.setTabContextListener({tabContext});
console.log("set tab context", tabContext.tabId, "to", this.componentId);
}
async doRenderBody() {
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 treeChangesService from "../services/branches.js";
import ws from "../services/ws.js";
import appContext from "../services/app_context.js";
import TabAwareWidget from "./tab_aware_widget.js";
import server from "../services/server.js";
import noteCreateService from "../services/note_create.js";
@ -51,7 +50,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
treeService.getNotePath(node).then(notePath => {
if (notePath) {
const tabContext = appContext.openEmptyTab();
const tabContext = this.tabManager.openEmptyTab();
tabContext.setNote(notePath);
}
});
@ -86,9 +85,9 @@ export default class NoteTreeWidget extends TabAwareWidget {
node.setFocus(true);
}
else if (event.ctrlKey) {
const tabContext = appContext.openEmptyTab();
const tabContext = this.tabManager.openEmptyTab();
treeService.getNotePath(node).then(notePath => tabContext.setNote(notePath));
appContext.tabManager.activateTab(tabContext.tabId);
this.tabManager.activateTab(tabContext.tabId);
}
else {
node.setActive();
@ -285,7 +284,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
}
async scrollToActiveNoteListener() {
const activeContext = appContext.tabManager.getActiveTabContext();
const activeContext = this.tabManager.getActiveTabContext();
if (activeContext && activeContext.notePath) {
this.tree.setFocus();
@ -409,6 +408,10 @@ export default class NoteTreeWidget extends TabAwareWidget {
collapseTreeListener() { this.collapseTree(); }
isEnabled() {
return this.tabContext && this.tabContext.isActive();
}
async refresh() {
this.toggle(this.isEnabled());
@ -467,7 +470,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
const notePath = await treeService.getNotePath(newActive);
appContext.tabManager.getActiveTabContext().setNote(notePath);
this.tabManager.getActiveTabContext().setNote(notePath);
}
node.remove();
@ -527,7 +530,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
}
}
const activateNotePath = appContext.tabManager.getActiveTabNotePath();
const activateNotePath = this.tabManager.getActiveTabNotePath();
if (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 appContext from "../services/app_context.js";
import noteCreateService from "../services/note_create.js";
import utils from "../services/utils.js";
const TPL = `
<div class="search-box">
@ -126,6 +127,8 @@ export default class SearchBoxWidget extends BasicWidget {
}
showSearchListener() {
utils.saveFocusedElement();
this.$searchBox.slideDown();
this.$searchBox.tooltip({

View File

@ -53,6 +53,9 @@ export default class TabCachingWidget extends TabAwareWidget {
if (widget) {
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) => {
if (cmd === 'removeAllTabs') {
this.trigger('removeAllTabs');
} else if (cmd === 'removeAllTabsExceptForThis') {
this.trigger('removeAllTabsExceptForThis', {tabId});
}
this.trigger(cmd, {tabId});
}
});
});
@ -398,11 +394,11 @@ export default class TabRowWidget extends BasicWidget {
setTabCloseEventListener($tab) {
$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 => {
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
}
@ -413,12 +409,14 @@ export default class TabRowWidget extends BasicWidget {
return this.$widget.find('.note-tab[active]')[0];
}
activeTabChangedListener({newActiveTabId}) {
activeTabChangedListener() {
const newActiveTabId = this.tabManager.activeTabId;
const tabEl = this.getTabById(newActiveTabId)[0];
const activeTabEl = this.activeTabEl;
if (activeTabEl === tabEl) return;
if (activeTabEl) activeTabEl.removeAttribute('active');
tabEl.setAttribute('active', '');
if (tabEl) tabEl.setAttribute('active', '');
}
newTabOpenedListener({tabId}) {
@ -603,7 +601,7 @@ export default class TabRowWidget extends BasicWidget {
}
async entitiesReloadedListener({loadResults}) {
for (const tabContext of this.tabManager.getTabContexts()) {
for (const tabContext of this.tabManager.tabContexts) {
if (loadResults.isNoteReloaded(tabContext.noteId)) {
const $tab = this.getTabById(tabContext.tabId);
@ -613,7 +611,7 @@ export default class TabRowWidget extends BasicWidget {
}
treeCacheReloadedListener() {
for (const tabContext of this.tabManager.getTabContexts()) {
for (const tabContext of this.tabManager.tabContexts) {
const $tab = this.getTabById(tabContext.tabId);
this.updateTab($tab, tabContext.note);

View File

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