Skip to content

feat: improve tab navigation and cycling #9441

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/browser/base/content/zen-keysets.inc.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
<command id="cmd_zenPinnedTabReset" />
<command id="cmd_zenPinnedTabResetNoTab" />

<command id="cmd_zenTabNext"/>
<command id="cmd_zenTabPrev"/>
<command id="cmd_zenToggleUnloadedCycling"/>

<command id="cmd_zenToggleSidebar" />

<command id="cmd_zenCopyCurrentURL" />
Expand Down
9 changes: 9 additions & 0 deletions src/browser/components/preferences/zen-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,10 @@ var zenMissingKeyboardShortcutL10n = {
key_wrToggleCaptureSequenceCmd: 'zen-key-wr-toggle-capture-sequence-cmd',
key_undoCloseWindow: 'zen-key-undo-close-window',

key_zenTabNext: 'zen-key-tab-next-shortcut',
key_zenTabPrevious: 'zen-key-tab-prev-shortcut',
key_toggleUnloadedCycling: 'zen-toggle-unloaded-cycling-shortcut',

key_selectTab1: 'zen-key-select-tab-1',
key_selectTab2: 'zen-key-select-tab-2',
key_selectTab3: 'zen-key-select-tab-3',
Expand Down Expand Up @@ -1174,4 +1178,9 @@ Preferences.addAll([
type: 'bool',
default: true,
},
{
id: 'zen.tabs.unloaded-navigation-mode',
type: 'string',
default: 'always',
},
]);
29 changes: 28 additions & 1 deletion src/browser/components/preferences/zenTabsManagement.inc.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,33 @@
</hbox>
</groupbox>

</html:template>
<hbox id="zenTabsUnloadCategory" class="subcategory" hidden="true" data-category="paneZenTabManagement">
<html:h1 data-l10n-id="pane-zen-tabs-unloader-title" />
</hbox>

<hbox id="zenPinnedTabsManagerCategory" class="subcategory" hidden="true" data-category="paneZenTabManagement">
<html:h1 data-l10n-id="pane-zen-tab-navigation-title" />
</hbox>

<groupbox id="zenTabsUnloadedNavigationGroup" data-category="paneZenTabManagement" hidden="true"
class="highlighting-group">
<label>
<html:h2 data-l10n-id="zen-tabs-unloaded-navigation-mode-label" />
</label>
<description class="description-deemphasized"
data-l10n-id="zen-tabs-unloaded-navigation-mode-description" />

<radiogroup id="zenTabsUnloadedNavigationMode" preference="zen.tabs.unloaded-navigation-mode"
oncommand="onZenTabsUnloadedNavigationModeChanged(this.value);">
<hbox align="center">
<radio id="zenTabsUnloadedNavigationModeAlways" value="always" />
<description data-l10n-id="zen-tabs-unloaded-navigation-mode-always" />
</hbox>
<hbox align="center">
<radio id="zenTabsUnloadedNavigationModeNever" value="never" />
<description data-l10n-id="zen-tabs-unloaded-navigation-mode-never" />
</hbox>
</radiogroup>
</groupbox>

</html:template>
33 changes: 33 additions & 0 deletions src/toolkit/content/widgets/tabbox-js.patch
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,39 @@ diff --git a/toolkit/content/widgets/tabbox.js b/toolkit/content/widgets/tabbox.
index 70afbfc87d543971e6f8a0661a44b682920a7bc4..2f767296db8043318fab2aeb39bfc5eee090b258 100644
--- a/toolkit/content/widgets/tabbox.js
+++ b/toolkit/content/widgets/tabbox.js
@@ -126,32 +126,32 @@
const { ShortcutUtils } = imports;

- switch (ShortcutUtils.getSystemActionForEvent(event)) {
- case ShortcutUtils.CYCLE_TABS:
- Glean.browserUiInteraction.keyboard["ctrl-tab"].add(1);
- Services.prefs.setBoolPref(
- "browser.engagement.ctrlTab.has-used",
- true
- );
- if (this.tabs && this.handleCtrlTab) {
- this.tabs.advanceSelectedTab(
- event.shiftKey ? DIRECTION_BACKWARD : DIRECTION_FORWARD,
- true
- );
- event.preventDefault();
- }
- break;
- case ShortcutUtils.PREVIOUS_TAB:
- if (this.tabs) {
- this.tabs.advanceSelectedTab(DIRECTION_BACKWARD, true);
- event.preventDefault();
- }
- break;
- case ShortcutUtils.NEXT_TAB:
- if (this.tabs) {
- this.tabs.advanceSelectedTab(DIRECTION_FORWARD, true);
- event.preventDefault();
- }
- break;
- }
}
}
@@ -213,7 +213,7 @@
) {
this._inAsyncOperation = false;
Expand Down
52 changes: 52 additions & 0 deletions src/zen/common/ZenCommonUtils.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,58 @@ var gZenCommonActions = {
}
},

zenNavigateTab(direction) {
try {
const basePref = Services.prefs.getStringPref('zen.tabs.unloaded-navigation-mode', 'never');
const invertedState = Services.prefs.getBoolPref('zen.tabs.unloaded-navigation-mode.inverted', false);
const cycleUnloaded = (basePref === 'always' && !invertedState) || (basePref === 'never' && invertedState);

let allTabs = window.gZenWorkspaces?.tabboxChildren?.filter(
(t) => !t.hidden && !t.hasAttribute('zen-empty-tab')
) || [];
let tabs = cycleUnloaded ? allTabs : allTabs.filter(t => !t.hasAttribute('pending'));
if (tabs.length === 0) return;
const selectedIndex = tabs.indexOf(window.gBrowser?.selectedTab);
let newIndex;
if (selectedIndex === -1) {
newIndex = direction > 0 ? 0 : tabs.length - 1;
} else {
newIndex = selectedIndex + direction;
if (newIndex < 0) newIndex = tabs.length - 1;
else if (newIndex >= tabs.length) newIndex = 0;
}
if (window.gBrowser) window.gBrowser.selectedTab = tabs[newIndex];
} catch (e) {
console.error('Error in gZenCommonActions.zenNavigateTab:', e);
}
},

nextTab() {
this.zenNavigateTab(1);
},
previousTab() {
this.zenNavigateTab(-1);
},

toggleUnloadedCycling() {
try {
const currentMode = Services.prefs.getCharPref('zen.tabs.unloaded-navigation-mode', 'always');
const nextMode = currentMode === 'always' ? 'never' : 'always';
Services.prefs.setCharPref('zen.tabs.unloaded-navigation-mode', nextMode);
const message = nextMode === 'always' ? 'Including unloaded tabs' : 'Skipping unloaded tabs';
gNotificationBox.appendNotification(
'zen-unloaded-cycle-toggle-notification',
{
label: message,
priority: gNotificationBox.PRIORITY_INFO_MEDIUM,
},
[]
);
} catch (e) {
console.error('[gZenCommonActions] Error on unloaded cycling:', e);
}
},

throttle(f, delay) {
let timer = 0;
return function (...args) {
Expand Down
9 changes: 9 additions & 0 deletions src/zen/common/zen-sets.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ document.addEventListener(
case 'cmd_zenSplitViewUnsplit':
gZenViewSplitter.toggleShortcut('unsplit');
break;
case 'cmd_zenTabNext':
gZenCommonActions.nextTab();
break;
case 'cmd_zenTabPrev':
gZenCommonActions.previousTab();
break;
case 'cmd_zenToggleUnloadedCycling':
gZenCommonActions.toggleUnloadedCycling();
break;
case 'cmd_zenSplitViewContextMenu':
gZenViewSplitter.contextSplitTabs();
break;
Expand Down
44 changes: 40 additions & 4 deletions src/zen/kbs/ZenKeyboardShortcuts.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,43 @@ class nsZenKeyboardShortcutsVersioner {
}
}
}
if (version < 10) {
// Migrate from version 9 to 10
// In this new version, we add customizable shortcuts for switching to the next/previous tab and toggling unloaded tab cycling.
data.push(
new KeyShortcut(
'zen-tab-next-shortcut',
'TAB',
'VK_TAB',
'windowAndTabManagement',
nsKeyShortcutModifiers.fromObject({ accel: true }),
'cmd_zenTabNext',
'zen-tab-next-shortcut'
)
);
data.push(
new KeyShortcut(
'zen-tab-prev-shortcut',
'TAB',
'VK_TAB',
'windowAndTabManagement',
nsKeyShortcutModifiers.fromObject({ accel: true, shift: true }),
'cmd_zenTabPrev',
'zen-tab-prev-shortcut'
)
);
data.push(
new KeyShortcut(
'zen-toggle-unloaded-cycling-shortcut',
'U',
'',
'windowAndTabManagement',
nsKeyShortcutModifiers.fromObject({ alt: true }),
'cmd_zenToggleUnloadedCycling',
'zen-toggle-unloaded-cycling-shortcut'
)
);
}
return data;
}
}
Expand Down Expand Up @@ -1014,10 +1051,9 @@ var gZenKeyboardShortcutsManager = {
async init() {
if (this.inBrowserView) {
const loadedShortcuts = await this._loadSaved();

this._currentShortcutList = this.versioner.fixedKeyboardShortcuts(loadedShortcuts);
this.versioner = new nsZenKeyboardShortcutsVersioner(loadedShortcuts);
this._currentShortcutList = this.versioner.fixedKeyboardShortcuts(loadedShortcuts) || [];
this._applyShortcuts();

await this._saveShortcuts();
}
},
Expand Down Expand Up @@ -1262,4 +1298,4 @@ document.addEventListener(
}
},
{ once: true }
);
);
2 changes: 1 addition & 1 deletion src/zen/workspaces/ZenWorkspaces.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2949,4 +2949,4 @@ var gZenWorkspaces = new (class extends ZenMultiWindowFeature {
document.getElementById('cmd_closeWindow').doCommand();
}
}
})();
})();