diff --git a/addon/chrome/content/minit/minit.js b/addon/chrome/content/minit/minit.js
index ebabd3a1..4844fa59 100644
--- a/addon/chrome/content/minit/minit.js
+++ b/addon/chrome/content/minit/minit.js
@@ -901,6 +901,7 @@ Tabmix.navToolbox = {
gNavToolbox.addEventListener("beforecustomization", this);
gNavToolbox.addEventListener("aftercustomization", this);
+ /** @type {CustomizableUIListener["onWidgetAfterDOMChange"]} */
const onWidgetAfterDOMChange = (aNode, aNextNode, aContainer, aWasRemoval) => {
if (this.customizeStarted)
return;
@@ -927,15 +928,6 @@ Tabmix.navToolbox = {
gNavToolbox.removeEventListener("beforecustomization", this);
gNavToolbox.removeEventListener("aftercustomization", this);
- // remove tabmix-tabs-closebutton when its position is immediately after
- // tabmix-scrollbox and save its position in preference for future use.
- let boxPosition = Tabmix.getPlacement("tabmix-scrollbox");
- let buttonPosition = Tabmix.getPlacement("tabmix-tabs-closebutton");
- if (buttonPosition == boxPosition + 1) {
- Tabmix.prefs.setIntPref("tabs-closeButton-position", buttonPosition);
- CustomizableUI.removeWidgetFromArea("tabmix-tabs-closebutton");
- }
-
CustomizableUI.removeWidgetFromArea("tabmix-scrollbox");
CustomizableUI.removeListener(this.listener);
@@ -1340,13 +1332,13 @@ Tabmix.navToolbox = {
* we restore tabmix-scrollbox position first since its position is fixed,
* to be on the safe side we check tabmix-scrollbox position again after we
* restore tabmix-tabs-closebutton and new-tab-button position.
+ * see ScriptsLoader._addCloseButton and VerticalTabs how we handle tabmix-tabs-closebutton
*/
- this.setScrollButtons();
- try {
- this.setCloseButtonPosition();
- } catch { }
- gTMPprefObserver.changeNewTabButtonSide(Tabmix.prefs.getIntPref("newTabButton.position"));
- this.setScrollButtons(false, true);
+ if (!Tabmix.tabsUtils.isVerticalTabBar) {
+ this.setScrollButtons();
+ gTMPprefObserver.changeNewTabButtonSide(Tabmix.prefs.getIntPref("newTabButton.position"));
+ this.setScrollButtons(false, true);
+ }
// reset tabsNewtabButton and afterTabsButtonsWidth
if (typeof privateTab == "object")
@@ -1354,6 +1346,9 @@ Tabmix.navToolbox = {
},
setScrollButtons(reset, onlyPosition) {
+ if (Tabmix.tabsUtils.isVerticalTabBar) {
+ return;
+ }
let box = document.getElementById("tabmix-scrollbox");
if (box?.parentNode !== gBrowser.tabContainer.parentNode) {
// nothing to do here when our button box is not a sibling of gBrowser.tabContainer
@@ -1372,32 +1367,6 @@ Tabmix.navToolbox = {
}
},
- _closeButtonInitialized: false,
- setCloseButtonPosition() {
- if (this._closeButtonInitialized)
- return;
-
- // if tabmix-tabs-closebutton was positioned immediately after
- // tabmix-scrollbox we removed the button on exit, to avoid bug 1034394.
- let pref = "tabs-closeButton-position";
- if (Tabmix.prefs.prefHasUserValue(pref)) {
- let position = Tabmix.prefs.getIntPref(pref);
- Tabmix.prefs.clearUserPref(pref);
- CustomizableUI.moveWidgetWithinArea("tabmix-tabs-closebutton", position);
- } else if (!document.getElementById("tabs-closebutton")) {
- // try to restore button position from tabs-closebutton position
- // if item with tabs-closebutton id exist, some other extension add it
- // will throw if called too early (before placements have been fetched)
- let currentset = CustomizableUI.getWidgetIdsInArea("TabsToolbar");
- let position = currentset.indexOf("tabs-closebutton");
- if (position > -1) {
- CustomizableUI.removeWidgetFromArea("tabs-closebutton");
- CustomizableUI.moveWidgetWithinArea("tabmix-tabs-closebutton", position);
- }
- }
- this._closeButtonInitialized = true;
- }
-
};
Tabmix.getPlacement = function(id) {
diff --git a/addon/chrome/content/overlay/browser.css b/addon/chrome/content/overlay/browser.css
index 18c44a3a..e1f2d2d5 100644
--- a/addon/chrome/content/overlay/browser.css
+++ b/addon/chrome/content/overlay/browser.css
@@ -167,8 +167,12 @@
visibility: visible;
}
-#TabsToolbar:not([customizing])[tabmix-show-newtabbutton*="aftertabs"] #new-tab-button,
-#TabsToolbar:not([tabmix-show-newtabbutton]) #new-tab-button {
+#nav-bar:not([customizing]) #new-tab-button:not([tabmix-show-newtabbutton]) {
+ display: none;
+}
+
+#TabsToolbar:not([customizing])[tabmix-show-newtabbutton*="aftertabs"] #new-tab-button,
+#TabsToolbar:not([tabmix-show-newtabbutton]) #new-tab-button {
visibility: collapse;
}
diff --git a/addon/chrome/content/preferences/appearance.js b/addon/chrome/content/preferences/appearance.js
index 666c20a4..42322084 100644
--- a/addon/chrome/content/preferences/appearance.js
+++ b/addon/chrome/content/preferences/appearance.js
@@ -41,7 +41,6 @@ var gAppearancePane = {
// rtl update position
if (RTL_UI) {
let right = $("newTabButton.position.right");
- // let left = $("newTabButton.position.left");
let left = $("newTabButton.position.left");
[right.label, left.label] = [left.label, right.label];
@@ -184,8 +183,7 @@ var gAppearancePane = {
// Display > Tab bar
function updateDisabledState(buttonID, itemID, aEnable) {
- let button = aWindow.document.getElementById(buttonID);
- let enablePosition = button && aWindow.document.getElementById("TabsToolbar").contains(button);
+ const enablePosition = Boolean(aWindow.CustomizableUI.getPlacementOfWidget(buttonID));
gPrefWindow.setDisabled(itemID, !enablePosition || null);
gPrefWindow.setDisabled("obs_" + itemID, !aEnable || !enablePosition || null);
}
diff --git a/addon/chrome/content/tab/tab.js b/addon/chrome/content/tab/tab.js
index c7184970..a67476be 100644
--- a/addon/chrome/content/tab/tab.js
+++ b/addon/chrome/content/tab/tab.js
@@ -51,6 +51,14 @@ var TabmixTabbar = {
return button && document.getElementById("TabsToolbar").contains(button);
},
+ isButtonOnToolBar(button) {
+ return (
+ button &&
+ (document.getElementById("TabsToolbar").contains(button) ||
+ document.getElementById("nav-bar").contains(button))
+ );
+ },
+
// get privateTab-toolbar-openNewPrivateTab, when the button is on the tabbar
newPrivateTabButton() {
let button = document.getElementById("privateTab-toolbar-openNewPrivateTab");
@@ -149,12 +157,12 @@ var TabmixTabbar = {
if (tabBar.mCloseButtons == 5)
tabBar._updateCloseButtons(true);
- // show on tabbar
+ // show on tabbar or nav-bar
let tabstripClosebutton = document.getElementById("tabmix-tabs-closebutton");
- if (this.isButtonOnTabsToolBar(tabstripClosebutton))
+ if (this.isButtonOnToolBar(tabstripClosebutton))
tabstripClosebutton.collapsed = Tabmix.prefs.getBoolPref("hideTabBarButton");
let allTabsButton = document.getElementById("alltabs-button");
- if (this.isButtonOnTabsToolBar(allTabsButton)) {
+ if (this.isButtonOnToolBar(allTabsButton)) {
allTabsButton.collapsed = !Services.prefs.getBoolPref("browser.tabs.tabmanager.enabled");
Tabmix.setItem("tabbrowser-tabs", "showalltabsbutton", !allTabsButton.collapsed || null);
}
@@ -176,10 +184,13 @@ var TabmixTabbar = {
},
setShowNewTabButtonAttr() {
- let newTabButton = document.getElementById("new-tab-button");
let showNewTabButton = Tabmix.prefs.getBoolPref("newTabButton") &&
- this.isButtonOnTabsToolBar(newTabButton);
+ Boolean(CustomizableUI.getPlacementOfWidget("new-tab-button"));
let position = Tabmix.prefs.getIntPref("newTabButton.position");
+ if (position === 2 && gBrowser.tabContainer.verticalMode && Tabmix.tabsUtils.isVerticalTabs) {
+ position = 1;
+ Tabmix.prefs.setIntPref("newTabButton.position", 1);
+ }
gTMPprefObserver.setShowNewTabButtonAttr(showNewTabButton, position);
},
@@ -1804,13 +1815,6 @@ window.gTMPprefObserver = {
const protonPrefVal = Services.prefs.getBoolPref("browser.proton.tabs.enabled", false);
let newRule;
if (!Tabmix.isVersion(880)) {
- // the button is not ready when we call dynamicProtonRules early
- // onContentLoaded>addDynamicRules>dynamicProtonRules
- setTimeout(() => {
- // tabmix-tabs-closebutton toolbarbutton
- document.getElementById("tabmix-tabs-closebutton").setAttribute("tabmix-fill-opacity", true);
- }, 100);
-
newRule = `#tabmix-tabs-closebutton[tabmix-fill-opacity] > .toolbarbutton-icon {
padding: ${protonPrefVal ? 7.4 : 4}px 4px !important;
}`;
@@ -2289,9 +2293,6 @@ window.gTMPprefObserver = {
},
changeNewTabButtonSide(aPosition) {
- if (gBrowser.tabContainer.verticalMode && Tabmix.tabsUtils.isVerticalTabs) {
- aPosition = 1;
- }
let $ = id => document.getElementById(id);
let newTabButton = $("new-tab-button");
if (TabmixTabbar.isButtonOnTabsToolBar(newTabButton)) {
@@ -2323,6 +2324,10 @@ window.gTMPprefObserver = {
else
doChange();
}
+ } else if (gBrowser.tabContainer.verticalMode && Tabmix.tabsUtils.isVerticalTabBar) {
+ let showNewTabButton = Tabmix.prefs.getBoolPref("newTabButton");
+ this.setShowNewTabButtonAttr(showNewTabButton, 1);
+ Tabmix.sideNewTabButton = newTabButton;
} else {
this.setShowNewTabButtonAttr(false);
Tabmix.sideNewTabButton = null;
@@ -2346,10 +2351,7 @@ window.gTMPprefObserver = {
let attrValue;
if (!aShow) {
attrValue = null;
- } else if (
- aPosition == 1 ||
- gBrowser.tabContainer.verticalMode && Tabmix.tabsUtils.isVerticalTabs
- ) {
+ } else if (aPosition == 1) {
attrValue = "right-side";
} else if (aPosition === 0) {
attrValue = "left-side";
@@ -2358,7 +2360,11 @@ window.gTMPprefObserver = {
}
// we use this value in disAllowNewtabbutton and overflow setters
Tabmix.tabsUtils._show_newtabbutton = attrValue;
- Tabmix.setItem("TabsToolbar", "tabmix-show-newtabbutton", attrValue);
+ if (gBrowser.tabContainer.verticalMode && Tabmix.tabsUtils.isVerticalTabs) {
+ Tabmix.setItem("new-tab-button", "tabmix-show-newtabbutton", attrValue);
+ } else {
+ Tabmix.setItem("TabsToolbar", "tabmix-show-newtabbutton", attrValue);
+ }
},
tabBarPositionChanged(aPosition) {
diff --git a/addon/chrome/content/tabmix.js b/addon/chrome/content/tabmix.js
index a08704fe..297596a1 100644
--- a/addon/chrome/content/tabmix.js
+++ b/addon/chrome/content/tabmix.js
@@ -402,10 +402,11 @@ var TMP_eventListener = {
}
if (!CustomizableUI.getPlacementOfWidget("tabmix-scrollbox")) {
+ const tabsWidget = CustomizableUI.getPlacementOfWidget("tabbrowser-tabs");
CustomizableUI.addWidgetToArea(
"tabmix-scrollbox",
CustomizableUI.AREA_TABSTRIP,
- CustomizableUI.getPlacementOfWidget("tabbrowser-tabs").position + 1
+ tabsWidget?.area === CustomizableUI.AREA_TABSTRIP ? tabsWidget.position + 1 : 0
);
}
@@ -564,25 +565,6 @@ var TMP_eventListener = {
Tabmix.setNewFunction(tabBar, "_updateCloseButtons", Tabmix._updateCloseButtons);
delete Tabmix._updateCloseButtons;
- // update tooltip for tabmix-tabs-closebutton
- const closeButton = document.getElementById("tabmix-tabs-closebutton");
- if (Tabmix.isVersion(1090)) {
- const [l10Id, attrName] = Tabmix.isVersion(1310) ? ["tabbrowser-close-tabs-button", "tooltiptext"] : ["tabbrowser-close-tabs-tooltip", "label"];
- document.l10n.setAttributes(closeButton, l10Id, {tabCount: 1});
- document.l10n.translateElements([closeButton]).then(() => {
- closeButton.removeAttribute("data-l10n-id");
- closeButton.setAttribute("tooltiptext", closeButton.getAttribute(attrName));
- });
- } else {
- closeButton.setAttribute("tooltiptext",
- window.PluralForm.get(
- 1,
- // eslint-disable-next-line no-undef
- gTabBrowserBundle.GetStringFromName("tabs.closeTabs.tooltip")
- )
- );
- }
-
Tabmix.allTabs.init();
MozXULElement.insertFTLIfNeeded("browser/tabContextMenu.ftl");
diff --git a/addon/chrome/content/tabmix.xhtml b/addon/chrome/content/tabmix.xhtml
index c731128a..5473fc90 100644
--- a/addon/chrome/content/tabmix.xhtml
+++ b/addon/chrome/content/tabmix.xhtml
@@ -282,12 +282,6 @@
tooltip="tabmix-rows-tooltip"
cui-areatype="toolbar"
removable="false"/>
-
-
diff --git a/addon/chrome/skin/general.css b/addon/chrome/skin/general.css
index 87ccd857..5d47cfe8 100644
--- a/addon/chrome/skin/general.css
+++ b/addon/chrome/skin/general.css
@@ -22,10 +22,14 @@
width: unset;
}
-#tabmix-tabs-closebutton:hover {
+#tabmix-tabs-closebutton:not([overflowedItem]):hover {
background-color: transparent;
}
+#widget-overflow-list #tabmix-tabs-closebutton.close-icon > .toolbarbutton-text {
+ display: block;
+}
+
/* :::: for light weight themes :::: */
#main-window[tabmix_lwt]:-moz-lwtheme {
background-repeat: repeat-y !important;
diff --git a/addon/modules/bootstrap/ScriptsLoader.jsm b/addon/modules/bootstrap/ScriptsLoader.jsm
index 6c75c71b..30ca7cdb 100644
--- a/addon/modules/bootstrap/ScriptsLoader.jsm
+++ b/addon/modules/bootstrap/ScriptsLoader.jsm
@@ -12,12 +12,17 @@ const {TabmixChromeUtils} = ChromeUtils.import("chrome://tabmix-resource/content
const lazy = {};
TabmixChromeUtils.defineLazyModuleGetters(lazy, {
+ CustomizableUI: "resource:///modules/CustomizableUI.jsm",
Overlays: "chrome://tabmix-resource/content/bootstrap/Overlays.jsm",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
SessionStore: "resource:///modules/sessionstore/SessionStore.jsm",
});
-const isVersion119 = Services.vc.compare(Services.appinfo.version, "119.0a1");
+function isVersion(versionNo) {
+ return Services.vc.compare(Services.appinfo.version, versionNo / 10 + ".0a1") >= 0;
+}
+
+const isVersion119 = isVersion(1190);
/**
* stylesheets and scripts for navigator:browser
@@ -59,6 +64,7 @@ const ScriptsLoader = {
}
initialized.add(window);
+ this._addCloseButton(window);
this._loadCSS(window);
this._loadScripts(window, promiseOverlayLoaded);
this._addListeners(window);
@@ -67,6 +73,51 @@ const ScriptsLoader = {
}
},
+ _closeButtonAdded: false,
+ _addCloseButton(window) {
+ // since Firefox version 132, we need to allow tabmix-tabs-closebutton to move to nav-bar
+ // when vertical tabs are enabled
+ // we create it as widget and add it to the proper area TabsToolbar or nav-bar
+ // we add it after alltabs-button by default but keep its position if user
+ // move it in the toolbar
+ if (!this._closeButtonAdded) {
+ const allTabsButtonPlacement = lazy.CustomizableUI.getPlacementOfWidget("alltabs-button");
+ const closeButtonPlacement = lazy.CustomizableUI.getPlacementOfWidget("tabmix-tabs-closebutton");
+ if (!closeButtonPlacement || closeButtonPlacement.area !== allTabsButtonPlacement?.area) {
+ const {area, position} = allTabsButtonPlacement ?? {area: lazy.CustomizableUI.AREA_TABSTRIP};
+ const finalPosition = typeof position === "number" ? position + 1 : undefined;
+ lazy.CustomizableUI.addWidgetToArea("tabmix-tabs-closebutton", area, finalPosition);
+ }
+ }
+ this._closeButtonAdded = true;
+
+ const {document} = window;
+ window.MozXULElement.insertFTLIfNeeded("browser/tabContextMenu.ftl");
+
+ // update label and tooltip for tabmix-tabs-closebutton
+ const closeButton = document.getElementById("tabmix-tabs-closebutton");
+ if (!closeButton) {
+ console.log("Tabmix Error:closeButton not found");
+ return;
+ }
+ if (!isVersion(880)) {
+ closeButton.setAttribute("tabmix-fill-opacity", true);
+ }
+ const [l10Id, attrName] = isVersion(1310) ?
+ ["tabbrowser-close-tabs-button", "tooltiptext"] :
+ isVersion(1090) ?
+ ["tabbrowser-close-tabs-tooltip", "label"] :
+ ["close-tab", "label"];
+ document.l10n?.setAttributes(closeButton, l10Id, {tabCount: 1});
+ document.l10n?.translateElements([closeButton]).then(() => {
+ closeButton.removeAttribute("data-l10n-id");
+ closeButton.removeAttribute("data-l10n-args");
+ const label = closeButton.getAttribute(attrName) ?? "";
+ closeButton.setAttribute("label", label);
+ closeButton.setAttribute("tooltiptext", label);
+ });
+ },
+
_loadCSS(window) {
const winUtils = window.windowUtils;
for (const url of CSS_URLS) {
diff --git a/addon/modules/bootstrap/TabmixWidgets.jsm b/addon/modules/bootstrap/TabmixWidgets.jsm
index 66987531..f6922e2f 100644
--- a/addon/modules/bootstrap/TabmixWidgets.jsm
+++ b/addon/modules/bootstrap/TabmixWidgets.jsm
@@ -98,6 +98,19 @@ const widgets = {
`;
},
},
+ tabsCloseButton: {
+ id: "tabmix-tabs-closebutton",
+ localizeFiles: [],
+ // we apply label and tooltip in ScriptsLoader._addCloseButton
+ get markup() {
+ return `
+ `;
+ },
+ },
};
function on_build(widget) {
diff --git a/types/general.d.ts b/types/general.d.ts
index 72627a37..37c6a743 100644
--- a/types/general.d.ts
+++ b/types/general.d.ts
@@ -602,6 +602,22 @@ interface HistoryMenu {
populateUndoWindowSubmenu: () => void;
}
+interface CustomizableUIListener {
+ onWidgetAfterDOMChange(aNode: Node, aNextNode: Node, aContainer: ParentNode, aWasRemoval: boolean): void;
+}
+
+interface CustomizableUI {
+ AREA_TABSTRIP: string;
+ addListener: (aListener: CustomizableUIListener) => void;
+ addShortcut(aShortcutNode: Node, aTargetNode?: Node): void;
+ addWidgetToArea: (aWidgetId: string, aArea: string, aPosition: number, aInitialAdd?: boolean) => void;
+ getWidgetIdsInArea: (aArea: string) => string[];
+ getPlacementOfWidget: (aWidgetId: string, aOnlyRegistered?: boolean, aDeadAreas?: boolean) => {area: string; position: number} | null;
+ moveWidgetWithinArea: (aWidgetId: string, aPosition: number) => void;
+ removeListener: (aListener: CustomizableUIListener) => void;
+ removeWidgetFromArea: (aWidgetId: string) => void;
+}
+
interface E10SUtils {
SERIALIZED_SYSTEMPRINCIPAL: string;
DEFAULT_REMOTE_TYPE: string;
@@ -693,6 +709,7 @@ declare function OpenBrowserWindow(params?: {private?: boolean; features?: strin
declare function urlSecurityCheck(aURL: string, aPrincipal: nsIPrincipal, aFlags?: nsIScriptSecurityManager): void;
declare function undoCloseWindow(index: number): void;
+declare var CustomizableUI: CustomizableUI;
declare var E10SUtils: E10SUtils;
declare var FullScreen: FullScreen;
declare var gBrowser: MockedGeckoTypes.TabBrowser;
@@ -743,7 +760,6 @@ declare var BrowserUtils: any;
declare var closeMenus: any;
declare var Components: any;
declare var ctrlTab: any;
-declare var CustomizableUI: any;
/** @deprecated removed from firefox on version 87 */
declare var getHtmlBrowser: any;
declare var gMultiProcessBrowser: any;
diff --git a/types/preferences.d.ts b/types/preferences.d.ts
index 776ba7f9..dd355bc8 100644
--- a/types/preferences.d.ts
+++ b/types/preferences.d.ts
@@ -40,6 +40,7 @@ interface XULCommandDispatcher {
interface Window {
_sminstalled: boolean;
$(selectors: K | string): K extends keyof GetByMap ? GetByMap[K] : HTMLElement | null;
+ CustomizableUI: typeof CustomizableUI;
}
interface EventTarget {