From 65768ddabf2ccaf7715464c80611f2cd84f73c75 Mon Sep 17 00:00:00 2001 From: Tim Roes Date: Fri, 18 Aug 2017 09:54:24 +0200 Subject: [PATCH] Improve Dev Tools accessibility (#13496) * Make console actions accessible Use a button isntead of a link will solve all accessibility issues, and we just need to style the button the same way we style the links. * Create kbnUiAceKeyboardModeService This will be needed for situations in which the initialization need to be started manually, and a simple directive won't be enough. * Make console input box accessible * Make editor_actions buttons instead of links --- .../console/public/css/sense.less | 6 +-- src/core_plugins/console/public/index.html | 13 ++--- .../src/controllers/sense_controller.js | 3 +- .../__tests__/kbn_ui_ace_keyboard_mode.js | 50 +++++++++++++++++++ .../accessibility/kbn_ui_ace_keyboard_mode.js | 12 +++-- src/ui/public/styles/bootstrap/dropdowns.less | 15 +++++- 6 files changed, 84 insertions(+), 15 deletions(-) diff --git a/src/core_plugins/console/public/css/sense.less b/src/core_plugins/console/public/css/sense.less index e63f82093ec70..8d2aaab4f5dff 100644 --- a/src/core_plugins/console/public/css/sense.less +++ b/src/core_plugins/console/public/css/sense.less @@ -93,9 +93,9 @@ sense-history-viewer, .editor_action { padding: 2px 4px; - &:hover { - text-decoration: none; - } + appearance: none; + border: none; + background: none; } .fa-wrench { diff --git a/src/core_plugins/console/public/index.html b/src/core_plugins/console/public/index.html index ceaa070f41095..6ea1009642ad6 100644 --- a/src/core_plugins/console/public/index.html +++ b/src/core_plugins/console/public/index.html @@ -4,22 +4,23 @@
- - + - - + diff --git a/src/core_plugins/console/public/src/controllers/sense_controller.js b/src/core_plugins/console/public/src/controllers/sense_controller.js index c87cab87e8ef4..3eacf8356447a 100644 --- a/src/core_plugins/console/public/src/controllers/sense_controller.js +++ b/src/core_plugins/console/public/src/controllers/sense_controller.js @@ -16,7 +16,7 @@ module.run(function (Private, $rootScope) { }; }); -module.controller('SenseController', function SenseController(Private, $scope, $timeout, $location, docTitle) { +module.controller('SenseController', function SenseController(Private, $scope, $timeout, $location, docTitle, kbnUiAceKeyboardModeService) { docTitle.change('Console'); $scope.topNavController = Private(SenseTopNavController); @@ -28,6 +28,7 @@ module.controller('SenseController', function SenseController(Private, $scope, $ output = initializeOutput($('#output')); input = initializeInput($('#editor'), $('#editor_actions'), $('#copy_as_curl'), output); init(input, output, $location.search().load_from); + kbnUiAceKeyboardModeService.initialize($scope, $('#editor')); }); $scope.sendSelected = () => { diff --git a/src/ui/public/accessibility/__tests__/kbn_ui_ace_keyboard_mode.js b/src/ui/public/accessibility/__tests__/kbn_ui_ace_keyboard_mode.js index d35c0561ab060..9bbfb4565d96a 100644 --- a/src/ui/public/accessibility/__tests__/kbn_ui_ace_keyboard_mode.js +++ b/src/ui/public/accessibility/__tests__/kbn_ui_ace_keyboard_mode.js @@ -55,3 +55,53 @@ describe('kbnUiAceKeyboardMode directive', () => { }); }); + +describe('kbnUiAceKeyboardModeService', () => { + let element; + + beforeEach(ngMock.module('kibana')); + + beforeEach(ngMock.inject(($compile, $rootScope, kbnUiAceKeyboardModeService) => { + const scope = $rootScope.$new(); + element = $compile(`
`)(scope); + kbnUiAceKeyboardModeService.initialize(scope, element); + })); + + it('should add the hint element', () => { + expect(element.find('.uiAceKeyboardHint').length).to.be(1); + }); + + describe('hint element', () => { + it('should be tabable', () => { + expect(element.find('.uiAceKeyboardHint').attr('tabindex')).to.be('0'); + }); + + it('should move focus to textbox and be inactive if pressed enter on it', () => { + const textarea = element.find('textarea'); + sinon.spy(textarea[0], 'focus'); + const ev = angular.element.Event('keydown'); // eslint-disable-line new-cap + ev.keyCode = ENTER_KEY; + element.find('.uiAceKeyboardHint').trigger(ev); + expect(textarea[0].focus.called).to.be(true); + expect(element.find('.uiAceKeyboardHint').hasClass('uiAceKeyboardHint-isInactive')).to.be(true); + }); + + it('should be shown again, when pressing Escape in ace editor', () => { + const textarea = element.find('textarea'); + const hint = element.find('.uiAceKeyboardHint'); + sinon.spy(hint[0], 'focus'); + const ev = angular.element.Event('keydown'); // eslint-disable-line new-cap + ev.keyCode = ESC_KEY_CODE; + textarea.trigger(ev); + expect(hint[0].focus.called).to.be(true); + expect(hint.hasClass('uiAceKeyboardHint-isInactive')).to.be(false); + }); + }); + + describe('ui-ace textarea', () => { + it('should not be tabable anymore', () => { + expect(element.find('textarea').attr('tabindex')).to.be('-1'); + }); + }); + +}); diff --git a/src/ui/public/accessibility/kbn_ui_ace_keyboard_mode.js b/src/ui/public/accessibility/kbn_ui_ace_keyboard_mode.js index 17642dff50a46..d2f2f8f2155dc 100644 --- a/src/ui/public/accessibility/kbn_ui_ace_keyboard_mode.js +++ b/src/ui/public/accessibility/kbn_ui_ace_keyboard_mode.js @@ -19,9 +19,9 @@ import { ESC_KEY_CODE, ENTER_KEY } from 'ui_framework/services'; let aceKeyboardModeId = 0; -uiModules.get('kibana').directive('kbnUiAceKeyboardMode', () => ({ - restrict: 'A', - link(scope, element) { +uiModules.get('kibana') +.factory('kbnUiAceKeyboardModeService', () => ({ + initialize(scope, element) { const uniqueId = `uiAceKeyboardHint-${scope.$id}-${aceKeyboardModeId++}`; const hint = angular.element( @@ -77,4 +77,10 @@ uiModules.get('kibana').directive('kbnUiAceKeyboardMode', () => ({ uiAceTextbox.attr('tabindex', '-1'); element.prepend(hint); } +})) +.directive('kbnUiAceKeyboardMode', (kbnUiAceKeyboardModeService) => ({ + restrict: 'A', + link(scope, element) { + kbnUiAceKeyboardModeService.initialize(scope, element); + } })); diff --git a/src/ui/public/styles/bootstrap/dropdowns.less b/src/ui/public/styles/bootstrap/dropdowns.less index bc21e28fa5dc7..b0376eb4a6317 100644 --- a/src/ui/public/styles/bootstrap/dropdowns.less +++ b/src/ui/public/styles/bootstrap/dropdowns.less @@ -62,7 +62,8 @@ } // Links within the dropdown menu - > li > a { + > li > a, + > li > button { display: block; padding: 3px 20px; clear: both; @@ -71,10 +72,19 @@ color: @dropdown-link-color; white-space: nowrap; // prevent links from randomly breaking onto new lines } + + > li > button { + appearance: none; + background: none; + border: none; + width: 100%; + text-align: left; + } } // Hover/Focus state -.dropdown-menu > li > a { +.dropdown-menu > li > a, +.dropdown-menu > li > button { &:hover, &:focus { text-decoration: none; @@ -84,6 +94,7 @@ } // Active state +.dropdown-menu > .active > button, .dropdown-menu > .active > a { &, &:hover,