mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
fixes in closing tabs and elsewhere
This commit is contained in:
parent
4401a8e1e8
commit
826c434630
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "trilium",
|
||||
"version": "0.40.2",
|
||||
"version": "0.40.3",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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});
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
};
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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({
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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") {
|
||||
|
Loading…
x
Reference in New Issue
Block a user