Skip to content

Commit

Permalink
Fix #13539: Utilize Sizzle hooks. Close jquerygh-1215.
Browse files Browse the repository at this point in the history
  • Loading branch information
gibson042 committed Apr 5, 2013
1 parent 3ec0dd8 commit 57137b4
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 145 deletions.
2 changes: 1 addition & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ module.exports = function( grunt ) {
src: [
"src/intro.js",
"src/core.js",
"src/selector-sizzle.js",
"src/callbacks.js",
"src/deferred.js",
"src/support.js",
"src/data.js",
"src/queue.js",
"src/attributes.js",
"src/event.js",
"src/selector-sizzle.js",
"src/traversing.js",
"src/manipulation.js",
{ flag: "css", src: "src/css.js" },
Expand Down
194 changes: 97 additions & 97 deletions src/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ var nodeHook, boolHook,
rreturn = /\r/g,
rfocusable = /^(?:input|select|textarea|button|object)$/i,
rclickable = /^(?:a|area)$/i,
rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,
ruseDefault = /^(?:checked|selected)$/i,
getSetAttribute = jQuery.support.getSetAttribute,
getSetInput = jQuery.support.input;
Expand Down Expand Up @@ -297,7 +296,7 @@ jQuery.extend({
},

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

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

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

// All attributes are lowercase
// Grab necessary hook if one is defined
if ( notxml ) {
if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
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 === null ) {
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;

} else {
elem.setAttribute( name, 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;

} else {

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

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

// Boolean attributes get special treatment (#10870)
if ( rboolean.test( name ) ) {
if ( jQuery.expr.match.boolean.test( name ) ) {
// Set corresponding property to false for boolean attributes
// Also clear defaultChecked/defaultSelected (if appropriate) for IE<8
if ( !getSetAttribute && ruseDefault.test( name ) ) {
if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
elem[ propName ] = false;
// Support: IE<9
// Also clear defaultChecked/defaultSelected (if appropriate)
} else {
elem[ jQuery.camelCase( "default-" + name ) ] =
elem[ propName ] = false;
} else {
elem[ propName ] = false;
}

// See #9699 for explanation of this approach (setting first, then removal)
Expand Down Expand Up @@ -398,18 +392,8 @@ jQuery.extend({
},

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

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

// Hook for boolean attributes
// Hooks for boolean attributes
boolHook = {
get: function( elem, name ) {
var
// Use .prop to determine if this attribute is understood as boolean
prop = jQuery.prop( elem, name ),

// Fetch it accordingly
attr = typeof prop === "boolean" && elem.getAttribute( name ),
detail = typeof prop === "boolean" ?

getSetInput && getSetAttribute ?
attr != null :
// oldIE fabricates an empty string for missing boolean attributes
// and conflates checked/selected into attroperties
ruseDefault.test( name ) ?
elem[ jQuery.camelCase( "default-" + name ) ] :
!!attr :

// fetch an attribute node for properties not recognized as boolean
elem.getAttributeNode( name );

return detail && detail.value !== false ?
name.toLowerCase() :
undefined;
},
set: function( elem, value, name ) {
if ( value === false ) {
// Remove boolean attributes when set to false
Expand All @@ -506,19 +466,44 @@ boolHook = {
return name;
}
};
jQuery.each( jQuery.expr.match.boolean.source.match( /\w+/g ), function( i, name ) {
var getter = jQuery.expr.attrHandle[ name ] || jQuery.find.attr;

jQuery.expr.attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ?
function( elem, name, isXML ) {
var fn = jQuery.expr.attrHandle[ name ],
ret = isXML ?
undefined :
/* jshint eqeqeq: false */
(jQuery.expr.attrHandle[ name ] = undefined) !=
getter( elem, name, isXML ) ?

name.toLowerCase() :
null;
jQuery.expr.attrHandle[ name ] = fn;
return ret;
} :
function( elem, name, isXML ) {
return isXML ?
undefined :
elem[ jQuery.camelCase( "default-" + name ) ] ?
name.toLowerCase() :
null;
};
});

// fix oldIE value attroperty
// fix oldIE attroperties
if ( !getSetInput || !getSetAttribute ) {
jQuery.attrHooks.value = {
get: function( elem, name ) {
var ret = elem.getAttributeNode( name );
return jQuery.nodeName( elem, "input" ) ?
jQuery.expr.attrHandle.value = function( elem, name, isXML ) {
var ret = elem.getAttributeNode( name );
return isXML ? undefined : jQuery.nodeName( elem, "input" ) ?

// Ignore the value *property* by using defaultValue
elem.defaultValue :
// Ignore the value *property* by using defaultValue
elem.defaultValue :

ret && ret.specified ? ret.value : undefined;
},
ret && ret.specified ? ret.value : undefined;
};
jQuery.attrHooks.value = {
set: function( elem, value, name ) {
if ( jQuery.nodeName( elem, "input" ) ) {
// Does not return so that setAttribute is also used
Expand All @@ -536,13 +521,7 @@ if ( !getSetAttribute ) {

// Use this for any attribute in IE6/7
// This fixes almost every IE6/7 issue
nodeHook = jQuery.valHooks.button = {
get: function( elem, name ) {
var ret = elem.getAttributeNode( name );
return ret && ( name === "id" || name === "name" || name === "coords" ? ret.value !== "" : ret.specified ) ?
ret.value :
undefined;
},
nodeHook = {
set: function( elem, value, name ) {
// Set the existing or create a new attribute node
var ret = elem.getAttributeNode( name );
Expand All @@ -560,11 +539,29 @@ if ( !getSetAttribute ) {
undefined;
}
};
jQuery.expr.attrHandle.id = jQuery.expr.attrHandle.name = jQuery.expr.attrHandle.coords =
// Some attributes are constructed with empty-string values when not defined
function( elem, name, isXML ) {
var ret;
return isXML ?
undefined :
(ret = elem.getAttributeNode( name )) && ret.value !== "" ?
ret.value :
null;
};
jQuery.valHooks.button = {
get: function( elem, name ) {
var ret = elem.getAttributeNode( name );
return ret && ret.specified ?
ret.value :
undefined;
},
set: nodeHook.set
};

// Set contenteditable to false on removals(#10429)
// Setting to empty string throws an error as an invalid value
jQuery.attrHooks.contenteditable = {
get: nodeHook.get,
set: function( elem, value, name ) {
nodeHook.set( elem, value === "" ? false : value, name );
}
Expand All @@ -573,30 +570,21 @@ if ( !getSetAttribute ) {
// Set width and height to auto instead of 0 on empty string( Bug #8150 )
// This is for removals
jQuery.each([ "width", "height" ], function( i, name ) {
jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
jQuery.attrHooks[ name ] = {
set: function( elem, value ) {
if ( value === "" ) {
elem.setAttribute( name, "auto" );
return value;
}
}
});
};
});
}


// Some attributes require a special call on IE
// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
if ( !jQuery.support.hrefNormalized ) {
jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
get: function( elem ) {
var ret = elem.getAttribute( name, 2 );
return ret == null ? undefined : ret;
}
});
});

// href/src property should get the full normalized URL (#10299/#12915)
jQuery.each([ "href", "src" ], function( i, name ) {
jQuery.propHooks[ name ] = {
Expand Down Expand Up @@ -624,7 +612,7 @@ if ( !jQuery.support.style ) {
// Safari mis-reports the default selected property of an option
// Accessing the parent's selectedIndex property fixes it
if ( !jQuery.support.optSelected ) {
jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
jQuery.propHooks.selected = {
get: function( elem ) {
var parent = elem.parentNode;

Expand All @@ -638,31 +626,43 @@ if ( !jQuery.support.optSelected ) {
}
return null;
}
});
};
}

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

// IE6/7 call enctype encoding
if ( !jQuery.support.enctype ) {
jQuery.propFix.enctype = "encoding";
}

// Radios and checkboxes getter/setter
if ( !jQuery.support.checkOn ) {
jQuery.each([ "radio", "checkbox" ], function() {
jQuery.valHooks[ this ] = {
get: function( elem ) {
// Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
return elem.getAttribute("value") === null ? "on" : elem.value;
}
};
});
}
jQuery.each([ "radio", "checkbox" ], function() {
jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
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 Diff line number Diff line change
@@ -1,5 +1,3 @@
// Override sizzle attribute retrieval
Sizzle.attr = jQuery.attr;
jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
jQuery.expr[":"] = jQuery.expr.pseudos;
Expand Down
Loading

0 comments on commit 57137b4

Please sign in to comment.