jQuery "attr" secrets finally revealed!

Discussion in 'Javascript' started by David Mark, Apr 21, 2011.

  1. David Mark

    David Mark Guest

    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. :)
    David Mark, Apr 21, 2011
    #1
    1. Advertising

  2. David Mark

    David Mark Guest

    On Apr 21, 11:50 am, David Mark <> wrote:

    >
    > 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? :)
    David Mark, Apr 21, 2011
    #2
    1. Advertising

  3. David Mark

    David Mark Guest

    On Apr 21, 11:50 am, David Mark <> wrote:
    > 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
    David Mark, Apr 21, 2011
    #3
  4. David Mark

    David Mark Guest

    On Apr 21, 12:29 pm, David Mark <> wrote:
    > On Apr 21, 11:50 am, David Mark <> wrote:
    >
    > >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 },


    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!) :)
    David Mark, Apr 21, 2011
    #4
  5. On Apr 21, 11:04 am, David Mark <> wrote:
    > On Apr 21, 11:50 am, David Mark <> wrote:
    >
    >
    >
    > > 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?  :)



    Perhaps you should make a habit of taking screenshots?
    Michael Haufe (\TNO\), Apr 22, 2011
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Web 2.0 Secrets Revealed

    , Mar 21, 2008, in forum: ASP .Net
    Replies:
    4
    Views:
    333
    Fernando Monteiro
    Mar 22, 2008
  2. debianna
    Replies:
    0
    Views:
    411
    debianna
    Mar 14, 2009
  3. Aaron Gray
    Replies:
    20
    Views:
    392
    Lasse Reichstein Nielsen
    Jul 27, 2008
  4. lorlarz
    Replies:
    6
    Views:
    210
    David Mark
    Mar 25, 2010
  5. RobG
    Replies:
    2
    Views:
    197
    David Mark
    May 11, 2011
Loading...

Share This Page