checkboxradio.js (7510B)
1 /*! 2 * jQuery UI Checkboxradio 1.12.1 3 * http://jqueryui.com 4 * 5 * Copyright jQuery Foundation and other contributors 6 * Released under the MIT license. 7 * http://jquery.org/license 8 */ 9 10 //>>label: Checkboxradio 11 //>>group: Widgets 12 //>>description: Enhances a form with multiple themeable checkboxes or radio buttons. 13 //>>docs: http://api.jqueryui.com/checkboxradio/ 14 //>>demos: http://jqueryui.com/checkboxradio/ 15 //>>css.structure: ../../themes/base/core.css 16 //>>css.structure: ../../themes/base/button.css 17 //>>css.structure: ../../themes/base/checkboxradio.css 18 //>>css.theme: ../../themes/base/theme.css 19 20 ( function( factory ) { 21 if ( typeof define === "function" && define.amd ) { 22 23 // AMD. Register as an anonymous module. 24 define( [ 25 "jquery", 26 "./core" 27 ], factory ); 28 } else { 29 30 // Browser globals 31 factory( jQuery ); 32 } 33 }( function( $ ) { 34 35 $.widget( "ui.checkboxradio", [ $.ui.formResetMixin, { 36 version: "1.12.1", 37 options: { 38 disabled: null, 39 label: null, 40 icon: true, 41 classes: { 42 "ui-checkboxradio-label": "ui-corner-all", 43 "ui-checkboxradio-icon": "ui-corner-all" 44 } 45 }, 46 47 _getCreateOptions: function() { 48 var disabled, labels; 49 var that = this; 50 var options = this._super() || {}; 51 52 // We read the type here, because it makes more sense to throw a element type error first, 53 // rather then the error for lack of a label. Often if its the wrong type, it 54 // won't have a label (e.g. calling on a div, btn, etc) 55 this._readType(); 56 57 labels = this.element.labels(); 58 59 // If there are multiple labels, use the last one 60 this.label = $( labels[ labels.length - 1 ] ); 61 if ( !this.label.length ) { 62 $.error( "No label found for checkboxradio widget" ); 63 } 64 65 this.originalLabel = ""; 66 67 // We need to get the label text but this may also need to make sure it does not contain the 68 // input itself. 69 this.label.contents().not( this.element[ 0 ] ).each( function() { 70 71 // The label contents could be text, html, or a mix. We concat each element to get a 72 // string representation of the label, without the input as part of it. 73 that.originalLabel += this.nodeType === 3 ? $( this ).text() : this.outerHTML; 74 } ); 75 76 // Set the label option if we found label text 77 if ( this.originalLabel ) { 78 options.label = this.originalLabel; 79 } 80 81 disabled = this.element[ 0 ].disabled; 82 if ( disabled != null ) { 83 options.disabled = disabled; 84 } 85 return options; 86 }, 87 88 _create: function() { 89 var checked = this.element[ 0 ].checked; 90 91 this._bindFormResetHandler(); 92 93 if ( this.options.disabled == null ) { 94 this.options.disabled = this.element[ 0 ].disabled; 95 } 96 97 this._setOption( "disabled", this.options.disabled ); 98 this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" ); 99 this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" ); 100 101 if ( this.type === "radio" ) { 102 this._addClass( this.label, "ui-checkboxradio-radio-label" ); 103 } 104 105 if ( this.options.label && this.options.label !== this.originalLabel ) { 106 this._updateLabel(); 107 } else if ( this.originalLabel ) { 108 this.options.label = this.originalLabel; 109 } 110 111 this._enhance(); 112 113 if ( checked ) { 114 this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" ); 115 if ( this.icon ) { 116 this._addClass( this.icon, null, "ui-state-hover" ); 117 } 118 } 119 120 this._on( { 121 change: "_toggleClasses", 122 focus: function() { 123 this._addClass( this.label, null, "ui-state-focus ui-visual-focus" ); 124 }, 125 blur: function() { 126 this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" ); 127 } 128 } ); 129 }, 130 131 _readType: function() { 132 var nodeName = this.element[ 0 ].nodeName.toLowerCase(); 133 this.type = this.element[ 0 ].type; 134 if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) { 135 $.error( "Can't create checkboxradio on element.nodeName=" + nodeName + 136 " and element.type=" + this.type ); 137 } 138 }, 139 140 // Support jQuery Mobile enhanced option 141 _enhance: function() { 142 this._updateIcon( this.element[ 0 ].checked ); 143 }, 144 145 widget: function() { 146 return this.label; 147 }, 148 149 _getRadioGroup: function() { 150 var group; 151 var name = this.element[ 0 ].name; 152 var nameSelector = "input[name='" + $.ui.escapeSelector( name ) + "']"; 153 154 if ( !name ) { 155 return $( [] ); 156 } 157 158 if ( this.form.length ) { 159 group = $( this.form[ 0 ].elements ).filter( nameSelector ); 160 } else { 161 162 // Not inside a form, check all inputs that also are not inside a form 163 group = $( nameSelector ).filter( function() { 164 return $( this ).form().length === 0; 165 } ); 166 } 167 168 return group.not( this.element ); 169 }, 170 171 _toggleClasses: function() { 172 var checked = this.element[ 0 ].checked; 173 this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked ); 174 175 if ( this.options.icon && this.type === "checkbox" ) { 176 this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked ) 177 ._toggleClass( this.icon, null, "ui-icon-blank", !checked ); 178 } 179 180 if ( this.type === "radio" ) { 181 this._getRadioGroup() 182 .each( function() { 183 var instance = $( this ).checkboxradio( "instance" ); 184 185 if ( instance ) { 186 instance._removeClass( instance.label, 187 "ui-checkboxradio-checked", "ui-state-active" ); 188 } 189 } ); 190 } 191 }, 192 193 _destroy: function() { 194 this._unbindFormResetHandler(); 195 196 if ( this.icon ) { 197 this.icon.remove(); 198 this.iconSpace.remove(); 199 } 200 }, 201 202 _setOption: function( key, value ) { 203 204 // We don't allow the value to be set to nothing 205 if ( key === "label" && !value ) { 206 return; 207 } 208 209 this._super( key, value ); 210 211 if ( key === "disabled" ) { 212 this._toggleClass( this.label, null, "ui-state-disabled", value ); 213 this.element[ 0 ].disabled = value; 214 215 // Don't refresh when setting disabled 216 return; 217 } 218 this.refresh(); 219 }, 220 221 _updateIcon: function( checked ) { 222 var toAdd = "ui-icon ui-icon-background "; 223 224 if ( this.options.icon ) { 225 if ( !this.icon ) { 226 this.icon = $( "<span>" ); 227 this.iconSpace = $( "<span> </span>" ); 228 this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" ); 229 } 230 231 if ( this.type === "checkbox" ) { 232 toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank"; 233 this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" ); 234 } else { 235 toAdd += "ui-icon-blank"; 236 } 237 this._addClass( this.icon, "ui-checkboxradio-icon", toAdd ); 238 if ( !checked ) { 239 this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" ); 240 } 241 this.icon.prependTo( this.label ).after( this.iconSpace ); 242 } else if ( this.icon !== undefined ) { 243 this.icon.remove(); 244 this.iconSpace.remove(); 245 delete this.icon; 246 } 247 }, 248 249 _updateLabel: function() { 250 251 // Remove the contents of the label ( minus the icon, icon space, and input ) 252 var contents = this.label.contents().not( this.element[ 0 ] ); 253 if ( this.icon ) { 254 contents = contents.not( this.icon[ 0 ] ); 255 } 256 if ( this.iconSpace ) { 257 contents = contents.not( this.iconSpace[ 0 ] ); 258 } 259 contents.remove(); 260 261 this.label.append( this.options.label ); 262 }, 263 264 refresh: function() { 265 var checked = this.element[ 0 ].checked, 266 isDisabled = this.element[ 0 ].disabled; 267 268 this._updateIcon( checked ); 269 this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked ); 270 if ( this.options.label !== null ) { 271 this._updateLabel(); 272 } 273 274 if ( isDisabled !== this.options.disabled ) { 275 this._setOptions( { "disabled": isDisabled } ); 276 } 277 } 278 279 } ] ); 280 281 return $.ui.checkboxradio; 282 283 } ) );