Skip to content
This repository has been archived by the owner on Oct 8, 2021. It is now read-only.

Commit

Permalink
Checkboxradio: Correctly assemble radio group
Browse files Browse the repository at this point in the history
Closes gh-6659
Closes gh-7082
Fixes gh-7088
  • Loading branch information
Gabriel Schulhof committed Feb 9, 2014
1 parent 4696651 commit dcbe28b
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 5 deletions.
89 changes: 84 additions & 5 deletions js/widgets/forms/checkboxradio.js
Expand Up @@ -182,14 +182,93 @@ $.widget( "mobile.checkboxradio", $.extend( {
});
},

//returns either a set of radios with the same name attribute, or a single checkbox
// Returns those radio buttons that are supposed to be in the same group as
// this radio button. In the case of a checkbox or a radio lacking a name
// attribute, it returns this.element.
_getInputSet: function() {
if ( this.inputtype === "checkbox" ) {
return this.element;
var formParent, inputSelector, thisPage, thisPageSelector,
thisElement = this.element,
formId = thisElement.attr( "form" ),
outsideForm = false,
returnValue = thisElement,
name = thisElement[ 0 ].name;

// We only look for group members if this widget is not a checkbox or
// an unnamed radio button
if ( !( this.inputtype === "checkbox" || !name ) ) {

inputSelector = "input[type='radio'][name='" + name + "']";

thisPageSelector = ":jqmData(role='page'), " +
":jqmData(role='dialog')" +
( $.mobile.page ? ", :mobile-page" : "" ) +
", body";
thisPage = thisElement.closest( thisPageSelector );

if ( formId ) {

// This element has a form attribute. Let's find the form.
formParent = thisPage.find( "#" + formId );
} else {

// Are we inside a form?
// We don't use .closest() here because we want the outermost
// form and some browsers may fail to discard any nested forms.
formParent = thisElement.parents( "form" ).last();
}

if ( formParent.length > 0 ) {
formId = formParent.attr( "id" );

// If the form has an ID, append those inputs that may be
// scattered throughout the page, but belonging to the parent
// form
if ( formId ) {
returnValue = thisPage
.find( inputSelector + "[form='" + formId + "']" )
.add( returnValue );
}
} else {
outsideForm = true;
formParent = thisPage;
}

returnValue = formParent
.find( inputSelector )
.filter( function() {
var formAttribute, otherRadio;

if ( this === thisElement[ 0 ] ) {
return true;
}

otherRadio = $( this );
formAttribute = otherRadio.attr( "form" );

return outsideForm ?

// If this.element is outside of a form then the other
// radio must not have a form attribute in order to be
// admitted to this group
( !formAttribute &&

// If it doesn't have a form attribute, it must
// still have the same parent form
otherRadio.closest( "form, " +
thisPageSelector )[ 0 ] ===
formParent[ 0 ] ):

// If this.element is inside a form then the other
// radio is part of this group if it either doesn't
// have a form attribute, or if its form attribute is
// equal to the formId (including an undefined formId)
( !formAttribute ) ||
( formAttribute === formId );
})
.add( returnValue );
}

return this.element.closest( "form, :jqmData(role='page'), :jqmData(role='dialog')" )
.find( "input[name='" + this.element[ 0 ].name + "'][type='" + this.inputtype + "']" );
return returnValue;
},

_updateAll: function() {
Expand Down
50 changes: 50 additions & 0 deletions tests/unit/checkboxradio/input-set-tests.html
@@ -0,0 +1,50 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>jQuery Mobile Checkboxradio Input Set Test Suite</title>

<script src="../../../external/requirejs/require.js"></script>
<script src="../../../js/requirejs.config.js"></script>
<script src="../../../js/jquery.tag.inserter.js"></script>
<script src="../../../tests/jquery.testHelper.js"></script>
<script src="../../../external/qunit/qunit.js"></script>
<script>
$.testHelper.asyncLoad([
[
"widgets/forms/checkboxradio",
],
[
"input_set_tests_core.js"
]
]);
</script>

<link rel="stylesheet" href="../../../external/qunit/qunit.css"/>
<link rel="stylesheet" href="../../jqm-tests.css"/>

<script src="../../swarminject.js"></script>
</head>
<body>

<div id="qunit"></div>

<div data-nstest-role="page">
<label>Radio<input id="radio1" type="radio" name="group1"></label>
<form id="the-form">
<label>Radio<input id="radio2" type="radio" name="group1"></label>
<label>Radio<input id="radio7" type="radio" name="group1" form="the-other-form"></label>
</form>
<label>Radio<input id="radio3" type="radio" name="group1" form="the-form"></label>
<form id="the-other-form">
<label>Radio<input id="radio6" type="radio" name="group1" form="the-form"></label>
<label>Radio<input id="radio4" type="radio" name="group1"></label>
</form>

<!-- radio5 (below) is not supposed to have a name -->
<label>Radio<input id="radio5" type="radio"></label>
</div>

<label>Radio<input id="radio8" type="radio" name="group1"></label>
</body>
</html>
37 changes: 37 additions & 0 deletions tests/unit/checkboxradio/input_set_tests_core.js
@@ -0,0 +1,37 @@
( function( $, undefined ) {

$.mobile.ns = "nstest-";

test( "Radio groups are correctly identified", function() {
var groups = {
"#radio1": "#radio1",
"#radio2": "#radio2,#radio3,#radio6",
"#radio3": "#radio2,#radio3,#radio6",
"#radio6": "#radio2,#radio3,#radio6",
"#radio4": "#radio4,#radio7",
"#radio7": "#radio4,#radio7",
"#radio5": "#radio5",
"#radio8": "#radio8"
};

$.each( groups, function( index, value ) {
var result,
radio = $( index ),
group = $( value );

result = $.mobile.checkboxradio.prototype._getInputSet.call({
element: radio,
inputtype: "radio",
document: $( document )
});
deepEqual( group.length, result.length,
index + ": length of group is correct" );
group.each( function() {
deepEqual( result.filter( this ).length, 1,
index + ": " + $( this ).attr( "id" ) +
" is correctly present in the result" );
});
});
});

})( jQuery );

0 comments on commit dcbe28b

Please sign in to comment.