diff --git a/src/_locales/dict.browser.json b/src/_locales/dict.browser.json index 31efe5f8..97b2d453 100644 --- a/src/_locales/dict.browser.json +++ b/src/_locales/dict.browser.json @@ -93,6 +93,12 @@ "zh_TW": "切換到下一個面板", "ja": "次のパネルに切り替え" }, + "KbLoopPanelsForwards": { + "en": "Loop through all panels (Forwards)" + }, + "KbLoopPanelsBackwards": { + "en": "Loop through all panels (Backwards)" + }, "KbPrevPanel": { "en": "Switch to previous panel", "de": "Zum vorherigen Panel wechseln", diff --git a/src/_locales/dict.setup-page.ts b/src/_locales/dict.setup-page.ts index 995d1875..4c8e0658 100644 --- a/src/_locales/dict.setup-page.ts +++ b/src/_locales/dict.setup-page.ts @@ -1202,7 +1202,7 @@ export const setupPageTranslations: Translations = { en: 'Required for:\n- Cleaning cookies\n- Proxy and URL rules of containers\n- Screenshots for the group page and windows selection panel\n- Changing the User-Agent per container', de: 'Benötigt für:\n- Cookies löschen\n- Proxy- und URL-Regeln für Umgebungen\n- Bildschirmfotos für die Gruppenseite und das Fensterauswahlmenü\n- User-Agent per Umgebung ändern', hu: 'A következő funkciókhoz szükséges:\n– Sütik törlése\n– A konténerek proxy- és URL-szabályainak beállítása\n– Képernyőképek a csoportoldalhoz és az ablakválasztóhoz\n– Konténerenkénti böngészőazonosító megadása', - pl: 'Wymagane dla:\n- Czyszczenia ciasteczek\n- Zasady proxy i URL dla kontenerów\n- Zrzuty ekranu dla grup stron i panelu zaznaczenia okna\n- Zmiana User-Agent\'a dla kontenera', + pl: "Wymagane dla:\n- Czyszczenia ciasteczek\n- Zasady proxy i URL dla kontenerów\n- Zrzuty ekranu dla grup stron i panelu zaznaczenia okna\n- Zmiana User-Agent'a dla kontenera", ru: 'Необходимо для:\n- Удаления cookies\n- Прокси и url-правил контейнеров\n- Скриншотов на групповой странице и на панели выбора окна', zh_CN: '用于:\n- 清除 Cookie\n- 容器的代理和 URL 规则\n- 分组页面和窗口选择面板的缩略图\n- 更改每个容器的用户代理', @@ -5383,7 +5383,7 @@ Przykłady: "*", "ctrl+$", "ctrl+alt+g"`, %Y - Jahr; %M - Monat; %D - Tag; %h - Stunde; %m - Minute; %s - Sekunde`, hu: `Megjegyzés: az elérési út a letöltések mappájához képest relatív. %Y: év; %M: hónap; %D: nap; %h: óra; %m: perc; %s: másodperc`, - pl: `Info: Ścieżka jest relatywna do folderu pobrane i Firefox nie pozwala ustawić ścieżki poza nim. + pl: `Info: Ścieżka jest relatywna do folderu pobrane i Firefox nie pozwala ustawić ścieżki poza nim. %Y - rok; %M - miesiąc; %D - dzień; %h - godzina; %m - minuta; %s - sekunda`, ru: `Примечание: Путь указывается относительно папки загрузок и Firefox не позволяет устанавливать путь за ее пределами. %Y - год; %M - месяц; %D - день; %h - час; %m - минута; %s - секунда`, @@ -5980,6 +5980,9 @@ Przykłady: "*", "ctrl+$", "ctrl+alt+g"`, zh_TW: '切換面板', ja: 'パネル間の切り替え', }, + 'settings.kb_switching_panel.ignore_hidden': { + en: 'Ignore hidden panels', + }, 'settings.kb_scroll_active_panel': { en: 'Scrolling the active panel', de: 'Scrollen des aktiven Panels', diff --git a/src/defaults/settings.ts b/src/defaults/settings.ts index bebbab0f..5aa4c076 100644 --- a/src/defaults/settings.ts +++ b/src/defaults/settings.ts @@ -248,6 +248,7 @@ export const DEFAULT_SETTINGS: SettingsState = { // Keybindings selectActiveTabFirst: true, + ignoreHiddenPanelsSwitching: false, } // prettier-ignore diff --git a/src/manifest.json b/src/manifest.json index 86e2b944..a3c60c81 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -64,6 +64,20 @@ }, "description": "__MSG_KbOpenSidebarPanel__" }, + "loop_panels_forwards": { + "suggested_key": { + "default": "Ctrl+Shift+D", + "mac": "MacCtrl+Shift+D" + }, + "description": "__MSG_KbLoopPanelsForwards__" + }, + "loop_panels_backwards": { + "suggested_key": { + "default": "Ctrl+Shift+A", + "mac": "MacCtrl+Shift+A" + }, + "description": "__MSG_KbLoopPanelsBackwards__" + }, "next_panel": { "suggested_key": { "default": "Alt+Period" diff --git a/src/page.setup/components/keybindings.vue b/src/page.setup/components/keybindings.vue index eba2fdd4..2fb7ccc6 100644 --- a/src/page.setup/components/keybindings.vue +++ b/src/page.setup/components/keybindings.vue @@ -14,7 +14,14 @@ section h2 {{translate('settings.kb_switching_panel')}} span.header-shadow - KeybindingField.-no-separator(:keybinding="Keybindings.reactive.byName.next_panel") + KeybindingField.-no-separator(:keybinding="Keybindings.reactive.byName.loop_panels_forwards") + .sub-fields + KeybindingField.-no-separator(:keybinding="Keybindings.reactive.byName.loop_panels_backwards") + ToggleField.-no-separator( + label="settings.kb_switching_panel.ignore_hidden" + v-model:value="Settings.state.ignoreHiddenPanelsSwitching" + @update:value="Settings.saveDebounced(150)") + KeybindingField(:keybinding="Keybindings.reactive.byName.next_panel") KeybindingField(:keybinding="Keybindings.reactive.byName.prev_panel") KeybindingField(:keybinding="Keybindings.reactive.byName.switch_to_panel_0") KeybindingField(:keybinding="Keybindings.reactive.byName.switch_to_panel_1") diff --git a/src/services/keybindings.actions.ts b/src/services/keybindings.actions.ts index 3b218254..7e2ca781 100644 --- a/src/services/keybindings.actions.ts +++ b/src/services/keybindings.actions.ts @@ -111,7 +111,11 @@ function onCmd(name: string): void { if (!kb) kb = Keybindings.reactive.list.find(k => k.name === name) if (!kb) return - if (name === 'next_panel') Sidebar.switchPanel(1, false, true) + if (name === 'loop_panels_forwards') + Sidebar.switchPanel(1, Settings.state.ignoreHiddenPanelsSwitching, true, undefined, true) + else if (name === 'loop_panels_backwards') + Sidebar.switchPanel(-1, Settings.state.ignoreHiddenPanelsSwitching, true, undefined, true) + else if (name === 'next_panel') Sidebar.switchPanel(1, false, true) else if (name === 'prev_panel') Sidebar.switchPanel(-1, false, true) else if (name === 'new_tab_on_panel') onKeyNewTabInPanel() else if (name === 'new_tab_in_group') onKeyNewTabAfter() diff --git a/src/services/sidebar.actions.ts b/src/services/sidebar.actions.ts index 539b54b0..0ef84770 100644 --- a/src/services/sidebar.actions.ts +++ b/src/services/sidebar.actions.ts @@ -1264,7 +1264,8 @@ export function switchPanel( dir: 1 | -1, ignoreHidden?: boolean, withoutTabCreation?: boolean, - restartDebouncer?: boolean + restartDebouncer?: boolean, + shouldLoop?: boolean ): void { // Single panel switch const delay = Settings.state.navSwitchPanelsDelay ?? 128 @@ -1285,7 +1286,6 @@ export function switchPanel( Selection.resetSelection() const activePanelId = Sidebar.activePanelId - // If current active panel is not exist let activePanel = Sidebar.panelsById[activePanelId] if (!activePanel) { @@ -1334,13 +1334,22 @@ export function switchPanel( } } } - if (actIndex === -1) return if (hdnIndex === -1 || isInline) hdnIndex = visiblePanels.length let panel if (!actIsHidden) { for (let i = actIndex + dir; i >= 0 || i < visiblePanels.length; i += dir) { + if (shouldLoop && dir < 0 && actIndex === 0) { + if (ignoreHidden) { + panel = visiblePanels[visiblePanels.length - 1] + newActIsHidden = false + } else { + panel = hiddenPanels[hiddenPanels.length - 1] + newActIsHidden = true + } + break + } panel = visiblePanels[i] newActIsHidden = false if ((dir > 0 && i === hdnIndex) || (dir < 0 && i + 1 === hdnIndex)) { @@ -1350,6 +1359,9 @@ export function switchPanel( else panel = hiddenPanels[hiddenPanels.length - 1] newActIsHidden = true } + if (shouldLoop && ignoreHidden) { + panel = visiblePanels[0] + } break } if (!panel) break @@ -1363,9 +1375,10 @@ export function switchPanel( if (!panel) { if (visiblePanels.length) { panel = visiblePanels[dir > 0 ? hdnIndex : hdnIndex - 1] - if (!panel) break + if (!panel && !shouldLoop) break if (hiddenPanelsPopupIsShown) Sidebar.reactive.hiddenPanelsPopup = false newActIsHidden = false + if (shouldLoop) panel = visiblePanels[dir > 0 ? 0 : visiblePanels.length - 1] } break } diff --git a/src/types/settings.ts b/src/types/settings.ts index 8219decb..5c6abf92 100644 --- a/src/types/settings.ts +++ b/src/types/settings.ts @@ -251,4 +251,5 @@ export interface SettingsState { // Keybindings selectActiveTabFirst: boolean + ignoreHiddenPanelsSwitching: boolean }