Diff
Modified: trunk/LayoutTests/ChangeLog (158712 => 158713)
--- trunk/LayoutTests/ChangeLog 2013-11-06 03:36:32 UTC (rev 158712)
+++ trunk/LayoutTests/ChangeLog 2013-11-06 03:50:51 UTC (rev 158713)
@@ -1,3 +1,28 @@
+2013-11-05 James Craig <[email protected]>
+
+ AX: media controls accessibility needs more work
+ https://bugs.webkit.org/show_bug.cgi?id=123749
+
+ Reviewed by Jer Noble.
+
+ Updated some of the control labels/roles to improve accessibility.
+ - Volume slider is now keyboard/screenreader accessible.
+ - muteButton was a checkbox toggling checked state, now a button that toggles label "mute/unmute"
+ - fullscreenButton was a checkbox toggling checked state, now a button that toggles label "display/exit full screen"
+ - captionButton was a checkbox, now a popup button that launches the newly accessible menu.
+ Subtitles menu is now keyboard/screenreader accessible (uses roaming tabindex).
+ Render dump expectations changed because volume slider is now hidden via...
+ ...opacity/size (to make accessible without hover) instead of display:none.
+
+ Updated existing test coverage.
+
+ * platform/mac/accessibility/media-element-expected.txt:
+ * platform/mac/media/audio-controls-rendering-expected.txt:
+ * platform/mac/media/controls-after-reload-expected.txt:
+ * platform/mac/media/controls-strict-expected.txt:
+ * platform/mac/media/controls-styling-strict-expected.txt:
+ * platform/mac/media/controls-without-preload-expected.txt:
+
2013-11-05 Ryosuke Niwa <[email protected]>
Add a test to obtain offsetWidth of expanded table cell
Modified: trunk/LayoutTests/platform/mac/accessibility/media-element-expected.txt (158712 => 158713)
--- trunk/LayoutTests/platform/mac/accessibility/media-element-expected.txt 2013-11-06 03:36:32 UTC (rev 158712)
+++ trunk/LayoutTests/platform/mac/accessibility/media-element-expected.txt 2013-11-06 03:50:51 UTC (rev 158713)
@@ -54,12 +54,20 @@
role: AXRole: AXStaticText
+ description: AXDescription: Volume
+ role: AXRole: AXSlider
+
+
+ description: AXDescription:
+ role: AXRole: AXValueIndicator
+
+
description: AXDescription: Mute
- role: AXRole: AXCheckBox
+ role: AXRole: AXButton
description: AXDescription: Display Full Screen
- role: AXRole: AXCheckBox
+ role: AXRole: AXButton
Modified: trunk/LayoutTests/platform/mac/media/audio-controls-rendering-expected.txt (158712 => 158713)
--- trunk/LayoutTests/platform/mac/media/audio-controls-rendering-expected.txt 2013-11-06 03:36:32 UTC (rev 158712)
+++ trunk/LayoutTests/platform/mac/media/audio-controls-rendering-expected.txt 2013-11-06 03:50:51 UTC (rev 158713)
@@ -43,6 +43,13 @@
RenderBlock {DIV} at (0,0) size 6x6 [bgcolor=#FFFFFF]
layer at (184,44) size 22x22
RenderFlexibleBox {DIV} at (176,2) size 22x22
+layer at (184,44) size 2x22
+ RenderFlexibleBox {DIV} at (0,0) size 2x22 [border: (1px solid #000000F3)]
+ RenderSlider {INPUT} at (-7,6) size 2x10 [color=#909090] [border: (1px solid #000000DF)]
+ RenderFlexibleBox {DIV} at (1,1) size 0x8
+ RenderBlock {DIV} at (0,0) size 0x8
+layer at (170,51) size 8x8
+ RenderBlock {DIV} at (-8,0) size 8x8
layer at (187,47) size 16x16
RenderButton {BUTTON} at (3,3) size 16x16 [color=#FFFFFF]
layer at (8,85) size 320x25
@@ -74,6 +81,13 @@
RenderBlock {DIV} at (0,0) size 6x6 [bgcolor=#FFFFFF]
layer at (304,87) size 22x22
RenderFlexibleBox {DIV} at (296,2) size 22x22
+layer at (304,87) size 2x22
+ RenderFlexibleBox {DIV} at (0,0) size 2x22 [border: (1px solid #000000F3)]
+ RenderSlider {INPUT} at (-7,6) size 2x10 [color=#909090] [border: (1px solid #000000DF)]
+ RenderFlexibleBox {DIV} at (1,1) size 0x8
+ RenderBlock {DIV} at (0,0) size 0x8
+layer at (290,94) size 8x8
+ RenderBlock {DIV} at (-8,0) size 8x8
layer at (307,90) size 16x16
RenderButton {BUTTON} at (3,3) size 16x16 [color=#FFFFFF]
layer at (8,128) size 320x100
@@ -107,5 +121,12 @@
RenderBlock {DIV} at (0,0) size 6x6 [bgcolor=#FFFFFF]
layer at (304,205) size 22x22
RenderFlexibleBox {DIV} at (296,2) size 22x22
+layer at (304,205) size 2x22
+ RenderFlexibleBox {DIV} at (0,0) size 2x22 [border: (1px solid #000000F3)]
+ RenderSlider {INPUT} at (-7,6) size 2x10 [color=#909090] [border: (1px solid #000000DF)]
+ RenderFlexibleBox {DIV} at (1,1) size 0x8
+ RenderBlock {DIV} at (0,0) size 0x8
+layer at (290,212) size 8x8
+ RenderBlock {DIV} at (-8,0) size 8x8
layer at (307,208) size 16x16
RenderButton {BUTTON} at (3,3) size 16x16 [color=#FFFFFF]
Modified: trunk/LayoutTests/platform/mac/media/controls-after-reload-expected.txt (158712 => 158713)
--- trunk/LayoutTests/platform/mac/media/controls-after-reload-expected.txt 2013-11-06 03:36:32 UTC (rev 158712)
+++ trunk/LayoutTests/platform/mac/media/controls-after-reload-expected.txt 2013-11-06 03:50:51 UTC (rev 158713)
@@ -39,6 +39,13 @@
RenderBlock {DIV} at (0,0) size 6x6 [bgcolor=#FFFFFF]
layer at (274,259) size 22x22
RenderFlexibleBox {DIV} at (266,2) size 22x22
+layer at (274,259) size 2x22
+ RenderFlexibleBox {DIV} at (0,0) size 2x22 [border: (1px solid #000000F3)]
+ RenderSlider {INPUT} at (-7,6) size 2x10 [color=#909090] [border: (1px solid #000000DF)]
+ RenderFlexibleBox {DIV} at (1,1) size 0x8
+ RenderBlock {DIV} at (0,0) size 0x8
+layer at (260,266) size 8x8
+ RenderBlock {DIV} at (-8,0) size 8x8
layer at (277,262) size 16x16
RenderButton {BUTTON} at (3,3) size 16x16 [color=#FFFFFF]
layer at (305,262) size 16x16
Modified: trunk/LayoutTests/platform/mac/media/controls-strict-expected.txt (158712 => 158713)
--- trunk/LayoutTests/platform/mac/media/controls-strict-expected.txt 2013-11-06 03:36:32 UTC (rev 158712)
+++ trunk/LayoutTests/platform/mac/media/controls-strict-expected.txt 2013-11-06 03:50:51 UTC (rev 158713)
@@ -39,6 +39,13 @@
RenderBlock {DIV} at (0,0) size 6x6 [bgcolor=#FFFFFF]
layer at (274,267) size 22x22
RenderFlexibleBox {DIV} at (266,2) size 22x22
+layer at (274,267) size 2x22
+ RenderFlexibleBox {DIV} at (0,0) size 2x22 [border: (1px solid #000000F3)]
+ RenderSlider {INPUT} at (-7,6) size 2x10 [color=#909090] [border: (1px solid #000000DF)]
+ RenderFlexibleBox {DIV} at (1,1) size 0x8
+ RenderBlock {DIV} at (0,0) size 0x8
+layer at (260,274) size 8x8
+ RenderBlock {DIV} at (-8,0) size 8x8
layer at (277,270) size 16x16
RenderButton {BUTTON} at (3,3) size 16x16 [color=#FFFFFF]
layer at (305,270) size 16x16
Modified: trunk/LayoutTests/platform/mac/media/controls-styling-strict-expected.txt (158712 => 158713)
--- trunk/LayoutTests/platform/mac/media/controls-styling-strict-expected.txt 2013-11-06 03:36:32 UTC (rev 158712)
+++ trunk/LayoutTests/platform/mac/media/controls-styling-strict-expected.txt 2013-11-06 03:50:51 UTC (rev 158713)
@@ -43,6 +43,13 @@
RenderBlock {DIV} at (0,0) size 6x6 [bgcolor=#FFFFFF]
layer at (274,267) size 22x22
RenderFlexibleBox {DIV} at (266,2) size 22x22
+layer at (274,267) size 2x22
+ RenderFlexibleBox {DIV} at (0,0) size 2x22 [border: (1px solid #000000F3)]
+ RenderSlider {INPUT} at (-7,6) size 2x10 [color=#909090] [border: (1px solid #000000DF)]
+ RenderFlexibleBox {DIV} at (1,1) size 0x8
+ RenderBlock {DIV} at (0,0) size 0x8
+layer at (260,274) size 8x8
+ RenderBlock {DIV} at (-8,0) size 8x8
layer at (277,270) size 16x16
RenderButton {BUTTON} at (3,3) size 16x16 [color=#FFFFFF]
layer at (305,270) size 16x16
@@ -76,6 +83,13 @@
RenderBlock {DIV} at (0,0) size 6x6 [bgcolor=#FFFFFF]
layer at (598,267) size 22x22
RenderFlexibleBox {DIV} at (266,2) size 22x22
+layer at (598,267) size 2x22
+ RenderFlexibleBox {DIV} at (0,0) size 2x22 [border: (1px solid #000000F3)]
+ RenderSlider {INPUT} at (-7,6) size 2x10 [color=#909090] [border: (1px solid #000000DF)]
+ RenderFlexibleBox {DIV} at (1,1) size 0x8
+ RenderBlock {DIV} at (0,0) size 0x8
+layer at (584,274) size 8x8
+ RenderBlock {DIV} at (-8,0) size 8x8
layer at (601,270) size 16x16
RenderButton {BUTTON} at (3,3) size 16x16 [color=#FFFFFF]
layer at (629,270) size 16x16
Modified: trunk/LayoutTests/platform/mac/media/controls-without-preload-expected.txt (158712 => 158713)
--- trunk/LayoutTests/platform/mac/media/controls-without-preload-expected.txt 2013-11-06 03:36:32 UTC (rev 158712)
+++ trunk/LayoutTests/platform/mac/media/controls-without-preload-expected.txt 2013-11-06 03:50:51 UTC (rev 158713)
@@ -39,6 +39,13 @@
RenderBlock {DIV} at (0,0) size 6x6 [bgcolor=#FFFFFF]
layer at (274,259) size 22x22
RenderFlexibleBox {DIV} at (266,2) size 22x22
+layer at (274,259) size 2x22
+ RenderFlexibleBox {DIV} at (0,0) size 2x22 [border: (1px solid #000000F3)]
+ RenderSlider {INPUT} at (-7,6) size 2x10 [color=#909090] [border: (1px solid #000000DF)]
+ RenderFlexibleBox {DIV} at (1,1) size 0x8
+ RenderBlock {DIV} at (0,0) size 0x8
+layer at (260,266) size 8x8
+ RenderBlock {DIV} at (-8,0) size 8x8
layer at (277,262) size 16x16
RenderButton {BUTTON} at (3,3) size 16x16 [color=#FFFFFF]
layer at (305,262) size 16x16
Modified: trunk/Source/WebCore/ChangeLog (158712 => 158713)
--- trunk/Source/WebCore/ChangeLog 2013-11-06 03:36:32 UTC (rev 158712)
+++ trunk/Source/WebCore/ChangeLog 2013-11-06 03:50:51 UTC (rev 158713)
@@ -1,3 +1,38 @@
+2013-11-05 James Craig <[email protected]>
+
+ AX: media controls accessibility needs more work
+ https://bugs.webkit.org/show_bug.cgi?id=123749
+
+ Reviewed by Jer Noble.
+
+ Updated some of the control labels/roles to improve accessibility.
+ - Volume slider is now keyboard/screenreader accessible.
+ - muteButton was a checkbox toggling checked state, now a button that toggles label "mute/unmute"
+ - fullscreenButton was a checkbox toggling checked state, now a button that toggles label "display/exit full screen"
+ - captionButton was a checkbox, now a popup button that launches the newly accessible menu.
+ Subtitles menu is now keyboard/screenreader accessible (uses roaming tabindex).
+ Render dump expectations changed because volume slider is now hidden via...
+ ...opacity/size (to make accessible without hover) instead of display:none.
+
+ Updated existing test coverage.
+
+ * Modules/mediacontrols/mediaControlsApple.css:
+ (audio::-webkit-media-controls-panel .volume-box):
+ (audio::-webkit-media-controls-panel .volume-box:active):
+ (audio::-webkit-media-controls-toggle-closed-captions-button):
+ (audio::-webkit-media-controls-closed-captions-container .list):
+ (audio::-webkit-media-controls-closed-captions-container li:focus):
+ * Modules/mediacontrols/mediaControlsApple.js:
+ (Controller.prototype.createControls):
+ (Controller.prototype.handleFullscreenChange):
+ (Controller.prototype.handleMuteButtonClicked):
+ (Controller.prototype.handleMinButtonClicked):
+ (Controller.prototype.handleMaxButtonClicked):
+ (Controller.prototype.handleVolumeSliderChange):
+ (Controller.prototype.buildCaptionMenu):
+ (Controller.prototype.focusSiblingCaptionItem):
+ (Controller.prototype.handleCaptionItemKeyUp):
+
2013-11-05 Andreas Kling <[email protected]>
Move some plugin-specific code from RenderWidget to RenderEmbeddedObject.
Modified: trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.css (158712 => 158713)
--- trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.css 2013-11-06 03:36:32 UTC (rev 158712)
+++ trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.css 2013-11-06 03:50:51 UTC (rev 158713)
@@ -172,7 +172,6 @@
position: absolute;
box-sizing: border-box;
height: 22px;
- width: 114px;
bottom: 0;
left: 0;
@@ -194,9 +193,12 @@
-webkit-justify-content: flex-end;
opacity: 0;
- display: none;
+ /* make zero width (rather than display:none) for AX and FKA */
+ width: 0; /* will become 114px when shown */
+
}
+/* FIXME: needs CSS4 !subject selector to show when slider inside .volume-box is focused */
video::-webkit-media-controls-panel .mute-box:hover .volume-box,
video::-webkit-media-controls-panel .volume-box:hover,
video::-webkit-media-controls-panel .volume-box:active,
@@ -204,7 +206,8 @@
audio::-webkit-media-controls-panel .volume-box:hover,
audio::-webkit-media-controls-panel .volume-box:active {
opacity: 1;
- display: inherit;
+ /* resize to usable amount (rather than display:none) for AX and FKA */
+ width: 114px;
}
audio::-webkit-media-controls-volume-slider,
@@ -268,8 +271,8 @@
width: 16px;
height: 16px;
margin: 0 7px;
-
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 102 105"><linearGradient id="gradient" x2="0" y2="100%" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="rgb(216, 216, 216)"/><stop offset="0.46875" stop-color="rgb(216, 216, 216)"/><stop offset="0.46875" stop-color="rgb(208, 208, 208)"/><stop offset="0.53125" stop-color="rgb(208, 208, 208)"/><stop offset="0.53125" stop-color="rgb(200, 200, 200)"/><stop offset="1" stop-color="rgb(208, 208, 208)"/></linearGradient><path d="M98.766,43.224c0-23.163-21.775-41.94-48.637-41.94c-26.859,0-48.635,18.777-48.635,41.94c0,18.266,13.546,33.796,32.444,39.549c1.131,8.356,26.037,24.255,22.864,19.921c-4.462-6.096-5.159-13.183-5.07-17.566C77.85,84.397,98.766,65.923,98.766,43.224z" fill="url(#gradient)"/></svg>');
+ outline: 0;
}
video::-webkit-media-controls-closed-captions-container,
@@ -294,7 +297,7 @@
video::-webkit-media-controls-closed-captions-container .list,
audio::-webkit-media-controls-closed-captions-container .list {
display: block;
- font-family: "Helvetica Bold", Helvetica;
+ font-family: "Helvetica Bold", Helvetica, sans-serif;
font-size: 10pt;
-webkit-user-select: none;
}
@@ -337,6 +340,12 @@
border-bottom: 1px solid transparent;
}
+video::-webkit-media-controls-closed-captions-container li:focus,
+audio::-webkit-media-controls-closed-captions-container li:focus {
+ outline: 0;
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, rgba(255, 255, 255, 0.3)), color-stop(1, rgba(255, 255, 255, 0.2)));
+}
+
video::-webkit-media-controls-closed-captions-container li:hover,
audio::-webkit-media-controls-closed-captions-container li:hover {
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, rgb(79, 112, 246)), color-stop(1, rgb(26, 68, 243)));
Modified: trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.js (158712 => 158713)
--- trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.js 2013-11-06 03:36:32 UTC (rev 158712)
+++ trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.js 2013-11-06 03:50:51 UTC (rev 158713)
@@ -76,6 +76,19 @@
thumbnailTrack: 'thumbnail-track',
volumeBox: 'volume-box',
},
+ KeyCodes: {
+ enter: 13,
+ escape: 27,
+ space: 32,
+ pageUp: 33,
+ pageDown: 34,
+ end: 35,
+ home: 36,
+ left: 37,
+ up: 38,
+ right: 39,
+ down: 40
+ },
// Localized string accessor
UIString: function(s){
@@ -88,23 +101,26 @@
// FIXME: Move localization to ext strings file <http://webkit.org/b/120956>
'Aborted': 'Aborted',
'Audio Playback': 'Audio Playback',
+ 'Captions': 'Captions',
'Display Full Screen': 'Display Full Screen',
'Duration': 'Duration',
+ 'Elapsed': 'Elapsed',
'Error': 'Error',
+ 'Exit Full Screen': 'Exit Full Screen',
'Fast Forward': 'Fast Forward',
'Loading': 'Loading',
'Maximum Volume': 'Maximum Volume',
'Minimum Volume': 'Minimum Volume',
'Mute': 'Mute',
+ 'Pause': 'Pause',
'Play': 'Play',
- 'Pause': 'Pause',
+ 'Remaining': 'Remaining',
'Rewind': 'Rewind',
'Rewind %%sec%% Seconds': 'Rewind %%sec%% Seconds',
- 'Show Captions': 'Show Captions',
'Stalled': 'Stalled',
+ 'Subtitles': 'Subtitles',
'Suspended': 'Suspended',
- 'Elapsed': 'Elapsed',
- 'Remaining': 'Remaining',
+ 'Unmute': 'Unmute',
'Video Playback': 'Video Playback',
'Volume': 'Volume',
'Waiting': 'Waiting'
@@ -301,8 +317,6 @@
var muteButton = this.controls.muteButton = document.createElement('button');
muteButton.setAttribute('pseudo', '-webkit-media-controls-mute-button');
muteButton.setAttribute('aria-label', this.UIString('Mute'));
- muteButton.setAttribute('role', 'checkbox');
- muteButton.setAttribute('aria-checked', 'false');
this.listenFor(muteButton, 'click', this.handleMuteButtonClicked);
var minButton = this.controls.minButton = document.createElement('button');
@@ -329,16 +343,13 @@
var captionButton = this.controls.captionButton = document.createElement('button');
captionButton.setAttribute('pseudo', '-webkit-media-controls-toggle-closed-captions-button');
- captionButton.setAttribute('aria-label', this.UIString('Show Captions'));
- captionButton.setAttribute('role', 'checkbox');
- captionButton.setAttribute('aria-checked', 'false');
+ captionButton.setAttribute('aria-label', this.UIString('Captions'));
+ captionButton.setAttribute('aria-haspopup', 'true');
this.listenFor(captionButton, 'click', this.handleCaptionButtonClicked);
var fullscreenButton = this.controls.fullscreenButton = document.createElement('button');
fullscreenButton.setAttribute('pseudo', '-webkit-media-controls-fullscreen-button');
fullscreenButton.setAttribute('aria-label', this.UIString('Display Full Screen'));
- fullscreenButton.setAttribute('role', 'checkbox');
- fullscreenButton.setAttribute('aria-checked', 'false');
this.listenFor(fullscreenButton, 'click', this.handleFullscreenButtonClicked);
},
@@ -519,11 +530,11 @@
if (this.isFullScreen()) {
this.controls.fullscreenButton.classList.add(this.ClassNames.exit);
- this.controls.fullscreenButton.setAttribute('aria-checked', 'true');
+ this.controls.fullscreenButton.setAttribute('aria-label', this.UIString('Exit Full Screen'));
this.setControlsType(Controller.FullScreenControls);
} else {
this.controls.fullscreenButton.classList.remove(this.ClassNames.exit);
- this.controls.fullscreenButton.setAttribute('aria-checked', 'false');
+ this.controls.fullscreenButton.setAttribute('aria-label', this.UIString('Display Full Screen'));
this.setControlsType(Controller.InlineControls);
}
},
@@ -668,14 +679,14 @@
{
this.video.muted = !this.video.muted;
if (this.video.muted)
- this.controls.muteButton.setAttribute('aria-checked', 'true');
+ this.controls.muteButton.setAttribute('aria-label', this.UIString('Unmute'));
},
handleMinButtonClicked: function(event)
{
if (this.video.muted) {
this.video.muted = false;
- this.controls.muteButton.setAttribute('aria-checked', 'false');
+ this.controls.muteButton.setAttribute('aria-label', this.UIString('Mute'));
}
this.video.volume = 0;
},
@@ -684,7 +695,7 @@
{
if (this.video.muted) {
this.video.muted = false;
- this.controls.muteButton.setAttribute('aria-checked', 'false');
+ this.controls.muteButton.setAttribute('aria-label', this.UIString('Mute'));
}
this.video.volume = 1;
},
@@ -693,7 +704,7 @@
{
if (this.video.muted) {
this.video.muted = false;
- this.controls.muteButton.setAttribute('aria-checked', 'false');
+ this.controls.muteButton.setAttribute('aria-label', this.UIString('Mute'));
}
this.video.volume = this.controls.volume.value;
},
@@ -928,16 +939,22 @@
list.classList.add(this.ClassNames.list);
var heading = document.createElement('h3');
+ heading.id = 'webkitMediaControlsClosedCaptionsHeading'; // for AX menu label
list.appendChild(heading);
- heading.innerText = 'Subtitles';
+ heading.innerText = this.UIString('Subtitles');
var ul = document.createElement('ul');
+ ul.setAttribute('role', 'menu');
+ ul.setAttribute('aria-labelledby', 'webkitMediaControlsClosedCaptionsHeading');
list.appendChild(ul);
for (var i = 0; i < tracks.length; ++i) {
var menuItem = document.createElement('li');
+ menuItem.setAttribute('role', 'menuitemradio');
+ menuItem.setAttribute('tabindex', '-1');
this.captionMenuItems.push(menuItem);
this.listenFor(menuItem, 'click', this.captionItemSelected);
+ this.listenFor(menuItem, 'keyup', this.handleCaptionItemKeyUp);
ul.appendChild(menuItem);
var track = tracks[i];
@@ -950,19 +967,38 @@
}
if (track === automaticItem) {
- if (displayMode === 'automatic')
+ if (displayMode === 'automatic') {
menuItem.classList.add(this.ClassNames.selected);
+ menuItem.setAttribute('tabindex', '0');
+ menuItem.setAttribute('aria-checked', 'true');
+ }
continue;
}
if (displayMode != 'automatic' && track.mode === 'showing') {
var trackMenuItemSelected = true;
menuItem.classList.add(this.ClassNames.selected);
+ menuItem.setAttribute('tabindex', '0');
+ menuItem.setAttribute('aria-checked', 'true');
}
+
}
- if (offMenu && displayMode === 'forced-only' && !trackMenuItemSelected)
+ if (offMenu && displayMode === 'forced-only' && !trackMenuItemSelected) {
offMenu.classList.add(this.ClassNames.selected);
+ menuItem.setAttribute('tabindex', '0');
+ menuItem.setAttribute('aria-checked', 'true');
+ }
+
+ // focus first selected menuitem
+ for (var i = 0, c = this.captionMenuItems.length; i < c; i++) {
+ var item = this.captionMenuItems[i];
+ if (item.classList.contains(this.ClassNames.selected)) {
+ item.focus();
+ break;
+ }
+ }
+
},
captionItemSelected: function(event)
@@ -971,6 +1007,51 @@
this.destroyCaptionMenu();
},
+ focusSiblingCaptionItem: function(event)
+ {
+ var currentItem = event.target;
+ var pendingItem = false;
+ switch(event.keyCode) {
+ case this.KeyCodes.left:
+ case this.KeyCodes.up:
+ pendingItem = currentItem.previousSibling;
+ break;
+ case this.KeyCodes.right:
+ case this.KeyCodes.down:
+ pendingItem = currentItem.nextSibling;
+ break;
+ }
+ if (pendingItem) {
+ currentItem.setAttribute('tabindex', '-1');
+ pendingItem.setAttribute('tabindex', '0');
+ pendingItem.focus();
+ }
+ },
+
+ handleCaptionItemKeyUp: function(event)
+ {
+ switch (event.keyCode) {
+ case this.KeyCodes.enter:
+ case this.KeyCodes.space:
+ this.captionItemSelected(event);
+ break;
+ case this.KeyCodes.escape:
+ this.destroyCaptionMenu();
+ break;
+ case this.KeyCodes.left:
+ case this.KeyCodes.up:
+ case this.KeyCodes.right:
+ case this.KeyCodes.down:
+ this.focusSiblingCaptionItem(event);
+ break;
+ default:
+ return;
+ }
+ // handled
+ event.stopPropagation();
+ event.preventDefault();
+ },
+
destroyCaptionMenu: function()
{
if (!this.captionMenu)
@@ -978,8 +1059,13 @@
this.captionMenuItems.forEach(function(item){
this.stopListeningFor(item, 'click', this.captionItemSelected);
+ this.stopListeningFor(item, 'keyup', this.handleCaptionItemKeyUp);
}, this);
+ // FKA and AX: focus the trigger before destroying the element with focus
+ if (this.controls.captionButton)
+ this.controls.captionButton.focus();
+
if (this.captionMenu.parentNode)
this.captionMenu.parentNode.removeChild(this.captionMenu);
delete this.captionMenu;