diff --git a/locales/en-US/browser/browser/zen-folders.ftl b/locales/en-US/browser/browser/zen-folders.ftl index ebeeaf33c..93180f314 100644 --- a/locales/en-US/browser/browser/zen-folders.ftl +++ b/locales/en-US/browser/browser/zen-folders.ftl @@ -23,9 +23,6 @@ zen-folders-panel-convert-folder-to-space = zen-folders-panel-change-folder-space = .label = Change Space... -zen-folders-panel-change-icon-folder = - .label = Change Icon - zen-folders-unload-all-tooltip = .tooltiptext = Unload active in this folder diff --git a/locales/en-US/browser/browser/zen-general.ftl b/locales/en-US/browser/browser/zen-general.ftl index 07a7546c8..0eab050d6 100644 --- a/locales/en-US/browser/browser/zen-general.ftl +++ b/locales/en-US/browser/browser/zen-general.ftl @@ -18,6 +18,10 @@ tab-context-zen-remove-essential = tab-context-zen-replace-pinned-url-with-current = .label = Replace Pinned URL with Current .accesskey = C +tab-context-zen-edit-title = + .label = Change Label... +tab-context-zen-edit-icon = + .label = Change Icon... zen-themes-corrupted = Your { -brand-short-name } mods file is corrupted. They have been reset to the default theme. zen-shortcuts-corrupted = Your { -brand-short-name } shortcuts file is corrupted. They have been reset to the default shortcuts. diff --git a/locales/en-US/browser/browser/zen-workspaces.ftl b/locales/en-US/browser/browser/zen-workspaces.ftl index 67f43f7fe..c7a5b64fd 100644 --- a/locales/en-US/browser/browser/zen-workspaces.ftl +++ b/locales/en-US/browser/browser/zen-workspaces.ftl @@ -43,12 +43,8 @@ zen-workspaces-panel-context-edit = .label = Edit Space .accesskey = E -context-zen-change-workspace-tab = - .label = Change Tab(s) To Workspace - .accesskey = C - zen-bookmark-edit-panel-workspace-selector = - .value = Workspaces + .value = Spaces .accesskey = W zen-panel-ui-gradient-generator-algo-complementary = @@ -66,6 +62,10 @@ zen-panel-ui-gradient-click-to-add = Click to add a color zen-workspace-creation-name = .placeholder = Space Name +zen-move-tab-to-workspace-button = + .label = Move To... + .tooltiptext = Move all tabs in this window to a Space + zen-workspaces-panel-context-reorder = .label = Reorder Spaces diff --git a/prefs/zen/view.yaml b/prefs/zen/view.yaml index 7f5939822..83d21386a 100644 --- a/prefs/zen/view.yaml +++ b/prefs/zen/view.yaml @@ -47,7 +47,7 @@ value: 25 - name: zen.view.context-menu.refresh - value: false + value: '@IS_TWILIGHT@' - name: zen.view.borderless-fullscreen value: true diff --git a/src/browser/base/content/zen-assets.inc.xhtml b/src/browser/base/content/zen-assets.inc.xhtml index 47f083c49..fb9693633 100644 --- a/src/browser/base/content/zen-assets.inc.xhtml +++ b/src/browser/base/content/zen-assets.inc.xhtml @@ -45,7 +45,6 @@ # Scripts used all over the browser - diff --git a/src/browser/base/content/zen-panels/popups.inc b/src/browser/base/content/zen-panels/popups.inc index d94f76ae0..864d88e10 100644 --- a/src/browser/base/content/zen-panels/popups.inc +++ b/src/browser/base/content/zen-panels/popups.inc @@ -36,7 +36,7 @@ - + @@ -59,3 +59,8 @@ + + +# Popup to move tabs to a synced workspace. +# This would be automatically populated with the list of available synced workspaces. + diff --git a/src/browser/base/content/zen-preloaded.inc.xhtml b/src/browser/base/content/zen-preloaded.inc.xhtml index ab5354092..76f32fd5f 100644 --- a/src/browser/base/content/zen-preloaded.inc.xhtml +++ b/src/browser/base/content/zen-preloaded.inc.xhtml @@ -6,7 +6,6 @@ # the window is fully loaded. # Make sure they are loaded before the global-scripts.inc file. - diff --git a/src/browser/components/places/content/editBookmark-js.patch b/src/browser/components/places/content/editBookmark-js.patch index 100ee182d..92392184f 100644 --- a/src/browser/components/places/content/editBookmark-js.patch +++ b/src/browser/components/places/content/editBookmark-js.patch @@ -1,5 +1,5 @@ diff --git a/browser/components/places/content/editBookmark.js b/browser/components/places/content/editBookmark.js -index f562f19741d882d92365da531b55e2810a0e79ea..9339e1158b074c41fc19bf91cbfde3c4016594b9 100644 +index f562f19741d882d92365da531b55e2810a0e79ea..a68ce8191314845c589f3a9f14b56028e0532628 100644 --- a/browser/components/places/content/editBookmark.js +++ b/browser/components/places/content/editBookmark.js @@ -387,6 +387,10 @@ var gEditItemOverlay = { @@ -31,34 +31,11 @@ index f562f19741d882d92365da531b55e2810a0e79ea..9339e1158b074c41fc19bf91cbfde3c4 } break; } -@@ -1280,6 +1288,148 @@ var gEditItemOverlay = { +@@ -1280,6 +1288,128 @@ var gEditItemOverlay = { get bookmarkState() { return this._bookmarkState; }, + -+ async _initWorkspaceSelector() { -+ if(document.documentElement.getAttribute("windowtype") === "Places:Organizer") { -+ return; -+ } -+ this._workspaces = await ZenWorkspacesStorage.getWorkspaces(); -+ -+ const selectElement = this._workspaceSelect; -+ -+ // Clear any existing options -+ while (selectElement.firstChild) { -+ selectElement.removeChild(selectElement.firstChild); -+ } -+ -+ // For each workspace, create an option element -+ for (let workspace of this._workspaces) { -+ const option = document.createElementNS("http://www.w3.org/1999/xhtml", "option"); -+ option.textContent = workspace.name; -+ option.value = workspace.uuid; -+ selectElement.appendChild(option); -+ } -+ -+ selectElement.disabled = this.readOnly; -+ }, + async onWorkspaceSelectionChange(event) { + if(document.documentElement.getAttribute("windowtype") === "Places:Organizer") { + return; @@ -129,7 +106,10 @@ index f562f19741d882d92365da531b55e2810a0e79ea..9339e1158b074c41fc19bf91cbfde3c4 + if(document.documentElement.getAttribute("windowtype") === "Places:Organizer") { + return; + } -+ this._workspaces = await ZenWorkspacesStorage.getWorkspaces(); ++ const { ZenSessionStore } = ChromeUtils.importESModule( ++ "resource:///modules/zen/ZenSessionManager.sys.mjs" ++ ); ++ this._workspaces = ZenSessionStore.getClonedSpaces(); + const workspaceList = this._workspaceList; + if(aInfo.node?.bookmarkGuid) { + this._selectedWorkspaces = await ZenWorkspaceBookmarksStorage.getBookmarkWorkspaces(aInfo.node.bookmarkGuid); @@ -180,7 +160,7 @@ index f562f19741d882d92365da531b55e2810a0e79ea..9339e1158b074c41fc19bf91cbfde3c4 }; ChromeUtils.defineLazyGetter(gEditItemOverlay, "_folderTree", () => { -@@ -1318,6 +1468,9 @@ for (let elt of [ +@@ -1318,6 +1448,9 @@ for (let elt of [ "locationField", "keywordField", "tagsField", diff --git a/src/browser/components/sessionstore/SessionStore-sys-mjs.patch b/src/browser/components/sessionstore/SessionStore-sys-mjs.patch index bab8fea24..4c660ca25 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 2c2f43bf743ef458b378e85e9ed44a971711e1d9..6894412f5dcf632c1d4c3dabeffabf9e5dd96222 100644 +index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..33f630dea72da70352e131144c87549060ccd78d 100644 --- a/browser/components/sessionstore/SessionStore.sys.mjs +++ b/browser/components/sessionstore/SessionStore.sys.mjs @@ -127,6 +127,8 @@ const TAB_EVENTS = [ @@ -11,7 +11,15 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..6894412f5dcf632c1d4c3dabeffabf9e ]; const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; -@@ -1911,6 +1913,8 @@ var SessionStoreInternal = { +@@ -196,6 +198,7 @@ ChromeUtils.defineESModuleGetters(lazy, { + TabStateCache: "resource:///modules/sessionstore/TabStateCache.sys.mjs", + TabStateFlusher: "resource:///modules/sessionstore/TabStateFlusher.sys.mjs", + setTimeout: "resource://gre/modules/Timer.sys.mjs", ++ ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs", + }); + + ChromeUtils.defineLazyGetter(lazy, "blankURI", () => { +@@ -1911,6 +1914,8 @@ var SessionStoreInternal = { case "TabPinned": case "TabUnpinned": case "SwapDocShells": @@ -20,19 +28,68 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..6894412f5dcf632c1d4c3dabeffabf9e this.saveStateDelayed(win); break; case "TabGroupCreate": -@@ -2384,11 +2388,9 @@ var SessionStoreInternal = { - tabbrowser.selectedTab.label; +@@ -2020,6 +2025,10 @@ var SessionStoreInternal = { + this._windows[aWindow.__SSi].isTaskbarTab = true; + } + ++ if (aWindow.document.documentElement.hasAttribute("zen-unsynced-window")) { ++ this._windows[aWindow.__SSi].isZenUnsynced = true; ++ } ++ + let tabbrowser = aWindow.gBrowser; + + // add tab change listeners to all already existing tabs +@@ -2151,7 +2160,6 @@ var SessionStoreInternal = { + if (closedWindowState) { + let newWindowState; + if ( +- AppConstants.platform == "macosx" || + !lazy.SessionStartup.willRestore() + ) { + // We want to split the window up into pinned tabs and unpinned tabs. +@@ -2215,6 +2223,15 @@ var SessionStoreInternal = { + }); + this._shouldRestoreLastSession = false; + } ++ else if (!aInitialState && isRegularWindow) { ++ let windowPromises = []; ++ for (let window of this._browserWindows) { ++ windowPromises.push(lazy.TabStateFlusher.flushWindow(window)); ++ } ++ Promise.all(windowPromises).finally(() => { ++ lazy.ZenSessionStore.restoreNewWindow(aWindow, this); ++ }); ++ } + + if (this._restoreLastWindow && aWindow.toolbar.visible) { + // always reset (if not a popup window) +@@ -2465,7 +2482,7 @@ var SessionStoreInternal = { + // 2) Flush the window. + // 3) When the flush is complete, revisit our decision to store the window + // in _closedWindows, and add/remove as necessary. +- if (!winData.isPrivate && !winData.isTaskbarTab) { ++ if (!winData.isPrivate && !winData.isTaskbarTab && !winData.isZenUnsynced) { + this.maybeSaveClosedWindow(winData, isLastWindow); } -- if (AppConstants.platform != "macosx") { - // Until we decide otherwise elsewhere, this window is part of a series - // of closing windows to quit. - winData._shouldRestore = true; -- } +@@ -2486,7 +2503,7 @@ var SessionStoreInternal = { - // Store the window's close date to figure out when each individual tab - // was closed. This timestamp should allow re-arranging data based on how -@@ -3373,7 +3375,7 @@ var SessionStoreInternal = { + // Save non-private windows if they have at + // least one saveable tab or are the last window. +- if (!winData.isPrivate && !winData.isTaskbarTab) { ++ if (!winData.isPrivate && !winData.isTaskbarTab && !winData.isZenUnsynced) { + this.maybeSaveClosedWindow(winData, isLastWindow); + + if (!isLastWindow && winData.closedId > -1) { +@@ -2582,6 +2599,7 @@ var SessionStoreInternal = { + let alreadyStored = winIndex != -1; + // If sidebar command is truthy, i.e. sidebar is open, store sidebar settings + let shouldStore = hasSaveableTabs || isLastWindow; ++ lazy.ZenSessionStore.maybeSaveClosedWindow(winData, isLastWindow); + + if (shouldStore && !alreadyStored) { + let index = this._closedWindows.findIndex(win => { +@@ -3373,7 +3391,7 @@ var SessionStoreInternal = { if (!isPrivateWindow && tabState.isPrivate) { return; } @@ -41,12 +98,12 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..6894412f5dcf632c1d4c3dabeffabf9e return; } -@@ -4089,6 +4091,12 @@ var SessionStoreInternal = { +@@ -4089,6 +4107,12 @@ var SessionStoreInternal = { Math.min(tabState.index, tabState.entries.length) ); tabState.pinned = false; + tabState.zenEssential = false; -+ tabState.zenPinnedId = null; ++ tabState.zenSyncId = null; + tabState.zenIsGlance = false; + tabState.zenGlanceId = null; + tabState.zenHasStaticLabel = false; @@ -54,7 +111,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..6894412f5dcf632c1d4c3dabeffabf9e if (inBackground === false) { aWindow.gBrowser.selectedTab = newTab; -@@ -4525,6 +4533,7 @@ var SessionStoreInternal = { +@@ -4525,6 +4549,7 @@ var SessionStoreInternal = { // Append the tab if we're opening into a different window, tabIndex: aSource == aTargetWindow ? pos : Infinity, pinned: state.pinned, @@ -62,7 +119,18 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..6894412f5dcf632c1d4c3dabeffabf9e userContextId: state.userContextId, skipLoad: true, preferredRemoteType, -@@ -5374,7 +5383,7 @@ var SessionStoreInternal = { +@@ -5032,7 +5057,10 @@ var SessionStoreInternal = { + !activePageData || + (activePageData && activePageData.url != "about:blank") + ) { ++ let hadZenStaticFlag = tab.hasAttribute("zen-has-static-icon"); ++ tab.removeAttribute("zen-has-static-icon"); + win.gBrowser.setIcon(tab, tabData.image); ++ if (hadZenStaticFlag) tab.setAttribute("zen-has-static-icon", true); + } + lazy.TabStateCache.update(browser.permanentKey, { + image: null, +@@ -5374,7 +5402,7 @@ var SessionStoreInternal = { for (let i = tabbrowser.pinnedTabCount; i < tabbrowser.tabs.length; i++) { let tab = tabbrowser.tabs[i]; @@ -71,16 +139,16 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..6894412f5dcf632c1d4c3dabeffabf9e removableTabs.push(tab); } } -@@ -5434,7 +5443,7 @@ var SessionStoreInternal = { - } +@@ -5483,7 +5511,7 @@ var SessionStoreInternal = { - let workspaceID = aWindow.getWorkspaceID(); -- if (workspaceID) { -+ if (workspaceID && !(this.isLastRestorableWindow() && AppConstants.platform == "macosx")) { - winData.workspaceID = workspaceID; - } - }, -@@ -5625,11 +5634,12 @@ var SessionStoreInternal = { + // collect the data for all windows + for (ix in this._windows) { +- if (this._windows[ix]._restoring || this._windows[ix].isTaskbarTab) { ++ if (this._windows[ix]._restoring || this._windows[ix].isTaskbarTab && !this._windows[ix].isZenUnsynced) { + // window data is still in _statesToRestore + continue; + } +@@ -5625,11 +5653,12 @@ var SessionStoreInternal = { } let tabbrowser = aWindow.gBrowser; @@ -94,15 +162,17 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..6894412f5dcf632c1d4c3dabeffabf9e // update the internal state data for this window for (let tab of tabs) { if (tab == aWindow.FirefoxViewHandler.tab) { -@@ -5640,6 +5650,7 @@ var SessionStoreInternal = { +@@ -5640,6 +5669,9 @@ var SessionStoreInternal = { tabsData.push(tabData); } + winData.folders = aWindow.gZenFolders?.storeDataForSessionStore() || []; ++ winData.activeZenSpace = aWindow.gZenWorkspaces?.activeWorkspace || null; ++ winData.spaces = aWindow.gZenWorkspaces?.getWorkspaces(); // update tab group state for this window winData.groups = []; for (let tabGroup of aWindow.gBrowser.tabGroups) { -@@ -5652,7 +5663,7 @@ var SessionStoreInternal = { +@@ -5652,7 +5684,7 @@ var SessionStoreInternal = { // a window is closed, point to the first item in the tab strip instead (it will never be the Firefox View tab, // since it's only inserted into the tab strip after it's selected). if (aWindow.FirefoxViewHandler.tab?.selected) { @@ -111,7 +181,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..6894412f5dcf632c1d4c3dabeffabf9e winData.title = tabbrowser.tabs[0].label; } winData.selected = selectedIndex; -@@ -5765,8 +5776,8 @@ var SessionStoreInternal = { +@@ -5765,8 +5797,8 @@ var SessionStoreInternal = { // selectTab represents. let selectTab = 0; if (overwriteTabs) { @@ -122,7 +192,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..6894412f5dcf632c1d4c3dabeffabf9e selectTab = Math.min(selectTab, winData.tabs.length); } -@@ -5788,6 +5799,7 @@ var SessionStoreInternal = { +@@ -5788,6 +5820,7 @@ var SessionStoreInternal = { if (overwriteTabs) { for (let i = tabbrowser.browsers.length - 1; i >= 0; i--) { if (!tabbrowser.tabs[i].selected) { @@ -130,16 +200,17 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..6894412f5dcf632c1d4c3dabeffabf9e tabbrowser.removeTab(tabbrowser.tabs[i]); } } -@@ -5809,6 +5821,8 @@ var SessionStoreInternal = { - winData.tabs, - winData.groups ?? [] +@@ -5821,6 +5854,9 @@ var SessionStoreInternal = { + savedTabGroup => !openTabGroupIdsInWindow.has(savedTabGroup.id) ); -+ aWindow.gZenFolders?.restoreDataFromSessionStore(winData.folders); -+ aWindow.gZenViewSplitter?.restoreDataFromSessionStore(winData.splitViewData); - this._log.debug( - `restoreWindow, createTabsForSessionRestore returned ${tabs.length} tabs` - ); -@@ -6372,6 +6386,25 @@ var SessionStoreInternal = { + } ++ aWindow.gZenFolders?.restoreDataFromSessionStore(winData.folders); ++ aWindow.gZenViewSplitter?.restoreDataFromSessionStore(winData.splitViewData); ++ aWindow.gZenWorkspaces?.restoreWorkspacesFromSessionStore(winData); + + // Move the originally open tabs to the end. + if (initialTabs) { +@@ -6372,6 +6408,28 @@ var SessionStoreInternal = { // Most of tabData has been restored, now continue with restoring // attributes that may trigger external events. @@ -150,11 +221,14 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..6894412f5dcf632c1d4c3dabeffabf9e + if (tabData.zenIsEmpty) { + tab.setAttribute("zen-empty-tab", "true"); + } -+ if (tabData.zenHasStaticLabel) { -+ tab.setAttribute("zen-has-static-label", "true"); ++ if (tabData.zenStaticLabel) { ++ tab.zenStaticLabel = tabData.zenStaticLabel; + } -+ if (tabData.zenPinnedId) { -+ tab.setAttribute("zen-pin-id", tabData.zenPinnedId); ++ if (tabData.zenHasStaticIcon) { ++ tab.setAttribute("zen-has-static-icon", "true"); ++ } ++ if (tabData.zenSyncId) { ++ tab.setAttribute("id", tabData.zenSyncId); + } + if (tabData.zenDefaultUserContextId) { + tab.setAttribute("zenDefaultUserContextId", true); @@ -165,7 +239,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..6894412f5dcf632c1d4c3dabeffabf9e if (tabData.pinned) { tabbrowser.pinTab(tab); -@@ -7290,7 +7323,7 @@ var SessionStoreInternal = { +@@ -7290,7 +7348,7 @@ var SessionStoreInternal = { let groupsToSave = new Map(); for (let tIndex = 0; tIndex < window.tabs.length; ) { @@ -174,7 +248,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..6894412f5dcf632c1d4c3dabeffabf9e // Adjust window.selected if (tIndex + 1 < window.selected) { window.selected -= 1; -@@ -7305,7 +7338,7 @@ var SessionStoreInternal = { +@@ -7305,7 +7363,7 @@ var SessionStoreInternal = { ); // We don't want to increment tIndex here. continue; diff --git a/src/browser/components/sessionstore/TabState-sys-mjs.patch b/src/browser/components/sessionstore/TabState-sys-mjs.patch index 2100e2334..2cbec42e4 100644 --- a/src/browser/components/sessionstore/TabState-sys-mjs.patch +++ b/src/browser/components/sessionstore/TabState-sys-mjs.patch @@ -1,22 +1,25 @@ diff --git a/browser/components/sessionstore/TabState.sys.mjs b/browser/components/sessionstore/TabState.sys.mjs -index 82721356d191055bec0d4b0ca49e481221988801..1ea5c394c704da295149443d7794961a12f2060b 100644 +index 82721356d191055bec0d4b0ca49e481221988801..e0fde4fc475471d170ce46c1207e6e7b67fcaf1d 100644 --- a/browser/components/sessionstore/TabState.sys.mjs +++ b/browser/components/sessionstore/TabState.sys.mjs -@@ -85,7 +85,22 @@ class _TabState { +@@ -85,7 +85,25 @@ class _TabState { tabData.groupId = tab.group.id; } + tabData.zenWorkspace = tab.getAttribute("zen-workspace-id"); -+ tabData.zenPinnedId = tab.getAttribute("zen-pin-id"); ++ tabData.zenSyncId = tab.getAttribute("id"); + tabData.zenEssential = tab.getAttribute("zen-essential"); + tabData.pinned = tabData.pinned || tabData.zenEssential; + tabData.zenDefaultUserContextId = tab.getAttribute("zenDefaultUserContextId"); + tabData.zenPinnedEntry = tab.getAttribute("zen-pinned-entry"); + tabData.zenPinnedIcon = tab.getAttribute("zen-pinned-icon"); + tabData.zenIsEmpty = tab.hasAttribute("zen-empty-tab"); -+ tabData.zenHasStaticLabel = tab.hasAttribute("zen-has-static-label"); ++ tabData.zenStaticLabel = tab.zenStaticLabel; ++ tabData.zenHasStaticIcon = tab.hasAttribute("zen-has-static-icon"); + tabData.zenGlanceId = tab.getAttribute("glance-id"); + tabData.zenIsGlance = tab.hasAttribute("zen-glance-tab"); ++ tabData._zenPinnedInitialState = tab._zenPinnedInitialState; ++ tabData._zenIsActiveTab = tab._zenContentsVisible; + tabData.searchMode = tab.ownerGlobal.gURLBar.getSearchMode(browser, true); + if (tabData.searchMode?.source === tab.ownerGlobal.UrlbarUtils.RESULT_SOURCE.ZEN_ACTIONS) { @@ -25,3 +28,12 @@ index 82721356d191055bec0d4b0ca49e481221988801..1ea5c394c704da295149443d7794961a tabData.userContextId = tab.userContextId || 0; +@@ -98,7 +116,7 @@ class _TabState { + + // Copy data from the tab state cache only if the tab has fully finished + // restoring. We don't want to overwrite data contained in __SS_data. +- this.copyFromCache(browser.permanentKey, tabData, options); ++ this.copyFromCache(tab.permanentKey, tabData, options); + + // After copyFromCache() was called we check for properties that are kept + // in the cache only while the tab is pending or restoring. Once that diff --git a/src/browser/components/tabbrowser/content/tab-js.patch b/src/browser/components/tabbrowser/content/tab-js.patch index 3f27154b7..dd0edd05f 100644 --- a/src/browser/components/tabbrowser/content/tab-js.patch +++ b/src/browser/components/tabbrowser/content/tab-js.patch @@ -1,5 +1,5 @@ diff --git a/browser/components/tabbrowser/content/tab.js b/browser/components/tabbrowser/content/tab.js -index 2dacb325190b6ae42ebeb3e9f0e862dc690ecdca..02d70e9b0261f92917d274759838cfbfd6214f77 100644 +index 2dacb325190b6ae42ebeb3e9f0e862dc690ecdca..23b134a8ba674978182415a8bac926f7600f564a 100644 --- a/browser/components/tabbrowser/content/tab.js +++ b/browser/components/tabbrowser/content/tab.js @@ -21,6 +21,7 @@ @@ -121,15 +121,7 @@ index 2dacb325190b6ae42ebeb3e9f0e862dc690ecdca..02d70e9b0261f92917d274759838cfbf on_click(event) { if (event.button != 0) { return; -@@ -575,6 +599,7 @@ - ) - ); - } else { -+ gZenPinnedTabManager._removePinnedAttributes(this, true); - gBrowser.removeTab(this, { - animate: true, - triggeringEvent: event, -@@ -587,6 +612,14 @@ +@@ -587,6 +611,14 @@ // (see tabbrowser-tabs 'click' handler). gBrowser.tabContainer._blockDblClick = true; } @@ -144,7 +136,7 @@ index 2dacb325190b6ae42ebeb3e9f0e862dc690ecdca..02d70e9b0261f92917d274759838cfbf } on_dblclick(event) { -@@ -610,6 +643,8 @@ +@@ -610,6 +642,8 @@ animate: true, triggeringEvent: event, }); diff --git a/src/browser/components/tabbrowser/content/tabbrowser-js.patch b/src/browser/components/tabbrowser/content/tabbrowser-js.patch index 8a71eaaae..32e12d994 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 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f53bc059b 100644 +index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..a87bcaf4e9b92a9f63e025409efabca90aa52900 100644 --- a/browser/components/tabbrowser/content/tabbrowser.js +++ b/browser/components/tabbrowser/content/tabbrowser.js @@ -386,6 +386,7 @@ @@ -10,7 +10,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f const browsers = []; if (this.#activeSplitView) { for (const tab of this.#activeSplitView.tabs) { -@@ -450,15 +451,64 @@ +@@ -450,15 +451,66 @@ return this.tabContainer.visibleTabs; } @@ -18,6 +18,8 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f + return this.#handleTabMove(...args); + } + ++ get zenTabProgressListener() { return TabProgressListener; } ++ + get _numVisiblePinTabsWithoutCollapsed() { + let i = 0; + for (let item of this.tabContainer.ariaFocusableItems) { @@ -77,7 +79,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f set selectedTab(val) { if ( gSharedTabWarning.willShowSharedTabWarning(val) || -@@ -613,6 +663,7 @@ +@@ -613,6 +665,7 @@ this.tabpanels.appendChild(panel); let tab = this.tabs[0]; @@ -85,7 +87,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f tab.linkedPanel = uniqueId; this._selectedTab = tab; this._selectedBrowser = browser; -@@ -898,13 +949,17 @@ +@@ -898,13 +951,17 @@ } this.showTab(aTab); @@ -104,7 +106,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f aTab.setAttribute("pinned", "true"); this._updateTabBarForPinnedTabs(); -@@ -917,11 +972,15 @@ +@@ -917,11 +974,15 @@ } this.#handleTabMove(aTab, () => { @@ -121,16 +123,19 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f }); aTab.style.marginInlineStart = ""; -@@ -1098,6 +1157,8 @@ +@@ -1098,6 +1159,11 @@ let LOCAL_PROTOCOLS = ["chrome:", "about:", "resource:", "data:"]; + try { -+ gZenPinnedTabManager.onTabIconChanged(aTab, aIconURL); ++ if (aTab.hasAttribute("zen-has-static-icon")) { ++ return; ++ } ++ gZenPinnedTabManager.onTabIconChanged(aTab, aIconURL); if ( aIconURL && !LOCAL_PROTOCOLS.some(protocol => aIconURL.startsWith(protocol)) -@@ -1107,6 +1168,9 @@ +@@ -1107,6 +1173,9 @@ ); return; } @@ -140,7 +145,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f let browser = this.getBrowserForTab(aTab); browser.mIconURL = aIconURL; -@@ -1379,7 +1443,6 @@ +@@ -1379,7 +1448,6 @@ // Preview mode should not reset the owner if (!this._previewMode && !oldTab.selected) { @@ -148,7 +153,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f } let lastRelatedTab = this._lastRelatedTabMap.get(oldTab); -@@ -1470,6 +1533,7 @@ +@@ -1470,6 +1538,7 @@ if (!this._previewMode) { newTab.recordTimeFromUnloadToReload(); newTab.updateLastAccessed(); @@ -156,7 +161,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f oldTab.updateLastAccessed(); // if this is the foreground window, update the last-seen timestamps. if (this.ownerGlobal == BrowserWindowTracker.getTopWindow()) { -@@ -1622,6 +1686,9 @@ +@@ -1622,6 +1691,9 @@ } let activeEl = document.activeElement; @@ -166,17 +171,19 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f // If focus is on the old tab, move it to the new tab. if (activeEl == oldTab) { newTab.focus(); -@@ -1945,7 +2012,8 @@ +@@ -1945,6 +2017,11 @@ } _setTabLabel(aTab, aLabel, { beforeTabOpen, isContentTitle, isURL } = {}) { -- if (!aLabel || aLabel.includes("about:reader?")) { ++ if (!aTab._zenContentsVisible && !aTab._zenChangeLabelFlag && !aTab._labelIsInitialTitle && !gZenWorkspaces.privateWindowOrDisabled) { ++ return false; ++ } ++ aLabel = aTab.zenStaticLabel || aLabel; + gZenPinnedTabManager.onTabLabelChanged(aTab); -+ if (!aLabel || aLabel.includes("about:reader?") || aTab.hasAttribute("zen-has-static-label")) { + if (!aLabel || aLabel.includes("about:reader?")) { return false; } - -@@ -2053,7 +2121,7 @@ +@@ -2053,7 +2130,7 @@ newIndex = this.selectedTab._tPos + 1; } @@ -185,7 +192,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f if (this.isTabGroupLabel(targetTab)) { throw new Error( "Replacing a tab group label with a tab is not supported" -@@ -2328,6 +2396,7 @@ +@@ -2328,6 +2405,7 @@ uriIsAboutBlank, userContextId, skipLoad, @@ -193,7 +200,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f } = {}) { let b = document.createXULElement("browser"); // Use the JSM global to create the permanentKey, so that if the -@@ -2401,8 +2470,7 @@ +@@ -2401,8 +2479,7 @@ // we use a different attribute name for this? b.setAttribute("name", name); } @@ -203,7 +210,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f b.setAttribute("transparent", "true"); } -@@ -2567,7 +2635,7 @@ +@@ -2567,7 +2644,7 @@ let panel = this.getPanel(browser); let uniqueId = this._generateUniquePanelID(); @@ -212,7 +219,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f aTab.linkedPanel = uniqueId; // Inject the into the DOM if necessary. -@@ -2626,8 +2694,8 @@ +@@ -2626,8 +2703,8 @@ // If we transitioned from one browser to two browsers, we need to set // hasSiblings=false on both the existing browser and the new browser. if (this.tabs.length == 2) { @@ -223,7 +230,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f } else { aTab.linkedBrowser.browsingContext.hasSiblings = this.tabs.length > 1; } -@@ -2814,7 +2882,6 @@ +@@ -2814,7 +2891,6 @@ this.selectedTab = this.addTrustedTab(BROWSER_NEW_TAB_URL, { tabIndex: tab._tPos + 1, userContextId: tab.userContextId, @@ -231,16 +238,17 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f focusUrlBar: true, }); resolve(this.selectedBrowser); -@@ -2923,6 +2990,8 @@ +@@ -2923,6 +2999,9 @@ schemelessInput, hasValidUserGestureActivation = false, textDirectiveUserActivation = false, + _forZenEmptyTab, + essential, ++ zenWorkspaceId, } = {} ) { // all callers of addTab that pass a params object need to pass -@@ -2933,10 +3002,17 @@ +@@ -2933,10 +3012,17 @@ ); } @@ -258,7 +266,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f // If we're opening a foreground tab, set the owner by default. ownerTab ??= inBackground ? null : this.selectedTab; -@@ -2944,6 +3020,7 @@ +@@ -2944,6 +3030,7 @@ if (this.selectedTab.owner) { this.selectedTab.owner = null; } @@ -266,14 +274,16 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f // Find the tab that opened this one, if any. This is used for // determining positioning, and inherited attributes such as the -@@ -2996,6 +3073,19 @@ +@@ -2996,6 +3083,21 @@ noInitialLabel, skipBackgroundNotify, }); + if (hasZenDefaultUserContextId) { + t.setAttribute("zenDefaultUserContextId", "true"); + } -+ if (zenForcedWorkspaceId !== undefined) { ++ if (zenWorkspaceId) { ++ t.setAttribute("zen-workspace-id", zenWorkspaceId); ++ } else if (zenForcedWorkspaceId !== undefined) { + t.setAttribute("zen-workspace-id", zenForcedWorkspaceId); + t.setAttribute("change-workspace", "") + } @@ -286,7 +296,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f if (insertTab) { // Insert the tab into the tab container in the correct position. this.#insertTabAtIndex(t, { -@@ -3004,6 +3094,7 @@ +@@ -3004,6 +3106,7 @@ ownerTab, openerTab, pinned, @@ -294,7 +304,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f bulkOrderedOpen, tabGroup: tabGroup ?? openerTab?.group, }); -@@ -3022,6 +3113,7 @@ +@@ -3022,6 +3125,7 @@ openWindowInfo, skipLoad, triggeringRemoteType, @@ -302,7 +312,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f })); if (focusUrlBar) { -@@ -3146,6 +3238,12 @@ +@@ -3146,6 +3250,12 @@ } } @@ -315,7 +325,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f // Additionally send pinned tab events if (pinned) { this.#notifyPinnedStatus(t); -@@ -3349,10 +3447,10 @@ +@@ -3349,10 +3459,10 @@ isAdoptingGroup = false, isUserTriggered = false, telemetryUserCreateSource = "unknown", @@ -327,7 +337,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f } if (!color) { -@@ -3373,9 +3471,14 @@ +@@ -3373,9 +3483,14 @@ label, isAdoptingGroup ); @@ -344,7 +354,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f ); group.addTabs(tabs); -@@ -3496,7 +3599,7 @@ +@@ -3496,7 +3611,7 @@ } this.#handleTabMove(tab, () => @@ -353,7 +363,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f ); } -@@ -3698,6 +3801,7 @@ +@@ -3698,6 +3813,7 @@ openWindowInfo, skipLoad, triggeringRemoteType, @@ -361,7 +371,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f } ) { // If we don't have a preferred remote type (or it is `NOT_REMOTE`), and -@@ -3767,6 +3871,7 @@ +@@ -3767,6 +3883,7 @@ openWindowInfo, name, skipLoad, @@ -369,7 +379,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f }); } -@@ -3955,7 +4060,7 @@ +@@ -3955,7 +4072,7 @@ // Add a new tab if needed. if (!tab) { let createLazyBrowser = @@ -378,7 +388,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f let url = "about:blank"; if (tabData.entries?.length) { -@@ -3992,8 +4097,10 @@ +@@ -3992,8 +4109,10 @@ insertTab: false, skipLoad: true, preferredRemoteType, @@ -390,7 +400,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f if (select) { tabToSelect = tab; } -@@ -4005,7 +4112,8 @@ +@@ -4005,7 +4124,8 @@ this.pinTab(tab); // Then ensure all the tab open/pinning information is sent. this._fireTabOpen(tab, {}); @@ -400,7 +410,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f let { groupId } = tabData; const tabGroup = tabGroupWorkingData.get(groupId); // if a tab refers to a tab group we don't know, skip any group -@@ -4019,7 +4127,10 @@ +@@ -4019,7 +4139,10 @@ tabGroup.stateData.id, tabGroup.stateData.color, tabGroup.stateData.collapsed, @@ -412,7 +422,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f ); tabsFragment.appendChild(tabGroup.node); } -@@ -4064,9 +4175,23 @@ +@@ -4064,9 +4187,23 @@ // to remove the old selected tab. if (tabToSelect) { let leftoverTab = this.selectedTab; @@ -436,7 +446,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f if (tabs.length > 1 || !tabs[0].selected) { this._updateTabsAfterInsert(); -@@ -4257,11 +4382,14 @@ +@@ -4257,11 +4394,14 @@ if (ownerTab) { tab.owner = ownerTab; } @@ -452,7 +462,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f if ( !bulkOrderedOpen && ((openerTab && -@@ -4273,7 +4401,7 @@ +@@ -4273,7 +4413,7 @@ let lastRelatedTab = openerTab && this._lastRelatedTabMap.get(openerTab); let previousTab = lastRelatedTab || openerTab || this.selectedTab; @@ -461,7 +471,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f tabGroup = previousTab.group; } if ( -@@ -4284,7 +4412,7 @@ +@@ -4284,7 +4424,7 @@ ) { elementIndex = Infinity; } else if (previousTab.visible) { @@ -470,7 +480,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f } else if (previousTab == FirefoxViewHandler.tab) { elementIndex = 0; } -@@ -4312,14 +4440,14 @@ +@@ -4312,14 +4452,14 @@ } // Ensure index is within bounds. if (tab.pinned) { @@ -489,7 +499,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f if (pinned && !itemAfter?.pinned) { itemAfter = null; -@@ -4330,7 +4458,7 @@ +@@ -4330,7 +4470,7 @@ this.tabContainer._invalidateCachedTabs(); @@ -498,7 +508,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f if (this.isTab(itemAfter) && itemAfter.group == tabGroup) { // Place at the front of, or between tabs in, the same tab group this.tabContainer.insertBefore(tab, itemAfter); -@@ -4358,7 +4486,11 @@ +@@ -4358,7 +4498,11 @@ const tabContainer = pinned ? this.tabContainer.pinnedTabsContainer : this.tabContainer; @@ -510,7 +520,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f } this._updateTabsAfterInsert(); -@@ -4366,6 +4498,7 @@ +@@ -4366,6 +4510,7 @@ if (pinned) { this._updateTabBarForPinnedTabs(); } @@ -518,17 +528,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f TabBarVisibility.update(); } -@@ -4655,6 +4788,9 @@ - return; - } - -+ for (let tab of selectedTabs) { -+ gZenPinnedTabManager._removePinnedAttributes(tab, true); -+ } - this.removeTabs(selectedTabs, { isUserTriggered, telemetrySource }); - } - -@@ -4916,6 +5052,7 @@ +@@ -4916,6 +5061,7 @@ telemetrySource, } = {} ) { @@ -536,7 +536,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f // When 'closeWindowWithLastTab' pref is enabled, closing all tabs // can be considered equivalent to closing the window. if ( -@@ -5005,6 +5142,7 @@ +@@ -5005,6 +5151,7 @@ if (lastToClose) { this.removeTab(lastToClose, aParams); } @@ -544,7 +544,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f } catch (e) { console.error(e); } -@@ -5043,6 +5181,12 @@ +@@ -5043,6 +5190,12 @@ aTab._closeTimeNoAnimTimerId = Glean.browserTabclose.timeNoAnim.start(); } @@ -557,7 +557,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f // Handle requests for synchronously removing an already // asynchronously closing tab. if (!animate && aTab.closing) { -@@ -5057,6 +5201,9 @@ +@@ -5057,6 +5210,9 @@ // state). let tabWidth = window.windowUtils.getBoundsWithoutFlushing(aTab).width; let isLastTab = this.#isLastTabInWindow(aTab); @@ -567,7 +567,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f if ( !this._beginRemoveTab(aTab, { closeWindowFastpath: true, -@@ -5105,7 +5252,13 @@ +@@ -5105,7 +5261,13 @@ // We're not animating, so we can cancel the animation stopwatch. Glean.browserTabclose.timeAnim.cancel(aTab._closeTimeAnimTimerId); aTab._closeTimeAnimTimerId = null; @@ -582,7 +582,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f return; } -@@ -5239,7 +5392,7 @@ +@@ -5239,7 +5401,7 @@ closeWindowWithLastTab != null ? closeWindowWithLastTab : !window.toolbar.visible || @@ -591,7 +591,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f if (closeWindow) { // We've already called beforeunload on all the relevant tabs if we get here, -@@ -5263,6 +5416,7 @@ +@@ -5263,6 +5425,7 @@ newTab = true; } @@ -599,7 +599,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f aTab._endRemoveArgs = [closeWindow, newTab]; // swapBrowsersAndCloseOther will take care of closing the window without animation. -@@ -5303,13 +5457,7 @@ +@@ -5303,13 +5466,7 @@ aTab._mouseleave(); if (newTab) { @@ -614,7 +614,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f } else { TabBarVisibility.update(); } -@@ -5442,6 +5590,7 @@ +@@ -5442,6 +5599,7 @@ this.tabs[i]._tPos = i; } @@ -622,7 +622,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f if (!this._windowIsClosing) { // update tab close buttons state this.tabContainer._updateCloseButtons(); -@@ -5663,6 +5812,7 @@ +@@ -5663,6 +5821,7 @@ } let excludeTabs = new Set(aExcludeTabs); @@ -630,7 +630,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f // If this tab has a successor, it should be selectable, since // hiding or closing a tab removes that tab as a successor. -@@ -5675,13 +5825,13 @@ +@@ -5675,13 +5834,13 @@ !excludeTabs.has(aTab.owner) && Services.prefs.getBoolPref("browser.tabs.selectOwnerOnClose") ) { @@ -646,7 +646,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f ); let tab = this.tabContainer.findNextTab(aTab, { -@@ -5697,7 +5847,7 @@ +@@ -5697,7 +5856,7 @@ } if (tab) { @@ -655,7 +655,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f } // If no qualifying visible tab was found, see if there is a tab in -@@ -5718,7 +5868,7 @@ +@@ -5718,7 +5877,7 @@ }); } @@ -664,7 +664,47 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f } _blurTab(aTab) { -@@ -6124,10 +6274,10 @@ +@@ -5729,7 +5888,7 @@ + * @returns {boolean} + * False if swapping isn't permitted, true otherwise. + */ +- swapBrowsersAndCloseOther(aOurTab, aOtherTab) { ++ swapBrowsersAndCloseOther(aOurTab, aOtherTab, zenCloseOther = true) { + // Do not allow transfering a private tab to a non-private window + // and vice versa. + if ( +@@ -5783,6 +5942,7 @@ + // fire the beforeunload event in the process. Close the other + // window if this was its last tab. + if ( ++ zenCloseOther && + !remoteBrowser._beginRemoveTab(aOtherTab, { + adoptedByTab: aOurTab, + closeWindowWithLastTab: true, +@@ -5794,7 +5954,7 @@ + // If this is the last tab of the window, hide the window + // immediately without animation before the docshell swap, to avoid + // about:blank being painted. +- let [closeWindow] = aOtherTab._endRemoveArgs; ++ let [closeWindow] = !zenCloseOther ? [false] : aOtherTab._endRemoveArgs; + if (closeWindow) { + let win = aOtherTab.ownerGlobal; + win.windowUtils.suppressAnimation(true); +@@ -5918,11 +6078,13 @@ + } + + // Finish tearing down the tab that's going away. ++ if (zenCloseOther) { + if (closeWindow) { + aOtherTab.ownerGlobal.close(); + } else { + remoteBrowser._endRemoveTab(aOtherTab); + } ++ } + + this.setTabTitle(aOurTab); + +@@ -6124,10 +6286,10 @@ SessionStore.deleteCustomTabValue(aTab, "hiddenBy"); } @@ -677,15 +717,33 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f aTab.selected || aTab.closing || // Tabs that are sharing the screen, microphone or camera cannot be hidden. -@@ -6186,6 +6336,7 @@ +@@ -6185,7 +6347,8 @@ + * * @param {MozTabbrowserTab|MozTabbrowserTabGroup|MozTabbrowserTabGroup.labelElement} aTab */ - replaceTabWithWindow(aTab, aOptions) { +- replaceTabWithWindow(aTab, aOptions) { ++ replaceTabWithWindow(aTab, aOptions, zenForceSync = false) { + if (!this.isTab(aTab)) return; // TODO: Handle tab groups if (this.tabs.length == 1) { return null; } -@@ -6319,7 +6470,7 @@ +@@ -6209,12 +6372,14 @@ + } + + // tell a new window to take the "dropped" tab +- return window.openDialog( ++ let win = window.openDialog( + AppConstants.BROWSER_CHROME_URL, + "_blank", + options, + aTab + ); ++ win._zenStartupSyncFlag = zenForceSync ? 'synced' : 'unsynced'; ++ return win; + } + + /** +@@ -6319,7 +6484,7 @@ * `true` if element is a `` */ isTabGroup(element) { @@ -694,7 +752,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f } /** -@@ -6404,8 +6555,8 @@ +@@ -6404,8 +6569,8 @@ } // Don't allow mixing pinned and unpinned tabs. @@ -705,7 +763,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f } else { tabIndex = Math.max(tabIndex, this.pinnedTabCount); } -@@ -6431,10 +6582,16 @@ +@@ -6431,10 +6596,16 @@ this.#handleTabMove( element, () => { @@ -724,7 +782,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f if (neighbor && this.isTab(element) && tabIndex > element._tPos) { neighbor.after(element); } else { -@@ -6492,23 +6649,28 @@ +@@ -6492,23 +6663,28 @@ #moveTabNextTo(element, targetElement, moveBefore = false, metricsContext) { if (this.isTabGroupLabel(targetElement)) { targetElement = targetElement.group; @@ -759,7 +817,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f } else if (!element.pinned && targetElement && targetElement.pinned) { // If the caller asks to move an unpinned element next to a pinned // tab, move the unpinned element to be the first unpinned element -@@ -6521,14 +6683,34 @@ +@@ -6521,14 +6697,34 @@ // move the tab group right before the first unpinned tab. // 4. Moving a tab group and the first unpinned tab is grouped: // move the tab group right before the first unpinned tab's tab group. @@ -795,7 +853,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f element.pinned ? this.tabContainer.pinnedTabsContainer : this.tabContainer; -@@ -6537,7 +6719,7 @@ +@@ -6537,7 +6733,7 @@ element, () => { if (moveBefore) { @@ -804,7 +862,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f } else if (targetElement) { targetElement.after(element); } else { -@@ -6607,10 +6789,10 @@ +@@ -6607,10 +6803,10 @@ * @param {TabMetricsContext} [metricsContext] */ moveTabToGroup(aTab, aGroup, metricsContext) { @@ -817,7 +875,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f return; } if (aTab.group && aTab.group.id === aGroup.id) { -@@ -6656,6 +6838,7 @@ +@@ -6656,6 +6852,7 @@ let state = { tabIndex: tab._tPos, @@ -825,7 +883,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f }; if (tab.visible) { state.elementIndex = tab.elementIndex; -@@ -6682,7 +6865,7 @@ +@@ -6682,7 +6879,7 @@ let changedTabGroup = previousTabState.tabGroupId != currentTabState.tabGroupId; @@ -834,7 +892,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f tab.dispatchEvent( new CustomEvent("TabMove", { bubbles: true, -@@ -6723,6 +6906,10 @@ +@@ -6723,6 +6920,10 @@ moveActionCallback(); @@ -845,7 +903,16 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f // Clear tabs cache after moving nodes because the order of tabs may have // changed. this.tabContainer._invalidateCachedTabs(); -@@ -7623,7 +7810,7 @@ +@@ -6815,6 +7016,8 @@ + params.userContextId = aTab.getAttribute("usercontextid"); + } + let newTab = this.addWebTab("about:blank", params); ++ newTab._zenContentsVisible = true; ++ newTab.zenStaticLabel = aTab.zenStaticLabel; + let newBrowser = this.getBrowserForTab(newTab); + + aTab.container.tabDragAndDrop.finishAnimateTabMove(); +@@ -7623,7 +7826,7 @@ // preventDefault(). It will still raise the window if appropriate. break; } @@ -854,7 +921,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f window.focus(); aEvent.preventDefault(); break; -@@ -7640,7 +7827,6 @@ +@@ -7640,7 +7843,6 @@ } case "TabGroupCollapse": aEvent.target.tabs.forEach(tab => { @@ -862,7 +929,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f }); break; case "TabGroupCreateByUser": -@@ -8589,6 +8775,7 @@ +@@ -8589,6 +8791,7 @@ aWebProgress.isTopLevel ) { this.mTab.setAttribute("busy", "true"); @@ -870,7 +937,15 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f gBrowser._tabAttrModified(this.mTab, ["busy"]); this.mTab._notselectedsinceload = !this.mTab.selected; } -@@ -9623,7 +9810,7 @@ var TabContextMenu = { +@@ -8670,6 +8873,7 @@ + // known defaults. Note we use the original URL since about:newtab + // redirects to a prerendered page. + const shouldRemoveFavicon = ++ !this.mTab.hasAttribute("zen-has-static-icon") && + !this.mBrowser.mIconURL && + !ignoreBlank && + !(originalLocation.spec in FAVICON_DEFAULTS); +@@ -9623,7 +9827,7 @@ var TabContextMenu = { ); contextUnpinSelectedTabs.hidden = !this.contextTab.pinned || !this.multiselected; @@ -879,11 +954,3 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..6aa725c0e5a6a29dc33fcb162f83522f // Build Ask Chat items TabContextMenu.GenAI.buildTabMenu( document.getElementById("context_askChat"), -@@ -9943,6 +10130,7 @@ var TabContextMenu = { - ) - ); - } else { -+ gZenPinnedTabManager._removePinnedAttributes(this.contextTab, true); - gBrowser.removeTab(this.contextTab, { - animate: true, - ...gBrowser.TabMetrics.userTriggeredContext( diff --git a/src/browser/components/urlbar/UrlbarProviderPlaces-sys-mjs.patch b/src/browser/components/urlbar/UrlbarProviderPlaces-sys-mjs.patch deleted file mode 100644 index 31608dbe0..000000000 --- a/src/browser/components/urlbar/UrlbarProviderPlaces-sys-mjs.patch +++ /dev/null @@ -1,44 +0,0 @@ -diff --git a/browser/components/urlbar/UrlbarProviderPlaces.sys.mjs b/browser/components/urlbar/UrlbarProviderPlaces.sys.mjs -index 4db61038e5e476bad3a61dbdb707e5222c1f08f8..9eca13d9cfac3b762917aaaa942267effb743cf7 100644 ---- a/browser/components/urlbar/UrlbarProviderPlaces.sys.mjs -+++ b/browser/components/urlbar/UrlbarProviderPlaces.sys.mjs -@@ -45,11 +45,13 @@ function defaultQuery(conditions = "") { - let query = ` - SELECT h.url, h.title, ${SQL_BOOKMARK_TAGS_FRAGMENT}, h.id, t.open_count, - ${lazy.PAGES_FRECENCY_FIELD} AS frecency, t.userContextId, -- h.last_visit_date, NULLIF(t.groupId, '') groupId -+ h.last_visit_date, NULLIF(t.groupId, '') groupId, zp.url AS pinned_url, zp.title AS pinned_title - FROM moz_places h - LEFT JOIN moz_openpages_temp t - ON t.url = h.url - AND (t.userContextId = :userContextId OR (t.userContextId <> -1 AND :userContextId IS NULL)) -+ LEFT JOIN zen_pins zp -+ ON zp.url = h.url - WHERE ( - (:switchTabsEnabled AND t.open_count > 0) OR - ${lazy.PAGES_FRECENCY_FIELD} <> 0 -@@ -63,7 +65,7 @@ function defaultQuery(conditions = "") { - :matchBehavior, :searchBehavior, NULL) - ELSE - AUTOCOMPLETE_MATCH(:searchString, h.url, -- h.title, '', -+ IFNULL(zp.title, h.title), '', - h.visit_count, h.typed, - 0, t.open_count, - :matchBehavior, :searchBehavior, NULL) -@@ -1176,11 +1178,13 @@ class Search { - ? lazy.PlacesUtils.toDate(lastVisitPRTime).getTime() - : undefined; - let tabGroup = row.getResultByName("groupId"); -+ let pinnedTitle = row.getResultByIndex(12); -+ let pinnedUrl = row.getResultByIndex("pinned_url"); - - let match = { - placeId, -- value: url, -- comment: bookmarkTitle || historyTitle, -+ value: pinnedUrl || url, -+ comment: pinnedTitle || bookmarkTitle || historyTitle, - icon: UrlbarUtils.getIconForUrl(url), - frecency: frecency || FRECENCY_DEFAULT, - userContextId, diff --git a/src/browser/themes/shared/tabbrowser/tabs-css.patch b/src/browser/themes/shared/tabbrowser/tabs-css.patch index cd32f20e4..e563c3ff5 100644 --- a/src/browser/themes/shared/tabbrowser/tabs-css.patch +++ b/src/browser/themes/shared/tabbrowser/tabs-css.patch @@ -1,5 +1,5 @@ diff --git a/browser/themes/shared/tabbrowser/tabs.css b/browser/themes/shared/tabbrowser/tabs.css -index 8a4d3860b344e2dc2128cfc2b1673de582e19c7c..f8e108d2c1c71070375fdae12df432311b0081e1 100644 +index 8a4d3860b344e2dc2128cfc2b1673de582e19c7c..086171783cd9a8629ccf4b2e90813e58c4793878 100644 --- a/browser/themes/shared/tabbrowser/tabs.css +++ b/browser/themes/shared/tabbrowser/tabs.css @@ -21,7 +21,7 @@ @@ -39,12 +39,7 @@ index 8a4d3860b344e2dc2128cfc2b1673de582e19c7c..f8e108d2c1c71070375fdae12df43231 &::before { position: absolute; -@@ -498,14 +498,11 @@ - .tab-icon-image { - -moz-context-properties: fill, stroke; - fill: currentColor; -+ border-radius: 4px; - +@@ -502,10 +502,6 @@ /* stylelint-disable-next-line media-query-no-invalid */ @media -moz-pref("browser.tabs.fadeOutUnloadedTabs") { &[pending] { @@ -55,7 +50,7 @@ index 8a4d3860b344e2dc2128cfc2b1673de582e19c7c..f8e108d2c1c71070375fdae12df43231 opacity: 0.5; /* Fade the favicon out */ transition-property: filter, opacity; -@@ -522,10 +519,6 @@ +@@ -522,10 +518,6 @@ /* stylelint-disable-next-line media-query-no-invalid */ @media -moz-pref("browser.tabs.fadeOutExplicitlyUnloadedTabs") { &[pending][discarded] { @@ -66,7 +61,7 @@ index 8a4d3860b344e2dc2128cfc2b1673de582e19c7c..f8e108d2c1c71070375fdae12df43231 opacity: 0.5; /* Fade the favicon out */ transition-property: filter, opacity; -@@ -593,7 +586,7 @@ +@@ -593,7 +585,7 @@ z-index: 1; /* Overlay tab title */ #tabbrowser-tabs[orient="vertical"] & { @@ -75,7 +70,7 @@ index 8a4d3860b344e2dc2128cfc2b1673de582e19c7c..f8e108d2c1c71070375fdae12df43231 } &[crashed] { -@@ -601,7 +594,7 @@ +@@ -601,7 +593,7 @@ } #tabbrowser-tabs[orient="vertical"]:not([expanded]) &:not([crashed]), @@ -84,7 +79,7 @@ index 8a4d3860b344e2dc2128cfc2b1673de582e19c7c..f8e108d2c1c71070375fdae12df43231 &[soundplaying] { list-style-image: url("chrome://browser/skin/tabbrowser/tab-audio-playing-small.svg"); } -@@ -658,7 +651,7 @@ +@@ -658,7 +650,7 @@ } } @@ -93,7 +88,7 @@ index 8a4d3860b344e2dc2128cfc2b1673de582e19c7c..f8e108d2c1c71070375fdae12df43231 &[crashed] { display: revert; } -@@ -759,7 +752,7 @@ +@@ -759,7 +751,7 @@ has not been added to root. There are certain scenarios when that attribute is temporarily removed from root such as when toggling the sidebar to expand with the toolbar button. */ #tabbrowser-tabs[orient="horizontal"] &:not([pinned]):not([crashed]), @@ -102,7 +97,7 @@ index 8a4d3860b344e2dc2128cfc2b1673de582e19c7c..f8e108d2c1c71070375fdae12df43231 &:is([soundplaying], [muted], [activemedia-blocked]) { display: flex; } -@@ -1446,7 +1439,7 @@ tab-group { +@@ -1446,7 +1438,7 @@ tab-group { } #tabbrowser-tabs[orient="vertical"][expanded] { @@ -111,16 +106,16 @@ index 8a4d3860b344e2dc2128cfc2b1673de582e19c7c..f8e108d2c1c71070375fdae12df43231 &[movingtab][movingtab-addToGroup]:not([movingtab-group], [movingtab-ungroup]) .tabbrowser-tab:is(:active, [multiselected]) { margin-inline-start: var(--space-medium); } -@@ -1893,7 +1886,7 @@ tab-group { +@@ -1893,7 +1885,7 @@ tab-group { } } -#tabbrowser-arrowscrollbox[orient="vertical"] > #tabbrowser-arrowscrollbox-periphery > #tabs-newtab-button, -+#tabbrowser-arrowscrollbox[orient="vertical"] #tabbrowser-arrowscrollbox-periphery > #tabs-newtab-button, ++#tabs-newtab-button, #vertical-tabs-newtab-button { appearance: none; min-height: var(--tab-min-height); -@@ -1904,7 +1897,7 @@ tab-group { +@@ -1904,7 +1896,7 @@ tab-group { margin-inline: var(--tab-inner-inline-margin); #tabbrowser-tabs[orient="vertical"]:not([expanded]) & > .toolbarbutton-text { @@ -129,7 +124,7 @@ index 8a4d3860b344e2dc2128cfc2b1673de582e19c7c..f8e108d2c1c71070375fdae12df43231 } &:hover { -@@ -1928,7 +1921,7 @@ tab-group { +@@ -1928,7 +1920,7 @@ tab-group { * flex container. #tabs-newtab-button is a child of the arrowscrollbox where * we don't want a gap (between tabs), so we have to add some margin. */ @@ -138,7 +133,7 @@ index 8a4d3860b344e2dc2128cfc2b1673de582e19c7c..f8e108d2c1c71070375fdae12df43231 margin-block: var(--tab-block-margin); } -@@ -2116,7 +2109,6 @@ tab-group { +@@ -2116,7 +2108,6 @@ tab-group { &:not([expanded]) { .tabbrowser-tab[pinned] { @@ -146,7 +141,7 @@ index 8a4d3860b344e2dc2128cfc2b1673de582e19c7c..f8e108d2c1c71070375fdae12df43231 } .tab-background { -@@ -2156,8 +2148,8 @@ tab-group { +@@ -2156,8 +2147,8 @@ tab-group { display: block; position: absolute; inset: auto; @@ -157,7 +152,7 @@ index 8a4d3860b344e2dc2128cfc2b1673de582e19c7c..f8e108d2c1c71070375fdae12df43231 &:-moz-window-inactive { background-image: -@@ -2276,7 +2268,6 @@ toolbar:not(#TabsToolbar) #firefox-view-button { +@@ -2276,7 +2267,6 @@ toolbar:not(#TabsToolbar) #firefox-view-button { list-style-image: url(chrome://global/skin/icons/plus.svg); } diff --git a/src/browser/themes/shared/toolbarbuttons-css.patch b/src/browser/themes/shared/toolbarbuttons-css.patch index f4dd140a8..10327ca10 100644 --- a/src/browser/themes/shared/toolbarbuttons-css.patch +++ b/src/browser/themes/shared/toolbarbuttons-css.patch @@ -1,8 +1,39 @@ diff --git a/browser/themes/shared/toolbarbuttons.css b/browser/themes/shared/toolbarbuttons.css -index e2b8a7cae70ed2bd3c80ee4214a09dbdb68a0d01..71320c7268d92aaa06bfa15c74bdbf02f1442745 100644 +index e2b8a7cae70ed2bd3c80ee4214a09dbdb68a0d01..e320faa158125d73876126f9be8847d395e465e3 100644 --- a/browser/themes/shared/toolbarbuttons.css +++ b/browser/themes/shared/toolbarbuttons.css -@@ -279,7 +279,7 @@ toolbar .toolbaritem-combined-buttons { +@@ -44,20 +44,6 @@ + --toolbarbutton-inner-padding: 9px; + --bookmark-block-padding: 7px; + } +- @media (width <= 900px) { +- --toolbarbutton-outer-padding: 1px; +- } +- @media (width <= 800px) { +- --toolbarbutton-inner-padding: 7px; +- &:where([uidensity="touch"]) { +- --toolbarbutton-inner-padding: 8px; +- } +- } +- /* 700px is just above half of the popular 1366px screen width, so two browser +- windows put next to each other will be below this threshold. */ +- @media (width <= 700px) { +- --toolbarbutton-inner-padding: 6px; +- } + &:where([uidensity="compact"]) { + --toolbarbutton-inner-padding: 6px; + --bookmark-block-padding: 1px; +@@ -67,9 +53,7 @@ + #TabsToolbar { + /* Override the inner padding to ensure the dimensions match the tabs, but also making sure + different types of buttons (combined-buttons-dropmarker or text) still look correct. */ +- @media (width > 900px) { + --toolbarbutton-inner-padding: calc((var(--tab-min-height) - 16px) / 2); +- } + } + + /* Primary toolbar buttons */ +@@ -279,7 +263,7 @@ toolbar .toolbaritem-combined-buttons { #nav-bar-overflow-button { list-style-image: url("chrome://global/skin/icons/chevron.svg"); @@ -11,7 +42,7 @@ index e2b8a7cae70ed2bd3c80ee4214a09dbdb68a0d01..71320c7268d92aaa06bfa15c74bdbf02 display: none; } -@@ -489,7 +489,7 @@ toolbarbutton.bookmark-item:not(.subviewbutton) { +@@ -489,7 +473,7 @@ toolbarbutton.bookmark-item:not(.subviewbutton) { */ align-items: stretch; > .toolbarbutton-icon { diff --git a/src/zen/ZenComponents.manifest b/src/zen/ZenComponents.manifest index 74c0232b8..0f38828a1 100644 --- a/src/zen/ZenComponents.manifest +++ b/src/zen/ZenComponents.manifest @@ -13,3 +13,4 @@ category app-startup nsBrowserGlue @mozilla.org/browser/browserglue;1 application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} #include common/Components.manifest +#include sessionstore/SessionComponents.manifest diff --git a/src/zen/common/emojis/ZenEmojiPicker.mjs b/src/zen/common/emojis/ZenEmojiPicker.mjs index 0f36a7caf..e20001d25 100644 --- a/src/zen/common/emojis/ZenEmojiPicker.mjs +++ b/src/zen/common/emojis/ZenEmojiPicker.mjs @@ -34,6 +34,7 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature { #panel; #anchor; + #emojiAsSVG = false; #currentPromise = null; #currentPromiseResolve = null; @@ -199,14 +200,22 @@ class nsZenEmojiPicker extends nsZenDOMOperatedFeature { } #selectEmoji(emoji) { + if (this.#emojiAsSVG && emoji && !emoji.startsWith('chrome://')) { + emoji = `data:image/svg+xml;base64,${btoa( + `${unescape( + encodeURIComponent(emoji) + )}` + )}`; + } this.#currentPromiseResolve?.(emoji); this.#panel.hidePopup(); } - open(anchor, { onlySvgIcons = false } = {}) { + open(anchor, { onlySvgIcons = false, emojiAsSVG = false } = {}) { if (this.#currentPromise) { return null; } + this.#emojiAsSVG = emojiAsSVG; this.#currentPromise = new Promise((resolve, reject) => { this.#currentPromiseResolve = resolve; this.#currentPromiseReject = reject; diff --git a/src/zen/common/modules/ZenSessionStore.mjs b/src/zen/common/modules/ZenSessionStore.mjs index 95b2aac20..dd53dbb83 100644 --- a/src/zen/common/modules/ZenSessionStore.mjs +++ b/src/zen/common/modules/ZenSessionStore.mjs @@ -21,8 +21,11 @@ class ZenSessionStore extends nsZenPreloadedFeature { if (tabData.zenSyncId || tabData.zenPinnedId) { tab.setAttribute('id', tabData.zenSyncId || tabData.zenPinnedId); } - if (tabData.zenHasStaticLabel) { - tab.setAttribute('zen-has-static-label', 'true'); + if (tabData.zenStaticLabel) { + tab.zenStaticLabel = tabData.zenStaticLabel; + } + if (tabData.zenHasStaticIcon) { + tab.setAttribute('zen-has-static-icon', 'true'); } if (tabData.zenEssential) { tab.setAttribute('zen-essential', 'true'); diff --git a/src/zen/common/modules/ZenUIManager.mjs b/src/zen/common/modules/ZenUIManager.mjs index 21c95a807..ae63ace1e 100644 --- a/src/zen/common/modules/ZenUIManager.mjs +++ b/src/zen/common/modules/ZenUIManager.mjs @@ -125,6 +125,8 @@ window.gZenUIManager = { } menu.setAttribute('hidden', 'true'); } + // The first separator in the tab context menu is now useless. + document.getElementById('tabContextMenu').querySelector('menuseparator').remove(); }, _initCreateNewPopup() { @@ -1294,6 +1296,7 @@ window.gZenVerticalTabsManager = { : this._tabEdited; let input = document.getElementById('tab-label-input'); let newName = input.value.replace(/\s+/g, ' ').trim(); + const hasChanged = input.value !== input._originalValue && newName; document.documentElement.removeAttribute('zen-renaming-tab'); input.remove(); @@ -1303,12 +1306,12 @@ window.gZenVerticalTabsManager = { // Check if name is blank, reset if so // Always remove, so we can always rename and if it's empty, // it will reset to the original name anyway - this._tabEdited.removeAttribute('zen-has-static-label'); - if (newName) { + if (hasChanged) { + this._tabEdited.zenStaticLabel = newName; gBrowser._setTabLabel(this._tabEdited, newName); - this._tabEdited.setAttribute('zen-has-static-label', 'true'); gZenUIManager.showToast('zen-tabs-renamed'); } else { + delete this._tabEdited.zenStaticLabel; gBrowser.setTabTitle(this._tabEdited); } @@ -1337,7 +1340,8 @@ window.gZenVerticalTabsManager = { }, renameTabStart(event) { - const isTab = !!event.target.closest('.tabbrowser-tab'); + let target = TabContextMenu.contextTab || event.target; + const isTab = !!target.closest('.tabbrowser-tab'); if ( this._tabEdited || ((!Services.prefs.getBoolPref('zen.tabs.rename-tabs') || @@ -1347,13 +1351,10 @@ window.gZenVerticalTabsManager = { ) return; this._tabEdited = - event.target.closest('.tabbrowser-tab') || - event.target.closest('.zen-current-workspace-indicator-name') || - (event.explicit && event.target.closest('.tab-group-label')); - if ( - !this._tabEdited || - ((!this._tabEdited.pinned || this._tabEdited.hasAttribute('zen-essential')) && isTab) - ) { + target.closest('.tabbrowser-tab') || + target.closest('.zen-current-workspace-indicator-name') || + (event.explicit && target.closest('.tab-group-label')); + if (!this._tabEdited || (this._tabEdited.hasAttribute('zen-essential') && isTab)) { this._tabEdited = null; return; } @@ -1370,8 +1371,10 @@ window.gZenVerticalTabsManager = { label.after(container); } const input = document.createElement('input'); + const content = isTab ? this._tabEdited.label : this._tabEdited.textContent; input.id = 'tab-label-input'; - input.value = isTab ? this._tabEdited.label : this._tabEdited.textContent; + input._originalValue = content; + input.value = content; input.addEventListener('keydown', this.renameTabKeydown.bind(this)); if (isTab) { diff --git a/src/zen/folders/ZenFolders.mjs b/src/zen/folders/ZenFolders.mjs index b25d1da78..d7ef4fb77 100644 --- a/src/zen/folders/ZenFolders.mjs +++ b/src/zen/folders/ZenFolders.mjs @@ -187,7 +187,6 @@ class nsZenFolders extends nsZenDOMOperatedFeature { window.addEventListener('TabSelect', this); window.addEventListener('TabOpen', this); const onNewFolder = this.#onNewFolder.bind(this); - document.getElementById('zen-context-menu-new-folder').addEventListener('command', onNewFolder); document .getElementById('zen-context-menu-new-folder-toolbar') .addEventListener('command', onNewFolder); @@ -543,9 +542,7 @@ class nsZenFolders extends nsZenDOMOperatedFeature { // that we want it to initially be collapsed. setTimeout( (folder) => { - gZenPinnedTabManager.promiseInitializedPinned.then(() => { - folder.collapsed = !!options.collapsed; - }); + folder.collapsed = !!options.collapsed; }, 0, folder diff --git a/src/zen/sessionstore/ZenWindowSync.sys.mjs b/src/zen/sessionstore/ZenWindowSync.sys.mjs index e0b0b79d9..c62bf2766 100644 --- a/src/zen/sessionstore/ZenWindowSync.sys.mjs +++ b/src/zen/sessionstore/ZenWindowSync.sys.mjs @@ -109,6 +109,9 @@ class nsZenWindowSync { for (let topic of OBSERVING) { Services.obs.addObserver(this, topic); } + lazy.SessionStore.promiseAllWindowsRestored.then(() => { + this.#onSessionStoreInitialized(); + }); } uninit() { @@ -135,7 +138,9 @@ class nsZenWindowSync { // 1. We are passing `zen-unsynced` in the window arguments. // 2. We are trying to open a link in a new window where other synced // windows already exist - let forcedSync = false; + // Note, we force syncing if the window is private or workspaces is disabled + // to avoid confusing the old private window behavior. + let forcedSync = !aWindow.gZenWorkspaces?.privateWindowOrDisabled; let hasUnsyncedArg = false; if (aWindow._zenStartupSyncFlag === 'synced') { forcedSync = true; @@ -160,6 +165,27 @@ class nsZenWindowSync { } } + /** + * Called when the session store has finished initializing for a window. + * + * @param {Window} aWindow - The browser window that has initialized session store. + */ + #onSessionStoreInitialized() { + // For every tab we have in where there's no sync ID, we need to + // assign one and sync it to other windows. + // This should only happen really when updating from an older version + // that didn't have this feature. + this.#runOnAllWindows(null, (aWindow) => { + const { gBrowser } = aWindow; + for (let tab of gBrowser.tabs) { + if (!tab.id) { + tab.id = this.#newTabSyncId; + lazy.TabStateFlusher.flush(tab.linkedBrowser); + } + } + }); + } + /** * @returns {string} A unique tab ID. */ @@ -277,6 +303,9 @@ class nsZenWindowSync { * @returns {MozTabbrowserTab|MozTabbrowserTabGroup|null} The item element if found, otherwise null. */ #getItemFromWindow(aWindow, aItemId) { + if (!aItemId) { + return null; + } return aWindow.document.getElementById(aItemId); } @@ -308,19 +337,24 @@ class nsZenWindowSync { } const { gBrowser, gZenFolders } = aWindow; if (flags & SYNC_FLAG_ICON) { + aTargetItem.removeAttribute('zen-has-static-icon'); if (gBrowser.isTab(aOriginalItem)) { - gBrowser.setIcon(aTargetItem, gBrowser.getIcon(aOriginalItem)); + gBrowser.setIcon( + aTargetItem, + aOriginalItem.getAttribute('image') || gBrowser.getIcon(aOriginalItem) + ); } else if (aOriginalItem.isZenFolder) { // Icons are a zen-only feature for tab groups. gZenFolders.setFolderUserIcon(aTargetItem, aOriginalItem.iconURL); } + this.#maybeSyncAttributeChange(aOriginalItem, aTargetItem, 'zen-has-static-icon'); } if (flags & SYNC_FLAG_LABEL) { if (gBrowser.isTab(aOriginalItem)) { aTargetItem._zenChangeLabelFlag = true; + aTargetItem.zenStaticLabel = aOriginalItem.zenStaticLabel; gBrowser._setTabLabel(aTargetItem, aOriginalItem.label); delete aTargetItem._zenChangeLabelFlag; - this.#maybeSyncAttributeChange(aOriginalItem, aTargetItem, 'zen-has-static-label'); } else if (gBrowser.isTabGroup(aOriginalItem)) { aTargetItem.label = aOriginalItem.label; } @@ -486,7 +520,7 @@ class nsZenWindowSync { } // Restore the listeners for the swapped in tab. - if (!onClose) { + if (!onClose && filter) { tabListener = new otherTabBrowser.zenTabProgressListener(aTab, otherBrowser, true, false); otherTabBrowser._tabListeners.set(aTab, tabListener); @@ -746,18 +780,21 @@ class nsZenWindowSync { * Sets the initial pinned state for a tab across all windows. * * @param {Object} aTab - The tab to set the pinned state for. + * @returns {Promise} A promise that resolves when the operation is complete. */ setPinnedTabState(aTab) { - const state = this.#getTabState(aTab); - const initialState = { - entry: state.entries[state.index - 1], - image: state.image, - }; - this.#runOnAllWindows(null, (win) => { - const targetTab = this.#getItemFromWindow(win, aTab.id); - if (targetTab) { - targetTab._zenPinnedInitialState = initialState; - } + return lazy.TabStateFlusher.flush(aTab.linkedBrowser).finally(() => { + const state = this.#getTabState(aTab); + const initialState = { + entry: state.entries[state.index - 1], + image: state.image, + }; + this.#runOnAllWindows(null, (win) => { + const targetTab = this.#getItemFromWindow(win, aTab.id); + if (targetTab) { + targetTab._zenPinnedInitialState = initialState; + } + }); }); } @@ -797,8 +834,6 @@ class nsZenWindowSync { success = false; continue; } - newTab._zenContentsVisible = true; - gBrowser.setTabTitle(newTab); gZenWorkspaces.moveTabToWorkspace(newTab, aWorkspaceId); } } diff --git a/src/zen/tabs/ZenPinnedTabManager.mjs b/src/zen/tabs/ZenPinnedTabManager.mjs index 78b7be434..70890db24 100644 --- a/src/zen/tabs/ZenPinnedTabManager.mjs +++ b/src/zen/tabs/ZenPinnedTabManager.mjs @@ -32,6 +32,7 @@ class ZenPinnedTabsObserver { ); ChromeUtils.defineESModuleGetters(lazy, { E10SUtils: 'resource://gre/modules/E10SUtils.sys.mjs', + TabStateCache: 'resource:///modules/sessionstore/TabStateCache.sys.mjs', }); this.#listenPinnedTabEvents(); } @@ -60,10 +61,6 @@ class ZenPinnedTabsObserver { } class nsZenPinnedTabManager extends nsZenDOMOperatedFeature { - promiseInitializedPinned = new Promise((resolve) => { - this._resolvePinnedInitializedInternal = resolve; - }); - init() { if (!this.enabled) { return; @@ -463,43 +460,73 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature { data-lazy-l10n-id="tab-context-zen-remove-essential" hidden="true" command="cmd_contextZenRemoveFromEssentials"/> + +