-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Keyboard events and ARIA markup added to speed control #2381
Keyboard events and ARIA markup added to speed control #2381
Conversation
@polesye @valera-rozuvan DO NOT MERGE. Please review the new functionality of the speed menu button, I made it adhere to the following standards: http://www.w3.org/TR/wai-aria-practices/#menubutton. I will then fix the tests that are failing. |
@polesye @valera-rozuvan By the way, I did not add aria-haspopup="true" to the speed button on purpose, it doesn't work well with Voice Over. If added, it will also announce the position of the video and its total length. Will investigate why. For the moment, it is not an issue as the volume control doesn't have that ARIA markup either. |
speedControl = $('div.speeds'), | ||
speedEntries = $('div.speeds>a'), | ||
firstSpeedEntry = speedEntries.first(), | ||
secondSpeedEntry = $(speedEntries.eq(1)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$(speedEntries.eq(1))
=> speedEntries.eq(1)
@polesye @valera-rozuvan Fixed tests. Will add a couple of missing cases (ENTER & ESC on speed entries) tomorrow. |
|
||
// Get previous element in array or cyles back to the last if it | ||
// is the first. | ||
previousSpeed = function(index) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jmclaus Why is this function declared globally? Use the var
keyword...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@valera-rozuvan Done. (Why is this function declared globally? Use the var keyword)
My thoughts: let's avoid navigation via TAB through the menu items.
What do you think about following behaviors: If focus is on the hint button:
If focus is on a hint item:
|
@polesye I was modeling the TAB behavior on menu items after this: http://adobe-accessibility.github.io/Accessible-Mega-Menu/ But I agree, it should rather adhere to the W3 standards. It's easy to change in the case of the speed control. And we should include this behavior in the upcoming plugin. I'm not sure of the behavior of:
This is also the standard behavior in native menus. |
I think we need to implement [Menu Button(http://www.w3.org/TR/wai-aria-practices/#menubutton) behavior in this PR and no need to support LEFT/RIGHT arrows like in Menu. I have updated behavior:
If focus is on a menu item:
|
@anton Agreed, lets not pack this PR with too many new features. I just noticed this (under 'Menu or Menu bar' not 'Menu button'): If a menu bar item has focus and the menu is not open, then: So I agree on behavior of Space/Enter as it is not an isolated menu button but part of a menu bar. I've added a few things. Here's the updated behavior: If focus is on the menu button: Enter/Space/Up arrow: Open menu and move focus onto the first menu item. If focus is on a menu item: Up arrow: Select previous menu item. |
beforeEach(function () { | ||
state = jasmine.initializePlayer(); | ||
speedControl = $('div.speeds'); | ||
speedEntries = $('div.speeds>a'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
speedEntries = speedControl.children('a')
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@polesye Done (speedEntries = speedControl.children('a')).
@polesye @valera-rozuvan Addressed your comments, please continue review. Two specs were added, ENTER and ESCAPE behavior on menu items (I can't figure how to test the speed change on the ENTER keypress and left a TODO note. Any idea?). Also, using 'toBeFocused()' now makes the tests fail... |
@polesye @valera-rozuvan New behavior left to implement after our recent discussion:
|
@polesye @valera-rozuvan Implemented the following: 'Pressing Space or Enter when Speed button has focus should open the menu and give focus to the last item in list (not the Speed button).' and changed the tests accordingly. Also reverted to not using 'toBeFocused()'. |
@polesye @valera-rozuvan Please continue review. I just implemented the following: Pressing TAB or SHIFT + TAB should give focus to Play/Pause button and Volume button respectively. and added related tests. In these, there are four things I cannot get to work (tests fail, therefore I omitted them):
I welcome any suggestion. |
|
|
Agree. |
Anyway it looks great! I believe we'll add the same behavior for the captions in future. |
$(nextSpeedLink).focus(); | ||
break; | ||
// Close menu. | ||
case KEY.TAB: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that we should not do that explicitly, it should works via native tab ordering.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@polesye If I remove the focus() call, things break. I'll leave it as is for the moment, let me wrap up the rest beforehand. Thanks.
// entries. | ||
speedLinks.on('click', _clickHandler.bind(state)); | ||
|
||
speedLinks.each(function(index, speedLink) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To improve performance and memory usage:
var speedButtonAnchor = state.videoSpeedControl.el.children('a');
state.videoSpeedControl.videoSpeedsEl.on('keydown', 'a.speed_link', function (event) {
event.preventDefault();
event.stopImmediatePropagation();
var el = state.videoSpeedControl.el,
index = $(event.currentTarget).parent().index();
switch (event.keyCode) {
// Scroll up menu, wrapping at the top. Keep menu open.
case KEY.UP:
_previousSpeedLink(speedLinks, index).focus();
break;
// Scroll down menu, wrapping at the bottom. Keep menu
// open.
case KEY.DOWN:
_nextSpeedLink(speedLinks, index).focus();
break;
// Close menu.
case KEY.TAB:
el.removeClass('open');
break;
// Close menu, give focus to speed control and change
// speed.
case KEY.ENTER:
case KEY.SPACE:
el.removeClass('open');
speedButtonAnchor.focus();
state.videoSpeedControl.changeVideoSpeed(event);
break;
// Close menu and give focus to speed control.
case KEY.ESCAPE:
el.removeClass('open');
speedButtonAnchor.focus();
break;
}
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@polesye Yes, delegated events, elegant. Done.
@polesye @valera-rozuvan The following has been done:
And addressed all comments, except the one regarding TAB (or Tab + SHIFT) keypress on the speed entries. Did a lot of refactoring and got rid of the last anonymous eventHandler (key press on speed entries). Left to do: correct the failing tests. And add a few more of them to test new functionality. It's starting to look good! Please review again when you have time. Thanks for all your help and comments! |
👍 once all tests will be written. |
👍 |
@valera-rozuvan @polesye OK, will let you know when they are done. Thanks. |
@polesye @valera-rozuvan I added the missing tests. Please review. What should we do with the 3 disabled tests? 2 of them are not relevant since the refactoring. Should I just remove them? And the other one, I cannot get it to function. Anton suggested that we open a new ticket for that issue. Should I do that and remove the test in video_speed_control_spec.js? |
@jmclaus I spent some time to figure out why this test doesn't work and found the problem: spyOn($.fn, 'focus').andCallThrough(); instead spyOn($.fn, 'focus'); And test do not close the speed menu on mouseleave if... pass.
Yes, remove them. |
@polesye @valera-rozuvan Removed 2 irrelevant tests. Fixed last test that wasn't working. Rebased and squashed commits. Good to merge? (when it passes Jenkins) |
|
||
function _closeMenu(state) { | ||
// Remove the previously added clickHandler from window element. | ||
$(window).off('click', _clickHandler.bind(state)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this handler really removed after this? I'm not sure, because of bind
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@polesye You are right. Let me remove the bind, it is not necessary here. |
focused = true | ||
} | ||
}); | ||
return focused; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Description: Check the current matched set of elements against a selector, element, or jQuery object and return true if at least one of these elements matches the given arguments. (See jquery
is
)
I think it can be rewritten so:
function _speedLinksFocused(state) {
var speedLinks = state.videoSpeedControl.videoSpeedsEl
.find('a.speed_link');
return speedLinks.is(':focus');
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You right, done.
Good job! 👍 once Jenkins pass. |
@polesye @valera-rozuvan Addressed latest comments. Rebased & squashed last commit. Checked new functionality -- all behaves correctly. All tests all pass locally. |
@jmclaus "Test Result (no failures)" means you should restart the Jenkins tests manually. Go to https://jenkins.testeng.edx.org/ , log in, select "edx-all-tests-manual-pr", click on "Build with Parameters", enter the PR number. After the second pass, Jenkins usually reports OK. |
@valera-rozuvan it doesn't help. I have the same issue in my PR. |
@jmclaus 👍 |
👍 |
…ymous event handlers by named functions. Menu stays open on mouseleave when a speed entry has focus. In that case, the menu can be closed by clicking anywhere outside of it. [BLD-402, BLD-363]
…_improved_a11y Keyboard events and ARIA markup added to speed control
Addresses BLD-402.