Skip to content
Permalink
Browse files

Don't have .val() return selected-but-disabled options, or selected o…

…ptions inside a disabled optgroup. Doesn't change the .val() returned for a disabled select. Fixes #3240, adapted from Nathan Hammond's patch there.
  • Loading branch information
dmethvin authored and jeresig committed Sep 24, 2010
1 parent 700ff05 commit 2c4b20809e5d32e916c479c9b63a6b7528c880ce
Showing with 31 additions and 12 deletions.
  1. +4 −2 src/attributes.js
  2. +9 −0 test/index.html
  3. +9 −1 test/unit/attributes.js
  4. +1 −1 test/unit/event.js
  5. +6 −6 test/unit/selector.js
  6. +2 −2 test/unit/traversing.js
@@ -163,8 +163,10 @@ jQuery.fn.extend({
for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
var option = options[ i ];

if ( option.selected ) {
// Get the specifc value for the option
// Don't return options that are disabled or in a disabled optgroup
if ( option.selected && !option.disabled &&
(!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
@@ -114,6 +114,15 @@ <h2 id="qunit-userAgent"></h2>
<option id="option3d" value="3">3</option>
<option id="option3e">no value</option>
</select>
<select name="select4" id="select4" multiple="multiple">
<optgroup disabled="disabled">
<option id="option4a" class="emptyopt" value="">Nothing</option>
<option id="option4b" disabled="disabled" selected="selected" value="1">1</option>
<option id="option4c" selected="selected" value="2">2</option>
</optgroup>
<option selected="selected" disabled="disabled" id="option4d" value="3">3</option>
<option id="option4e">no value</option>
</select>

<object id="object1" codebase="stupid">
<param name="p1" value="x1" />
@@ -302,7 +302,7 @@ test("removeAttr(String)", function() {
});

test("val()", function() {
expect(17);
expect(20);

document.getElementById('text1').value = "bla";
equals( jQuery("#text1").val(), "bla", "Check for modified value of input element" );
@@ -329,6 +329,14 @@ test("val()", function() {
jQuery('#select3').val("");
same( jQuery('#select3').val(), [''], 'Call val() on a multiple="multiple" select' );

same( jQuery('#select4').val(), [], 'Call val() on multiple="multiple" select with all disabled options' );

jQuery('#select4 optgroup').add('#select4 > [disabled]').attr('disabled', false);
same( jQuery('#select4').val(), ['2', '3'], 'Call val() on multiple="multiple" select with some disabled options' );

jQuery('#select4').attr('disabled', true);
same( jQuery('#select4').val(), ['2', '3'], 'Call val() on disabled multiple="multiple" select' );

This comment has been minimized.

Copy link
@jitter

jitter Sep 27, 2010

Contributor

This test fails for all Webkit browsers listed on the testswarm http://swarm.jquery.org/job/225/. The cause seems to be that Webkit (different from all other browsers) returns true for the disabled attribute of all options which are immediate childrens of a disabled select. Even when the options itself hasn't the disabled attribute set explicitly

This is the reason why the option with id option4d is missing from the actual result. The only workaround I could find is to use the getAttribute() function in Safari (didn't test if this also works in the other Webkit based browsers). Which returns null if the disabled attribute isn't set or false and an empty string if it is set to true / disabled. While option.disabled always returns true if the parent select is disabled not matter if the option itself is explicitly disabled or not.

So we would basically need to check if we are using a Webkit based browser or find other means to determine if we can rely on option.disabled in attribute.js val() and I don't know if that's acceptable.

This comment has been minimized.

Copy link
@jeresig

jeresig Sep 27, 2010

Member

Thanks for the catch! I did some additional testing on the technique that you proposed and it seems to work fine everywhere that I can test so I'm going to push ahead with that. Landed in 157a383


var checks = jQuery("<input type='checkbox' name='test' value='1'/><input type='checkbox' name='test' value='2'/><input type='checkbox' name='test' value=''/><input type='checkbox' name='test'/>").appendTo("#form");

same( checks.serialize(), "", "Get unchecked values." );
@@ -255,7 +255,7 @@ test("bind(), iframes", function() {
});

test("bind(), trigger change on select", function() {
expect(3);
expect(4);
var counter = 0;
function selectOnChange(event) {
equals( event.data, counter++, "Event.data is not a global event object" );
@@ -21,7 +21,7 @@ test("element", function() {
same( jQuery("p", jQuery("div")).get(), q("firstp","ap","sndp","en","sap","first"), "Finding elements with a context." );
same( jQuery("div").find("p").get(), q("firstp","ap","sndp","en","sap","first"), "Finding elements with a context." );

same( jQuery("#form").find("select").get(), q("select1","select2","select3"), "Finding selects with a context." );
same( jQuery("#form").find("select").get(), q("select1","select2","select3","select4"), "Finding selects with a context." );

ok( jQuery("#length").length, '&lt;input name="length"&gt; cannot be found under IE, see #945' );
ok( jQuery("#lengthtest input").length, '&lt;input name="length"&gt; cannot be found under IE, see #945' );
@@ -338,7 +338,7 @@ test("pseudo - :not", function() {
expect(24);
t( "Not", "a.blog:not(.link)", ["mark"] );

t( "Not - multiple", "#form option:not(:contains(Nothing),#option1b,:selected)", ["option1c", "option1d", "option2b", "option2c", "option3d", "option3e"] );
t( "Not - multiple", "#form option:not(:contains(Nothing),#option1b,:selected)", ["option1c", "option1d", "option2b", "option2c", "option3d", "option3e", "option4e"] );
t( "Not - recursive", "#form option:not(:not(:selected))[id^='option3']", [ "option3b", "option3c"] );

t( ":not() failing interior", "p:not(.foo)", ["firstp","ap","sndp","en","sap","first"] );
@@ -360,8 +360,8 @@ test("pseudo - :not", function() {
t( "No element not selector", ".container div:not(.excluded) div", [] );

t( ":not() Existing attribute", "#form select:not([multiple])", ["select1", "select2"]);
t( ":not() Equals attribute", "#form select:not([name=select1])", ["select2", "select3"]);
t( ":not() Equals quoted attribute", "#form select:not([name='select1'])", ["select2", "select3"]);
t( ":not() Equals attribute", "#form select:not([name=select1])", ["select2", "select3", "select4"]);
t( ":not() Equals quoted attribute", "#form select:not([name='select1'])", ["select2", "select3", "select4"]);

t( ":not() Multiple Class", "#foo a:not(.blog)", ["yahoo","anchor2"] );
t( ":not() Multiple Class", "#foo a:not(.link)", ["yahoo","anchor2"] );
@@ -427,13 +427,13 @@ test("pseudo - visibility", function() {
test("pseudo - form", function() {
expect(8);

t( "Form element :input", "#form :input", ["text1", "text2", "radio1", "radio2", "check1", "check2", "hidden1", "hidden2", "name", "search", "button", "area1", "select1", "select2", "select3"] );
t( "Form element :input", "#form :input", ["text1", "text2", "radio1", "radio2", "check1", "check2", "hidden1", "hidden2", "name", "search", "button", "area1", "select1", "select2", "select3", "select4"] );
t( "Form element :radio", "#form :radio", ["radio1", "radio2"] );
t( "Form element :checkbox", "#form :checkbox", ["check1", "check2"] );
t( "Form element :text", "#form :text:not(#search)", ["text1", "text2", "hidden2", "name"] );
t( "Form element :radio:checked", "#form :radio:checked", ["radio2"] );
t( "Form element :checkbox:checked", "#form :checkbox:checked", ["check1"] );
t( "Form element :radio:checked, :checkbox:checked", "#form :radio:checked, #form :checkbox:checked", ["radio2", "check1"] );

t( "Selected Option Element", "#form option:selected", ["option1a","option2d","option3b","option3c"] );
t( "Selected Option Element", "#form option:selected", ["option1a","option2d","option3b","option3c","option4b","option4c","option4d"] );
});
@@ -152,7 +152,7 @@ test("not(Selector)", function() {
equals( jQuery("#main > p#ap > a").not("#google").length, 2, "not('selector')" );
same( jQuery("p").not(".result").get(), q("firstp", "ap", "sndp", "en", "sap", "first"), "not('.class')" );
same( jQuery("p").not("#ap, #sndp, .result").get(), q("firstp", "en", "sap", "first"), "not('selector, selector')" );
same( jQuery("#form option").not("option.emptyopt:contains('Nothing'),[selected],[value='1']").get(), q("option1c", "option1d", "option2c", "option3d", "option3e" ), "not('complex selector')");
same( jQuery("#form option").not("option.emptyopt:contains('Nothing'),[selected],[value='1']").get(), q("option1c", "option1d", "option2c", "option3d", "option3e", "option4e" ), "not('complex selector')");

same( jQuery('#ap *').not('code').get(), q("google", "groups", "anchor1", "mark"), "not('tag selector')" );
same( jQuery('#ap *').not('code, #mark').get(), q("google", "groups", "anchor1"), "not('tag, ID selector')" );
@@ -163,7 +163,7 @@ test("not(Element)", function() {
expect(1);

var selects = jQuery("#form select");
same( selects.not( selects[1] ).get(), q("select1", "select3"), "filter out DOM element");
same( selects.not( selects[1] ).get(), q("select1", "select3", "select4"), "filter out DOM element");
});

test("not(Function)", function() {

0 comments on commit 2c4b208

Please sign in to comment.
You can’t perform that action at this time.