// ========================================================================== // Project: SproutCore - JavaScript Application Framework // Copyright: ©2006-2009 Sprout Systems, Inc. and contributors. // Portions ©2008-2009 Apple Inc. All rights reserved. // License: Licened under MIT license (see license.js) // ========================================================================== /** @class A RadioView is used to create a group of radio buttons. The user can use these buttons to pick from a choice of options. This view renders simulated radio buttons that can display a mixed state and has other features not found in platform-native controls. The radio buttons themselves are designed to be styled using CSS classes with the following structure: Setting up a RadioView accepts a number of properties, for example: { items: [{ title: "Red", value: "red", enabled: YES, icon: "button_red" }, { title: "Green", value: "green", enabled: YES, icon: 'button_green' }], value: 'red', itemTitleKey: 'title', itemValueKey: 'value', itemIconKey: 'icon', itemIsEnabledKey: 'enabled', isEnabled: YES, layoutDirection: SC.LAYOUT_HORIZONTAL } Default layoutDirection is vertical. Default isEnabled is YES. The value property can be either a string, as above, or an array of strings for pre-checking multiple values. The items array can contain either strings, or as in the example above a hash. When using a hash, make sure to also specify the itemTitleKey and itemValueKey you are using. Similarly, you will have to provide itemIconKey if you are using icons radio buttons. The individual items enabled property is YES by default, and the icon is optional. @extends SC.FieldView @since SproutCore 1.0 */ SC.RadioView = SC.FieldView.extend( /** @scope SC.RadioView.prototype */ { // HTML design options classNames: ['sc-radio-view'], /** The value of the currently selected item, and which will be checked in the UI. This can be either a string or an array with strings for checking multiple values. */ value: null, layoutDirection: SC.LAYOUT_VERTICAL, // escape the HTML in label text escapeHTML: YES, /** The items property can be either an array with strings, or a hash. When using a hash, make sure to also specify the appropriate itemTitleKey, itemValueKey, itemIsEnabledKey and itemIconKey. */ items: [], /** If items property is a hash, specify which property will function as the title with this itemTitleKey property. */ itemTitleKey: null, /** If items property is a hash, specify which property will function as the value with this itemValueKey property. */ itemValueKey: null, /** If items property is a hash, specify which property will function as the value with this itemIsEnabledKey property. */ itemIsEnabledKey: null, /** If items property is a hash, specify which property will function as the value with this itemIconKey property. */ itemIconKey: null, /** @private - Will iterate the items property to return an array with items that is indexed in the following structure: [0] => Title (or label) [1] => Value [2] => Enabled (YES default) [3] => Icon (image URL) */ displayItems: function() { var items = this.get('items'), loc = this.get('localize'), titleKey = this.get('itemTitleKey'), valueKey = this.get('itemValueKey'), isEnabledKey = this.get('itemIsEnabledKey'), iconKey = this.get('itemIconKey'); var ret = [], max = (items)? items.length : 0 ; var item, title, value, idx, isArray, isEnabled, icon; for(idx=0;idx=0) ? icon : static_url('blank'); className = (url === icon) ? '' : icon ; icon = ''.fmt(url, className); } else icon = ''; selectionStateClassNames = this._getSelectionState(item, value, isArray, false); disabled = (!item[2]) || (!this.get('isEnabled')) ? 'disabled="disabled" ' : ''; labelText = this.escapeHTML ? SC.RenderContext.escapeHTML(item[0]) : item[0]; var blankImage = static_url('blank'); context.push(''); } // first remove listener on existing radio buttons this._field_setFieldValue(this.get('value')); } else { // update the selection state on all of the DOM elements. The options are // sel or mixed. These are used to display the proper setting... this.$input().forEach(function(input) { input = this.$(input); idx = parseInt(input.val(),0); item = (idx>=0) ? items[idx] : null; input.attr('disabled', (!item[2]) ? 'disabled' : null); selectionState = this._getSelectionState(item, value, isArray, true); // set class of label input.parent().setClass(selectionState); // avoid memory leaks input = val = idx = selectionState = null; }, this); } }, /** @private - Will figure out what class names to assign each radio button. This method can be invoked either as part of render() either when: 1. firstTime is set and we need to assign the class names as a string 2. we already have the DOM rendered but we just need to update class names assigned to the the input field parent */ _getSelectionState: function(item, value, isArray, shouldReturnObject) { var sel, classNames; // determine if the current item is selected if (item) { sel = (isArray) ? (value.indexOf(item[1])>=0) : (value===item[1]); } else { sel = NO; } // now set class names classNames = { sel: (sel && !isArray), mixed: (sel && isArray), disabled: (!item[2]) } if(shouldReturnObject) { return classNames; } else { // convert object values to string var classNameArray = []; for(key in classNames) { if(!classNames.hasOwnProperty(key)) continue; if(classNames[key]) classNameArray.push(key); } return classNameArray.join(" "); } }, getFieldValue: function() { var val = this.$input().filter(function() { return this.checked; }).val(); var items = this.get('displayItems') ; val = items[parseInt(val,0)]; // if no items are selected there is a saved mixed value, return that... return val ? val[1] : this._mixedValue; }, setFieldValue: function(v) { // if setting a mixed value, actually clear everything and save mixed // value if (SC.isArray(v)) { if (v.get('length')>1) { this._mixedValue = v; v = undefined ; } else v = v.objectAt(0); } // v now contains one item only. find the index in the display items // array matching that value. var items, idx; if (v === undefined) { idx = -1; } else { items = this.get('displayItems'); idx = items.indexOf(items.find(function(x) { return x[1] === v; })); } // now loop through input elements. set their checked value accordingly this.$input().forEach(function(input) { input = SC.$(input); input.attr('checked', parseInt(input.val(),0) === idx); input = null; }); return this; } });