2 * "checkboxradio" plugin
5 (function( $, undefined ) {
7 $.widget( "mobile.checkboxradio", $.mobile.widget, {
10 initSelector: "input[type='checkbox'],input[type='radio']"
15 inheritAttr = function( input, dataAttr ) {
16 return input.jqmData( dataAttr ) || input.closest( "form, fieldset" ).jqmData( dataAttr );
18 // NOTE: Windows Phone could not find the label through a selector
19 // filter works though.
20 parentLabel = $( input ).closest( "label" ),
21 label = parentLabel.length ? parentLabel : ( input[0].id ? $( input ).closest( "form, fieldset, :jqmData(role='page'), :jqmData(role='dialog')" ).find( "label" ).filter( "[for='" + input[0].id + "']" ) : [ ] ),
22 inputtype = input[0].type,
23 mini = inheritAttr( input, "mini" ),
24 checkedState = inputtype + "-on",
25 uncheckedState = inputtype + "-off",
26 icon = input.parents( ":jqmData(type='horizontal')" ).length ? undefined : uncheckedState,
27 iconpos = inheritAttr( input, "iconpos" ),
28 activeBtn = icon ? "" : " " + $.mobile.activeBtnClass,
29 checkedClass = "ui-" + checkedState + activeBtn,
30 uncheckedClass = "ui-" + uncheckedState,
31 checkedicon = "ui-icon-" + checkedState,
32 uncheckedicon = "ui-icon-" + uncheckedState,
35 if ( inputtype !== "checkbox" && inputtype !== "radio" ) {
39 ariaCheckedAttr = ( inputtype === "checkbox" ) ? "aria-checked" : "aria-selected";
42 if ( label.length == 0 ) {
43 label = $( "<label for='" + input[ 0 ].id +
47 // Expose for other methods
51 checkedClass: checkedClass,
52 uncheckedClass: uncheckedClass,
53 checkedicon: checkedicon,
54 uncheckedicon: uncheckedicon,
55 ariaCheckedAttr : ariaCheckedAttr
58 // If there's no selected theme check the data attr
59 if ( !this.options.theme ) {
60 this.options.theme = $.mobile.getInheritedTheme( this.element, "c" );
64 theme: this.options.theme,
71 // Wrap the input + label in a div
72 var wrapper = document.createElement('div');
73 wrapper.className = 'ui-' + inputtype;
74 wrapper.setAttribute( "role", inputtype );
76 if ( input.hasClass( "favorite" ) ) {
77 wrapper.className += ' favorite';
80 input.add( label ).wrapAll( wrapper );
83 vmouseover: function( event ) {
84 if ( $( this ).parent().is( ".ui-disabled" ) ) {
85 event.stopPropagation();
89 vclick: function( event ) {
90 if ( input.is( ":disabled" ) ) {
91 event.preventDefault();
97 input.prop( "checked", inputtype === "radio" && true || !input.prop( "checked" ) );
99 // trigger click handler's bound directly to the input as a substitute for
100 // how label clicks behave normally in the browsers
101 // TODO: it would be nice to let the browser's handle the clicks and pass them
102 // through to the associate input. we can swallow that click at the parent
103 // wrapper element level
104 input.triggerHandler( 'click' );
106 // Input set for common radio buttons will contain all the radio
107 // buttons, but will not for checkboxes. clearing the checked status
108 // of other radios ensures the active button state is applied properly
109 self._getInputSet().not( input ).prop( "checked", false );
118 vmousedown: function() {
123 var $this = $( this );
125 // Adds checked attribute to checked input when keyboard is used
126 if ( $this.is( ":checked" ) ) {
128 $this.prop( "checked", true);
129 self._getInputSet().not( $this ).prop( "checked", false );
132 $this.prop( "checked", false );
139 label.addClass( $.mobile.focusClass );
143 label.removeClass( $.mobile.focusClass );
150 _cacheVals: function() {
151 this._getInputSet().each(function() {
152 $( this ).jqmData( "cacheVal", this.checked );
156 //returns either a set of radios with the same name attribute, or a single checkbox
157 _getInputSet: function() {
158 if ( this.inputtype === "checkbox" ) {
162 return this.element.closest( "form, fieldset, :jqmData(role='page'), :jqmData(role='dialog')" )
163 .find( "input[name='" + this.element[0].name + "'][type='" + this.inputtype + "']" );
166 _updateAll: function() {
169 this._getInputSet().each(function() {
170 var $this = $( this );
172 if ( this.checked || self.inputtype === "checkbox" ) {
173 $this.trigger( "change" );
177 .checkboxradio( "refresh" );
180 refresh: function() {
181 var input = this.element[0],
183 wrapper = input.parentNode,
184 icon = label.find( ".ui-icon" );
186 if ( input.checked ) {
187 label.addClass( this.checkedClass ).removeClass( this.uncheckedClass );
188 icon.addClass( this.checkedicon ).removeClass( this.uncheckedicon );
189 wrapper.setAttribute( this.ariaCheckedAttr, true );
191 label.removeClass( this.checkedClass ).addClass( this.uncheckedClass );
192 icon.removeClass( this.checkedicon ).addClass( this.uncheckedicon );
193 wrapper.setAttribute( this.ariaCheckedAttr, false );
196 if ( input.disabled ) {
203 disable: function() {
204 this.element.prop( "disabled", true ).parent().addClass( "ui-disabled" );
208 this.element.prop( "disabled", false ).parent().removeClass( "ui-disabled" );
212 //auto self-init widgets
213 $.mobile.$document.bind( "pagecreate create", function( e ) {
214 $.mobile.checkboxradio.prototype.enhanceWithin( e.target, true );