Skip to content

Commit

Permalink
Fix #13539: Utilize Sizzle hooks. Close gh-1215.
Browse files Browse the repository at this point in the history
(cherry picked from commit 4ef5169)
  • Loading branch information
gibson042 committed Apr 5, 2013
1 parent 6358da8 commit 5d1dfe7
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 106 deletions.
2 changes: 1 addition & 1 deletion Gruntfile.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ module.exports = function( grunt ) {
src: [ src: [
"src/intro.js", "src/intro.js",
"src/core.js", "src/core.js",
{ flag: "sizzle", src: "src/selector-sizzle.js", alt: "src/selector-native.js" },
"src/callbacks.js", "src/callbacks.js",
"src/deferred.js", "src/deferred.js",
"src/support.js", "src/support.js",
"src/data.js", "src/data.js",
"src/queue.js", "src/queue.js",
"src/attributes.js", "src/attributes.js",
"src/event.js", "src/event.js",
{ flag: "sizzle", src: "src/selector-sizzle.js", alt: "src/selector-native.js" },
"src/traversing.js", "src/traversing.js",
"src/manipulation.js", "src/manipulation.js",
{ flag: "css", src: "src/css.js" }, { flag: "css", src: "src/css.js" },
Expand Down
125 changes: 68 additions & 57 deletions src/attributes.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ var nodeHook, boolHook,
rclass = /[\t\r\n]/g, rclass = /[\t\r\n]/g,
rreturn = /\r/g, rreturn = /\r/g,
rfocusable = /^(?:input|select|textarea|button|object)$/i, rfocusable = /^(?:input|select|textarea|button|object)$/i,
rclickable = /^(?:a|area)$/i, rclickable = /^(?:a|area)$/i;
rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i;


jQuery.fn.extend({ jQuery.fn.extend({
attr: function( name, value ) { attr: function( name, value ) {
Expand Down Expand Up @@ -291,7 +290,7 @@ jQuery.extend({
}, },


attr: function( elem, name, value ) { attr: function( elem, name, value ) {
var ret, hooks, notxml, var hooks, ret,
nType = elem.nodeType; nType = elem.nodeType;


// don't get/set attributes on text, comment and attribute nodes // don't get/set attributes on text, comment and attribute nodes
Expand All @@ -304,38 +303,32 @@ jQuery.extend({
return jQuery.prop( elem, name, value ); return jQuery.prop( elem, name, value );
} }


notxml = nType !== 1 || !jQuery.isXMLDoc( elem );

// All attributes are lowercase // All attributes are lowercase
// Grab necessary hook if one is defined // Grab necessary hook if one is defined
if ( notxml ) { if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
name = name.toLowerCase(); name = name.toLowerCase();
hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); hooks = jQuery.attrHooks[ name ] ||
( jQuery.expr.match.boolean.test( name ) ? boolHook : nodeHook );
} }


if ( value !== undefined ) { if ( value !== undefined ) {


if ( value === null ) { if ( value === null ) {
jQuery.removeAttr( elem, name ); jQuery.removeAttr( elem, name );


} else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
return ret; return ret;


} else { } else {
elem.setAttribute( name, value + "" ); elem.setAttribute( name, value + "" );
return value; return value;
} }


} else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
return ret; return ret;


} else { } else {

ret = jQuery.find.attr( elem, name );
// In IE9+, Flash objects don't have .getAttribute (#12945)
// Support: IE9+
if ( typeof elem.getAttribute !== core_strundefined ) {
ret = elem.getAttribute( name );
}


// Non-existent attributes return null, we normalize to undefined // Non-existent attributes return null, we normalize to undefined
return ret == null ? return ret == null ?
Expand All @@ -354,8 +347,8 @@ jQuery.extend({
propName = jQuery.propFix[ name ] || name; propName = jQuery.propFix[ name ] || name;


// Boolean attributes get special treatment (#10870) // Boolean attributes get special treatment (#10870)
// Set corresponding property to false for boolean attributes if ( jQuery.expr.match.boolean.test( name ) ) {
if ( rboolean.test( name ) ) { // Set corresponding property to false
elem[ propName ] = false; elem[ propName ] = false;
} }


Expand All @@ -382,18 +375,8 @@ jQuery.extend({
}, },


propFix: { propFix: {
tabindex: "tabIndex",
readonly: "readOnly",
"for": "htmlFor", "for": "htmlFor",
"class": "className", "class": "className"
maxlength: "maxLength",
cellspacing: "cellSpacing",
cellpadding: "cellPadding",
rowspan: "rowSpan",
colspan: "colSpan",
usemap: "useMap",
frameborder: "frameBorder",
contenteditable: "contentEditable"
}, },


prop: function( elem, name, value ) { prop: function( elem, name, value ) {
Expand Down Expand Up @@ -448,13 +431,8 @@ jQuery.extend({
} }
}); });


// Hook for boolean attributes // Hooks for boolean attributes
boolHook = { boolHook = {
get: function( elem, name ) {
return elem.getAttribute( name ) !== null ?
name.toLowerCase() :
undefined;
},
set: function( elem, value, name ) { set: function( elem, value, name ) {
if ( value === false ) { if ( value === false ) {
// Remove boolean attributes when set to false // Remove boolean attributes when set to false
Expand All @@ -465,38 +443,71 @@ boolHook = {
return name; return name;
} }
}; };
jQuery.each( jQuery.expr.match.boolean.source.match( /\w+/g ), function( i, name ) {
var getter = jQuery.expr.attrHandle[ name ] || jQuery.find.attr;


// Radios and checkboxes getter/setter jQuery.expr.attrHandle[ name ] = function( elem, name, isXML ) {
if ( !jQuery.support.checkOn ) { var fn = jQuery.expr.attrHandle[ name ],
jQuery.each([ "radio", "checkbox" ], function() { ret = isXML ?
jQuery.valHooks[ this ] = { undefined :
get: function( elem ) { /* jshint eqeqeq: false */
// Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified // Temporarily disable this handler to check existence
return elem.getAttribute("value") === null ? "on" : elem.value; (jQuery.expr.attrHandle[ name ] = undefined) !=
} getter( elem, name, isXML ) ?
};
}); name.toLowerCase() :
} null;
jQuery.each([ "radio", "checkbox" ], function() {
jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { // Restore handler
set: function( elem, value ) { jQuery.expr.attrHandle[ name ] = fn;
if ( jQuery.isArray( value ) ) {
return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); return ret;
} };
}
});
}); });


// IE9/10 do not see a selected option inside an optgroup unless you access it // Support: IE9+
// Support: IE9, IE10 // Selectedness for an option in an optgroup can be inaccurate
if ( !jQuery.support.optSelected ) { if ( !jQuery.support.optSelected ) {
jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { jQuery.propHooks.selected = {
get: function( elem ) { get: function( elem ) {
var parent = elem.parentNode; var parent = elem.parentNode;
if ( parent && parent.parentNode ) { if ( parent && parent.parentNode ) {
parent.parentNode.selectedIndex; parent.parentNode.selectedIndex;
} }
return null; return null;
} }
}); };
} }

jQuery.each([
"tabIndex",
"readOnly",
"maxLength",
"cellSpacing",
"cellPadding",
"rowSpan",
"colSpan",
"useMap",
"frameBorder",
"contentEditable"
], function() {
jQuery.propFix[ this.toLowerCase() ] = this;
});

// Radios and checkboxes getter/setter
jQuery.each([ "radio", "checkbox" ], function() {
jQuery.valHooks[ this ] = {
set: function( elem, value ) {
if ( jQuery.isArray( value ) ) {
return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
}
}
};
if ( !jQuery.support.checkOn ) {
jQuery.valHooks[ this ].get = function( elem ) {
// Support: Webkit
// "" is returned instead of "on" if a value isn't specified
return elem.getAttribute("value") === null ? "on" : elem.value;
};
}
});
2 changes: 1 addition & 1 deletion src/sizzle
2 changes: 0 additions & 2 deletions src/sizzle-jquery.js
Original file line number Original file line Diff line number Diff line change
@@ -1,5 +1,3 @@
// Override sizzle attribute retrieval
Sizzle.attr = jQuery.attr;
jQuery.find = Sizzle; jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors; jQuery.expr = Sizzle.selectors;
jQuery.expr[":"] = jQuery.expr.pseudos; jQuery.expr[":"] = jQuery.expr.pseudos;
Expand Down
57 changes: 26 additions & 31 deletions src/traversing.js
Original file line number Original file line Diff line number Diff line change
@@ -1,6 +1,4 @@
var runtil = /Until$/, var isSimple = /^.[^:#\[\.,]*$/,
rparentsprev = /^(?:parents|prev(?:Until|All))/,
isSimple = /^.[^:#\[\.,]*$/,
rneedsContext = jQuery.expr.match.needsContext, rneedsContext = jQuery.expr.match.needsContext,
// methods guaranteed to produce a unique set when starting from a unique set // methods guaranteed to produce a unique set when starting from a unique set
guaranteedUnique = { guaranteedUnique = {
Expand Down Expand Up @@ -52,11 +50,11 @@ jQuery.fn.extend({
}, },


not: function( selector ) { not: function( selector ) {
return this.pushStack( winnow(this, selector, false) ); return this.pushStack( winnow(this, selector || [], true) );
}, },


filter: function( selector ) { filter: function( selector ) {
return this.pushStack( winnow(this, selector, true) ); return this.pushStack( winnow(this, selector || [], false) );
}, },


is: function( selector ) { is: function( selector ) {
Expand Down Expand Up @@ -186,7 +184,7 @@ jQuery.each({
jQuery.fn[ name ] = function( until, selector ) { jQuery.fn[ name ] = function( until, selector ) {
var matched = jQuery.map( this, fn, until ); var matched = jQuery.map( this, fn, until );


if ( !runtil.test( name ) ) { if ( name.slice( -5 ) !== "Until" ) {
selector = until; selector = until;
} }


Expand All @@ -195,11 +193,13 @@ jQuery.each({
} }


if ( this.length > 1 ) { if ( this.length > 1 ) {
// Remove duplicates
if ( !guaranteedUnique[ name ] ) { if ( !guaranteedUnique[ name ] ) {
jQuery.unique( matched ); jQuery.unique( matched );
} }


if ( rparentsprev.test( name ) ) { // Reverse order for parents* and prev*
if ( name[ 0 ] === "p" ) {
matched.reverse(); matched.reverse();
} }
} }
Expand All @@ -210,13 +210,17 @@ jQuery.each({


jQuery.extend({ jQuery.extend({
filter: function( expr, elems, not ) { filter: function( expr, elems, not ) {
var elem = elems[ 0 ];

if ( not ) { if ( not ) {
expr = ":not(" + expr + ")"; expr = ":not(" + expr + ")";
} }


return elems.length === 1 ? return elems.length === 1 && elem.nodeType === 1 ?
jQuery.find.matchesSelector( elems[ 0 ], expr ) ? [ elems[ 0 ] ] : [] : jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
jQuery.find.matches( expr, elems ); jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
return elem.nodeType === 1;
}));
}, },


dir: function( elem, dir, until ) { dir: function( elem, dir, until ) {
Expand Down Expand Up @@ -248,40 +252,31 @@ jQuery.extend({
}); });


// Implement the identical functionality for filter and not // Implement the identical functionality for filter and not
function winnow( elements, qualifier, keep ) { function winnow( elements, qualifier, not ) {

// Can't pass null or undefined to indexOf
// Set to 0 to skip string check
qualifier = qualifier || 0;

var filtered;

if ( jQuery.isFunction( qualifier ) ) { if ( jQuery.isFunction( qualifier ) ) {
return jQuery.grep(elements, function( elem, i ) { return jQuery.grep( elements, function( elem, i ) {
var retVal = !!qualifier.call( elem, i, elem ); /* jshint -W018 */
return retVal === keep; return !!qualifier.call( elem, i, elem ) !== not;
}); });

} }


if ( qualifier.nodeType ) { if ( qualifier.nodeType ) {
return jQuery.grep(elements, function( elem ) { return jQuery.grep( elements, function( elem ) {
return ( elem === qualifier ) === keep; return ( elem === qualifier ) !== not;
}); });

} }


if ( typeof qualifier === "string" ) { if ( typeof qualifier === "string" ) {
filtered = jQuery.grep(elements, function( elem ) {
return elem.nodeType === 1;
});

if ( isSimple.test( qualifier ) ) { if ( isSimple.test( qualifier ) ) {
return jQuery.filter( qualifier, filtered, !keep ); return jQuery.filter( qualifier, elements, not );
} }


qualifier = jQuery.filter( qualifier, filtered ); qualifier = jQuery.filter( qualifier, elements );
} }


return jQuery.grep(elements, function( elem ) { return jQuery.grep( elements, function( elem ) {
return ( core_indexOf.call( qualifier, elem ) >= 0 ) === keep; return ( core_indexOf.call( qualifier, elem ) >= 0 ) !== not;
}); });
} }
4 changes: 2 additions & 2 deletions test/unit/css.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -864,8 +864,8 @@ test( ":visible/:hidden selectors", function() {
ok( !jQuery("#nothiddendiv").is(":visible"), "Modified CSS display: Assert element is hidden" ); ok( !jQuery("#nothiddendiv").is(":visible"), "Modified CSS display: Assert element is hidden" );
jQuery("#nothiddendiv").css({"display": "block"}); jQuery("#nothiddendiv").css({"display": "block"});
ok( jQuery("#nothiddendiv").is(":visible"), "Modified CSS display: Assert element is visible"); ok( jQuery("#nothiddendiv").is(":visible"), "Modified CSS display: Assert element is visible");
ok( jQuery(window).is(":visible"), "Calling is(':visible') on window does not throw an error in IE."); ok( jQuery(window).is(":visible") || true, "Calling is(':visible') on window does not throw an exception (#10267)");
ok( jQuery(document).is(":visible"), "Calling is(':visible') on document does not throw an error in IE."); ok( jQuery(document).is(":visible") || true, "Calling is(':visible') on document does not throw an exception (#10267)");


ok( jQuery("#nothiddendiv").is(":visible"), "Modifying CSS display: Assert element is visible"); ok( jQuery("#nothiddendiv").is(":visible"), "Modifying CSS display: Assert element is visible");
jQuery("#nothiddendiv").css("display", "none"); jQuery("#nothiddendiv").css("display", "none");
Expand Down
9 changes: 1 addition & 8 deletions test/unit/selector.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -31,17 +31,10 @@ test("class - jQuery only", function() {
}); });


test("attributes - jQuery only", function() { test("attributes - jQuery only", function() {
expect( 6 ); expect( 5 );


t( "Find elements with a tabindex attribute", "[tabindex]", ["listWithTabIndex", "foodWithNegativeTabIndex", "linkWithTabIndex", "linkWithNegativeTabIndex", "linkWithNoHrefWithTabIndex", "linkWithNoHrefWithNegativeTabIndex"] ); t( "Find elements with a tabindex attribute", "[tabindex]", ["listWithTabIndex", "foodWithNegativeTabIndex", "linkWithTabIndex", "linkWithNegativeTabIndex", "linkWithNoHrefWithTabIndex", "linkWithNoHrefWithNegativeTabIndex"] );


// #12523
deepEqual(
jQuery.find( "[title]", null, null, jQuery("#qunit-fixture a").get().concat( document.createTextNode("") ) ),
q("google"),
"Text nodes fail attribute tests without exception"
);

// #12600 // #12600
ok( ok(
jQuery("<select value='12600'><option value='option' selected='selected'></option><option value=''></option></select>") jQuery("<select value='12600'><option value='option' selected='selected'></option><option value=''></option></select>")
Expand Down
Loading

0 comments on commit 5d1dfe7

Please sign in to comment.