From 74eacec3deba9a874f84d4262474eab544921b2f Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Wed, 13 Jul 2016 16:51:02 +0200 Subject: [PATCH] extension viewlet keyboard accessibility fixes #8621 --- src/vs/base/browser/ui/list/listWidget.ts | 60 +++++++++++++++++-- .../electron-browser/extensionsViewlet.ts | 15 ----- .../media/extensionActions.css | 5 ++ 3 files changed, 59 insertions(+), 21 deletions(-) diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 20a87567715..901ef728da6 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -7,7 +7,9 @@ import 'vs/css!./list'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { isNumber } from 'vs/base/common/types'; import * as DOM from 'vs/base/browser/dom'; -import Event, { Emitter, mapEvent, EventBufferer } from 'vs/base/common/event'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import Event, { Emitter, mapEvent, EventBufferer, filterEvent } from 'vs/base/common/event'; import { domEvent } from 'vs/base/browser/event'; import { IDelegate, IRenderer, IListMouseEvent, IFocusChangeEvent, ISelectionChangeEvent } from './list'; import { ListView, IListViewOptions } from './listView'; @@ -120,15 +122,23 @@ class FocusTrait extends Trait { class Controller implements IDisposable { - private toDispose: IDisposable[]; + private disposables: IDisposable[]; constructor( private list: List, private view: ListView ) { - this.toDispose = []; - this.toDispose.push(view.addListener('mousedown', e => this.onMouseDown(e))); - this.toDispose.push(view.addListener('click', e => this.onClick(e))); + this.disposables = []; + this.disposables.push(view.addListener('mousedown', e => this.onMouseDown(e))); + this.disposables.push(view.addListener('click', e => this.onClick(e))); + + const onRawKeyDown = domEvent(view.domNode, 'keydown'); + const onKeyDown = mapEvent(onRawKeyDown, e => new StandardKeyboardEvent(e)); + filterEvent(onKeyDown, e => e.keyCode === KeyCode.Enter)(this.onEnter, this, this.disposables); + filterEvent(onKeyDown, e => e.keyCode === KeyCode.UpArrow)(this.onUpArrow, this, this.disposables); + filterEvent(onKeyDown, e => e.keyCode === KeyCode.DownArrow)(this.onDownArrow, this, this.disposables); + filterEvent(onKeyDown, e => e.keyCode === KeyCode.PageUp)(this.onPageUpArrow, this, this.disposables); + filterEvent(onKeyDown, e => e.keyCode === KeyCode.PageDown)(this.onPageDownArrow, this, this.disposables); } private onMouseDown(e: IListMouseEvent) { @@ -144,8 +154,46 @@ class Controller implements IDisposable { this.list.setSelection(e.index); } + private onEnter(e: StandardKeyboardEvent): void { + e.preventDefault(); + e.stopPropagation(); + this.list.setSelection(...this.list.getFocus()); + } + + private onUpArrow(e: StandardKeyboardEvent): void { + e.preventDefault(); + e.stopPropagation(); + this.list.focusPrevious(); + this.list.reveal(this.list.getFocus()[0]); + this.view.domNode.focus(); + } + + private onDownArrow(e: StandardKeyboardEvent): void { + e.preventDefault(); + e.stopPropagation(); + this.list.focusNext(); + this.list.reveal(this.list.getFocus()[0]); + this.view.domNode.focus(); + } + + private onPageUpArrow(e: StandardKeyboardEvent): void { + e.preventDefault(); + e.stopPropagation(); + this.list.focusPreviousPage(); + this.list.reveal(this.list.getFocus()[0]); + this.view.domNode.focus(); + } + + private onPageDownArrow(e: StandardKeyboardEvent): void { + e.preventDefault(); + e.stopPropagation(); + this.list.focusNextPage(); + this.list.reveal(this.list.getFocus()[0]); + this.view.domNode.focus(); + } + dispose() { - this.toDispose = dispose(this.toDispose); + this.disposables = dispose(this.disposables); } } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts index 1bc8c9eb0eb..fea4902277f 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsViewlet.ts @@ -39,7 +39,6 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet { private extensionsBox: HTMLElement; private list: PagedList; private disposables: IDisposable[] = []; - private focusInvokedByTab: boolean; private clearAction: ClearExtensionsInputAction; constructor( @@ -80,7 +79,6 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet { const onDownArrow = filterEvent(onKeyDown, e => e.keyCode === KeyCode.DownArrow); const onPageUpArrow = filterEvent(onKeyDown, e => e.keyCode === KeyCode.PageUp); const onPageDownArrow = filterEvent(onKeyDown, e => e.keyCode === KeyCode.PageDown); - const onTab = filterEvent(onKeyDown, e => e.keyCode === KeyCode.Tab); onEnter(this.onEnter, this, this.disposables); onEscape(this.onEscape, this, this.disposables); @@ -88,19 +86,10 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet { onDownArrow(this.onDownArrow, this, this.disposables); onPageUpArrow(this.onPageUpArrow, this, this.disposables); onPageDownArrow(this.onPageDownArrow, this, this.disposables); - onTab(this.onTab, this, this.disposables); const onInput = domEvent(this.searchBox, 'input'); onInput(() => this.triggerSearch(), null, this.disposables); - this.list.onDOMFocus(focusEvent => { - // Allow tab to move focus out of search box #7966 - if (!this.focusInvokedByTab) { - this.searchBox.focus(); - } - this.focusInvokedByTab = false; - }, null, this.disposables); - const onSelectedExtension = filterEvent(mapEvent(this.list.onSelectionChange, e => e.elements[0]), e => !!e); onSelectedExtension(this.onExtensionSelected, this, this.disposables); @@ -229,10 +218,6 @@ export class ExtensionsViewlet extends Viewlet implements IExtensionsViewlet { this.list.reveal(this.list.getFocus()[0]); } - private onTab(): void { - this.focusInvokedByTab = true; - } - dispose(): void { this.disposables = dispose(this.disposables); super.dispose(); diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/extensionActions.css b/src/vs/workbench/parts/extensions/electron-browser/media/extensionActions.css index e059a619c91..f1a00390db2 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/extensionActions.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/extensionActions.css @@ -50,6 +50,11 @@ background-color: #6DA770; } +.monaco-action-bar .action-item:not(.disabled) .action-label:focus.extension-action.install, +.monaco-action-bar .action-item:not(.disabled) .action-label:focus.extension-action.update { + outline: 1px solid rgb(14, 99, 156) !important; +} + .monaco-action-bar .action-item .action-label.extension-action.enable { color: white; -- GitLab