diff --git a/src/browser/components/sessionstore/SessionStore-sys-mjs.patch b/src/browser/components/sessionstore/SessionStore-sys-mjs.patch index 24e438105..18c77b523 100644 --- a/src/browser/components/sessionstore/SessionStore-sys-mjs.patch +++ b/src/browser/components/sessionstore/SessionStore-sys-mjs.patch @@ -1,5 +1,5 @@ diff --git a/browser/components/sessionstore/SessionStore.sys.mjs b/browser/components/sessionstore/SessionStore.sys.mjs -index 2a055f0c5f34f0a2667f659185120c07d38f4e41..959e73ab86bdb78203e3aed0c939c1b9acbe4897 100644 +index 2a055f0c5f34f0a2667f659185120c07d38f4e41..27f85dc47d66f2f83820e964198832d82bff04c1 100644 --- a/browser/components/sessionstore/SessionStore.sys.mjs +++ b/browser/components/sessionstore/SessionStore.sys.mjs @@ -127,6 +127,9 @@ const TAB_EVENTS = [ @@ -235,7 +235,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..959e73ab86bdb78203e3aed0c939c1b9 + if (tabData.zenIsEmpty) { + tab.setAttribute("zen-empty-tab", "true"); + } -+ if (tabData.zenStaticLabel) { ++ if (typeof tabData.zenStaticLabel === "string") { + tab.zenStaticLabel = tabData.zenStaticLabel; + } + if (tabData.zenHasStaticIcon && tabData.image) { diff --git a/src/browser/components/tabbrowser/content/tabbrowser-js.patch b/src/browser/components/tabbrowser/content/tabbrowser-js.patch index e14cb6678..2330cf504 100644 --- a/src/browser/components/tabbrowser/content/tabbrowser-js.patch +++ b/src/browser/components/tabbrowser/content/tabbrowser-js.patch @@ -1,5 +1,5 @@ diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js -index 0eaca7a58e0026237b71b2ad515efe84d9e8c779..64b6fc581be1791ef9a750e03ab9a91c92325be3 100644 +index 0eaca7a58e0026237b71b2ad515efe84d9e8c779..452879acc73898eb28cabae66d2d5692e301f853 100644 --- a/browser/components/tabbrowser/content/tabbrowser.js +++ b/browser/components/tabbrowser/content/tabbrowser.js @@ -398,6 +398,7 @@ @@ -191,7 +191,7 @@ index 0eaca7a58e0026237b71b2ad515efe84d9e8c779..64b6fc581be1791ef9a750e03ab9a91c + if (!aTab._zenContentsVisible && !aTab._zenChangeLabelFlag && !aTab._labelIsInitialTitle && !gZenWorkspaces.privateWindowOrDisabled) { + return false; + } -+ aLabel = aTab.zenStaticLabel || aLabel; ++ aLabel = (typeof aTab.zenStaticLabel === "string" && aTab.zenStaticLabel) ? aTab.zenStaticLabel : aLabel; + gZenPinnedTabManager.onTabLabelChanged(aTab); if (!aLabel || aLabel.includes("about:reader?")) { return false; diff --git a/src/zen/common/modules/ZenSessionStore.mjs b/src/zen/common/modules/ZenSessionStore.mjs index 677277f15..fed920f3b 100644 --- a/src/zen/common/modules/ZenSessionStore.mjs +++ b/src/zen/common/modules/ZenSessionStore.mjs @@ -21,7 +21,7 @@ class ZenSessionStore extends nsZenPreloadedFeature { if (tabData.zenSyncId || tabData.zenPinnedId) { tab.setAttribute("id", tabData.zenSyncId || tabData.zenPinnedId); } - if (tabData.zenStaticLabel) { + if (typeof tabData.zenStaticLabel === "string") { tab.zenStaticLabel = tabData.zenStaticLabel; } if (tabData.zenHasStaticIcon && tabData.image) { diff --git a/src/zen/drag-and-drop/ZenDragAndDrop.js b/src/zen/drag-and-drop/ZenDragAndDrop.js index 359bcc7ab..4d08e6a6c 100644 --- a/src/zen/drag-and-drop/ZenDragAndDrop.js +++ b/src/zen/drag-and-drop/ZenDragAndDrop.js @@ -851,6 +851,7 @@ ":is(.tabbrowser-tab, .zen-drop-target, .tab-group-label, tab-group[split-view-group])"; let shouldPlayHapticFeedback = false; let showIndicatorUnderNewTabButton = false; + let dropBefore = false; let dropElement = event.target.closest(dropZoneSelector); if (!dropElement) { if (event.target.classList.contains("zen-workspace-empty-space")) { @@ -862,7 +863,7 @@ const numPinned = gBrowser.pinnedTabCount - numEssentials; const tabToUse = event.target.closest(dropZoneSelector); if (!tabToUse) { - return; + return null; } const isPinned = tabToUse.pinned; const relativeTabs = tabs.slice( @@ -896,7 +897,7 @@ (!dropElement.pinned || dropElement.hasAttribute("zen-essential")) ) { this.clearDragOverVisuals(); - return; + return null; } if ( isTab(dropElement) || @@ -913,8 +914,10 @@ Services.prefs.getIntPref("browser.tabs.dragDrop.moveOverThresholdPercent") / 100; if (overlapPercent > threshold) { top = Math.round(rect.top + rect.height) + "px"; + dropBefore = false; } else { top = Math.round(rect.top) + "px"; + dropBefore = true; } if (indicator.style.top !== top) { shouldPlayHapticFeedback = true; @@ -937,12 +940,14 @@ dropElement = elementToMove(this._tabbrowserTabs.ariaFocusableItems.at(gBrowser._numZenEssentials)) || dropElement; + dropBefore = true; } } if (shouldPlayHapticFeedback) { // eslint-disable-next-line mozilla/valid-services Services.zen.playHapticFeedback(); } + return [dropBefore, dropElement]; } #getDragImageOffset(event, tab, draggingTabs) { diff --git a/src/zen/sessionstore/ZenSessionManager.sys.mjs b/src/zen/sessionstore/ZenSessionManager.sys.mjs index cd4af5b99..1a9e78233 100644 --- a/src/zen/sessionstore/ZenSessionManager.sys.mjs +++ b/src/zen/sessionstore/ZenSessionManager.sys.mjs @@ -133,6 +133,21 @@ export class nsZenSessionManager { } : null, })); + rows = await db.execute("SELECT * FROM zen_pins ORDER BY position ASC"); + data.pins = rows.map((row) => ({ + uuid: row.getResultByName("uuid"), + title: row.getResultByName("title"), + url: row.getResultByName("url"), + containerTabId: row.getResultByName("container_id"), + workspaceUuid: row.getResultByName("workspace_uuid"), + position: row.getResultByName("position"), + isEssential: Boolean(row.getResultByName("is_essential")), + isGroup: Boolean(row.getResultByName("is_group")), + parentUuid: row.getResultByName("folder_parent_uuid"), + editedTitle: Boolean(row.getResultByName("edited_title")), + folderIcon: row.getResultByName("folder_icon"), + isFolderCollapsed: Boolean(row.getResultByName("is_folder_collapsed")), + })); this._migrationData = data; } catch { /* ignore errors during migration */ @@ -188,35 +203,7 @@ export class nsZenSessionManager { // object will always be empty after migration because we haven't // gotten the opportunity to save the session yet. if (this._shouldRunMigration) { - this.log("Restoring tabs from Places DB after migration"); - if (!this.#sidebar.spaces?.length) { - this.#sidebar = { - ...this.#sidebar, - spaces: this._migrationData?.spaces || [], - }; - } - // There might be cases where there are no windows in the - // initial state, for example if the user had 'restore previous - // session' disabled before migration. In that case, we try - // to restore the last closed normal window. - if (!initialState?.windows?.length) { - let normalClosedWindow = initialState?._closedWindows?.find( - (win) => !win.isPopup && !win.isTaskbarTab && !win.isPrivate - ); - if (normalClosedWindow) { - initialState.windows = [Cu.cloneInto(normalClosedWindow, {})]; - this.log("Restoring tabs from last closed normal window"); - } - } - for (const winData of initialState?.windows || []) { - winData.spaces = this._migrationData?.spaces || []; - } - // Save the state to the sidebar object so that it gets written - // to the session file. - this.saveState(initialState); - delete this._migrationData; - delete this._shouldRunMigration; - return; + this.#runStateMigration(initialState); } // If there are no windows, we create an empty one. By default, // firefox would create simply a new empty window, but we want @@ -269,6 +256,55 @@ export class nsZenSessionManager { this.#sidebarObject.data = data; } + /** + * Runs the state migration to restore spaces and pinned tabs + * from the Places database into the initial session state. + * + * @param {object} initialState + * The initial session state read from the session file. + */ + #runStateMigration(initialState) { + this.log("Restoring tabs from Places DB after migration"); + if (!this.#sidebar.spaces?.length) { + this.#sidebar = { + ...this.#sidebar, + spaces: this._migrationData?.spaces || [], + }; + } + // There might be cases where there are no windows in the + // initial state, for example if the user had 'restore previous + // session' disabled before migration. In that case, we try + // to restore the last closed normal window. + if (!initialState?.windows?.length) { + let normalClosedWindow = initialState?._closedWindows?.find( + (win) => !win.isPopup && !win.isTaskbarTab && !win.isPrivate + ); + if (normalClosedWindow) { + initialState.windows = [Cu.cloneInto(normalClosedWindow, {})]; + this.log("Restoring tabs from last closed normal window"); + } + } + for (const winData of initialState?.windows || []) { + winData.spaces = this._migrationData?.spaces || []; + if (winData.tabs) { + for (const tabData of winData.tabs) { + let storeId = tabData.zenSyncId || tabData.zenPinnedId; + const pinData = this._migrationData?.pins?.find((pin) => pin.uuid === storeId); + // We need to migrate the static label from the pin data as this information + // was not stored in the session file before. + if (pinData) { + tabData.zenStaticLabel = pinData.editedTitle ? pinData.title : undefined; + } + } + } + } + // Save the state to the sidebar object so that it gets written + // to the session file. + this.saveState(initialState); + delete this._migrationData; + delete this._shouldRunMigration; + } + /** * Saves the current session state. Collects data and writes to disk. *