From a6e446e5cfb5f011f73a849cc7eff95ea6ea8013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristijan=20Ribari=C4=87?= Date: Mon, 17 Feb 2025 15:56:57 +0100 Subject: [PATCH 1/2] Fix: Update pinned tab title in storage on rename This commit addresses an issue where renaming a pinned tab wouldn't update the title stored in `ZenPinnedTabsStorage`. The following changes were made: - Modified `ZenUIManager.mjs` to asynchronously call `ZenPinnedTabsStorage.updatePinTitle` when a tab is renamed via the keyboard. This ensures the stored title is synchronized with the displayed title. - Added the `updatePinTitle` function to `ZenPinnedTabsStorage.mjs`. This function updates the title of a zen pin within the database. This ensures consistency between the tab title displayed in the UI and the title stored for pinned tabs. --- src/browser/base/content/ZenUIManager.mjs | 7 ++- .../zen-components/ZenPinnedTabsStorage.mjs | 52 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/browser/base/content/ZenUIManager.mjs b/src/browser/base/content/ZenUIManager.mjs index 4c6ac5ed4..d95de21b1 100644 --- a/src/browser/base/content/ZenUIManager.mjs +++ b/src/browser/base/content/ZenUIManager.mjs @@ -665,7 +665,7 @@ var gZenVerticalTabsManager = { target.appendChild(child); }, - renameTabKeydown(event) { + async renameTabKeydown(event) { if (event.key === 'Enter') { let label = this._tabEdited.querySelector('.tab-label-container-editing'); let input = this._tabEdited.querySelector('#tab-label-input'); @@ -681,6 +681,11 @@ var gZenVerticalTabsManager = { } else { gBrowser.setTabTitle(this._tabEdited); } + const pinId = this._tabEdited.getAttribute('zen-pin-id'); + if (pinId) { + // Update pin title in storage + await ZenPinnedTabsStorage.updatePinTitle(pinId, this._tabEdited.label); + } // Maybe add some confetti here?!? gZenUIManager.motion.animate( diff --git a/src/browser/base/zen-components/ZenPinnedTabsStorage.mjs b/src/browser/base/zen-components/ZenPinnedTabsStorage.mjs index b47850b4e..c5b5a07a3 100644 --- a/src/browser/base/zen-components/ZenPinnedTabsStorage.mjs +++ b/src/browser/base/zen-components/ZenPinnedTabsStorage.mjs @@ -351,6 +351,58 @@ var ZenPinnedTabsStorage = { this._notifyPinsChanged('zen-pin-updated', Array.from(changedUUIDs)); }, + async updatePinTitle(uuid, newTitle, notifyObservers = true) { + if (!uuid || typeof newTitle !== 'string') { + throw new Error('Invalid parameters: uuid and newTitle are required'); + } + + const changedUUIDs = new Set(); + + await PlacesUtils.withConnectionWrapper('ZenPinnedTabsStorage.updatePinTitle', async (db) => { + await db.executeTransaction(async () => { + const now = Date.now(); + + // Update the pin's title + const result = await db.execute( + ` + UPDATE zen_pins + SET title = :newTitle, + updated_at = :now + WHERE uuid = :uuid + `, + { + uuid, + newTitle, + now, + } + ); + + // Only proceed with change tracking if a row was actually updated + if (result.rowsAffected > 0) { + changedUUIDs.add(uuid); + + // Record the change + await db.execute( + ` + INSERT OR REPLACE INTO zen_pins_changes (uuid, timestamp) + VALUES (:uuid, :timestamp) + `, + { + uuid, + timestamp: Math.floor(now / 1000), + } + ); + + await this.updateLastChangeTimestamp(db); + } + }); + }); + + if (notifyObservers && changedUUIDs.size > 0) { + this._notifyPinsChanged('zen-pin-updated', Array.from(changedUUIDs)); + } + }, + async __dropTables() { await PlacesUtils.withConnectionWrapper('ZenPinnedTabsStorage.__dropTables', async (db) => { await db.execute(`DROP TABLE IF EXISTS zen_pins`); From 57a33beb810ed26513c24df88726bc0197be5756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristijan=20Ribari=C4=87?= Date: Mon, 17 Feb 2025 17:22:44 +0100 Subject: [PATCH 2/2] Fix: Properly update pinned tab titles after edit This commit addresses an issue where edited pinned tab titles were not consistently updated across all windows and in storage. The following changes were made: - **ZenUIManager.mjs:** Removed redundant `pinId` variable and directly checked `zen-pin-id` attribute. - **ZenPinnedTabsStorage.mjs:** Added `edited_title` column to the `zen_pins` table to track if a pin's title has been manually edited. Also, the `updatePinTitle` function now accepts an `isEdited` flag (defaults to true) and updates the `edited_title` column accordingly. - **ZenPinnedTabManager.mjs:** The `updatePinTitle` function was added to handle the update of pin titles. It updates the title in storage using `ZenPinnedTabsStorage.updatePinTitle`, refreshes the pinned tabs, and then iterates through all browser windows to update the labels of corresponding pinned tabs. Also, a check was added to `_initializePinnedTabs` to set the `zen-has-static-label` attribute on tabs with `editedTitle` set to `true`. - **ZenWorkspaces.mjs:** Added a null check for `activeWorkspaceStrip` to avoid errors when it's not available. These changes ensure that when a pinned tab title is edited, the updated title is correctly persisted in storage and reflected across all open windows. The `edited_title` flag allows distinguishing between default titles and custom ones. --- src/browser/base/content/ZenUIManager.mjs | 5 +-- .../zen-components/ZenPinnedTabManager.mjs | 45 ++++++++++++++++--- .../zen-components/ZenPinnedTabsStorage.mjs | 21 ++++++++- .../base/zen-components/ZenWorkspaces.mjs | 2 +- 4 files changed, 60 insertions(+), 13 deletions(-) diff --git a/src/browser/base/content/ZenUIManager.mjs b/src/browser/base/content/ZenUIManager.mjs index d95de21b1..c895c0109 100644 --- a/src/browser/base/content/ZenUIManager.mjs +++ b/src/browser/base/content/ZenUIManager.mjs @@ -681,10 +681,9 @@ var gZenVerticalTabsManager = { } else { gBrowser.setTabTitle(this._tabEdited); } - const pinId = this._tabEdited.getAttribute('zen-pin-id'); - if (pinId) { + if (this._tabEdited.getAttribute('zen-pin-id')) { // Update pin title in storage - await ZenPinnedTabsStorage.updatePinTitle(pinId, this._tabEdited.label); + await gZenPinnedTabManager.updatePinTitle(this._tabEdited, this._tabEdited.label, !!newName); } // Maybe add some confetti here?!? diff --git a/src/browser/base/zen-components/ZenPinnedTabManager.mjs b/src/browser/base/zen-components/ZenPinnedTabManager.mjs index 084cb0ad1..cddcb5b3a 100644 --- a/src/browser/base/zen-components/ZenPinnedTabManager.mjs +++ b/src/browser/base/zen-components/ZenPinnedTabManager.mjs @@ -70,7 +70,7 @@ } if (onInit) { - await this._refreshPinnedTabs(newWorkspace, { init: onInit }); + await this._refreshPinnedTabs({ init: onInit }); } } @@ -98,9 +98,9 @@ return this._enabled; } - async _refreshPinnedTabs(currentWorkspace, { init = false } = {}) { + async _refreshPinnedTabs({ init = false } = {}) { await this._initializePinsCache(); - await this._initializePinnedTabs(init, currentWorkspace); + await this._initializePinnedTabs(init); } async _initializePinsCache() { @@ -141,7 +141,7 @@ return this._pinsCache; } - async _initializePinnedTabs(init = false, currentWorkspace) { + async _initializePinnedTabs(init = false) { const pins = this._pinsCache; if (!pins?.length) { return; @@ -213,6 +213,10 @@ newTab.setAttribute('zen-essential', 'true'); } + if (pin.editedTitle) { + newTab.setAttribute('zen-has-static-label', 'true'); + } + // Initialize browser state if needed if (!newTab.linkedBrowser._remoteAutoRemoved) { let state = { @@ -349,7 +353,7 @@ await ZenPinnedTabsStorage.savePin(pin); const currentWorkspace = await ZenWorkspaces.getActiveWorkspace(); - await this._refreshPinnedTabs(currentWorkspace); + await this._refreshPinnedTabs(); } async _setPinnedAttributes(tab) { @@ -386,7 +390,7 @@ return; } const currentWorkspace = await ZenWorkspaces.getActiveWorkspace(); - await this._refreshPinnedTabs(currentWorkspace); + await this._refreshPinnedTabs(); } async _removePinnedAttributes(tab, isClosing = false) { @@ -411,7 +415,7 @@ } } const currentWorkspace = await ZenWorkspaces.getActiveWorkspace(); - await this._refreshPinnedTabs(currentWorkspace); + await this._refreshPinnedTabs(); } _initClosePinnedTabShortcut() { @@ -707,6 +711,33 @@ return document.documentElement.getAttribute('zen-sidebar-expanded') === 'true'; } + async updatePinTitle(tab, newTitle, isEdited = true, notifyObservers = true) { + const uuid = tab.getAttribute('zen-pin-id'); + await ZenPinnedTabsStorage.updatePinTitle(uuid, newTitle, isEdited, notifyObservers); + + await this._refreshPinnedTabs(); + + const browsers = Services.wm.getEnumerator('navigator:browser'); + + // update the label for the same pin across all windows + for (const browser of browsers) { + const tabs = browser.gBrowser.tabs; + for (let i = 0; i < tabs.length; i++) { + const tabToEdit = tabs[i]; + if (tabToEdit.getAttribute('zen-pin-id') === uuid && tabToEdit !== tab) { + tabToEdit.removeAttribute('zen-has-static-label'); + if (isEdited) { + gBrowser._setTabLabel(tabToEdit, newTitle); + tabToEdit.setAttribute('zen-has-static-label', 'true'); + } else { + gBrowser.setTabTitle(tabToEdit); + } + break; + } + } + } + } + applyDragoverClass(event, draggedTab) { const pinnedTabsTarget = event.target.closest('#vertical-pinned-tabs-container'); const essentialTabsTarget = event.target.closest('#zen-essentials-container'); diff --git a/src/browser/base/zen-components/ZenPinnedTabsStorage.mjs b/src/browser/base/zen-components/ZenPinnedTabsStorage.mjs index c5b5a07a3..02bbb1aac 100644 --- a/src/browser/base/zen-components/ZenPinnedTabsStorage.mjs +++ b/src/browser/base/zen-components/ZenPinnedTabsStorage.mjs @@ -24,6 +24,19 @@ var ZenPinnedTabsStorage = { ) `); + const columns = await db.execute(`PRAGMA table_info(zen_pins)`); + const columnNames = columns.map((row) => row.getResultByName('name')); + + // Helper function to add column if it doesn't exist + const addColumnIfNotExists = async (columnName, definition) => { + if (!columnNames.includes(columnName)) { + await db.execute(`ALTER TABLE zen_pins ADD COLUMN ${columnName} ${definition}`); + } + }; + + // Add edited_title column if it doesn't exist + await addColumnIfNotExists('edited_title', 'BOOLEAN NOT NULL DEFAULT 0'); + // Create indices await db.execute(` CREATE INDEX IF NOT EXISTS idx_zen_pins_uuid ON zen_pins(uuid) @@ -152,6 +165,7 @@ var ZenPinnedTabsStorage = { isEssential: Boolean(row.getResultByName('is_essential')), isGroup: Boolean(row.getResultByName('is_group')), parentUuid: row.getResultByName('parent_uuid'), + editedTitle: Boolean(row.getResultByName('edited_title')), })); }, @@ -176,6 +190,7 @@ var ZenPinnedTabsStorage = { isEssential: Boolean(row.getResultByName('is_essential')), isGroup: Boolean(row.getResultByName('is_group')), parentUuid: row.getResultByName('parent_uuid'), + editedTitle: Boolean(row.getResultByName('edited_title')), })); }, @@ -351,7 +366,7 @@ var ZenPinnedTabsStorage = { this._notifyPinsChanged('zen-pin-updated', Array.from(changedUUIDs)); }, - async updatePinTitle(uuid, newTitle, notifyObservers = true) { + async updatePinTitle(uuid, newTitle, isEdited = true, notifyObservers = true) { if (!uuid || typeof newTitle !== 'string') { throw new Error('Invalid parameters: uuid and newTitle are required'); } @@ -362,17 +377,19 @@ var ZenPinnedTabsStorage = { await db.executeTransaction(async () => { const now = Date.now(); - // Update the pin's title + // Update the pin's title and edited_title flag const result = await db.execute( ` UPDATE zen_pins SET title = :newTitle, + edited_title = :isEdited, updated_at = :now WHERE uuid = :uuid `, { uuid, newTitle, + isEdited, now, } ); diff --git a/src/browser/base/zen-components/ZenWorkspaces.mjs b/src/browser/base/zen-components/ZenWorkspaces.mjs index bc15851bc..d6baa4175 100644 --- a/src/browser/base/zen-components/ZenWorkspaces.mjs +++ b/src/browser/base/zen-components/ZenWorkspaces.mjs @@ -154,7 +154,7 @@ var ZenWorkspaces = new (class extends ZenMultiWindowFeature { } get tabboxChildren() { - return this.activeWorkspaceStrip.children; + return this.activeWorkspaceStrip?.children || []; } get pinnedTabsContainer() {