diff --git a/src/ZenKeyboardShortcuts.mjs b/src/ZenKeyboardShortcuts.mjs
index ea62b6a..8559d3e 100644
--- a/src/ZenKeyboardShortcuts.mjs
+++ b/src/ZenKeyboardShortcuts.mjs
@@ -3,573 +3,518 @@ const kZKSActions = {
// otherwise "oncommand=" will be added.
// Split view actions
- zenSplitViewGrid: [
- "gZenViewSplitter.toggleShortcut('grid')",
- "zen-split-view-grid",
- "split-view-action",
- ],
- zenSplitViewVertical: [
- "gZenViewSplitter.toggleShortcut('vsep')",
- "zen-split-view-vertical",
- "split-view-action",
- ],
- zenSplitViewHorizontal: [
- "gZenViewSplitter.toggleShortcut('hsep')",
- "zen-split-view-horizontal",
- "split-view-action",
- ],
- zenSplitViewClose: [
- "gZenViewSplitter.toggleShortcut('unsplit')",
- "zen-split-view-close",
- "split-view-action",
- ],
+ zenSplitViewGrid: ["gZenViewSplitter.toggleShortcut('grid')", 'zen-split-view-grid', 'split-view-action'],
+ zenSplitViewVertical: ["gZenViewSplitter.toggleShortcut('vsep')", 'zen-split-view-vertical', 'split-view-action'],
+ zenSplitViewHorizontal: ["gZenViewSplitter.toggleShortcut('hsep')", 'zen-split-view-horizontal', 'split-view-action'],
+ zenSplitViewClose: ["gZenViewSplitter.toggleShortcut('unsplit')", 'zen-split-view-close', 'split-view-action'],
// Workspace actions
- zenChangeWorkspace: [
- "ZenWorkspaces.changeWorkspaceShortcut()",
- "zen-change-workspace",
- "workspace-action",
- ],
+ zenChangeWorkspace: ['ZenWorkspaces.changeWorkspaceShortcut()', 'zen-change-workspace', 'workspace-action'],
// manage actions
- openNewTab: [
- "command:cmd_newNavigatorTabNoEvent",
- "open-new-tab",
- "tab-action",
- ],
- duplicateTab: [
- "duplicateTabIn(gBrowser.selectedTab, 'tab')",
- "duplicate-tab",
- "tab-action",
- ],
- closeTab: ["command:cmd_close", "close-tab", "tab-action"],
- openNewWindow: ["command:cmd_newNavigator", "open-new-window", "tab-action"],
- openNewPrivateWindow: [
- "command:Tools:PrivateBrowsing",
- "open-new-private-window",
- "tab-action",
- ],
- closeWindow: ["command:cmd_closeWindow", "close-window", "tab-action"],
- restoreLastTab: ["undoCloseTab()", "restore-last-session", "tab-action"],
- restoreLastWindow: [
- "command:History:UndoCloseWindow",
- "restore-last-window",
- "tab-action",
- ],
- showNextTab: [
- "gBrowser.tabContainer.advanceSelectedTab(1, true)",
- "show-next-tab",
- "tab-action",
- ],
- showPreviousTab: [
- "gBrowser.tabContainer.advanceSelectedTab(-1, true)",
- "show-previous-tab",
- "tab-action",
- ],
- showAllTabsPanel: [
- "gTabsPanel.showAllTabsPanel()",
- "show-all-tabs-panel",
- "tab-action",
- ],
+ openNewTab: ['command:cmd_newNavigatorTabNoEvent', 'open-new-tab', 'tab-action'],
+ duplicateTab: ["duplicateTabIn(gBrowser.selectedTab, 'tab')", 'duplicate-tab', 'tab-action'],
+ closeTab: ['command:cmd_close', 'close-tab', 'tab-action'],
+ openNewWindow: ['command:cmd_newNavigator', 'open-new-window', 'tab-action'],
+ openNewPrivateWindow: ['command:Tools:PrivateBrowsing', 'open-new-private-window', 'tab-action'],
+ closeWindow: ['command:cmd_closeWindow', 'close-window', 'tab-action'],
+ restoreLastTab: ['undoCloseTab()', 'restore-last-session', 'tab-action'],
+ restoreLastWindow: ['command:History:UndoCloseWindow', 'restore-last-window', 'tab-action'],
+ showNextTab: ['gBrowser.tabContainer.advanceSelectedTab(1, true)', 'show-next-tab', 'tab-action'],
+ showPreviousTab: ['gBrowser.tabContainer.advanceSelectedTab(-1, true)', 'show-previous-tab', 'tab-action'],
+ showAllTabsPanel: ['gTabsPanel.showAllTabsPanel()', 'show-all-tabs-panel', 'tab-action'],
// Compact mode actions
- zenToggleCompactMode: [
- "gZenCompactModeManager.toggle()",
- "zen-toggle-compact-mode",
- "compact-mode-action",
- ],
+ zenToggleCompactMode: ['gZenCompactModeManager.toggle()', 'zen-toggle-compact-mode', 'compact-mode-action'],
zenToggleCompactModeSidebar: [
- "gZenCompactModeManager.toggleSidebar()",
- "zen-toggle-compact-mode-sidebar",
- "compact-mode-action",
+ 'gZenCompactModeManager.toggleSidebar()',
+ 'zen-toggle-compact-mode-sidebar',
+ 'compact-mode-action',
],
zenToggleCompactModeToolbar: [
- "gZenCompactModeManager.toggleToolbar()",
- "zen-toggle-compact-mode-toolbar",
- "compact-mode-action",
+ 'gZenCompactModeManager.toggleToolbar()',
+ 'zen-toggle-compact-mode-toolbar',
+ 'compact-mode-action',
],
// Page actions
- sendWithMail: ["command:Browser:SendLink", "send-with-mail", "page-action"],
- savePage: ["command:Browser:SavePage", "save-page", "page-action"],
- printPage: ["command:cmd_print", "print-page", "page-action"],
- muteCurrentTab: ["command:cmd_toggleMute", "mute-current-tab", "page-action"],
- showSourceOfPage: [
- "command:View:PageSource",
- "show-source-of-page",
- "page-action",
- ],
- showPageInfo: ["command:View:PageInfo", "show-page-info", "page-action"],
+ sendWithMail: ['command:Browser:SendLink', 'send-with-mail', 'page-action'],
+ savePage: ['command:Browser:SavePage', 'save-page', 'page-action'],
+ printPage: ['command:cmd_print', 'print-page', 'page-action'],
+ muteCurrentTab: ['command:cmd_toggleMute', 'mute-current-tab', 'page-action'],
+ showSourceOfPage: ['command:View:PageSource', 'show-source-of-page', 'page-action'],
+ showPageInfo: ['command:View:PageInfo', 'show-page-info', 'page-action'],
// Visible actions
- zoomIn: ["command:cmd_fullZoomEnlarge", "zoom-in", "visible-action"],
- zoomOut: ["command:cmd_fullZoomReduce", "zoom-out", "visible-action"],
- resetZoom: ["command:cmd_fullZoomReset", "reset-zoom", "visible-action"],
+ zoomIn: ['command:cmd_fullZoomEnlarge', 'zoom-in', 'visible-action'],
+ zoomOut: ['command:cmd_fullZoomReduce', 'zoom-out', 'visible-action'],
+ resetZoom: ['command:cmd_fullZoomReset', 'reset-zoom', 'visible-action'],
// History actions
- back: ["command:Browser:Back", "back", "history-action"],
- forward: ["command:Browser:Forward", "forward", "history-action"],
- stop: ["command:Browser:Stop", "stop", "history-action"],
- reload: ["command:Browser:Reload", "reload", "history-action"],
- forceReload: [
- "command:Browser:ReloadSkipCache",
- "force-reload",
- "history-action",
- ],
+ back: ['command:Browser:Back', 'back', 'history-action'],
+ forward: ['command:Browser:Forward', 'forward', 'history-action'],
+ stop: ['command:Browser:Stop', 'stop', 'history-action'],
+ reload: ['command:Browser:Reload', 'reload', 'history-action'],
+ forceReload: ['command:Browser:ReloadSkipCache', 'force-reload', 'history-action'],
// search actions
- searchInThisPage: [
- "gLazyFindCommand('onFindCommand')",
- "search-in-this-page",
- "search-action",
- ],
- showNextSearchResult: [
- "gLazyFindCommand('onFindAgainCommand', false)",
- "show-next-search-result",
- "search-action",
- ],
- showPreviousSearchResult: [
- "gLazyFindCommand('onFindAgainCommand', true)",
- "show-previous-search-result",
- "search-action",
- ],
- searchTheWeb: ["command:Tools:Search", "search-the-web", "search-action"],
+ searchInThisPage: ["gLazyFindCommand('onFindCommand')", 'search-in-this-page', 'search-action'],
+ showNextSearchResult: ["gLazyFindCommand('onFindAgainCommand', false)", 'show-next-search-result', 'search-action'],
+ showPreviousSearchResult: ["gLazyFindCommand('onFindAgainCommand', true)", 'show-previous-search-result', 'search-action'],
+ searchTheWeb: ['command:Tools:Search', 'search-the-web', 'search-action'],
// Tools actions
- openMigrationWizard: [
- "command:cmd_file_importFromAnotherBrowser",
- "open-migration-wizard",
- "tools-action",
- ],
- quitFromApplication: [
- "command:goQuitApplication",
- "quit-from-application",
- "tools-action",
- ],
- enterIntoCustomizeMode: [
- "gCustomizeMode.enter()",
- "enter-into-customize-mode",
- "tools-action",
- ],
- enterIntoOfflineMode: [
- "command:cmd_toggleOfflineStatus",
- "enter-into-offline-mode",
- "tools-action",
- ],
- openScreenCapture: [
- "command:Browser:Screenshot",
- "open-screen-capture",
- "tools-action",
- ],
+ openMigrationWizard: ['command:cmd_file_importFromAnotherBrowser', 'open-migration-wizard', 'tools-action'],
+ quitFromApplication: ['command:goQuitApplication', 'quit-from-application', 'tools-action'],
+ enterIntoCustomizeMode: ['gCustomizeMode.enter()', 'enter-into-customize-mode', 'tools-action'],
+ enterIntoOfflineMode: ['command:cmd_toggleOfflineStatus', 'enter-into-offline-mode', 'tools-action'],
+ openScreenCapture: ['command:Browser:Screenshot', 'open-screen-capture', 'tools-action'],
// Bookmark actions
bookmarkThisPage: [
"BrowserPageActions.doCommandForAction(PageActions.actionForID('bookmark'), event, this);",
- "bookmark-this-page",
- "bookmark-action",
+ 'bookmark-this-page',
+ 'bookmark-action',
],
openBookmarkAddTool: [
- "PlacesUIUtils.showBookmarkPagesDialog(PlacesCommandHook.uniqueCurrentPages)",
- "open-bookmark-add-tool",
- "bookmark-action",
- ],
- openBookmarksManager: [
- "SidebarController.toggle('viewBookmarksSidebar');",
- "open-bookmarks-manager",
- "bookmark-action",
+ 'PlacesUIUtils.showBookmarkPagesDialog(PlacesCommandHook.uniqueCurrentPages)',
+ 'open-bookmark-add-tool',
+ 'bookmark-action',
],
+ openBookmarksManager: ["SidebarController.toggle('viewBookmarksSidebar');", 'open-bookmarks-manager', 'bookmark-action'],
toggleBookmarkToolbar: [
"BookmarkingUI.toggleBookmarksToolbar('bookmark-tools')",
- "toggle-bookmark-toolbar",
- "bookmark-action",
+ 'toggle-bookmark-toolbar',
+ 'bookmark-action',
],
// Open Page actions
- openGeneralPreferences: [
- "openPreferences()",
- "open-general-preferences",
- "open-page-action",
- ],
- openPrivacyPreferences: [
- "openPreferences('panePrivacy')",
- "open-privacy-preferences",
- "open-page-action",
- ],
- openWorkspacesPreferences: [
- "openPreferences('paneWorkspaces')",
- "open-workspaces-preferences",
- "open-page-action",
- ],
- openContainersPreferences: [
- "openPreferences('paneContainers')",
- "open-containers-preferences",
- "open-page-action",
- ],
- openSearchPreferences: [
- "openPreferences('paneSearch')",
- "open-search-preferences",
- "open-page-action",
- ],
- openSyncPreferences: [
- "openPreferences('paneSync')",
- "open-sync-preferences",
- "open-page-action",
- ],
- openTaskManager: [
- "command:View:AboutProcesses",
- "open-task-manager",
- "open-page-action",
- ],
- openAddonsManager: [
- "command:Tools:Addons",
- "open-addons-manager",
- "open-page-action",
- ],
- openHomePage: ["BrowserHome()", "open-home-page", "open-page-action"],
+ openGeneralPreferences: ['openPreferences()', 'open-general-preferences', 'open-page-action'],
+ openPrivacyPreferences: ["openPreferences('panePrivacy')", 'open-privacy-preferences', 'open-page-action'],
+ openWorkspacesPreferences: ["openPreferences('paneWorkspaces')", 'open-workspaces-preferences', 'open-page-action'],
+ openContainersPreferences: ["openPreferences('paneContainers')", 'open-containers-preferences', 'open-page-action'],
+ openSearchPreferences: ["openPreferences('paneSearch')", 'open-search-preferences', 'open-page-action'],
+ openSyncPreferences: ["openPreferences('paneSync')", 'open-sync-preferences', 'open-page-action'],
+ openTaskManager: ['command:View:AboutProcesses', 'open-task-manager', 'open-page-action'],
+ openAddonsManager: ['command:Tools:Addons', 'open-addons-manager', 'open-page-action'],
+ openHomePage: ['BrowserHome()', 'open-home-page', 'open-page-action'],
// History actions
- forgetHistory: ["command:Tools:Sanitize", "forget-history", "history-action"],
- quickForgetHistory: [
- "PlacesUtils.history.clear(true)",
- "quick-forget-history",
- "history-action",
- ],
- clearRecentHistory: [
- "command:cmd_closeWindow",
- "clear-recent-history",
- "history-action",
- ],
- restoreLastSession: [
- "command:Browser:RestoreLastSession",
- "restore-last-session",
- "history-action",
- ],
- searchHistory: [
- "command:History:SearchHistory",
- "search-history",
- "history-action",
- ],
- manageHistory: [
- "PlacesCommandHook.showPlacesOrganizer('History')",
- "manage-history",
- "history-action",
- ],
+ forgetHistory: ['command:Tools:Sanitize', 'forget-history', 'history-action'],
+ quickForgetHistory: ['PlacesUtils.history.clear(true)', 'quick-forget-history', 'history-action'],
+ clearRecentHistory: ['command:cmd_closeWindow', 'clear-recent-history', 'history-action'],
+ restoreLastSession: ['command:Browser:RestoreLastSession', 'restore-last-session', 'history-action'],
+ searchHistory: ['command:History:SearchHistory', 'search-history', 'history-action'],
+ manageHistory: ["PlacesCommandHook.showPlacesOrganizer('History')", 'manage-history', 'history-action'],
// Downloads actions
- openDownloads: [
- "DownloadsPanel.showDownloadsHistory()",
- "open-downloads",
- "downloads-action",
- ],
+ openDownloads: ['DownloadsPanel.showDownloadsHistory()', 'open-downloads', 'downloads-action'],
// Sidebar actions
- showBookmarkSidebar: [
- "SidebarController.show('viewBookmarksSidebar')",
- "show-bookmark-sidebar",
- "sidebar-action",
- ],
- showHistorySidebar: [
- "SidebarController.show('viewHistorySidebar')",
- "show-history-sidebar",
- "sidebar-action",
- ],
- showSyncedTabsSidebar: [
- "SidebarController.show('viewTabsSidebar')",
- "show-synced-tabs-sidebar",
- "sidebar-action",
- ],
- reverseSidebarPosition: [
- "SidebarController.reversePosition()",
- "reverse-sidebar",
- "sidebar-action",
- ],
- hideSidebar: ["SidebarController.hide()", "hide-sidebar", "sidebar-action"],
- toggleSidebar: [
- "SidebarController.toggle()",
- "toggle-sidebar",
- "sidebar-action",
- ],
- zenToggleWebPanels: [
- "gZenBrowserManagerSidebar.toggle()",
- "zen-toggle-web-panels",
- "sidebar-action",
- ],
+ showBookmarkSidebar: ["SidebarController.show('viewBookmarksSidebar')", 'show-bookmark-sidebar', 'sidebar-action'],
+ showHistorySidebar: ["SidebarController.show('viewHistorySidebar')", 'show-history-sidebar', 'sidebar-action'],
+ showSyncedTabsSidebar: ["SidebarController.show('viewTabsSidebar')", 'show-synced-tabs-sidebar', 'sidebar-action'],
+ reverseSidebarPosition: ['SidebarController.reversePosition()', 'reverse-sidebar', 'sidebar-action'],
+ hideSidebar: ['SidebarController.hide()', 'hide-sidebar', 'sidebar-action'],
+ toggleSidebar: ['SidebarController.toggle()', 'toggle-sidebar', 'sidebar-action'],
+ zenToggleWebPanels: ['gZenBrowserManagerSidebar.toggle()', 'zen-toggle-web-panels', 'sidebar-action'],
};
const kZenDefaultShortcuts = {
// Split view actions
- zenSplitViewGrid: "Ctrl+Alt+G",
- zenSplitViewVertical: "Ctrl+Alt+V",
- zenSplitViewHorizontal: "Ctrl+Alt+H",
- zenSplitViewClose: "Ctrl+Alt+U",
+ zenSplitViewGrid: 'Ctrl+Alt+G',
+ zenSplitViewVertical: 'Ctrl+Alt+V',
+ zenSplitViewHorizontal: 'Ctrl+Alt+H',
+ zenSplitViewClose: 'Ctrl+Alt+U',
// Workspace actions
- zenChangeWorkspace: "Ctrl+Shift+E",
+ zenChangeWorkspace: 'Ctrl+Shift+E',
// Compact mode actions
- zenToggleCompactMode: "Ctrl+Alt+C",
- zenToggleCompactModeSidebar: "Ctrl+Alt+S",
- zenToggleCompactModeToolbar: "Ctrl+Alt+T",
+ zenToggleCompactMode: 'Ctrl+Alt+C',
+ zenToggleCompactModeSidebar: 'Ctrl+Alt+S',
+ zenToggleCompactModeToolbar: 'Ctrl+Alt+T',
// manage actions
- zenToggleWebPanels: "Alt+P",
+ zenToggleWebPanels: 'Alt+P',
};
// Section: ZenKeyboardShortcuts
-const kZKSStorageKey = "zen.keyboard.shortcuts";
const kZKSKeyCodeMap = {
- F1: "VK_F1",
- F2: "VK_F2",
- F3: "VK_F3",
- F4: "VK_F4",
- F5: "VK_F5",
- F6: "VK_F6",
- F7: "VK_F7",
- F8: "VK_F8",
- F9: "VK_F9",
- F10: "VK_F10",
- F11: "VK_F11",
- F12: "VK_F12",
- TAB: "VK_TAB",
- ENTER: "VK_RETURN",
- ESCAPE: "VK_ESCAPE",
- SPACE: "VK_SPACE",
- ARROWLEFT: "VK_LEFT",
- ARROWRIGHT: "VK_RIGHT",
- ARROWUP: "VK_UP",
- ARROWDOWN: "VK_DOWN",
- DELETE: "VK_DELETE",
- BACKSPACE: "VK_BACK",
+ F1: 'VK_F1',
+ F2: 'VK_F2',
+ F3: 'VK_F3',
+ F4: 'VK_F4',
+ F5: 'VK_F5',
+ F6: 'VK_F6',
+ F7: 'VK_F7',
+ F8: 'VK_F8',
+ F9: 'VK_F9',
+ F10: 'VK_F10',
+ F11: 'VK_F11',
+ F12: 'VK_F12',
+ TAB: 'VK_TAB',
+ ENTER: 'VK_RETURN',
+ ESCAPE: 'VK_ESCAPE',
+ SPACE: 'VK_SPACE',
+ ARROWLEFT: 'VK_LEFT',
+ ARROWRIGHT: 'VK_RIGHT',
+ ARROWUP: 'VK_UP',
+ ARROWDOWN: 'VK_DOWN',
+ DELETE: 'VK_DELETE',
+ BACKSPACE: 'VK_BACK',
};
-var gZenKeyboardShortcuts = {
+const SHORTCUTS_STORAGE_KEY = 'zen.keyboard.shortcuts';
+const ZEN_SHORTCUTS_GROUP = 'zen';
+const FIREFOX_SHORTCUTS_GROUP = 'firefox';
+const VALID_SHORTCUT_GROUPS = [ZEN_SHORTCUTS_GROUP, FIREFOX_SHORTCUTS_GROUP];
+
+class KeyShortcutModifiers {
+ #ctrl = false;
+ #alt = false;
+ #shift = false;
+ #meta = false;
+
+ constructor(ctrl, alt, shift, meta) {
+ this.#ctrl = ctrl;
+ this.#alt = alt;
+ this.#shift = shift;
+ this.#meta = meta;
+ }
+
+ static parseFromString(modifiers) {
+ if (modifiers == null) {
+ return new KeyShortcutModifiers(false, false, false, false);
+ }
+
+ return new KeyShortcutModifiers(modifiers['ctrl'], modifiers['alt'], modifiers['shift'], modifiers['meta']);
+ }
+
+ toUserString() {
+ let str = '';
+ if (this.#ctrl) {
+ str += 'Ctrl+';
+ }
+ if (this.#alt) {
+ str += AppConstants.platform == 'macosx' ? 'Option+' : 'Alt+';
+ }
+ if (this.#shift) {
+ str += 'Shift+';
+ }
+ if (this.#meta) {
+ str += AppConstants.platform == 'macosx' ? 'Cmd+' : 'Win+';
+ }
+ return str;
+ }
+
+ toString() {
+ let str = '';
+ if (this.#ctrl) {
+ str += 'accel,';
+ }
+ if (this.#alt) {
+ str += 'alt,';
+ }
+ if (this.#shift) {
+ str += 'shift,';
+ }
+ if (this.#meta) {
+ str += 'meta';
+ }
+ return str;
+ }
+
+ toJSONString() {
+ return {
+ ctrl: this.#ctrl,
+ alt: this.#alt,
+ shift: this.#shift,
+ meta: this.#meta,
+ };
+ }
+
+ areAnyActive() {
+ return this.#ctrl || this.#alt || this.#shift || this.#meta;
+ }
+}
+
+class KeyShortcut {
+ #id = '';
+ #key = '';
+ #keycode = '';
+ #group = FIREFOX_SHORTCUTS_GROUP;
+ #modifiers = new KeyShortcutModifiers(false, false, false, false);
+ #action = '';
+ #l10nId = '';
+ #disabled = false;
+ #reserved = false;
+ #internal = false;
+
+ constructor(id, key, keycode, group, modifiers, action, l10nId, disabled, reserved, internal) {
+ this.#id = id;
+ this.#key = key;
+ this.#keycode = keycode;
+
+ if (!VALID_SHORTCUT_GROUPS.includes(group)) {
+ throw new Error('Illegal group value: ' + group);
+ }
+
+ this.#group = group;
+ this.#modifiers = modifiers;
+ this.#action = action;
+ this.#l10nId = l10nId;
+ this.#disabled = disabled;
+ this.#reserved = reserved;
+ this.#internal = internal;
+ }
+
+ static parseFromSaved(json) {
+ let rv = [];
+
+ for (let key of json) {
+ rv.push(this.#parseFromJSON(key));
+ }
+
+ return rv;
+ }
+
+ static #parseFromJSON(json) {
+ return new KeyShortcut(
+ json['id'],
+ json['key'],
+ json['keycode'],
+ json['group'],
+ KeyShortcutModifiers.parseFromString(json['modifiers']),
+ json['action'],
+ json['l10nId'],
+ json['disabled'] == 'true',
+ json['reserved'] == 'true',
+ json['internal'] == 'true'
+ );
+ }
+
+ static parseFromXHTML(key, group) {
+ return new KeyShortcut(
+ key.getAttribute('id'),
+ key.getAttribute('key'),
+ key.getAttribute('keycode'),
+ group,
+ KeyShortcutModifiers.parseFromString(key.getAttribute('modifiers')),
+ key.getAttribute('command'),
+ key.getAttribute('data-l10n-id'),
+ key.getAttribute('disabled') == 'true',
+ key.getAttribute('reserved') == 'true',
+ key.getAttribute('internal') == 'true'
+ );
+ }
+
+ toXHTMLElement() {
+ let str = '`;
+
+ return window.MozXULElement.parseXULToFragment(str);
+ }
+
+ getID() {
+ return this.#id;
+ }
+
+ getAction() {
+ return this.#action;
+ }
+
+ getL10NID() {
+ return this.#l10nId;
+ }
+
+ getGroup() {
+ return this.#group;
+ }
+
+ setModifiers(modifiers) {
+ if ((!modifiers) instanceof KeyShortcutModifiers) {
+ throw new Error('Only KeyShortcutModifiers allowed');
+ }
+ this.#modifiers = modifiers;
+ }
+
+ toJSONForm() {
+ return {
+ id: this.#id,
+ key: this.#key,
+ keycode: this.#keycode,
+ group: this.#group,
+ l10nId: this.#l10nId,
+ modifiers: this.#modifiers.toJSONString(),
+ action: this.#action,
+ disabled: this.#disabled,
+ reserved: this.#reserved,
+ internal: this.#internal,
+ };
+ }
+
+ toUserString() {
+ let str = this.#modifiers.toUserString();
+ if (this.#key) {
+ str += this.#key;
+ } else if (this.#keycode) {
+ str += this.#keycode;
+ } else if (this.#id) {
+ str += this.#id;
+ } else {
+ return '';
+ }
+ return str;
+ }
+
+ isUserEditable() {
+ if (!this.#id || !this.#action || this.#action == '' || this.#internal || this.#reserved) {
+ return false;
+ }
+ return true;
+ }
+
+ clearKeybind() {
+ this.#key = '';
+ this.#keycode = '';
+ this.#modifiers = null;
+ }
+}
+
+var gZenKeyboardShortcutsManager = {
init() {
- if (!Services.prefs.getBoolPref("zen.keyboard.shortcuts.enabled")) {
- return;
+ if (window.location.href == 'chrome://browser/content/browser.xhtml') {
+ console.info('Zen CKS: Initializing shortcuts');
+
+ this._currentShortcutList = this._loadSaved();
+ this._applyShortcuts();
+ this._saveShortcuts();
+
+ console.info('Zen CKS: Initialized');
}
- this._initShortcuts();
},
- get _savedShortcuts() {
- if (!this.__savedShortcuts) {
- try {
- const data = Services.prefs.getStringPref(kZKSStorageKey);
- if (data.length == 0) {
- this._startUpShortcuts();
- return this._savedShortcuts;
- }
- this.__savedShortcuts = JSON.parse(data);
- } catch (e) {
- console.error("Zen CKS: Error parsing saved shortcuts", e);
- this.__savedShortcuts = {};
- }
+ _loadSaved() {
+ let data = JSON.parse(Services.prefs.getStringPref(SHORTCUTS_STORAGE_KEY));
+ if (!data || data.length == 0) {
+ return this._loadDefaults();
+ }
+
+ try {
+ return KeyShortcut.parseFromSaved(data);
+ } catch (e) {
+ console.error('Zen CKS: Error parsing saved shortcuts. Resetting to defaults...', e);
+ return this._loadDefaults();
}
- return this.__savedShortcuts;
},
- _startUpShortcuts() {
- this.__savedShortcuts = {};
- this._addDefaultShortcuts();
- this._saveShortcuts();
+ _loadDefaults() {
+ let newShortcutList = [];
+
+ // Firefox's standard keyset
+ for (let key of _mainKeyset.children) {
+ let parsed = KeyShortcut.parseFromXHTML(key, FIREFOX_SHORTCUTS_GROUP);
+ newShortcutList.push(parsed);
+ }
+
+ // TODO: Add Zen's custom actions
+
+ return newShortcutList;
+ },
+
+ _applyShortcuts() {
+ console.debug(window.location.href);
+ let keySet = document.getElementById('mainKeyset');
+ if (!keySet) {
+ throw new Error('Main keyset not found');
+ }
+
+ let parent = keySet.parentElement;
+
+ keySet.remove();
+ keySet.innerHTML = '';
+
+ for (let key of this._currentShortcutList) {
+ let child = key.toXHTMLElement();
+ keySet.appendChild(child);
+ }
+
+ parent.prepend(keySet);
+ console.debug(document.getElementById('mainKeyset'));
},
_saveShortcuts() {
- Services.prefs.setStringPref(
- kZKSStorageKey,
- JSON.stringify(this._savedShortcuts),
- );
+ let json = [];
+ for (shortcut of this._currentShortcutList) {
+ json.push(shortcut.toJSONForm());
+ }
+
+ Services.prefs.setStringPref(SHORTCUTS_STORAGE_KEY, JSON.stringify(json));
},
- _parseDefaultShortcut(shortcut) {
- let ctrl = shortcut.includes("Ctrl+");
- let alt = shortcut.includes("Alt+") || shortcut.includes("Option+");
- let shift = shortcut.includes("Shift+");
- let meta = shortcut.includes("Meta+") || shortcut.includes("Cmd+");
- let key = shortcut.replace(
- /Ctrl\+|Alt\+|Option\+|Shift\+|Meta\+|Cmd\+/g,
- "",
- );
- if (
- [
- "Tab",
- "Enter",
- "Escape",
- "Space",
- "ArrowLeft",
- "ArrowRight",
- "ArrowUp",
- "ArrowDown",
- ].includes(key)
- ) {
- return { ctrl, alt, shift, meta, key: undefined, keycode: key };
+ setShortcut(action, newShortcut, modifiers) {
+ if (!action) {
+ throw new Error('Action cannot be null');
}
- let isKeyCode = key.length > 1;
- return {
- ctrl,
- alt,
- shift,
- meta,
- key: isKeyCode ? undefined : key,
- keycode: isKeyCode ? key : undefined,
- };
- },
- _addDefaultShortcuts() {
- for (let action in kZenDefaultShortcuts) {
- if (!this._savedShortcuts[action]) {
- this._savedShortcuts[action] = this._parseDefaultShortcut(
- kZenDefaultShortcuts[action],
- );
- }
+ // Unsetting shortcut
+ let targetShortcut = this._currentShortcutList.filter((key) => key.getAction() == action)[0];
+ if (!targetShortcut) {
+ throw new Error('Shortcut for action ' + action + ' not found');
}
- },
- setShortcut(id, shortcut) {
- if (!shortcut) {
- delete this._savedShortcuts[id];
- } else if (this.isValidShortcut(shortcut)) {
- this._savedShortcuts[id] = shortcut;
+ console.debug(targetShortcut.toJSONForm());
+
+ if (!newShortcut && !modifiers) {
+ targetShortcut.clearKeybind();
+ } else {
+ targetShortcut.setModifiers(modifiers);
}
+
+ this._applyShortcuts();
this._saveShortcuts();
},
- _initShortcuts() {
- if (window.location.href == "chrome://browser/content/browser.xhtml") {
- console.info("Zen CKS: Initializing shortcuts");
- Services.prefs.addObserver(
- kZKSStorageKey,
- this._onShortcutChange.bind(this),
- );
- Services.prefs.addObserver(
- "zen.keyboard.shortcuts.disable-firefox",
- this._disableFirefoxShortcuts.bind(this),
- );
- this._initSavedShortcuts();
- this._disableFirefoxShortcuts();
- }
- },
-
- _disableFirefoxShortcuts() {
- let disable = Services.prefs.getBoolPref(
- "zen.keyboard.shortcuts.disable-firefox",
- );
- if (!disable) {
- return;
- }
- window.SessionStore.promiseInitialized.then(() => {
- let keySet = document.getElementById("mainKeyset");
- if (!keySet) {
- throw new Error("Zen CKS: No main keyset found");
- }
- for (let child of keySet.children) {
- if (!child.id.startsWith("zen-key_")) {
- child.setAttribute("disabled", true);
- }
- }
- console.info("Remove already exist shortcut keys");
- });
- },
-
- _onShortcutChange() {
- console.info("Zen CKS: Shortcut changed");
- this.__savedShortcuts = null;
- this._initSavedShortcuts(true);
- },
-
- _getCommandAttribute(action) {
- if (action.startsWith("command:")) {
- return `command="${action.substring(8)}"`;
- }
- return `oncommand="${action}"`;
- },
-
- _createShortcutElement(_action) {
- let shortcut = this._savedShortcuts[_action];
- if (!shortcut) {
- return null;
+ getModifiableShortcuts() {
+ let rv = [];
+ if (!this._currentShortcutList) {
+ this._currentShortcutList = this._loadSaved();
}
- const action = kZKSActions[_action][0];
- const key = shortcut.key.toUpperCase();
- let modifiers = {
- accel: shortcut.ctrl,
- alt: shortcut.alt,
- shift: shortcut.shift,
- meta: shortcut.meta,
- };
-
- modifiers = Object.keys(modifiers)
- .filter((mod) => modifiers[mod])
- .join(",");
-
- return window.MozXULElement.parseXULToFragment(`
-
- `);
- },
-
- _initSavedShortcuts(fromUpdate = false) {
- let keySet = document.getElementById("mainKeyset");
- if (!keySet) {
- throw new Error("Zen CKS: No main keyset found");
- }
-
- for (let action in kZKSActions) {
- let id = `zen-key_${action}`;
- let existing = document.getElementById(id);
- if (existing) {
- existing.remove();
- }
- let shortcut = this._createShortcutElement(action);
- if (shortcut) {
- keySet.prepend(shortcut);
+ for (let shortcut of this._currentShortcutList) {
+ if (shortcut.isUserEditable()) {
+ rv.push(shortcut);
}
}
- this._fixMainKeyset();
- },
-
- _fixMainKeyset() {
- let keySet = document.getElementById("mainKeyset");
- if (!keySet) {
- throw new Error("Zen CKS: No main keyset found");
- }
- const parent = keySet.parentElement;
- // We need to re-append the main keyset to the document to make the shortcuts work
- keySet.remove();
- parent.prepend(keySet);
- },
-
- getShortcut(action) {
- return this._savedShortcuts[action];
- },
-
- isValidShortcut(shortcut) {
- return shortcut && (shortcut.key || shortcut.keycode);
- },
-
- shortCutToString(shortcut) {
- let str = "";
- if (shortcut.ctrl) {
- str += "Ctrl+";
- }
- if (shortcut.alt) {
- str += AppConstants.platform == "macosx" ? "Option+" : "Alt+";
- }
- if (shortcut.shift) {
- str += "Shift+";
- }
- if (shortcut.meta) {
- str += AppConstants.platform == "macosx" ? "Cmd+" : "Meta+";
- }
- if (shortcut.key) {
- str += shortcut.key;
- }
- return str;
+ return rv;
},
};