]> source.dussan.org Git - jquery.git/commitdiff
A more modest valHooks proposal
authortimmywil <tim.willison@thisismedium.com>
Sat, 2 Apr 2011 21:05:04 +0000 (17:05 -0400)
committertimmywil <tim.willison@thisismedium.com>
Sat, 2 Apr 2011 21:05:04 +0000 (17:05 -0400)
- The main difference is that this does not allow arbitrarily adding hooks to any collection of elements.

- Modularizes val into a set of easily maintainable and conditional hooks.

- valHooks is placed at jQuery.valHooks

  + This could technically be extended, but I do not see it being used except in very rare cases since you can only apply valHooks to nodeNames and input types, and not a collection of elements as before. We could theoretically privatize valHooks taking it off of jQuery and only use it internally for our own convenience, but again, I do not believe this patch carries with it the dangers of the first proposal.

- Slightly improved performance of val on radios and checkboxes for browsers that support checkOn, given the conditional attachment of its hook.

src/attributes.js

index 599721055a1fb96b9250eaf719ce21a602f8d9fa..4c59a675f7c5f36bc8d9924d5bd017a31bf7b6e3 100644 (file)
@@ -154,82 +154,35 @@ jQuery.fn.extend({
        },
 
        val: function( value ) {
+               var hooks, val,
+                       elem = this[0];
+               
                if ( !arguments.length ) {
-                       var elem = this[0];
-
                        if ( elem ) {
-                               if ( jQuery.nodeName( elem, "option" ) ) {
-                                       // attributes.value is undefined in Blackberry 4.7 but
-                                       // uses .value. See #6932
-                                       var val = elem.attributes.value;
-                                       return !val || val.specified ? elem.value : elem.text;
-                               }
-
-                               // We need to handle select boxes special
-                               if ( jQuery.nodeName( elem, "select" ) ) {
-                                       var index = elem.selectedIndex,
-                                               values = [],
-                                               options = elem.options,
-                                               one = elem.type === "select-one";
-
-                                       // Nothing was selected
-                                       if ( index < 0 ) {
-                                               return null;
-                                       }
-
-                                       // Loop through all the selected options
-                                       for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
-                                               var option = options[ i ];
-
-                                               // Don't return options that are disabled or in a disabled optgroup
-                                               if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
-                                                               (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
+                               hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ];
 
-                                                       // Get the specific value for the option
-                                                       value = jQuery(option).val();
-
-                                                       // We don't need an array for one selects
-                                                       if ( one ) {
-                                                               return value;
-                                                       }
-
-                                                       // Multi-Selects return an array
-                                                       values.push( value );
-                                               }
-                                       }
-
-                                       // Fixes Bug #2551 -- select.val() broken in IE after form.reset()
-                                       if ( one && !values.length && options.length ) {
-                                               return jQuery( options[ index ] ).val();
-                                       }
-
-                                       return values;
-                               }
-
-                               // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
-                               if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) {
-                                       return elem.getAttribute("value") === null ? "on" : elem.value;
+                               if ( hooks && "get" in hooks && (val = hooks.get( elem )) !== undefined ) {
+                                       return val;
                                }
 
-                               // Everything else, we just grab the value
                                return (elem.value || "").replace(rreturn, "");
-
                        }
 
                        return undefined;
                }
 
-               var isFunction = jQuery.isFunction(value);
+               var isFunction = jQuery.isFunction( value );
 
-               return this.each(function(i) {
-                       var self = jQuery(this), val = value;
+               return this.each(function( i ) {
+                       var self = jQuery(this);
 
                        if ( this.nodeType !== 1 ) {
                                return;
                        }
 
+                       val = value;
                        if ( isFunction ) {
-                               val = value.call(this, i, self.val());
+                               val = value.call( this, i, self.val() );
                        }
 
                        // Treat null/undefined as ""; convert numbers to string
@@ -237,34 +190,88 @@ jQuery.fn.extend({
                                val = "";
                        } else if ( typeof val === "number" ) {
                                val += "";
-                       } else if ( jQuery.isArray(val) ) {
-                               val = jQuery.map(val, function (value) {
+                       } else if ( jQuery.isArray( val ) ) {
+                               val = jQuery.map(val, function ( value ) {
                                        return value == null ? "" : value + "";
                                });
                        }
 
-                       if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) {
-                               this.checked = jQuery.inArray( self.val(), val ) >= 0;
+                       hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ];
+
+                       // If set returns undefined, fall back to normal setting
+                       if ( !hooks || ("set" in hooks && hooks.set( this, val ) === undefined) ) {
+                               this.value = val;
+                       }
+               });
+       }
+});
+
+jQuery.extend({
+       valHooks: {
+               option: {
+                       get: function( elem ) {
+                               // attributes.value is undefined in Blackberry 4.7 but
+                               // uses .value. See #6932
+                               var val = elem.attributes.value;
+                               return !val || val.specified ? elem.value : elem.text;
+                       }
+               },
+               select: {
+                       get: function( elem ) {
+                               var index = elem.selectedIndex,
+                                       values = [],
+                                       options = elem.options,
+                                       one = elem.type === "select-one";
+
+                               // Nothing was selected
+                               if ( index < 0 ) {
+                                       return null;
+                               }
+
+                               // Loop through all the selected options
+                               for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
+                                       var option = options[ i ];
+
+                                       // Don't return options that are disabled or in a disabled optgroup
+                                       if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
+                                                       (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
+
+                                               // Get the specific value for the option
+                                               value = jQuery( option ).val();
+
+                                               // We don't need an array for one selects
+                                               if ( one ) {
+                                                       return value;
+                                               }
+
+                                               // Multi-Selects return an array
+                                               values.push( value );
+                                       }
+                               }
 
-                       } else if ( jQuery.nodeName( this, "select" ) ) {
-                               var values = jQuery.makeArray(val);
+                               // Fixes Bug #2551 -- select.val() broken in IE after form.reset()
+                               if ( one && !values.length && options.length ) {
+                                       return jQuery( options[ index ] ).val();
+                               }
 
-                               jQuery( "option", this ).each(function() {
+                               return values;
+                       },
+
+                       set: function( elem, value ) {
+                               var values = jQuery.makeArray( value );
+
+                               jQuery(elem).find("option").each(function() {
                                        this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
                                });
 
                                if ( !values.length ) {
-                                       this.selectedIndex = -1;
+                                       elem.selectedIndex = -1;
                                }
-
-                       } else {
-                               this.value = val;
+                               return values;
                        }
-               });
-       }
-});
+               }
+       },
 
-jQuery.extend({
        attrFn: {
                val: true,
                css: true,
@@ -386,4 +393,25 @@ jQuery.extend({
        }
 });
 
+// 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 ], {
+               set: function( elem, value ) {
+                       if ( jQuery.isArray( value ) ) {
+                               return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0);
+                       }
+               }
+       });
+});
+
 })( jQuery );