Skip to content

Menubar: move to next item applied focus() to too many items #953

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

Merged
merged 4 commits into from
May 3, 2013
Merged

Menubar: move to next item applied focus() to too many items #953

merged 4 commits into from
May 3, 2013

Conversation

sgharms
Copy link

@sgharms sgharms commented Apr 7, 2013

_move was believed to specify just one item,
called focusableTarget. Using the broader
selectors this would return anything matching a or
button. This means that the next item as well
as
any buttons or as found thereunder would
also have their focus() event fired.

@scottgonzalez
Copy link
Member

Thanks, can you add a unit test showing the behavior? Also, this new selector is unnecessarily duplicative.

I haven't reviewed menubar yet, but this is pointing out a pretty big problem to me. Menubar cannot use button's classes without a dependency on button.

@sgharms
Copy link
Author

sgharms commented Apr 9, 2013

My feeling on menubar at the moment is that its entire construction is flawed. It's built like a giant piece of DOM that responds to events instead of a series of encapsulating widgets. I'm of the opinion that there should be better abstractions in place: yes there should be a menubar widget but also a menubarItem widget (using $.Widget) and a submenu widget, and probably others.

There's considerable mental pain and hidden bugs in the current design (which, yes, I had a hand in). I feel like this could be a whole lot less buggy if it were to be designed this way. Am I opening an unholy can of worms? Or should widgets not depend on other widgets? I personally think that would be a whole lot simpler (to say nothing of infinitely easier to test).

@jzaefferer
Copy link
Member

Menubar actually uses the menu widget, so its not entirely monolithic. So we're generally open to composing widgets of other widgets. If further splits would actually help here remains to be seen. Is that something you're interested in prototyping?

In general considering the complexity of menu itself its not suprising that menubar ends up even more complex. The combination of mouse and keyboard handling, while managing focus, just leads to that. I'm not sure if further decomposition can really make a positive difference.

@scottgonzalez
Copy link
Member

I am strongly opposed to the addition of a menubaritem widget.

@kborchers
Copy link
Member

I also agree that a menubaritem widget is not a good idea.

@sgharms
Copy link
Author

sgharms commented Apr 10, 2013

@jzaefferer It's reassuring that you see that menubar will be an increment of weirdness around menu.

Others: will not create a new widget.

@scottgonzalez Will create test case

All: Finishing up the top two bugs at http://wiki.jqueryui.com/w/page/38666403/Menubar.

@sgharms
Copy link
Author

sgharms commented Apr 12, 2013

@scottgonzalez Changes made, tests provided. I should be more wary when writing code before work 🌔 .

@sgharms
Copy link
Author

sgharms commented Apr 12, 2013

@jzaefferer Where does this leave things in terms of http://wiki.jqueryui.com/w/page/38666403/Menubar ? If this is squared away, I can move to "Disable items/menus with class="ui-state-disabled" "

@sgharms
Copy link
Author

sgharms commented Apr 14, 2013

@kborchers and @scottgonzalez I know you both were against the idea of creating a new widget but...

I have this PR: #958 where I show what happened when I played with the idea. I think the code is much better for it, but I would really like a way to:

  1. Get the benefits of $.Widget
  2. Create a private widget ( or such as that is possible in Javascript ;) )

If you could take a look at that PR and see if there's anything good about it that can be brought over, or tell me how to implement a private widget, I think this code would be the better for it.

@jzaefferer
Copy link
Member

  • Rebase this branch against origin/menubar, to allow a fast-forward merge, currently needs a merge commit
  • Clean up the commits, probably getting rid of all but the first two
  • Fix more bugs, for example: Tab to the first menubar, cursor right, shift tab. Moves focus to the first item, instead of something before the menubar. Similar when tabbing to the second menubar, cursor right, then shift-tab. It moves focus to the next(?) menubar instead of the previous.
  • There's probably a lot more issues like that. I don't really want to do more testing like that, since the back and forth is pretty inefficient. Can you do more manual testing like that, then encode those tests as unit tests?
  • There are a bunch of issues with the code itself, but I'd like to get rid of most of the bugs first, along with unit tests and then start refactoring.

@sgharms
Copy link
Author

sgharms commented Apr 16, 2013

Can do these top 3 today. Writing more test suite will need to be ongoing.

Steven G. Harms added 2 commits April 16, 2013 10:13
`_move` was believed to specify just one item,
called `focusableTarget`.  Using the broader
selectors this would return anything matching `a` or
`button`.  This means that the next item _as well
as_ any `button`s or `a`s found thereunder would
_also_ have their focus() event fired.
1.  Load page
1.  Tab to first bar
1.  Right cursor
1.  Down cursor
1.  Right cursor
1.  Error

Test the object that is tested for an `active` for
definition before querying that property.

Create new method for assessing whether or not a
new submenu should be opened. The testing here is
a smell.  This logic should be simplified.
@sgharms
Copy link
Author

sgharms commented Apr 17, 2013

Closing. Will re-open when I have more tests.

@sgharms sgharms closed this Apr 17, 2013
@sgharms sgharms reopened this Apr 18, 2013
@sgharms
Copy link
Author

sgharms commented Apr 18, 2013

Is there a test I can crib from which tests TAB and shift-TAB behavior? I want to provide the
requested unit tests that ensure TAB order is working properly. I think i have
it working, but this has (ahem) proved faillible in the past and I'd like to
have the insurance.

@scottgonzalez
Copy link
Member

asyncTest( "Prevent tabbing out of dialogs", function() {

@sgharms
Copy link
Author

sgharms commented Apr 24, 2013

@jzaefferer

Per your comments of 2013-04-16

Fix more bugs, for example: Tab to the first menubar, cursor right, shift tab. Moves focus to the first item, instead of something before the menubar. Similar when tabbing to the second menubar, cursor right, then shift-tab. It moves focus to the next(?) menubar instead of the previous.

These two specific bugs have been addressed. I've attempted to break things manually but have not been able to produce any other cursor key or TAB-order bugs.

There's probably a lot more issues like that. I don't really want to do more testing like that, since the back and forth is pretty inefficient. Can you do more manual testing like that, then encode those tests as unit tests?

Commit 4e47df2 brings in unit testing for some of the basics of this but, per its commit message, I don't see why my invocations are failing as the demo works and my other uses of simulate work. Perhaps someone can suggest a fix in this PR.

https://github.com/sgharms/jquery-ui/blob/4e47df29134b45cb19a6ce712b1ac6e9838a6186/tests/unit/menubar/menubar_events.js#L62

unit tests and then start refactoring.

My goal would be now to move to this phase of things with focus on getting the unit tests in place. I suspect I can mutate this code to look a great deal more like dialog (cf. previous discussion on internal code structuring) without too much supervision, but getting a bug free (but ugly) build that starts to get some testing around events (particularly cursor and TAB events) is what I'd like to see this PR achieve.

@sgharms
Copy link
Author

sgharms commented Apr 24, 2013

@scottgonzalez Removed junk you pointed out in meeting today.

@@ -46,4 +46,76 @@ test( "hover over a menu item with no sub-menu should close open menu", function
equal($(".ui-menu:visible").length, 0, "After triggering a sub-menu, a click on a peer menu item should close the opened sub-menu");
});

test ( "_findNextFocusableTarget should find one and only one item", function() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we testing an internal method?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You asked:

Thanks, can you add a unit test showing the behavior? Also, this new selector is unnecessarily duplicative

To ensure that I got the extracted method to return the right thing, I wrote this unit test. I didn't want to have to do the unit-test-as-integration test where a widget is created, actions are executed and then the state of some element is assessed. That seemed less in the spirit of unit test. I'm open to suggestions though: How would you recommend exercising this?

But, let me say, this is going to go away when I reorganize the internals so let's not spend much time on this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of our tests aren't unit tests. We don't really care about that level of coverage. We care about our public APIs.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very helpful. Will comply.

});
} else {
menubar._off( $anItem, "click mouseenter" );
menubar._hoverable( $anItem );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming the _off call above can be removed, this can probably be dropped as well, since _hoverable is already called in _initializeItems.

@jzaefferer
Copy link
Member

Done with my review for now. I've left a bunch of comments on individual commits as well as the PR itself. I hope fixing the tabIndex=1 issue resolves a lot of the bugs we've seen before.

Otherwise I think you're doing a great job at improving things. The codebase looks much better now. There are still a few odditities, as noted, but overall I can understand what's going on even though it has been years since I wrote some of the original code.

@jzaefferer
Copy link
Member

As for the tab unit test, I lost track of what the issue is there. Maybe I can get together with @scottgonzalez later today to dig into that together.

@scottgonzalez
Copy link
Member

The reason the test fails is because you can't actually test the behavior of tab navigation. Simulating a TAB key won't actually move focus, because it's just triggering an event. We need Selenium/WebDriver in order to test this functionality, but we don't currently have a system for writing those tests. The reason this works in the dialog test suite is because the dialog plugin actually manages what happens when you press tab (assuming you're on the first or last tabbable element).

You can write a test that verifies that only one menu item is tabbable at a time, and that the tabindex updates appropriately as you move focus via arrow keys, but that's about the extent of the testing that can be done at this time.

@sgharms
Copy link
Author

sgharms commented May 1, 2013

Completed fixing several small points of Jörn: mostly whitespace or incorrect method, etc. More "substantive" changes that require a test case are underway.

@sgharms
Copy link
Author

sgharms commented May 1, 2013

Great Scott! I will have those tests added in a jiffy.

});

asyncTest( "Cursor keys should move focus within the menu items", function() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few things here:

  • Since you're not actually triggering focus, it doesn't have to be an async test anymore.
  • The debugDelay variable can go away.
  • You should add an assertion that checks that the now focussed element is the only one that's tabbable. Can be one or more assertions.

@jzaefferer
Copy link
Member

Looking pretty good already. Once you fixed the tabindex to 0 (instead of 1), along with whatever other changes are still missing, I'll get back to actual testing.

@sgharms
Copy link
Author

sgharms commented May 2, 2013

@jzaefferer I have finished implementing the issues you mentioned in various commit notes, line notes, etc.

Outstanding Issues

  1. unwrap() seeming not to work: see eaaf323
  2. Style review

Steps Forward

  1. Clear outstanding issues, above
  2. Squash these tons of commits
  3. Merge it! 🎏

Status

For the moment, I'm undertaking no new actions.

@jzaefferer
Copy link
Member

I don't think those two issues are reason enough to stop. I've pinged Scott about the unwrap issue, since I don't see why it wouldn't work, and we can do the style review later, or step by step with other updates. Can you go ahead and squash commits? I'll merge then.

This code base had been noted for being "unusual"
in comparison with other widgets e.g. `dialog` by
@scottgonzalez et al.  Further drift was
introduced by @sgharms.

This commit reflects the work of bringing
`menubar` closer to `dialog` by means of removing
extremely unusual code invocations and by
implementing feedback from a detailed review by
@jzaefferer.
@sgharms
Copy link
Author

sgharms commented May 3, 2013

@jzaefferer, @scottgonzalez: We're all squashed up and ready to merge.

@jzaefferer jzaefferer merged commit d81479b into jquery:menubar May 3, 2013
@jzaefferer
Copy link
Member

Did a bit of local testing, then merged this and origin/master to bring the branch up-to-date. Great work, Steven! Of course there's still more to do.

@honeypc
Copy link

honeypc commented May 21, 2013

Cannot call methods on menu prior to initialization; attempted to call method 'collapseAll'. When using menubar don''t exist submenu.

  • New
  • Edit
  • Delete

$(function () {
$('#command-menubar').menubar();
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

6 participants