diff --git a/libraries/chrome-tabs/chrome-tabs.js b/libraries/chrome-tabs/chrome-tabs.js index a6ea988eb..789d76e13 100644 --- a/libraries/chrome-tabs/chrome-tabs.js +++ b/libraries/chrome-tabs/chrome-tabs.js @@ -50,8 +50,7 @@ ` const defaultTapProperties = { - title: 'New tab', - favicon: false + title: 'New tab' } let instanceId = 0 diff --git a/src/public/javascripts/services/note_context.js b/src/public/javascripts/services/note_context.js index 718e8273a..cf34ff7f5 100644 --- a/src/public/javascripts/services/note_context.js +++ b/src/public/javascripts/services/note_context.js @@ -17,10 +17,6 @@ import noteDetailRelationMap from "./note_detail_relation_map.js"; const $noteTabContentsContainer = $("#note-tab-container"); -const el = $('.chrome-tabs')[0]; -const chromeTabs = new ChromeTabs(); -chromeTabs.init(el); - const componentClasses = { 'code': noteDetailCode, 'text': noteDetailText, @@ -31,12 +27,25 @@ const componentClasses = { 'relation-map': noteDetailRelationMap }; +let tabIdCounter = 1; + class NoteContext { - constructor(note, openOnBackground) { + constructor(chromeTabs, note, openOnBackground) { + this.tabId = tabIdCounter++; + this.chromeTabs = chromeTabs; /** @type {NoteFull} */ this.note = note; this.noteId = note.noteId; - this.$noteTabContent = $noteTabContentsContainer.find(`[data-note-id="${this.noteId}"]`); + + this.$noteTabContent = $(".note-tab-content-template").clone(); + this.$noteTabContent.removeClass('note-tab-content-template'); + this.$noteTabContent.attr('data-note-id', this.noteId); + this.$noteTabContent.attr('data-tab-id', this.tabId); + + $noteTabContentsContainer.append(this.$noteTabContent); + + console.log(`Creating note tab ${this.tabId} for ${this.noteId}`); + this.$noteTitle = this.$noteTabContent.find(".note-title"); this.$noteDetailComponents = this.$noteTabContent.find(".note-detail-component"); this.$protectButton = this.$noteTabContent.find(".protect-button"); @@ -58,9 +67,9 @@ class NoteContext { treeService.setNoteTitle(this.noteId, title); }); - this.tab = chromeTabs.addTab({ + this.tab = this.chromeTabs.addTab({ title: note.title, - favicon: false + id: this.tabId }, { background: openOnBackground }); @@ -73,9 +82,11 @@ class NoteContext { this.note = note; this.$noteTabContent.attr('data-note-id', note.noteId); - chromeTabs.updateTab(this.tab, {title: note.title}); + this.chromeTabs.updateTab(this.tab, {title: note.title}); this.attributes.invalidateAttributes(); + + console.log(`Switched tab ${this.tabId} to ${this.noteId}`); } getComponent(type) { diff --git a/src/public/javascripts/services/note_detail.js b/src/public/javascripts/services/note_detail.js index 161241bbd..beccf47d5 100644 --- a/src/public/javascripts/services/note_detail.js +++ b/src/public/javascripts/services/note_detail.js @@ -12,6 +12,10 @@ import bundleService from "./bundle.js"; import utils from "./utils.js"; import importDialog from "../dialogs/import.js"; +const chromeTabsEl = document.querySelector('.chrome-tabs'); +const chromeTabs = new ChromeTabs(); +chromeTabs.init(chromeTabsEl); + const $noteTabContentsContainer = $("#note-tab-container"); const $savedIndicator = $(".saved-indicator"); @@ -84,7 +88,7 @@ async function handleProtectedSession() { } /** @type {NoteContext[]} */ -const noteContexts = []; +let noteContexts = []; /** @returns {NoteContext} */ function getContext(noteId) { @@ -107,9 +111,11 @@ function getActiveContext() { } } -function showTab(noteId) { +function showTab(tabId) { + tabId = parseInt(tabId); + for (const ctx of noteContexts) { - ctx.$noteTabContent.toggle(ctx.noteId === noteId); + ctx.$noteTabContent.toggle(ctx.tabId === tabId); } } @@ -118,19 +124,12 @@ async function loadNoteDetail(noteId, newTab = false) { let ctx; if (noteContexts.length === 0 || newTab) { - const $tabContent = $(".note-tab-content-template").clone(); - - $tabContent.removeClass('note-tab-content-template'); - $tabContent.attr('data-note-id', noteId); - - $noteTabContentsContainer.append($tabContent); - // if it's a new tab explicitly by user then it's in background - ctx = new NoteContext(loadedNote, newTab); + ctx = new NoteContext(chromeTabs, loadedNote, newTab); noteContexts.push(ctx); if (!newTab) { - showTab(noteId); + showTab(ctx.tabId); } } else { @@ -270,8 +269,32 @@ $noteTabContentsContainer.on("drop", e => { }); }); -document.querySelector('.chrome-tabs') - .addEventListener('activeTabChange', ({ detail }) => showTab(detail.tabEl.getAttribute('data-note-id'))); +chromeTabsEl.addEventListener('activeTabChange', ({ detail }) => { + const tabId = detail.tabEl.getAttribute('data-tab-id'); + + showTab(tabId); + + console.log(`Activated tab ${tabId}`); +}); + +chromeTabsEl.addEventListener('tabRemove', ({ detail }) => { + const tabId = parseInt(detail.tabEl.getAttribute('data-tab-id')); + + noteContexts = noteContexts.filter(nc => nc.tabId !== tabId); + + console.log(`Removed tab ${tabId}`); +}); + +if (utils.isElectron()) { + utils.bindShortcut('ctrl+w', () => { + if (noteContexts.length === 1) { + // at least one tab must be present + return; + } + + chromeTabs.removeTab(chromeTabs.activeTabEl); + }); +} // this makes sure that when user e.g. reloads the page or navigates away from the page, the note's content is saved // this sends the request asynchronously and doesn't wait for result diff --git a/src/public/javascripts/services/server.js b/src/public/javascripts/services/server.js index 261c51d44..a8afa62d8 100644 --- a/src/public/javascripts/services/server.js +++ b/src/public/javascripts/services/server.js @@ -1,6 +1,8 @@ import utils from './utils.js'; import infoService from "./info.js"; +const REQUEST_LOGGING_ENABLED = false; + function getHeaders() { // headers need to be lowercase because node.js automatically converts them to lower case // so hypothetical protectedSessionId becomes protectedsessionid on the backend @@ -45,7 +47,9 @@ async function call(method, url, data) { return new Promise((resolve, reject) => { reqResolves[requestId] = resolve; - console.log(utils.now(), "Request #" + requestId + " to " + method + " " + url); + if (REQUEST_LOGGING_ENABLED) { + console.log(utils.now(), "Request #" + requestId + " to " + method + " " + url); + } ipc.send('server-request', { requestId: requestId, @@ -89,7 +93,9 @@ if (utils.isElectron()) { const ipc = require('electron').ipcRenderer; ipc.on('server-response', (event, arg) => { - console.log(utils.now(), "Response #" + arg.requestId + ": " + arg.statusCode); + if (REQUEST_LOGGING_ENABLED) { + console.log(utils.now(), "Response #" + arg.requestId + ": " + arg.statusCode); + } reqResolves[arg.requestId](arg.body);