UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

541 lines (443 loc) 13.3 kB
/* ************************************************************************ qooxdoo - the new era of web development http://qooxdoo.org Copyright: 2004-2008 1&1 Internet AG, Germany, http://www.1und1.de License: MIT: https://opensource.org/licenses/MIT See the LICENSE file in the project's top-level directory for details. Authors: * Sebastian Werner (wpbasti) * Andreas Ecker (ecker) * Christian Hagendorn (chris_schmidt) * Martin Wittemann (martinwittemann) ************************************************************************ */ /** * The radio group handles a collection of items from which only one item * can be selected. Selection another item will deselect the previously selected * item. * * This class is e.g. used to create radio groups or {@link qx.ui.form.RadioButton} * or {@link qx.ui.toolbar.RadioButton} instances. * * We also offer a widget for the same purpose which uses this class. So if * you like to act with a widget instead of a pure logic coupling of the * widgets, take a look at the {@link qx.ui.form.RadioButtonGroup} widget. */ qx.Class.define("qx.ui.form.RadioGroup", { extend : qx.core.Object, implement : [ qx.ui.core.ISingleSelection, qx.ui.form.IField, qx.ui.form.IForm, qx.ui.form.IModelSelection ], include : [ qx.ui.core.MSingleSelectionHandling, qx.ui.form.MModelSelection ], /* ***************************************************************************** CONSTRUCTOR ***************************************************************************** */ /** * @param varargs {qx.core.Object} A variable number of items, which are * initially added to the radio group, the first item will be selected. */ construct : function(varargs) { this.base(arguments); // create item array this.__items = []; // add listener before call add!!! this.addListener("changeSelection", this.__onChangeSelection, this); if (varargs != null) { this.add.apply(this, arguments); } }, /* ***************************************************************************** PROPERTIES ***************************************************************************** */ properties : { /** * The property name in each of the added widgets that is grouped */ groupedProperty : { check : "String", apply : "_applyGroupedProperty", event : "changeGroupedProperty", init : "value" }, /** * The property name in each of the added widgets that is informed of the * RadioGroup object it is a member of */ groupProperty : { check : "String", event : "changeGroupProperty", init : "group" }, /** * Whether the radio group is enabled */ enabled : { check : "Boolean", apply : "_applyEnabled", event : "changeEnabled", init: true }, /** * Whether the selection should wrap around. This means that the successor of * the last item is the first item. */ wrap : { check : "Boolean", init: true }, /** * If is set to <code>true</code> the selection could be empty, * otherwise is always one <code>RadioButton</code> selected. */ allowEmptySelection : { check : "Boolean", init : false, apply : "_applyAllowEmptySelection" }, /** * Flag signaling if the group at all is valid. All children will have the * same state. */ valid : { check : "Boolean", init : true, apply : "_applyValid", event : "changeValid" }, /** * Flag signaling if the group is required. */ required : { check : "Boolean", init : false, event : "changeRequired" }, /** * Message which is shown in an invalid tooltip. */ invalidMessage : { check : "String", init: "", event : "changeInvalidMessage", apply : "_applyInvalidMessage" }, /** * Message which is shown in an invalid tooltip if the {@link #required} is * set to true. */ requiredInvalidMessage : { check : "String", nullable : true, event : "changeInvalidMessage" } }, /* ***************************************************************************** MEMBERS ***************************************************************************** */ members : { /** @type {qx.ui.form.IRadioItem[]} The items of the radio group */ __items : null, /* --------------------------------------------------------------------------- UTILITIES --------------------------------------------------------------------------- */ /** * Get all managed items * * @return {qx.ui.form.IRadioItem[]} All managed items. */ getItems : function() { return this.__items; }, /* --------------------------------------------------------------------------- REGISTRY --------------------------------------------------------------------------- */ /** * Add the passed items to the radio group. * * @param varargs {qx.ui.form.IRadioItem} A variable number of items to add. */ add : function(varargs) { var items = this.__items; var item; var groupedProperty = this.getGroupedProperty(); var groupedPropertyUp = qx.lang.String.firstUp(groupedProperty); for (var i=0, l=arguments.length; i<l; i++) { item = arguments[i]; if (items.includes(item)) { continue; } // Register listeners item.addListener( "change" + groupedPropertyUp, this._onItemChangeChecked, this); // Push RadioButton to array items.push(item); // Inform radio button about new group item.set(this.getGroupProperty(), this); // Need to update internal value? if (item.get(groupedProperty)) { this.setSelection([item]); } } // Select first item when only one is registered if (!this.isAllowEmptySelection() && items.length > 0 && !this.getSelection()[0]) { this.setSelection([items[0]]); } }, /** * Remove an item from the radio group. * * @param item {qx.ui.form.IRadioItem} The item to remove. */ remove : function(item) { var items = this.__items; var groupedProperty = this.getGroupedProperty(); var groupedPropertyUp = qx.lang.String.firstUp(groupedProperty); if (items.includes(item)) { // Remove RadioButton from array qx.lang.Array.remove(items, item); // Inform radio button about new group if (item.get(this.getGroupProperty()) === this) { item.reset(this.getGroupProperty()); } // Deregister listeners item.removeListener( "change" + groupedPropertyUp, this._onItemChangeChecked, this); // if the radio was checked, set internal selection to null if (item.get(groupedProperty)) { this.resetSelection(); } } }, /** * Returns an array containing the group's items. * * @return {qx.ui.form.IRadioItem[]} The item array */ getChildren : function() { return this.__items; }, /* --------------------------------------------------------------------------- LISTENER FOR ITEM CHANGES --------------------------------------------------------------------------- */ /** * Event listener for <code>changeValue</code> event of every managed item. * * @param e {qx.event.type.Data} Data event */ _onItemChangeChecked : function(e) { var item = e.getTarget(); var groupedProperty = this.getGroupedProperty(); if (item.get(groupedProperty)) { this.setSelection([item]); } else if (this.getSelection()[0] == item) { this.resetSelection(); } }, /* --------------------------------------------------------------------------- APPLY ROUTINES --------------------------------------------------------------------------- */ // property apply _applyGroupedProperty : function(value, old) { var item; var oldFirstUp = qx.lang.String.firstUp(old); var newFirstUp = qx.lang.String.firstUp(value); for (var i = 0; i < this.__items.length; i++) { item = this.__items[i]; // remove the listener for the old change event item.removeListener( "change" + oldFirstUp, this._onItemChangeChecked, this); // add the listener for the new change event item.removeListener( "change" + newFirstUp, this._onItemChangeChecked, this); } }, // property apply _applyInvalidMessage : function(value, old) { for (var i = 0; i < this.__items.length; i++) { this.__items[i].setInvalidMessage(value); } }, // property apply _applyValid: function(value, old) { for (var i = 0; i < this.__items.length; i++) { this.__items[i].setValid(value); } }, // property apply _applyEnabled : function(value, old) { var items = this.__items; if (value == null) { for (var i=0, l=items.length; i<l; i++) { items[i].resetEnabled(); } } else { for (var i=0, l=items.length; i<l; i++) { items[i].setEnabled(value); } } }, // property apply _applyAllowEmptySelection : function(value, old) { if (!value && this.isSelectionEmpty()) { this.resetSelection(); } }, /* --------------------------------------------------------------------------- SELECTION --------------------------------------------------------------------------- */ /** * Select the item following the given item. */ selectNext : function() { var item = this.getSelection()[0]; var items = this.__items; var index = items.indexOf(item); if (index == -1) { return; } var i = 0; var length = items.length; // Find next enabled item if (this.getWrap()) { index = (index + 1) % length; } else { index = Math.min(index + 1, length - 1); } while (i < length && !items[index].getEnabled()) { index = (index + 1) % length; i++; } this.setSelection([items[index]]); }, /** * Select the item previous the given item. */ selectPrevious : function() { var item = this.getSelection()[0]; var items = this.__items; var index = items.indexOf(item); if (index == -1) { return; } var i = 0; var length = items.length; // Find previous enabled item if (this.getWrap()) { index = (index - 1 + length) % length; } else { index = Math.max(index - 1, 0); } while (i < length && !items[index].getEnabled()) { index = (index - 1 + length) % length; i++; } this.setSelection([items[index]]); }, /* --------------------------------------------------------------------------- HELPER METHODS FOR SELECTION API --------------------------------------------------------------------------- */ /** * Returns the items for the selection. * * @return {qx.ui.form.IRadioItem[]} Items to select. */ _getItems : function() { return this.getItems(); }, /** * Returns if the selection could be empty or not. * * @return {Boolean} <code>true</code> If selection could be empty, * <code>false</code> otherwise. */ _isAllowEmptySelection: function() { return this.isAllowEmptySelection(); }, /** * Returns whether the item is selectable. In opposite to the default * implementation (which checks for visible items) every radio button * which is part of the group is selected even if it is currently not visible. * * @param item {qx.ui.form.IRadioItem} The item to check if its selectable. * @return {Boolean} <code>true</code> if the item is part of the radio group * <code>false</code> otherwise. */ _isItemSelectable : function(item) { return this.__items.indexOf(item) != -1; }, /** * Event handler for <code>changeSelection</code>. * * @param e {qx.event.type.Data} Data event. */ __onChangeSelection : function(e) { var value = e.getData()[0]; var old = e.getOldData()[0]; var groupedProperty = this.getGroupedProperty(); if (old) { old.set(groupedProperty, false); } if (value) { value.set(groupedProperty, true); } } }, /* ***************************************************************************** DESTRUCTOR ***************************************************************************** */ destruct : function() { this._disposeArray("__items"); } });