From 0b8e20847a7730235a449b0150c0b19613cb1636 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 17 Aug 2018 18:40:02 -0700 Subject: [PATCH] #54140 - add keyboard shortcut for setting context menu --- .../browser/media/settingsEditor2.css | 4 ++ .../preferences/browser/settingsEditor2.ts | 31 +++++++--- .../parts/preferences/browser/settingsTree.ts | 61 ++++++++++++++----- .../preferences/browser/settingsTreeModels.ts | 2 +- .../parts/preferences/common/preferences.ts | 1 + .../preferences.contribution.ts | 18 +++++- 6 files changed, 93 insertions(+), 24 deletions(-) diff --git a/src/vs/workbench/parts/preferences/browser/media/settingsEditor2.css b/src/vs/workbench/parts/preferences/browser/media/settingsEditor2.css index 27f4b7f24f2..7e038adc1d1 100644 --- a/src/vs/workbench/parts/preferences/browser/media/settingsEditor2.css +++ b/src/vs/workbench/parts/preferences/browser/media/settingsEditor2.css @@ -160,6 +160,10 @@ display: flex; } +.settings-editor > .settings-body .settings-tree-container .monaco-tree-row .setting-item.focused .monaco-toolbar { + display: flex; +} + .settings-editor > .settings-body .settings-tree-container .monaco-toolbar .toolbar-toggle-more { display: block; width: 22px; diff --git a/src/vs/workbench/parts/preferences/browser/settingsEditor2.ts b/src/vs/workbench/parts/preferences/browser/settingsEditor2.ts index 3c242ed3deb..14ef50470e2 100644 --- a/src/vs/workbench/parts/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/parts/preferences/browser/settingsEditor2.ts @@ -186,6 +186,23 @@ export class SettingsEditor2 extends BaseEditor { } } + showContextMenu(): void { + const settingDOMElement = this.settingsTreeRenderer.getSettingDOMElementForDOMElement(document.activeElement); + if (!settingDOMElement) { + return; + } + + const focusedKey = this.settingsTreeRenderer.getKeyForDOMElementInSetting(settingDOMElement); + if (!focusedKey) { + return; + } + + const elements = this.currentSettingsModel.getElementsByName(focusedKey); + if (elements && elements[0]) { + this.settingsTreeRenderer.showContextMenu(elements[0], settingDOMElement); + } + } + focusSearch(): void { this.searchWidget.focus(); } @@ -275,12 +292,8 @@ export class SettingsEditor2 extends BaseEditor { this.toolbar.context = { target: this.settingsTargetsWidget.settingsTarget }; } - private getElementsByKey(settingKey: string): SettingsTreeSettingElement[] | null { - return this.currentSettingsModel.getElementByName(settingKey); - } - private revealSettingByKey(settingKey: string): void { - const elements = this.getElementsByKey(settingKey); + const elements = this.currentSettingsModel.getElementsByName(settingKey); if (elements && elements[0]) { this.settingsTree.reveal(elements[0]); @@ -413,7 +426,9 @@ export class SettingsEditor2 extends BaseEditor { }); })); this._register(this.settingsTreeRenderer.onDidClickSettingLink(settingName => this.revealSettingByKey(settingName))); - this._register(this.settingsTreeRenderer.onDidFocusSetting(element => this.settingsTree.reveal(element))); + this._register(this.settingsTreeRenderer.onDidFocusSetting(element => { + this.settingsTree.reveal(element); + })); this.settingsTree = this._register(this.instantiationService.createInstance(SettingsTree, this.settingsTreeContainer, @@ -696,7 +711,7 @@ export class SettingsEditor2 extends BaseEditor { let refreshP: TPromise; if (key) { - const elements = this.getElementsByKey(key); + const elements = this.currentSettingsModel.getElementsByName(key); if (elements && elements.length) { refreshP = TPromise.join(elements.map(e => this.settingsTree.refresh(e))); } else { @@ -714,7 +729,7 @@ export class SettingsEditor2 extends BaseEditor { } private updateModifiedLabelForKey(key: string): void { - const dataElements = this.getElementsByKey(key); + const dataElements = this.currentSettingsModel.getElementsByName(key); const isModified = dataElements && dataElements[0] && dataElements[0].isConfigured; // all elements are either configured or not const elements = this.settingsTreeRenderer.getDOMElementsForSettingKey(this.settingsTree.getHTMLElement(), key); if (elements && elements[0]) { diff --git a/src/vs/workbench/parts/preferences/browser/settingsTree.ts b/src/vs/workbench/parts/preferences/browser/settingsTree.ts index cff2867413d..3b30e7efc61 100644 --- a/src/vs/workbench/parts/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/parts/preferences/browser/settingsTree.ts @@ -7,10 +7,13 @@ import * as DOM from 'vs/base/browser/dom'; import { renderMarkdown } from 'vs/base/browser/htmlContentRenderer'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { IMouseEvent } from 'vs/base/browser/mouseEvent'; +import { alert as ariaAlert } from 'vs/base/browser/ui/aria/aria'; import { Button } from 'vs/base/browser/ui/button/button'; import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox'; import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox'; import { SelectBox } from 'vs/base/browser/ui/selectBox/selectBox'; +import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; +import { Action, IAction } from 'vs/base/common/actions'; import * as arrays from 'vs/base/common/arrays'; import { Color, RGBA } from 'vs/base/common/color'; import { onUnexpectedError } from 'vs/base/common/errors'; @@ -25,23 +28,20 @@ import { IAccessibilityProvider, IDataSource, IFilter, IRenderer as ITreeRendere import { DefaultTreestyler } from 'vs/base/parts/tree/browser/treeDefaults'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; import { localize } from 'vs/nls'; +import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { WorkbenchTreeController } from 'vs/platform/list/browser/listService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { editorBackground, focusBorder, foreground, errorForeground, inputValidationErrorBackground, inputValidationErrorBorder } from 'vs/platform/theme/common/colorRegistry'; +import { editorBackground, errorForeground, focusBorder, foreground, inputValidationErrorBackground, inputValidationErrorBorder } from 'vs/platform/theme/common/colorRegistry'; import { attachButtonStyler, attachInputBoxStyler, attachSelectBoxStyler, attachStyler } from 'vs/platform/theme/common/styler'; import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { ITOCEntry } from 'vs/workbench/parts/preferences/browser/settingsLayout'; import { ISettingsEditorViewState, isExcludeSetting, SettingsTreeElement, SettingsTreeGroupElement, SettingsTreeNewExtensionsElement, SettingsTreeSettingElement } from 'vs/workbench/parts/preferences/browser/settingsTreeModels'; import { ExcludeSettingWidget, IExcludeDataItem, settingsHeaderForeground, settingsNumberInputBackground, settingsNumberInputBorder, settingsNumberInputForeground, settingsSelectBackground, settingsSelectBorder, settingsSelectForeground, settingsTextInputBackground, settingsTextInputBorder, settingsTextInputForeground } from 'vs/workbench/parts/preferences/browser/settingsWidgets'; import { ISetting, ISettingsGroup } from 'vs/workbench/services/preferences/common/preferences'; -import { alert as ariaAlert } from 'vs/base/browser/ui/aria/aria'; -import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; -import { Action, IAction } from 'vs/base/common/actions'; -import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; const $ = DOM.$; @@ -328,6 +328,17 @@ export class SettingsRenderer implements ITreeRenderer { ]; } + showContextMenu(element: SettingsTreeSettingElement, settingDOMElement: HTMLElement): void { + const toolbarElement: HTMLElement = settingDOMElement.querySelector('.toolbar-toggle-more'); + if (toolbarElement) { + this.contextMenuService.showContextMenu({ + getActions: () => TPromise.wrap(this.settingActions), + getAnchor: () => toolbarElement, + getActionsContext: () => element + }); + } + } + updateWidth(width: number): void { if (this.lastRenderedWidth !== width) { this.rowHeightCache = new Map(); @@ -514,9 +525,7 @@ export class SettingsRenderer implements ITreeRenderer { const toDispose = []; - const toolbar = new ToolBar(container, this.contextMenuService, {}); - toolbar.setActions([], this.settingActions)(); - toDispose.push(toolbar); + const toolbar = this.renderSettingToolbar(container); const template: ISettingItemTemplate = { toDispose, @@ -545,11 +554,21 @@ export class SettingsRenderer implements ITreeRenderer { } private addSettingElementFocusHandler(template: ISettingItemTemplate): void { - template.toDispose.push(DOM.addDisposableListener(template.containerElement, 'focus', e => { + const focusTracker = DOM.trackFocus(template.containerElement); + template.toDispose.push(focusTracker); + focusTracker.onDidBlur(() => { + if (template.containerElement.classList.contains('focused')) { + template.containerElement.classList.remove('focused'); + } + }); + + focusTracker.onDidFocus(() => { + template.containerElement.classList.add('focused'); + if (template.context) { this._onDidFocusSetting.fire(template.context); } - }, true)); + }); } private renderSettingTextTemplate(tree: ITree, container: HTMLElement, type = 'text'): ISettingTextItemTemplate { @@ -614,6 +633,17 @@ export class SettingsRenderer implements ITreeRenderer { return template; } + private renderSettingToolbar(container: HTMLElement): ToolBar { + const toolbar = new ToolBar(container, this.contextMenuService, {}); + toolbar.setActions([], this.settingActions)(); + const button = container.querySelector('.toolbar-toggle-more'); + if (button) { + (button).tabIndex = -1; + } + + return toolbar; + } + private renderSettingBoolTemplate(tree: ITree, container: HTMLElement): ISettingBoolItemTemplate { DOM.addClass(container, 'setting-item'); DOM.addClass(container, 'setting-item-bool'); @@ -639,9 +669,7 @@ export class SettingsRenderer implements ITreeRenderer { } })); checkbox.domNode.classList.add(SettingsRenderer.CONTROL_CLASS); - - const toolbar = new ToolBar(container, this.contextMenuService, {}); - toolbar.setActions([], this.settingActions)(); + const toolbar = this.renderSettingToolbar(container); toDispose.push(toolbar); const template: ISettingBoolItemTemplate = { @@ -853,6 +881,11 @@ export class SettingsRenderer implements ITreeRenderer { return treeContainer.querySelectorAll(`[${SettingsRenderer.SETTING_KEY_ATTR}="${key}"]`); } + public getKeyForDOMElementInSetting(element: HTMLElement): string { + const settingElement = this.getSettingDOMElementForDOMElement(element); + return settingElement && settingElement.getAttribute(SettingsRenderer.SETTING_KEY_ATTR); + } + private renderSettingElement(tree: ITree, element: SettingsTreeSettingElement, templateId: string, template: ISettingItemTemplate | ISettingBoolItemTemplate): void { template.context = element; template.toolbar.context = element; diff --git a/src/vs/workbench/parts/preferences/browser/settingsTreeModels.ts b/src/vs/workbench/parts/preferences/browser/settingsTreeModels.ts index be293cc59f9..a603d2906cc 100644 --- a/src/vs/workbench/parts/preferences/browser/settingsTreeModels.ts +++ b/src/vs/workbench/parts/preferences/browser/settingsTreeModels.ts @@ -210,7 +210,7 @@ export class SettingsTreeModel { return this._treeElementsById.get(id); } - getElementByName(name: string): SettingsTreeSettingElement[] { + getElementsByName(name: string): SettingsTreeSettingElement[] { return this._treeElementsBySettingName.get(name); } diff --git a/src/vs/workbench/parts/preferences/common/preferences.ts b/src/vs/workbench/parts/preferences/common/preferences.ts index d74acccec86..8d084c1559a 100644 --- a/src/vs/workbench/parts/preferences/common/preferences.ts +++ b/src/vs/workbench/parts/preferences/common/preferences.ts @@ -75,6 +75,7 @@ export const SETTINGS_EDITOR_COMMAND_FOCUS_FILE = 'settings.action.focusSettings export const SETTINGS_EDITOR_COMMAND_EDIT_FOCUSED_SETTING = 'settings.action.editFocusedSetting'; export const SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_FROM_SEARCH = 'settings.action.focusSettingsFromSearch'; export const SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_LIST = 'settings.action.focusSettingsList'; +export const SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU = 'settings.action.showContextMenu'; export const KEYBINDINGS_EDITOR_COMMAND_SEARCH = 'keybindings.editor.searchKeybindings'; export const KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS = 'keybindings.editor.clearSearchResults'; diff --git a/src/vs/workbench/parts/preferences/electron-browser/preferences.contribution.ts b/src/vs/workbench/parts/preferences/electron-browser/preferences.contribution.ts index b81ff8c21d4..7159ac5c1b1 100644 --- a/src/vs/workbench/parts/preferences/electron-browser/preferences.contribution.ts +++ b/src/vs/workbench/parts/preferences/electron-browser/preferences.contribution.ts @@ -22,7 +22,7 @@ import { KeybindingsEditor } from 'vs/workbench/parts/preferences/browser/keybin import { OpenDefaultKeybindingsFileAction, OpenRawDefaultSettingsAction, OpenSettingsAction, OpenGlobalSettingsAction, OpenGlobalKeybindingsFileAction, OpenWorkspaceSettingsAction, OpenFolderSettingsAction, ConfigureLanguageBasedSettingsAction, OPEN_FOLDER_SETTINGS_COMMAND, OpenGlobalKeybindingsAction, OpenSettings2Action, OpenSettingsJsonAction } from 'vs/workbench/parts/preferences/browser/preferencesActions'; import { IKeybindingsEditor, IPreferencesSearchService, CONTEXT_KEYBINDING_FOCUS, CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_SEARCH, - KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_SEARCH, CONTEXT_SETTINGS_EDITOR, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, CONTEXT_SETTINGS_SEARCH_FOCUS, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, SETTINGS_EDITOR_COMMAND_EDIT_FOCUSED_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_FROM_SEARCH, CONTEXT_TOC_ROW_FOCUS, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_LIST + KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_SEARCH, CONTEXT_SETTINGS_EDITOR, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, CONTEXT_SETTINGS_SEARCH_FOCUS, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, SETTINGS_EDITOR_COMMAND_EDIT_FOCUSED_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_FROM_SEARCH, CONTEXT_TOC_ROW_FOCUS, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_LIST, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU } from 'vs/workbench/parts/preferences/common/preferences'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; @@ -470,6 +470,22 @@ const focusSettingsListCommand = new FocusSettingsListCommand({ }); focusSettingsListCommand.register(); +class ShowContextMenuCommand extends SettingsCommand { + public runCommand(accessor: ServicesAccessor, args: any): void { + const preferencesEditor = this.getPreferencesEditor(accessor); + if (preferencesEditor instanceof SettingsEditor2) { + preferencesEditor.showContextMenu(); + } + } +} + +const showContextMenuCommand = new ShowContextMenuCommand({ + id: SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU, + precondition: ContextKeyExpr.and(CONTEXT_SETTINGS_EDITOR), + kbOpts: { primary: KeyMod.Shift | KeyCode.F9, weight: KeybindingWeight.WorkbenchContrib } +}); +showContextMenuCommand.register(); + // Preferences menu MenuRegistry.appendMenuItem(MenuId.MenubarPreferencesMenu, { -- GitLab