jQuery "attr" secrets finally revealed!

D

David Mark

http://www.timmywillison.com/2011/A-New-jQuery.attr-and-the-New-jQuery.prop-Method.html

From the comments:

"Thanks for this Timmy. Over the years I've read that jQuery's attr
implementation was broken and needed a rewrite, but never knew why or
how it was broken. Looking forward to 1.6!"

They still don't know why or how (and I don't think Timmy does
either). They don't know what they are looking forward too. These
are simply zombies.

Love how the lemmings claim that all I ever did for jQuery was insult
them. Hell, they might as well rename it to dQuery for 1.6. Their
code is starting to look a lot like mine (circa 2007-8). Nobody has
contributed more over the years to their pathetic efforts. All they
ever did was bitch about it and pass the losses onto other customers
(who seemed to enjoy endless ineptitude and failure). Then, years
later, they try to "catch up" (too late) and there is more rejoicing,
despite the fact that they broke the most-used method in jQuery for no
reason. I suppose it doesn't matter as jQuery (and the rest) are now
"officially" out of fashion (according to the last lemming I talked
to).

If you have been using and/or recommending jQuery over the past few
years, you now "officially" look like an idiot. I'm looking right at
you, Matt Kruse (he of the "you are not being helpful!" line). Join
the Dojo disciples on the bread line. :)

Anyway, I'm banned from that blurry page now. In Timmy We Trust. :)
 
D

David Mark

Anyway, I'm banned from that blurry page now.  In Timmy We Trust.  :)

Even better; the little twerp deleted all of my comments, so none of
his fans will realize how badly he screwed this up.

Ain't that always the way? :)
 
D

David Mark

http://www.timmywillison.com/2011/A-New-jQuery.attr-and-the-New-jQuer...

From the comments:

"Thanks for this Timmy. Over the years I've read that jQuery's attr
implementation was broken and needed a rewrite, but never knew why or
how it was broken. Looking forward to 1.6!"

They still don't know why or how (and I don't think Timmy does
either).  They don't know what they are looking forward too.  These
are simply zombies.

Sorry for the line numbers and screwed up indentation. I'll post a
better copy when I review it.

But this doesn't really need review, does it? It's the same old BS,
but slightly rearranged (with little regard for the ramifications).
Certainly nothing close to competence, which is disappointing after
years of examples. And, as mentioned, most of the issues they attempt
to address here are related to IE6/7. Too little, too late and too
bad.

The line numbers do serve to illustrate the futility though as it
appears the entire boondoggle fits in roughly 300 lines of code
(including comments). This is the "wheel" they so feverishly
protected all those years? What was the line? Don't reinvent the
wheel? No, wait three plus years and some clod will come along and
reinvent it for you (breaking your code to boot).

Lazy, defensive and ignorant is not a good combination for
programming. ;)

jQuery.extend({
2066 valHooks: {
2067 option: {
2068 get: function( elem ) {
2069 // attributes.value is undefined in Blackberry 4.7 but
2070 // uses .value. See #6932
2071 var val = elem.attributes.value;
2072 return !val || val.specified ? elem.value : elem.text;
2073 }
2074 },
2075 select: {
2076 get: function( elem ) {
2077 var index = elem.selectedIndex,
2078 values = [],
2079 options = elem.options,
2080 one = elem.type === "select-one";
2081
2082 // Nothing was selected
2083 if ( index < 0 ) {
2084 return null;
2085 }
2086
2087 // Loop through all the selected options
2088 for ( var i = one ? index : 0, max = one ? index + 1 :
options.length; i < max; i++ ) {
2089 var option = options[ i ];
2090
2091 // Don't return options that are disabled or in a disabled
optgroup
2092 if ( option.selected && (jQuery.support.optDisabled ? !
option.disabled : option.getAttribute("disabled") === null) &&
2093 (!option.parentNode.disabled || !
jQuery.nodeName( option.parentNode, "optgroup" )) ) {
2094
2095 // Get the specific value for the option
2096 value = jQuery( option ).val();
2097
2098 // We don't need an array for one selects
2099 if ( one ) {
2100 return value;
2101 }
2102
2103 // Multi-Selects return an array
2104 values.push( value );
2105 }
2106 }
2107
2108 // Fixes Bug #2551 -- select.val() broken in IE after
form.reset()
2109 if ( one && !values.length && options.length ) {
2110 return jQuery( options[ index ] ).val();
2111 }
2112
2113 return values;
2114 },
2115
2116 set: function( elem, value ) {
2117 var values = jQuery.makeArray( value );
2118
2119 jQuery(elem).find("option").each(function() {
2120 this.selected = jQuery.inArray( jQuery(this).val(), values ) >=
0;
2121 });
2122
2123 if ( !values.length ) {
2124 elem.selectedIndex = -1;
2125 }
2126 return values;
2127 }
2128 }
2129 },
2130
2131 attrFn: {
2132 val: true,
2133 css: true,
2134 html: true,
2135 text: true,
2136 data: true,
2137 width: true,
2138 height: true,
2139 offset: true
2140 },
2141
2142 attrFix: {
2143 // Always normalize to ensure hook usage
2144 tabindex: "tabIndex",
2145 readonly: "readOnly"
2146 },
2147
2148 attr: function( elem, name, value, pass ) {
2149 var nType = elem.nodeType;
2150
2151 // don't get/set attributes on text, comment and attribute nodes
2152 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
2153 return undefined;
2154 }
2155
2156 if ( pass && name in jQuery.attrFn ) {
2157 return jQuery( elem )[ name ]( value );
2158 }
2159
2160 var ret, hooks,
2161 notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
2162
2163 // Normalize the name if needed
2164 name = notxml && jQuery.attrFix[ name ] || name;
2165
2166 // Get the appropriate hook, or the formHook
2167 // if getSetAttribute is not supported and we have form objects
in IE6/7
2168 hooks = jQuery.attrHooks[ name ] || ( elem.nodeName === "FORM"&&
formHook );
2169
2170 if ( value !== undefined ) {
2171
2172 if ( value === null ) {
2173 jQuery.removeAttr( elem, name );
2174 return undefined;
2175
2176 } else if ( hooks && "set" in hooks && notxml && (ret =
hooks.set( elem, value, name )) !== undefined ) {
2177 return ret;
2178
2179 } else {
2180 elem.setAttribute( name, "" + value );
2181 return value;
2182 }
2183
2184 } else {
2185
2186 if ( hooks && "get" in hooks && notxml ) {
2187 return hooks.get( elem, name );
2188
2189 } else {
2190
2191 ret = elem.getAttribute( name );
2192
2193 // Non-existent attributes return null, we normalize to undefined
2194 return ret === null ?
2195 undefined :
2196 ret;
2197 }
2198 }
2199 },
2200
2201 removeAttr: function( elem, name ) {
2202 if ( elem.nodeType === 1 ) {
2203 name = jQuery.attrFix[ name ] || name;
2204
2205 if ( jQuery.support.getSetAttribute ) {
2206 // Use removeAttribute in browsers that support it
2207 elem.removeAttribute( name );
2208 } else {
2209 jQuery.attr( elem, name, "" );
2210 elem.removeAttributeNode( elem.getAttributeNode( name ) );
2211 }
2212 }
2213 },
2214
2215 attrHooks: {
2216 type: {
2217 set: function( elem, value ) {
2218 // We can't allow the type property to be changed (since it
causes problems in IE)
2219 if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
2220 jQuery.error( "type property can't be changed" );
2221 }
2222 }
2223 },
2224 tabIndex: {
2225 get: function( elem ) {
2226 // elem.tabIndex doesn't always return the correct value when it
hasn't been explicitly set
2227 // http://fluidproject.org/blog/2008/0...and-removing-tabindex-values-with-javascript/
2228 var attributeNode = elem.getAttributeNode("tabIndex");
2229
2230 return attributeNode && attributeNode.specified ?
2231 parseInt( attributeNode.value, 10 ) :
2232 rfocusable.test( elem.nodeName ) ||
rclickable.test( elem.nodeName ) && elem.href ?
2233 0 :
2234 undefined;
2235 }
2236 }
2237 },
2238
2239 propFix: {},
2240
2241 prop: function( elem, name, value ) {
2242 var nType = elem.nodeType;
2243
2244 // don't get/set properties on text, comment and attribute nodes
2245 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
2246 return undefined;
2247 }
2248
2249 var ret, hooks,
2250 notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
2251
2252 // Try to normalize/fix the name
2253 name = notxml && jQuery.propFix[ name ] || name;
2254
2255 hooks = jQuery.propHooks[ name ];
2256
2257 if ( value !== undefined ) {
2258 if ( hooks && "set" in hooks && (ret = hooks.set( elem, value,
name )) !== undefined ) {
2259 return ret;
2260
2261 } else {
2262 return (elem[ name ] = value);
2263 }
2264
2265 } else {
2266 if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !
== undefined ) {
2267 return ret;
2268
2269 } else {
2270 return elem[ name ];
2271 }
2272 }
2273 },
2274
2275 propHooks: {}
2276});
2277
2278// IE6/7 do not support getting/setting some attributes with get/
setAttribute
2279if ( !jQuery.support.getSetAttribute ) {
2280 jQuery.attrFix = jQuery.extend( jQuery.attrFix, {
2281 "for": "htmlFor",
2282 "class": "className",
2283 maxlength: "maxLength",
2284 cellspacing: "cellSpacing",
2285 cellpadding: "cellPadding",
2286 rowspan: "rowSpan",
2287 colspan: "colSpan",
2288 usemap: "useMap",
2289 frameborder: "frameBorder"
2290 });
2291
2292 // Use this for any attribute on a form in IE6/7
2293 // And the name attribute
2294 formHook = jQuery.attrHooks.name = jQuery.attrHooks.value =
jQuery.valHooks.button = {
2295 get: function( elem, name ) {
2296 if ( name === "value" && !jQuery.nodeName( elem, "button" ) ) {
2297 return elem.getAttribute( name );
2298 }
2299 var ret = elem.getAttributeNode( name );
2300 // Return undefined if not specified instead of empty string
2301 return ret && ret.specified ?
2302 ret.nodeValue :
2303 undefined;
2304 },
2305 set: function( elem, value, name ) {
2306 // Check form objects in IE (multiple bugs related)
2307 // Only use nodeValue if the attribute node exists on the form
2308 var ret = elem.getAttributeNode( name );
2309 if ( ret ) {
2310 ret.nodeValue = value;
2311 return value;
2312 }
2313 }
2314 };
2315
2316 // Set width and height to auto instead of 0 on empty string( Bug
#8150 )
2317 // This is for removals
2318 jQuery.each([ "width", "height" ], function( i, name ) {
2319 jQuery.attrHooks[ name ] =
jQuery.extend( jQuery.attrHooks[ name ], {
2320 set: function( elem, value ) {
2321 if ( value === "" ) {
2322 elem.setAttribute( name, "auto" );
2323 return value;
2324 }
2325 }
2326 });
2327 });
2328}
2329
2330// Remove certain attrs if set to false
2331jQuery.each([ "selected", "checked", "readOnly", "disabled" ],
function( i, name ) {
2332 jQuery.attrHooks[ name ] =
jQuery.extend( jQuery.attrHooks[ name ], {
2333 set: function( elem, value ) {
2334 if ( value === true ) {
2335 elem.setAttribute( name, name );
2336 return value;
2337 } else if ( value === false ) {
2338 jQuery.removeAttr( elem, name );
2339 return value;
2340 }
2341 }
2342 });
2343});
2344
2345// Some attributes require a special call on IE
2346if ( !jQuery.support.hrefNormalized ) {
2347 jQuery.each([ "href", "src", "width", "height" ], function( i,
name ) {
2348 jQuery.attrHooks[ name ] =
jQuery.extend( jQuery.attrHooks[ name ], {
2349 get: function( elem ) {
2350 var ret = elem.getAttribute( name, 2 );
2351 return ret === null ? undefined : ret;
2352 }
2353 });
2354 });
2355}
2356
2357if ( !jQuery.support.style ) {
2358 jQuery.attrHooks.style = {
2359 get: function( elem ) {
2360 // Return undefined in the case of empty string
2361 // Normalize to lowercase since IE uppercases css property names
2362 return elem.style.cssText.toLowerCase() || undefined;
2363 },
2364 set: function( elem, value ) {
2365 return (elem.style.cssText = "" + value);
2366 }
2367 };
2368}
2369
2370// Safari mis-reports the default selected property of an option
2371// Accessing the parent's selectedIndex property fixes it
2372if ( !jQuery.support.optSelected ) {
2373 jQuery.propHooks.selected =
jQuery.extend( jQuery.propHooks.selected, {
2374 get: function( elem ) {
2375 var parent = elem.parentNode;
2376
2377 if ( parent ) {
2378 parent.selectedIndex;
2379
2380 // Make sure that it also works with optgroups, see #5701
2381 if ( parent.parentNode ) {
2382 parent.parentNode.selectedIndex;
2383 }
2384 }
2385 }
2386 });
2387}
2388
2389// Radios and checkboxes getter/setter
2390if ( !jQuery.support.checkOn ) {
2391 jQuery.each([ "radio", "checkbox" ], function() {
2392 jQuery.valHooks[ this ] = {
2393 get: function( elem ) {
2394 // Handle the case where in Webkit "" is returned instead of "on"
if a value isn't specified
2395 return elem.getAttribute("value") === null ? "on" : elem.value;
2396 }
2397 };
2398 });
2399}
2400jQuery.each([ "radio", "checkbox" ], function() {
2401 jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ],
{
2402 set: function( elem, value ) {
2403 if ( jQuery.isArray( value ) ) {
2404 return (elem.checked = jQuery.inArray( jQuery(elem).val(),
value ) >= 0);
2405 }
2406 }
2407 });
2408});
2409
 
D

David Mark

Sorry for the line numbers and screwed up indentation.  I'll post a
better copy when I review it.

But this doesn't really need review, does it?  It's the same old BS,
but slightly rearranged (with little regard for the ramifications).
Certainly nothing close to competence, which is disappointing after
years of examples.  And, as mentioned, most of the issues they attempt
to address here are related to IE6/7.  Too little, too late and too
bad.

The line numbers do serve to illustrate the futility though as it
appears the entire boondoggle fits in roughly 300 lines of code
(including comments).  This is the "wheel" they so feverishly
protected all those years?  What was the line?  Don't reinvent the
wheel?  No, wait three plus years and some clod will come along and
reinvent it for you (breaking your code to boot).

Lazy, defensive and ignorant is not a good combination for
programming.  ;)

jQuery.extend({
2066 valHooks: {
2067 option: {
2068 get: function( elem ) {
2069 // attributes.value is undefined in Blackberry 4.7 but
2070 // uses .value. See #6932
2071 var val = elem.attributes.value;
2072 return !val || val.specified ? elem.value : elem.text;
2073 }
2074 },

I'd say there's no real need to go past this point.

This is a very poorly executed object inference (a form of browser
sniffing).

They are concerned with the case of OPTION elements that lack VALUE
attributes. All browsers will submit the option text instead, but
some will not return this text for the value property.

Whatever to do? First thing would be to check if the attribute
exists. Unfortunately, jQuery is (still) all thumbs when it comes to
attributes. I'm not sure if they even have a hasAttribute wrapper.
If they do, they didn't use it. :(

So what did they do? Without any sort of feature detection, they
assume there is an "attributes" property and reference its "value"
property (which may not exist either).

Here's the punchline:-

return !val || val.specified ? elem.value : elem.text;

So, if val is an empty string (or undefined, null, etc.), return the
value property; otherwise, if val has a truthy "specified" property,
return the value property; otherwise return the text property.
Suffice to say, this comes nowhere near accomplishing the goal. Of
course, I didn't read the related ticket about their Blackberry
problem, so perhaps they had a different goal in mind. If history is
any indicator, their goal was to force this one browser to "work" (per
their own dubious unit tests).

It's the usual random gibberish with very sparse comments. That last
line could use some parenthesis as well.

That's one. At a glance, the rest of the functions are just as
botched. Will they fix them (ever?) or continue to bitterly complain
about how put-upon they are (help, I'm being repressed!) :)
 
M

Michael Haufe (\TNO\)

Even better; the little twerp deleted all of my comments, so none of
his fans will realize how badly he screwed this up.

Ain't that always the way?  :)


Perhaps you should make a habit of taking screenshots?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top