Permalink
Browse files

Core: Remove ancestor visibility requirement from `:focusable` selector

* Check computed visibility in addition to :visible
* Add tests for nested visibility override

Fixes #14596
Closes gh-1583
  • Loading branch information...
westonruter authored and scottgonzalez committed Aug 4, 2015
1 parent 6308a26 commit 0db243a7369bc1e642a83d8b84be9437c360f7e2
Showing with 16 additions and 14 deletions.
  1. +5 −0 tests/unit/core/core.html
  2. +8 −2 tests/unit/core/selector.js
  3. +3 −12 ui/focusable.js
@@ -80,6 +80,11 @@
<div id="visibilityHiddenAncestor" style="visibility: hidden;">
<input id="visibilityHiddenAncestor-input">
<span tabindex="1" id="visibilityHiddenAncestor-span">.</span>
<span id="nestedVisibilityOverrideAncestor" style="visibility: visible">
<input id="nestedVisibilityOverrideAncestor-input">
<span tabindex="1" id="nestedVisibilityOverrideAncestor-span">.</span>
</span>
</div>
<span tabindex="1" id="displayNone-span" style="display: none;">.</span>
@@ -125,14 +125,17 @@ test( "focusable - disabled elements", function() {
} );
test( "focusable - hidden styles", function() {
expect( 8 );
expect( 10 );
isNotFocusable( "#displayNoneAncestor-input", "input, display: none parent" );
isNotFocusable( "#displayNoneAncestor-span", "span with tabindex, display: none parent" );
isNotFocusable( "#visibilityHiddenAncestor-input", "input, visibility: hidden parent" );
isNotFocusable( "#visibilityHiddenAncestor-span", "span with tabindex, visibility: hidden parent" );
isFocusable( "#nestedVisibilityOverrideAncestor-input", "input, visibility: visible parent but visibility: hidden grandparent" );
isFocusable( "#nestedVisibilityOverrideAncestor-span", "span with tabindex, visibility: visible parent but visibility: hidden grandparent " );
isNotFocusable( "#displayNone-input", "input, display: none" );
isNotFocusable( "#visibilityHidden-input", "input, visibility: hidden" );
@@ -210,14 +213,17 @@ test( "tabbable - disabled elements", function() {
} );
test( "tabbable - hidden styles", function() {
expect( 8 );
expect( 10 );
isNotTabbable( "#displayNoneAncestor-input", "input, display: none parent" );
isNotTabbable( "#displayNoneAncestor-span", "span with tabindex, display: none parent" );
isNotTabbable( "#visibilityHiddenAncestor-input", "input, visibility: hidden parent" );
isNotTabbable( "#visibilityHiddenAncestor-span", "span with tabindex, visibility: hidden parent" );
isTabbable( "#nestedVisibilityOverrideAncestor-input", "input, visibility: visible parent but visibility: hidden grandparent" );
isTabbable( "#nestedVisibilityOverrideAncestor-span", "span with tabindex, visibility: visible parent but visibility: hidden grandparent " );
isNotTabbable( "#displayNone-input", "input, display: none" );
isNotTabbable( "#visibilityHidden-input", "input, visibility: hidden" );
View
@@ -34,26 +34,17 @@ $.ui.focusable = function( element, hasTabindex ) {
if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
return false;
}
img = $( "img[usemap='#" + mapName + "']" )[ 0 ];
return !!img && visible( img );
img = $( "img[usemap='#" + mapName + "']" );
return img.length > 0 && img.is( ":visible" );
}
return ( /^(input|select|textarea|button|object)$/.test( nodeName ) ?
!element.disabled :
"a" === nodeName ?
element.href || hasTabindex :
hasTabindex ) &&
// The element and all of its ancestors must be visible
visible( element );
$( element ).is( ":visible" ) && $( element ).css( "visibility" ) === "visible";
};
function visible( element ) {
return $.expr.filters.visible( element ) &&
!$( element ).parents().addBack().filter( function() {
return $.css( this, "visibility" ) === "hidden";
} ).length;
}
$.extend( $.expr[ ":" ], {
focusable: function( element ) {
return $.ui.focusable( element, $.attr( element, "tabindex" ) != null );

0 comments on commit 0db243a

Please sign in to comment.