feat(tabs): 添加标签页切换快捷键支持
This commit is contained in:
parent
c8a2292fe9
commit
a1d8594dca
|
|
@ -58,9 +58,12 @@ import {
|
|||
isResetZoomShortcut,
|
||||
isRefreshDataShortcut,
|
||||
isSaveShortcut,
|
||||
isSwitchToNextTabShortcut,
|
||||
isSwitchToPreviousTabShortcut,
|
||||
isToggleSidebarShortcut,
|
||||
isZoomInShortcut,
|
||||
isZoomOutShortcut,
|
||||
switchToTabIndexFromShortcut,
|
||||
} from "@/lib/keyboardShortcuts";
|
||||
import { isPreviewTab } from "@/lib/tabPresentation";
|
||||
import { supportsSqlFileExecution } from "@/lib/databaseCapabilities";
|
||||
|
|
@ -1161,10 +1164,37 @@ async function handleQuickOpenSelect(item: any) {
|
|||
}
|
||||
}
|
||||
|
||||
function dispatchBeforeTabSwitch(tabId: string) {
|
||||
if (tabId === queryStore.activeTabId) return;
|
||||
window.dispatchEvent(new CustomEvent("dbx:before-tab-switch", { detail: { tabId, fromTabId: queryStore.activeTabId } }));
|
||||
}
|
||||
|
||||
function activateQueryTab(tabId: string): boolean {
|
||||
if (!queryStore.tabs.some((tab) => tab.id === tabId)) return false;
|
||||
dispatchBeforeTabSwitch(tabId);
|
||||
queryStore.activeTabId = tabId;
|
||||
driverStoreActive.value = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function activateTabByIndex(index: number): boolean {
|
||||
const tab = queryStore.tabs[index];
|
||||
return tab ? activateQueryTab(tab.id) : false;
|
||||
}
|
||||
|
||||
function activateAdjacentTab(direction: -1 | 1): boolean {
|
||||
const count = queryStore.tabs.length;
|
||||
if (count < 2) return false;
|
||||
const currentIndex = queryStore.tabs.findIndex((tab) => tab.id === queryStore.activeTabId);
|
||||
const nextIndex = currentIndex < 0 ? (direction > 0 ? 0 : count - 1) : (currentIndex + direction + count) % count;
|
||||
return activateTabByIndex(nextIndex);
|
||||
}
|
||||
|
||||
function handleKeydown(e: KeyboardEvent) {
|
||||
if (e.defaultPrevented) return;
|
||||
|
||||
const shortcuts = settingsStore.editorSettings.shortcuts;
|
||||
const switchTabIndex = switchToTabIndexFromShortcut(e, shortcuts);
|
||||
|
||||
if (isOpenSettingsShortcut(e, shortcuts)) {
|
||||
e.preventDefault();
|
||||
|
|
@ -1204,6 +1234,27 @@ function handleKeydown(e: KeyboardEvent) {
|
|||
setSidebarOpen(!sidebarOpen.value);
|
||||
return;
|
||||
}
|
||||
if (switchTabIndex != null) {
|
||||
if (activateTabByIndex(switchTabIndex)) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (isSwitchToPreviousTabShortcut(e, shortcuts)) {
|
||||
if (activateAdjacentTab(-1)) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (isSwitchToNextTabShortcut(e, shortcuts)) {
|
||||
if (activateAdjacentTab(1)) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (isCloseTabShortcut(e, shortcuts)) {
|
||||
e.preventDefault();
|
||||
if (showDriverStore.value) {
|
||||
|
|
|
|||
|
|
@ -2694,6 +2694,17 @@ export default {
|
|||
shortcutCloseTab: "Close tab",
|
||||
shortcutFocusSearch: "Focus search",
|
||||
shortcutQuickOpen: "Quick open (search all database objects)",
|
||||
shortcutSwitchToPreviousTab: "Switch to previous tab",
|
||||
shortcutSwitchToNextTab: "Switch to next tab",
|
||||
shortcutSwitchToTab1: "Switch to tab 1",
|
||||
shortcutSwitchToTab2: "Switch to tab 2",
|
||||
shortcutSwitchToTab3: "Switch to tab 3",
|
||||
shortcutSwitchToTab4: "Switch to tab 4",
|
||||
shortcutSwitchToTab5: "Switch to tab 5",
|
||||
shortcutSwitchToTab6: "Switch to tab 6",
|
||||
shortcutSwitchToTab7: "Switch to tab 7",
|
||||
shortcutSwitchToTab8: "Switch to tab 8",
|
||||
shortcutSwitchToTab9: "Switch to tab 9",
|
||||
shortcutZoomInUi: "Zoom in UI",
|
||||
shortcutZoomOutUi: "Zoom out UI",
|
||||
shortcutResetUiZoom: "Reset UI zoom",
|
||||
|
|
|
|||
|
|
@ -2689,6 +2689,17 @@ export default withEnglishFallback({
|
|||
shortcutToggleSidebar: "Alternar barra lateral",
|
||||
shortcutFocusSearch: "Enfocar búsqueda",
|
||||
shortcutQuickOpen: "Abrir rápido (buscar todos los objetos de base de datos)",
|
||||
shortcutSwitchToPreviousTab: "Cambiar a la pestaña anterior",
|
||||
shortcutSwitchToNextTab: "Cambiar a la pestaña siguiente",
|
||||
shortcutSwitchToTab1: "Cambiar a la pestaña 1",
|
||||
shortcutSwitchToTab2: "Cambiar a la pestaña 2",
|
||||
shortcutSwitchToTab3: "Cambiar a la pestaña 3",
|
||||
shortcutSwitchToTab4: "Cambiar a la pestaña 4",
|
||||
shortcutSwitchToTab5: "Cambiar a la pestaña 5",
|
||||
shortcutSwitchToTab6: "Cambiar a la pestaña 6",
|
||||
shortcutSwitchToTab7: "Cambiar a la pestaña 7",
|
||||
shortcutSwitchToTab8: "Cambiar a la pestaña 8",
|
||||
shortcutSwitchToTab9: "Cambiar a la pestaña 9",
|
||||
shortcutZoomInUi: "Ampliar interfaz",
|
||||
shortcutZoomOutUi: "Reducir interfaz",
|
||||
shortcutResetUiZoom: "Restablecer zoom de interfaz",
|
||||
|
|
|
|||
|
|
@ -2692,6 +2692,17 @@ export default withEnglishFallback({
|
|||
shortcutToggleSidebar: "Attiva/disattiva barra laterale",
|
||||
shortcutFocusSearch: "Focalizza ricerca",
|
||||
shortcutQuickOpen: "Apertura rapida (ricerca tutti gli oggetti del database)",
|
||||
shortcutSwitchToPreviousTab: "Passa alla scheda precedente",
|
||||
shortcutSwitchToNextTab: "Passa alla scheda successiva",
|
||||
shortcutSwitchToTab1: "Passa alla scheda 1",
|
||||
shortcutSwitchToTab2: "Passa alla scheda 2",
|
||||
shortcutSwitchToTab3: "Passa alla scheda 3",
|
||||
shortcutSwitchToTab4: "Passa alla scheda 4",
|
||||
shortcutSwitchToTab5: "Passa alla scheda 5",
|
||||
shortcutSwitchToTab6: "Passa alla scheda 6",
|
||||
shortcutSwitchToTab7: "Passa alla scheda 7",
|
||||
shortcutSwitchToTab8: "Passa alla scheda 8",
|
||||
shortcutSwitchToTab9: "Passa alla scheda 9",
|
||||
shortcutZoomInUi: "Ingrandisci UI",
|
||||
shortcutZoomOutUi: "Rimpicciolisci UI",
|
||||
shortcutResetUiZoom: "Reimposta zoom UI",
|
||||
|
|
|
|||
|
|
@ -2674,6 +2674,17 @@ export default withEnglishFallback({
|
|||
shortcutCloseTab: "タブを閉じる",
|
||||
shortcutFocusSearch: "検索にフォーカス",
|
||||
shortcutQuickOpen: "クイックオープン (すべてのデータベースオブジェクトを検索)",
|
||||
shortcutSwitchToPreviousTab: "前のタブに切り替え",
|
||||
shortcutSwitchToNextTab: "次のタブに切り替え",
|
||||
shortcutSwitchToTab1: "タブ 1 に切り替え",
|
||||
shortcutSwitchToTab2: "タブ 2 に切り替え",
|
||||
shortcutSwitchToTab3: "タブ 3 に切り替え",
|
||||
shortcutSwitchToTab4: "タブ 4 に切り替え",
|
||||
shortcutSwitchToTab5: "タブ 5 に切り替え",
|
||||
shortcutSwitchToTab6: "タブ 6 に切り替え",
|
||||
shortcutSwitchToTab7: "タブ 7 に切り替え",
|
||||
shortcutSwitchToTab8: "タブ 8 に切り替え",
|
||||
shortcutSwitchToTab9: "タブ 9 に切り替え",
|
||||
shortcutZoomInUi: "UIを拡大",
|
||||
shortcutZoomOutUi: "UIを縮小",
|
||||
shortcutResetUiZoom: "UIズームをリセット",
|
||||
|
|
|
|||
|
|
@ -2701,6 +2701,17 @@ export default withEnglishFallback({
|
|||
shortcutToggleSidebar: "Alternar barra lateral",
|
||||
shortcutFocusSearch: "Focar na pesquisa",
|
||||
shortcutQuickOpen: "Abrir rapidamente (pesquisar todos os objetos do banco de dados)",
|
||||
shortcutSwitchToPreviousTab: "Alternar para a aba anterior",
|
||||
shortcutSwitchToNextTab: "Alternar para a próxima aba",
|
||||
shortcutSwitchToTab1: "Alternar para a aba 1",
|
||||
shortcutSwitchToTab2: "Alternar para a aba 2",
|
||||
shortcutSwitchToTab3: "Alternar para a aba 3",
|
||||
shortcutSwitchToTab4: "Alternar para a aba 4",
|
||||
shortcutSwitchToTab5: "Alternar para a aba 5",
|
||||
shortcutSwitchToTab6: "Alternar para a aba 6",
|
||||
shortcutSwitchToTab7: "Alternar para a aba 7",
|
||||
shortcutSwitchToTab8: "Alternar para a aba 8",
|
||||
shortcutSwitchToTab9: "Alternar para a aba 9",
|
||||
shortcutZoomInUi: "Aumentar zoom da UI",
|
||||
shortcutZoomOutUi: "Diminuir zoom da UI",
|
||||
shortcutResetUiZoom: "Redefinir zoom da UI",
|
||||
|
|
|
|||
|
|
@ -2702,6 +2702,17 @@ export default withEnglishFallback({
|
|||
shortcutToggleSidebar: "切换侧边栏",
|
||||
shortcutFocusSearch: "聚焦搜索",
|
||||
shortcutQuickOpen: "快速打开 (搜索所有数据库对象)",
|
||||
shortcutSwitchToPreviousTab: "切换到左侧标签页",
|
||||
shortcutSwitchToNextTab: "切换到右侧标签页",
|
||||
shortcutSwitchToTab1: "切换到第 1 个标签页",
|
||||
shortcutSwitchToTab2: "切换到第 2 个标签页",
|
||||
shortcutSwitchToTab3: "切换到第 3 个标签页",
|
||||
shortcutSwitchToTab4: "切换到第 4 个标签页",
|
||||
shortcutSwitchToTab5: "切换到第 5 个标签页",
|
||||
shortcutSwitchToTab6: "切换到第 6 个标签页",
|
||||
shortcutSwitchToTab7: "切换到第 7 个标签页",
|
||||
shortcutSwitchToTab8: "切换到第 8 个标签页",
|
||||
shortcutSwitchToTab9: "切换到第 9 个标签页",
|
||||
shortcutZoomInUi: "放大全局界面",
|
||||
shortcutZoomOutUi: "缩小全局界面",
|
||||
shortcutResetUiZoom: "重置全局界面缩放",
|
||||
|
|
|
|||
|
|
@ -2579,6 +2579,17 @@ export default withEnglishFallback({
|
|||
shortcutToggleSidebar: "切換側邊欄",
|
||||
shortcutFocusSearch: "聚焦搜尋",
|
||||
shortcutQuickOpen: "快速開啟 (搜尋所有資料庫物件)",
|
||||
shortcutSwitchToPreviousTab: "切換到左側分頁",
|
||||
shortcutSwitchToNextTab: "切換到右側分頁",
|
||||
shortcutSwitchToTab1: "切換到第 1 個分頁",
|
||||
shortcutSwitchToTab2: "切換到第 2 個分頁",
|
||||
shortcutSwitchToTab3: "切換到第 3 個分頁",
|
||||
shortcutSwitchToTab4: "切換到第 4 個分頁",
|
||||
shortcutSwitchToTab5: "切換到第 5 個分頁",
|
||||
shortcutSwitchToTab6: "切換到第 6 個分頁",
|
||||
shortcutSwitchToTab7: "切換到第 7 個分頁",
|
||||
shortcutSwitchToTab8: "切換到第 8 個分頁",
|
||||
shortcutSwitchToTab9: "切換到第 9 個分頁",
|
||||
shortcutZoomInUi: "放大全域介面",
|
||||
shortcutZoomOutUi: "縮小全域介面",
|
||||
shortcutResetUiZoom: "重設全域介面縮放",
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ function actionShortcut(actionId: ShortcutActionId, shortcuts?: Partial<Shortcut
|
|||
return normalizeShortcutSettings(shortcuts)[actionId];
|
||||
}
|
||||
|
||||
const SWITCH_TO_TAB_ACTIONS: ShortcutActionId[] = ["switchToTab1", "switchToTab2", "switchToTab3", "switchToTab4", "switchToTab5", "switchToTab6", "switchToTab7", "switchToTab8", "switchToTab9"];
|
||||
|
||||
export function isExecuteSqlShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): boolean {
|
||||
return matchesShortcut(event, actionShortcut("executeSql", shortcuts));
|
||||
}
|
||||
|
|
@ -148,6 +150,20 @@ export function isQuickOpenShortcut(event: ShortcutLikeEvent, shortcuts?: Partia
|
|||
return matchesShortcut(event, actionShortcut("quickOpen", shortcuts));
|
||||
}
|
||||
|
||||
export function isSwitchToPreviousTabShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): boolean {
|
||||
return matchesShortcut(event, actionShortcut("switchToPreviousTab", shortcuts));
|
||||
}
|
||||
|
||||
export function isSwitchToNextTabShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): boolean {
|
||||
return matchesShortcut(event, actionShortcut("switchToNextTab", shortcuts));
|
||||
}
|
||||
|
||||
export function switchToTabIndexFromShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): number | null {
|
||||
const normalized = normalizeShortcutSettings(shortcuts);
|
||||
const index = SWITCH_TO_TAB_ACTIONS.findIndex((actionId) => matchesShortcut(event, normalized[actionId]));
|
||||
return index >= 0 ? index : null;
|
||||
}
|
||||
|
||||
export function isBrowserReloadShortcut(event: ShortcutLikeEvent): boolean {
|
||||
if (event.isComposing || event.altKey) return false;
|
||||
const key = normalizeKey(event.key);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,17 @@ export type ShortcutActionId =
|
|||
| "closeTab"
|
||||
| "focusSearch"
|
||||
| "quickOpen"
|
||||
| "switchToPreviousTab"
|
||||
| "switchToNextTab"
|
||||
| "switchToTab1"
|
||||
| "switchToTab2"
|
||||
| "switchToTab3"
|
||||
| "switchToTab4"
|
||||
| "switchToTab5"
|
||||
| "switchToTab6"
|
||||
| "switchToTab7"
|
||||
| "switchToTab8"
|
||||
| "switchToTab9"
|
||||
| "zoomInUi"
|
||||
| "zoomOutUi"
|
||||
| "resetUiZoom"
|
||||
|
|
@ -175,6 +186,72 @@ export const SHORTCUT_DEFINITIONS: ShortcutDefinition[] = [
|
|||
scope: "global",
|
||||
defaultShortcut: "Mod+P",
|
||||
},
|
||||
{
|
||||
id: "switchToPreviousTab",
|
||||
labelKey: "settings.shortcutSwitchToPreviousTab",
|
||||
scope: "global",
|
||||
defaultShortcut: "Shift+Mod+[",
|
||||
},
|
||||
{
|
||||
id: "switchToNextTab",
|
||||
labelKey: "settings.shortcutSwitchToNextTab",
|
||||
scope: "global",
|
||||
defaultShortcut: "Shift+Mod+]",
|
||||
},
|
||||
{
|
||||
id: "switchToTab1",
|
||||
labelKey: "settings.shortcutSwitchToTab1",
|
||||
scope: "global",
|
||||
defaultShortcut: "Mod+1",
|
||||
},
|
||||
{
|
||||
id: "switchToTab2",
|
||||
labelKey: "settings.shortcutSwitchToTab2",
|
||||
scope: "global",
|
||||
defaultShortcut: "Mod+2",
|
||||
},
|
||||
{
|
||||
id: "switchToTab3",
|
||||
labelKey: "settings.shortcutSwitchToTab3",
|
||||
scope: "global",
|
||||
defaultShortcut: "Mod+3",
|
||||
},
|
||||
{
|
||||
id: "switchToTab4",
|
||||
labelKey: "settings.shortcutSwitchToTab4",
|
||||
scope: "global",
|
||||
defaultShortcut: "Mod+4",
|
||||
},
|
||||
{
|
||||
id: "switchToTab5",
|
||||
labelKey: "settings.shortcutSwitchToTab5",
|
||||
scope: "global",
|
||||
defaultShortcut: "Mod+5",
|
||||
},
|
||||
{
|
||||
id: "switchToTab6",
|
||||
labelKey: "settings.shortcutSwitchToTab6",
|
||||
scope: "global",
|
||||
defaultShortcut: "Mod+6",
|
||||
},
|
||||
{
|
||||
id: "switchToTab7",
|
||||
labelKey: "settings.shortcutSwitchToTab7",
|
||||
scope: "global",
|
||||
defaultShortcut: "Mod+7",
|
||||
},
|
||||
{
|
||||
id: "switchToTab8",
|
||||
labelKey: "settings.shortcutSwitchToTab8",
|
||||
scope: "global",
|
||||
defaultShortcut: "Mod+8",
|
||||
},
|
||||
{
|
||||
id: "switchToTab9",
|
||||
labelKey: "settings.shortcutSwitchToTab9",
|
||||
scope: "global",
|
||||
defaultShortcut: "Mod+9",
|
||||
},
|
||||
{
|
||||
id: "zoomInUi",
|
||||
labelKey: "settings.shortcutZoomInUi",
|
||||
|
|
|
|||
|
|
@ -14,11 +14,14 @@ import {
|
|||
isResetZoomShortcut,
|
||||
isRefreshDataShortcut,
|
||||
isSaveShortcut,
|
||||
isSwitchToNextTabShortcut,
|
||||
isSwitchToPreviousTabShortcut,
|
||||
isCopyCurrentRowShortcut,
|
||||
isDeleteCurrentRowShortcut,
|
||||
isToggleTransposeShortcut,
|
||||
isZoomInShortcut,
|
||||
isZoomOutShortcut,
|
||||
switchToTabIndexFromShortcut,
|
||||
} from "../../apps/desktop/src/lib/keyboardShortcuts.ts";
|
||||
import { shortcutToCodeMirrorKey } from "../../apps/desktop/src/lib/shortcutRegistry.ts";
|
||||
|
||||
|
|
@ -58,6 +61,37 @@ test("matches Cmd+T for opening a new query", () => {
|
|||
assert.equal(isNewQueryShortcut({ key: "t", metaKey: true }), true);
|
||||
});
|
||||
|
||||
test("matches Shift+Mod+brackets for switching adjacent tabs", () => {
|
||||
assert.equal(isSwitchToPreviousTabShortcut({ key: "[", metaKey: true, shiftKey: true }), true);
|
||||
assert.equal(isSwitchToPreviousTabShortcut({ key: "[", ctrlKey: true, shiftKey: true }), true);
|
||||
assert.equal(isSwitchToNextTabShortcut({ key: "]", metaKey: true, shiftKey: true }), true);
|
||||
assert.equal(isSwitchToNextTabShortcut({ key: "]", ctrlKey: true, shiftKey: true }), true);
|
||||
assert.equal(isSwitchToPreviousTabShortcut({ key: "[", metaKey: true }), false);
|
||||
assert.equal(isSwitchToNextTabShortcut({ key: "]", metaKey: true }), false);
|
||||
});
|
||||
|
||||
test("matches Mod+number for switching to numbered tabs", () => {
|
||||
assert.equal(switchToTabIndexFromShortcut({ key: "1", metaKey: true }), 0);
|
||||
assert.equal(switchToTabIndexFromShortcut({ key: "5", ctrlKey: true }), 4);
|
||||
assert.equal(switchToTabIndexFromShortcut({ key: "9", metaKey: true }), 8);
|
||||
assert.equal(switchToTabIndexFromShortcut({ key: "0", metaKey: true }), null);
|
||||
assert.equal(switchToTabIndexFromShortcut({ key: "1", metaKey: true, altKey: true }), null);
|
||||
});
|
||||
|
||||
test("matches custom shortcut settings for tab switching", () => {
|
||||
const shortcuts = {
|
||||
switchToPreviousTab: "Alt+ArrowLeft",
|
||||
switchToNextTab: "Alt+ArrowRight",
|
||||
switchToTab3: "Shift+Mod+3",
|
||||
} as any;
|
||||
|
||||
assert.equal(isSwitchToPreviousTabShortcut({ key: "[", metaKey: true }, shortcuts), false);
|
||||
assert.equal(isSwitchToPreviousTabShortcut({ key: "ArrowLeft", altKey: true }, shortcuts), true);
|
||||
assert.equal(isSwitchToNextTabShortcut({ key: "ArrowRight", altKey: true }, shortcuts), true);
|
||||
assert.equal(switchToTabIndexFromShortcut({ key: "3", metaKey: true }, shortcuts), null);
|
||||
assert.equal(switchToTabIndexFromShortcut({ key: "3", metaKey: true, shiftKey: true }, shortcuts), 2);
|
||||
});
|
||||
|
||||
test("matches custom shortcut settings for opening a new query", () => {
|
||||
assert.equal(isNewQueryShortcut({ key: "t", metaKey: true }, { newQuery: "Shift+Mod+N" } as any), false);
|
||||
assert.equal(isNewQueryShortcut({ key: "n", ctrlKey: true, shiftKey: true } as any, { newQuery: "Shift+Mod+N" } as any), true);
|
||||
|
|
|
|||
Loading…
Reference in New Issue