// ==========================================================================
// 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;
}
});