feat: implement automatic tab grouping
This commit is contained in:
@@ -1382,6 +1382,9 @@
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
newTab.dispatchEvent(event);
|
newTab.dispatchEvent(event);
|
||||||
|
|
||||||
|
// Notify observers for native tab grouping feature
|
||||||
|
Services.obs.notifyObservers(newTab, "browser-tab-activated");
|
||||||
|
|
||||||
this._tabAttrModified(oldTab, ["selected"]);
|
this._tabAttrModified(oldTab, ["selected"]);
|
||||||
this._tabAttrModified(newTab, ["selected"]);
|
this._tabAttrModified(newTab, ["selected"]);
|
||||||
@@ -4037,6 +4040,9 @@
|
|||||||
detail: eventDetail || {},
|
detail: eventDetail || {},
|
||||||
});
|
});
|
||||||
tab.dispatchEvent(evt);
|
tab.dispatchEvent(evt);
|
||||||
|
|
||||||
|
// Notify observers for native tab grouping feature
|
||||||
|
Services.obs.notifyObservers(tab, "browser-tab-created");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -5013,6 +5019,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
_endRemoveTab(aTab) {
|
_endRemoveTab(aTab) {
|
||||||
|
// Notify observers for native tab grouping feature
|
||||||
|
Services.obs.notifyObservers(aTab, "browser-tab-removed");
|
||||||
if (!aTab || !aTab._endRemoveArgs) {
|
if (!aTab || !aTab._endRemoveArgs) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -7220,6 +7228,10 @@
|
|||||||
// Intentional fallthrough
|
// Intentional fallthrough
|
||||||
case "deactivate":
|
case "deactivate":
|
||||||
this.selectedTab.updateLastSeenActive();
|
this.selectedTab.updateLastSeenActive();
|
||||||
|
// Notify observers for native tab grouping feature
|
||||||
|
if (aEvent.type === "activate") {
|
||||||
|
Services.obs.notifyObservers(null, "browser-window-focus-changed");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -271,6 +271,7 @@
|
|||||||
@RESPATH@/browser/defaults/settings
|
@RESPATH@/browser/defaults/settings
|
||||||
; Waterfox preference files
|
; Waterfox preference files
|
||||||
@RESPATH@/browser/@PREF_DIR@/prefs-lepton.js
|
@RESPATH@/browser/@PREF_DIR@/prefs-lepton.js
|
||||||
|
@RESPATH@/browser/@PREF_DIR@/prefs-tabgroups.js
|
||||||
|
|
||||||
# channel-prefs.js has been removed on macOS.
|
# channel-prefs.js has been removed on macOS.
|
||||||
#ifndef XP_MACOSX
|
#ifndef XP_MACOSX
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
|
|||||||
PrivateTab: "resource:///modules/PrivateTab.sys.mjs",
|
PrivateTab: "resource:///modules/PrivateTab.sys.mjs",
|
||||||
StatusBar: "resource:///modules/StatusBar.sys.mjs",
|
StatusBar: "resource:///modules/StatusBar.sys.mjs",
|
||||||
TabFeatures: "resource:///modules/TabFeatures.sys.mjs",
|
TabFeatures: "resource:///modules/TabFeatures.sys.mjs",
|
||||||
|
TabGrouping: "resource:///modules/TabGrouping.sys.mjs",
|
||||||
setTimeout: "resource://gre/modules/Timer.sys.mjs",
|
setTimeout: "resource://gre/modules/Timer.sys.mjs",
|
||||||
UICustomizations: "resource:///modules/UICustomizations.sys.mjs",
|
UICustomizations: "resource:///modules/UICustomizations.sys.mjs",
|
||||||
});
|
});
|
||||||
@@ -75,6 +76,9 @@ export const WaterfoxGlue = {
|
|||||||
this.addAddonListener();
|
this.addAddonListener();
|
||||||
// Register about:cfg
|
// Register about:cfg
|
||||||
lazy.AboutPages.init();
|
lazy.AboutPages.init();
|
||||||
|
|
||||||
|
// Initialize automatic tab grouping
|
||||||
|
lazy.TabGrouping.init();
|
||||||
},
|
},
|
||||||
|
|
||||||
async _setPrefObservers() {
|
async _setPrefObservers() {
|
||||||
@@ -215,6 +219,9 @@ export const WaterfoxGlue = {
|
|||||||
this._beforeUIStartup();
|
this._beforeUIStartup();
|
||||||
this._delayedTasks();
|
this._delayedTasks();
|
||||||
break;
|
break;
|
||||||
|
case "quit-application-granted":
|
||||||
|
this.shutdown();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -406,6 +413,11 @@ export const WaterfoxGlue = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
shutdown() {
|
||||||
|
// Shutdown TabGrouping
|
||||||
|
lazy.TabGrouping.shutdown();
|
||||||
|
},
|
||||||
|
|
||||||
updateCustomStylesheets(addon) {
|
updateCustomStylesheets(addon) {
|
||||||
if (addon.type === "theme") {
|
if (addon.type === "theme") {
|
||||||
// If any theme and WF on any theme, reload stylesheets for every theme enable.
|
// If any theme and WF on any theme, reload stylesheets for every theme enable.
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ DIRS += [
|
|||||||
"search",
|
"search",
|
||||||
"statusbar",
|
"statusbar",
|
||||||
"tabfeatures",
|
"tabfeatures",
|
||||||
|
"tabgrouping",
|
||||||
"uicustomizations",
|
"uicustomizations",
|
||||||
"utils",
|
"utils",
|
||||||
]
|
]
|
||||||
|
|||||||
21
waterfox/browser/components/tabgrouping/LICENSE
Normal file
21
waterfox/browser/components/tabgrouping/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 David Demri
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the “Software”), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
58
waterfox/browser/components/tabgrouping/README.md
Normal file
58
waterfox/browser/components/tabgrouping/README.md
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# Automatic Tab Grouping Feature
|
||||||
|
|
||||||
|
This feature is inspired by the Firefox WebExtension "New Tab Same Group" by onlybets.
|
||||||
|
(Source: https://github.com/onlybets/firefox-addon-new-tab-same-group/blob/main/README.md)
|
||||||
|
|
||||||
|
This module implements automatic tab grouping functionality, which automatically adds new tabs to the same group as the currently active tab.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Automatic Grouping**: When enabled, new tabs are automatically added to the same group as the source tab (the tab that was active when the new tab was created).
|
||||||
|
|
||||||
|
- **Configurable Placement**: Users can choose where new tabs appear within the group:
|
||||||
|
- After the source tab (default)
|
||||||
|
- At the beginning of the group
|
||||||
|
- At the end of the group
|
||||||
|
|
||||||
|
- **Optional Delay**: Users can enable a 1-second delay before grouping occurs, allowing them to cancel the operation if desired.
|
||||||
|
|
||||||
|
- **Keyboard Shortcut**: When delay is enabled, users can press a keyboard shortcut (default: Ctrl+` on Windows/Linux, Alt+` on macOS) to cancel pending grouping operations.
|
||||||
|
|
||||||
|
- **Bypass Shortcut**: Press Alt+Shift+T to open a new tab in the standard way (no grouping). This can be configured via preferences.
|
||||||
|
|
||||||
|
- **Smart Tab Tracking**: The feature maintains a history of active tabs to handle edge cases where the source tab might not be immediately available.
|
||||||
|
|
||||||
|
## Implementation
|
||||||
|
|
||||||
|
The feature consists of:
|
||||||
|
|
||||||
|
1. **TabGrouping.sys.mjs**: Core module that handles all the grouping logic
|
||||||
|
2. **Preferences**: User-configurable settings with defaults
|
||||||
|
3. **UI Overlays**: Integration with the preferences UI
|
||||||
|
4. **Localization**: User-facing strings in tabgrouping.ftl
|
||||||
|
|
||||||
|
## Preferences
|
||||||
|
|
||||||
|
- `browser.tabs.autoGroupNewTabs`: Enable/disable the feature (default: true)
|
||||||
|
- `browser.tabs.autoGroupNewTabs.placement`: Tab placement mode (default: "after")
|
||||||
|
- `browser.tabs.autoGroupNewTabs.delayEnabled`: Enable grouping delay (default: false)
|
||||||
|
- `browser.tabs.autoGroupNewTabs.delayMs`: Delay duration in milliseconds (default: 1000)
|
||||||
|
- `browser.tabs.autoGroupNewTabs.cancelShortcut`: Keyboard shortcut to cancel (platform-specific default)
|
||||||
|
- `browser.tabs.autoGroupNewTabs.bypassShortcut`: Keyboard shortcut to open a standard new tab without grouping (default: "Alt+Shift+T")
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
The module:
|
||||||
|
- Listens for tab creation events via observer notifications
|
||||||
|
- Tracks active tab history to determine the appropriate source tab
|
||||||
|
- Manages pending grouping operations with timers
|
||||||
|
- Handles keyboard shortcuts dynamically when delay is enabled
|
||||||
|
- Integrates with the existing tab group infrastructure in tabbrowser.js
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The feature is automatically initialized when the browser starts via WaterfoxGlue.sys.mjs.
|
||||||
|
|
||||||
|
This project contains code under two licenses:
|
||||||
|
- Original implementation: MIT License (see LICENSE)
|
||||||
|
- Rewritten portions: Mozilla Public License 2.0
|
||||||
1045
waterfox/browser/components/tabgrouping/TabGrouping.sys.mjs
Normal file
1045
waterfox/browser/components/tabgrouping/TabGrouping.sys.mjs
Normal file
File diff suppressed because it is too large
Load Diff
13
waterfox/browser/components/tabgrouping/moz.build
Normal file
13
waterfox/browser/components/tabgrouping/moz.build
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||||
|
# vim: set filetype=python:
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
EXTRA_JS_MODULES += [
|
||||||
|
"TabGrouping.sys.mjs",
|
||||||
|
]
|
||||||
|
|
||||||
|
JS_PREFERENCE_PP_FILES += [
|
||||||
|
"prefs-tabgroups.js",
|
||||||
|
]
|
||||||
40
waterfox/browser/components/tabgrouping/prefs-tabgroups.js
Normal file
40
waterfox/browser/components/tabgrouping/prefs-tabgroups.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
// Default preferences for automatic tab grouping feature
|
||||||
|
|
||||||
|
// Enable automatic tab grouping
|
||||||
|
pref("browser.tabs.autoGroupNewTabs", false);
|
||||||
|
|
||||||
|
// Placement mode for new tabs in groups
|
||||||
|
// Options: "after" (after source tab), "first" (beginning of group), "last" (end of group)
|
||||||
|
pref("browser.tabs.autoGroupNewTabs.placement", "after");
|
||||||
|
|
||||||
|
// Enable delay before grouping (allows user to cancel)
|
||||||
|
pref("browser.tabs.autoGroupNewTabs.delayEnabled", false);
|
||||||
|
|
||||||
|
// Delay in milliseconds before grouping occurs
|
||||||
|
pref("browser.tabs.autoGroupNewTabs.delayMs", 1000);
|
||||||
|
|
||||||
|
// Keyboard shortcut to cancel pending grouping
|
||||||
|
// Default: Ctrl+` on Windows/Linux, Option+` on macOS
|
||||||
|
#ifdef XP_MACOSX
|
||||||
|
pref("browser.tabs.autoGroupNewTabs.cancelShortcut", "Option+`");
|
||||||
|
#else
|
||||||
|
pref("browser.tabs.autoGroupNewTabs.cancelShortcut", "Ctrl+`");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Keyboard shortcut to open a standard new tab (bypass grouping)
|
||||||
|
// Default: Alt+Shift+T (Windows/Linux), Option+Shift+T (macOS)
|
||||||
|
#ifdef XP_MACOSX
|
||||||
|
pref("browser.tabs.autoGroupNewTabs.bypassShortcut", "Option+Shift+T");
|
||||||
|
#else
|
||||||
|
pref("browser.tabs.autoGroupNewTabs.bypassShortcut", "Alt+Shift+T");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Enable verbose debug logging for TabGrouping
|
||||||
|
pref("browser.tabs.autoGroupNewTabs.debugLog", false);
|
||||||
|
|
||||||
|
// Grace period after session restore before resuming auto-grouping (ms)
|
||||||
|
pref("browser.tabs.autoGroupNewTabs.resumeGraceMs", 1000);
|
||||||
Reference in New Issue
Block a user