mirror of
https://github.com/jquery/jquery-ui.git
synced 2024-11-21 11:04:24 +00:00
Core: Better support for areas in :focusable and :tabbable selectors. Partial fix for #4488 - :focusable and :tabbable are broken with jQuery 1.3.2.
This commit is contained in:
parent
4deb824699
commit
fe13fbadd4
@ -42,6 +42,17 @@
|
|||||||
|
|
||||||
<div id="main" style="position: absolute; top: -10000px; left: -10000px;">
|
<div id="main" style="position: absolute; top: -10000px; left: -10000px;">
|
||||||
|
|
||||||
|
<img src="images/jqueryui_32x32.png" usemap="#mymap" width="10", height="10">
|
||||||
|
<map name="mymap">
|
||||||
|
<area shape="rect" coords="0,0,1,1" id="areaCoordsNoHref">
|
||||||
|
<area shape="rect" coords="1,1,2,2" href="foo.html" id="areaCoordsHref">
|
||||||
|
<area shape="rect" coords="0,0,0,0" href="foo.html" id="areaCoordsNoSizeHref">
|
||||||
|
<area href="foo.html" id="areaNoCoordsHref">
|
||||||
|
</map>
|
||||||
|
<map name="mymap2">
|
||||||
|
<area shape="rect" coords="1,1,2,2" href="foo.html" id="areaNoImg">
|
||||||
|
</map>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<input id="visibleAncestor-inputTypeNone" />
|
<input id="visibleAncestor-inputTypeNone" />
|
||||||
<input type="text" id="visibleAncestor-inputTypeText" />
|
<input type="text" id="visibleAncestor-inputTypeText" />
|
||||||
@ -57,10 +68,6 @@
|
|||||||
<object id="visibleAncestor-object">xxx</object>
|
<object id="visibleAncestor-object">xxx</object>
|
||||||
<a href="#" id="visibleAncestor-anchorWithHref">anchor</a>
|
<a href="#" id="visibleAncestor-anchorWithHref">anchor</a>
|
||||||
<a id="visibleAncestor-anchorWithoutHref">anchor</a>
|
<a id="visibleAncestor-anchorWithoutHref">anchor</a>
|
||||||
<map>
|
|
||||||
<area href="#" id="visibleAncestor-areaWithHref" alt="" />
|
|
||||||
<area id="visibleAncestor-areaWithoutHref" alt="" />
|
|
||||||
</map>
|
|
||||||
<span id="visibleAncestor-span">x</span>
|
<span id="visibleAncestor-span">x</span>
|
||||||
<div id="visibleAncestor-div">x</div>
|
<div id="visibleAncestor-div">x</div>
|
||||||
<span id="visibleAncestor-spanWithTabindex" tabindex="1">x</span>
|
<span id="visibleAncestor-spanWithTabindex" tabindex="1">x</span>
|
||||||
|
@ -79,7 +79,7 @@ test("data", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("focusable - visible, enabled elements", function() {
|
test("focusable - visible, enabled elements", function() {
|
||||||
expect(18);
|
expect(16);
|
||||||
|
|
||||||
isFocusable('#visibleAncestor-inputTypeNone', 'input, no type');
|
isFocusable('#visibleAncestor-inputTypeNone', 'input, no type');
|
||||||
isFocusable('#visibleAncestor-inputTypeText', 'input, type text');
|
isFocusable('#visibleAncestor-inputTypeText', 'input, type text');
|
||||||
@ -93,9 +93,6 @@ test("focusable - visible, enabled elements", function() {
|
|||||||
isFocusable('#visibleAncestor-object', 'object');
|
isFocusable('#visibleAncestor-object', 'object');
|
||||||
isFocusable('#visibleAncestor-anchorWithHref', 'anchor with href');
|
isFocusable('#visibleAncestor-anchorWithHref', 'anchor with href');
|
||||||
isNotFocusable('#visibleAncestor-anchorWithoutHref', 'anchor without href');
|
isNotFocusable('#visibleAncestor-anchorWithoutHref', 'anchor without href');
|
||||||
// fails: $("map").is(":visible") and $("map").is(":hidden") both return true
|
|
||||||
isFocusable('#visibleAncestor-areaWithHref', 'area with href');
|
|
||||||
isNotFocusable('#visibleAncestor-areaWithoutHref', 'area without href');
|
|
||||||
isNotFocusable('#visibleAncestor-span', 'span');
|
isNotFocusable('#visibleAncestor-span', 'span');
|
||||||
isNotFocusable('#visibleAncestor-div', 'div');
|
isNotFocusable('#visibleAncestor-div', 'div');
|
||||||
isFocusable("#visibleAncestor-spanWithTabindex", 'span with tabindex');
|
isFocusable("#visibleAncestor-spanWithTabindex", 'span with tabindex');
|
||||||
@ -159,8 +156,16 @@ test("focusable - invalid tabindex", function() {
|
|||||||
isNotFocusable('#spanTabindex3foo', 'span, tabindex 3foo');
|
isNotFocusable('#spanTabindex3foo', 'span, tabindex 3foo');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("focusable - area elements", function() {
|
||||||
|
isNotFocusable('#areaCoordsNoHref', 'coords but no href');
|
||||||
|
isFocusable('#areaCoordsHref', 'coords and href');
|
||||||
|
isFocusable('#areaCoordsNoSizeHref', 'coords of zero px and href');
|
||||||
|
isFocusable('#areaNoCoordsHref', 'href but no coords');
|
||||||
|
isNotFocusable('#areaNoImg', 'not associated with an image');
|
||||||
|
});
|
||||||
|
|
||||||
test("tabbable - visible, enabled elements", function() {
|
test("tabbable - visible, enabled elements", function() {
|
||||||
expect(18);
|
expect(16);
|
||||||
|
|
||||||
isTabbable('#visibleAncestor-inputTypeNone', 'input, no type');
|
isTabbable('#visibleAncestor-inputTypeNone', 'input, no type');
|
||||||
isTabbable('#visibleAncestor-inputTypeText', 'input, type text');
|
isTabbable('#visibleAncestor-inputTypeText', 'input, type text');
|
||||||
@ -174,16 +179,13 @@ test("tabbable - visible, enabled elements", function() {
|
|||||||
isTabbable('#visibleAncestor-object', 'object');
|
isTabbable('#visibleAncestor-object', 'object');
|
||||||
isTabbable('#visibleAncestor-anchorWithHref', 'anchor with href');
|
isTabbable('#visibleAncestor-anchorWithHref', 'anchor with href');
|
||||||
isNotTabbable('#visibleAncestor-anchorWithoutHref', 'anchor without href');
|
isNotTabbable('#visibleAncestor-anchorWithoutHref', 'anchor without href');
|
||||||
// fails: $("map").is(":visible") and $("map").is(":hidden") both return true
|
|
||||||
isTabbable('#visibleAncestor-areaWithHref', 'area with href');
|
|
||||||
isNotTabbable('#visibleAncestor-areaWithoutHref', 'area without href');
|
|
||||||
isNotTabbable('#visibleAncestor-span', 'span');
|
isNotTabbable('#visibleAncestor-span', 'span');
|
||||||
isNotTabbable('#visibleAncestor-div', 'div');
|
isNotTabbable('#visibleAncestor-div', 'div');
|
||||||
isTabbable("#visibleAncestor-spanWithTabindex", 'span with tabindex');
|
isTabbable("#visibleAncestor-spanWithTabindex", 'span with tabindex');
|
||||||
isNotTabbable("#visibleAncestor-divWithNegativeTabindex", 'div with tabindex');
|
isNotTabbable("#visibleAncestor-divWithNegativeTabindex", 'div with tabindex');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Tabbable - disabled elements", function() {
|
test("tabbable - disabled elements", function() {
|
||||||
expect(9);
|
expect(9);
|
||||||
|
|
||||||
isNotTabbable('#disabledElement-inputTypeNone', 'input, no type');
|
isNotTabbable('#disabledElement-inputTypeNone', 'input, no type');
|
||||||
@ -197,25 +199,23 @@ test("Tabbable - disabled elements", function() {
|
|||||||
isNotTabbable('#disabledElement-textarea', 'textarea');
|
isNotTabbable('#disabledElement-textarea', 'textarea');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Tabbable - hidden styles", function() {
|
test("tabbable - hidden styles", function() {
|
||||||
expect(8);
|
expect(8);
|
||||||
|
|
||||||
isNotTabbable('#displayNoneAncestor-input', 'input, display: none parent');
|
isNotTabbable('#displayNoneAncestor-input', 'input, display: none parent');
|
||||||
isNotTabbable('#displayNoneAncestor-span', 'span with tabindex, display: none parent');
|
isNotTabbable('#displayNoneAncestor-span', 'span with tabindex, display: none parent');
|
||||||
|
|
||||||
// fails: element hidden by parent-visibility-hidden is still visible according to :visible
|
|
||||||
isNotTabbable('#visibilityHiddenAncestor-input', 'input, visibility: hidden parent');
|
isNotTabbable('#visibilityHiddenAncestor-input', 'input, visibility: hidden parent');
|
||||||
isNotTabbable('#visibilityHiddenAncestor-span', 'span with tabindex, visibility: hidden parent');
|
isNotTabbable('#visibilityHiddenAncestor-span', 'span with tabindex, visibility: hidden parent');
|
||||||
|
|
||||||
isNotTabbable('#displayNone-input', 'input, display: none');
|
isNotTabbable('#displayNone-input', 'input, display: none');
|
||||||
// fails: element hidden by parent-visibility-hidden is still visible according to :visible
|
|
||||||
isNotTabbable('#visibilityHidden-input', 'input, visibility: hidden');
|
isNotTabbable('#visibilityHidden-input', 'input, visibility: hidden');
|
||||||
|
|
||||||
isNotTabbable('#displayNone-span', 'span with tabindex, display: none');
|
isNotTabbable('#displayNone-span', 'span with tabindex, display: none');
|
||||||
isNotTabbable('#visibilityHidden-span', 'span with tabindex, visibility: hidden');
|
isNotTabbable('#visibilityHidden-span', 'span with tabindex, visibility: hidden');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Tabbable - natively tabbable with various tabindex", function() {
|
test("tabbable - natively tabbable with various tabindex", function() {
|
||||||
expect(4);
|
expect(4);
|
||||||
|
|
||||||
isTabbable('#inputTabindex0', 'input, tabindex 0');
|
isTabbable('#inputTabindex0', 'input, tabindex 0');
|
||||||
@ -224,7 +224,7 @@ test("Tabbable - natively tabbable with various tabindex", function() {
|
|||||||
isNotTabbable('#inputTabindex-50', 'input, tabindex -50');
|
isNotTabbable('#inputTabindex-50', 'input, tabindex -50');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Tabbable - not natively tabbable with various tabindex", function() {
|
test("tabbable - not natively tabbable with various tabindex", function() {
|
||||||
expect(4);
|
expect(4);
|
||||||
|
|
||||||
isTabbable('#spanTabindex0', 'span, tabindex 0');
|
isTabbable('#spanTabindex0', 'span, tabindex 0');
|
||||||
@ -233,7 +233,7 @@ test("Tabbable - not natively tabbable with various tabindex", function() {
|
|||||||
isNotTabbable('#spanTabindex-50', 'span, tabindex -50');
|
isNotTabbable('#spanTabindex-50', 'span, tabindex -50');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Tabbable - invalid tabindex", function() {
|
test("tabbable - invalid tabindex", function() {
|
||||||
expect(4);
|
expect(4);
|
||||||
|
|
||||||
isTabbable('#inputTabindexfoo', 'input, tabindex foo');
|
isTabbable('#inputTabindexfoo', 'input, tabindex foo');
|
||||||
@ -242,4 +242,12 @@ test("Tabbable - invalid tabindex", function() {
|
|||||||
isNotTabbable('#spanTabindex3foo', 'span, tabindex 3foo');
|
isNotTabbable('#spanTabindex3foo', 'span, tabindex 3foo');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("tabbable - area elements", function() {
|
||||||
|
isNotTabbable('#areaCoordsNoHref', 'coords but no href');
|
||||||
|
isTabbable('#areaCoordsHref', 'coords and href');
|
||||||
|
isTabbable('#areaCoordsNoSizeHref', 'coords of zero px and href');
|
||||||
|
isTabbable('#areaNoCoordsHref', 'href but no coords');
|
||||||
|
isNotTabbable('#areaNoImg', 'not associated with an image');
|
||||||
|
});
|
||||||
|
|
||||||
})(jQuery);
|
})(jQuery);
|
||||||
|
25
ui/jquery.ui.core.js
vendored
25
ui/jquery.ui.core.js
vendored
@ -231,6 +231,13 @@ $.each( [ "Width", "Height" ], function( i, name ) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
//Additional selectors
|
//Additional selectors
|
||||||
|
function visible( element ) {
|
||||||
|
return !$(element).parents().andSelf().filter(function() {
|
||||||
|
return $.curCSS( this, "visibility" ) === "hidden" ||
|
||||||
|
$.expr.filters.hidden( this );
|
||||||
|
}).length;
|
||||||
|
}
|
||||||
|
|
||||||
$.extend($.expr[':'], {
|
$.extend($.expr[':'], {
|
||||||
data: function(elem, i, match) {
|
data: function(elem, i, match) {
|
||||||
return !!$.data(elem, match[3]);
|
return !!$.data(elem, match[3]);
|
||||||
@ -239,17 +246,23 @@ $.extend($.expr[':'], {
|
|||||||
focusable: function(element) {
|
focusable: function(element) {
|
||||||
var nodeName = element.nodeName.toLowerCase(),
|
var nodeName = element.nodeName.toLowerCase(),
|
||||||
tabIndex = $.attr(element, 'tabindex');
|
tabIndex = $.attr(element, 'tabindex');
|
||||||
|
if ( "area" === nodeName ) {
|
||||||
|
var map = element.parentNode,
|
||||||
|
mapName = map.name,
|
||||||
|
img;
|
||||||
|
if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
img = $( "img[usemap=#" + mapName + "]" )[0];
|
||||||
|
return !!img && visible( img );
|
||||||
|
}
|
||||||
return (/input|select|textarea|button|object/.test(nodeName)
|
return (/input|select|textarea|button|object/.test(nodeName)
|
||||||
? !element.disabled
|
? !element.disabled
|
||||||
: 'a' == nodeName || 'area' == nodeName
|
: 'a' == nodeName
|
||||||
? element.href || !isNaN(tabIndex)
|
? element.href || !isNaN(tabIndex)
|
||||||
: !isNaN(tabIndex))
|
: !isNaN(tabIndex))
|
||||||
// the element and all of its ancestors must be visible
|
// the element and all of its ancestors must be visible
|
||||||
// the browser may report that the area is hidden
|
&& visible( element );
|
||||||
&& !$(element).parents().andSelf().filter(function() {
|
|
||||||
return $.curCSS( this, "visibility" ) === "hidden" ||
|
|
||||||
$.expr.filters.hidden( this );
|
|
||||||
}).length;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
tabbable: function(element) {
|
tabbable: function(element) {
|
||||||
|
Loading…
Reference in New Issue
Block a user