Skip to content

Commit

Permalink
A more modest valHooks proposal
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
timmywil committed Apr 2, 2011
1 parent ff06d41 commit 64a0005
Showing 1 changed file with 101 additions and 73 deletions.
174 changes: 101 additions & 73 deletions src/attributes.js
Expand Up @@ -154,117 +154,124 @@ 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
if ( val == null ) {
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,
Expand Down Expand Up @@ -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 );

0 comments on commit 64a0005

Please sign in to comment.