Widget-Parent.js revision 0159bcf230ef375f776f086fbee832e538128737
57775f39a19dc392e5882d5217d5a9148688aa4aMatt Sweeney * Extension enabling a Widget to be a parent of another Widget.
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * @module widget-parent
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * Widget extension providing functionality enabling a Widget to be a
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * parent of another Widget.
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * @class WidgetParent
eaa9719567e2ec55d96f9298077f5fc0effe1ed3Satyen Desai * @param {Object} config User configuration object.
86fa3fa071113dfe732100d1a15cb149f67ffc83Jenny Donnelly * Fires when a Widget is add as a child. The event object will have a
86fa3fa071113dfe732100d1a15cb149f67ffc83Jenny Donnelly * 'child' property that returns a reference to the child Widget, as well
86fa3fa071113dfe732100d1a15cb149f67ffc83Jenny Donnelly * as an 'index' property that returns a reference to the index specified
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * when the add() method was called.
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * Subscribers to the "on" moment of this event, will be notified
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * before a child is added.
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * Subscribers to the "after" moment of this event, will be notified
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * after a child is added.
57775f39a19dc392e5882d5217d5a9148688aa4aMatt Sweeney * @event childAdded
57775f39a19dc392e5882d5217d5a9148688aa4aMatt Sweeney * @preventable _defAddChildFn
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * @param {EventFacade} e The Event Facade
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * Fires when a child Widget is removed. The event object will have a
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * 'child' property that returns a reference to the child Widget, as well
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * as an 'index' property that returns a reference child's ordinal position.
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * Subscribers to the "on" moment of this event, will be notified
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * before a child is removed.
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * Subscribers to the "after" moment of this event, will be notified
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * after a child is removed.
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * @event childRemoved
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * @preventable _defRemoveChildFn
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * @param {EventFacade} e The Event Facade
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai // TO DO: Document ability to populate children via the constructor
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai handle = this.after("initializedChange", function (e) {
eaa9719567e2ec55d96f9298077f5fc0effe1ed3Satyen Desai // Widget method overlap
57775f39a19dc392e5882d5217d5a9148688aa4aMatt Sweeney Y.after(this._renderChildren, this, "renderUI");
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai Y.before(this._destroyChildren, this, "destructor");
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai this.after("selectionChange", this._afterSelectionChange);
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai this.after("selectedChange", this._afterParentSelectedChange);
57775f39a19dc392e5882d5217d5a9148688aa4aMatt Sweeney this.after("activeDescendantChange", this._afterActiveDescendantChange);
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai this._hDestroyChild = this.after("*:destroy", this._afterDestroyChild);
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai this.after("*:focusedChange", this._updateActiveDescendant);
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * @attribute defaultChildType
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * @type {String|Object}
57775f39a19dc392e5882d5217d5a9148688aa4aMatt Sweeney * @description String representing the default type of the children
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * managed by this Widget. Can also supply default type as a constructor
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * reference.
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai FnConstructor = Lang.isString(val) ? Y[val] : val;
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai * @attribute activeDescendant
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * @type Widget
57775f39a19dc392e5882d5217d5a9148688aa4aMatt Sweeney * @description Returns the Widget's currently focused descendant Widget.
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * @attribute multiple
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * @type Boolean
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * @default false
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai * @writeOnce
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * @description Boolean indicating if multiple children can be selected at
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai * once. Whether or not multiple selection is enabled is always delegated
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * to the value of the <code>multiple</code> attribute of the root widget
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai * in the object hierarchy.
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai return (root && root != this) ? root.get("multiple") : value;
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai * @attribute selection
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai * @type {Y.ArrayList|Widget}
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai * @description Returns the currently selected child Widget. If the
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai * <code>mulitple</code> attribte is set to <code>true</code> will
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai * return an Y.ArrayList instance containing the currently selected
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai * children. If no children are selected, will return null.
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai // Enforces selection behavior on for parent Widgets. Parent's
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai // selected attribute can be set to the following:
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai // 0 - Not selected
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai // 1 - Fully selected (all children are selected). In order for
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai // all children to be selected, multiple selection must be
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai // enabled. Therefore, you cannot set the "selected" attribute
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai // on a parent Widget to 1 unless multiple selection is enabled.
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai // 2 - Partially selected, meaning one ore more (but not all)
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai // children are selected.
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai Y.log('The selected attribute can only be set to 1 if the "multiple" attribute is set to true.', "error", "widget");
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai * Destroy event listener for each child Widget, responsible for removing
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai * the destroyed child Widget from the parent's internal array of children
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai * (_items property).
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai * @method _afterDestroyChild
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai * @protected
75013e52e14f366e77d0a078bc1bfedfa421fe70Satyen Desai * @param {EventFacade} event The event facade for the attribute change.
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * Attribute change listener for the <code>selection</code>
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * attribute, responsible for setting the value of the
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * parent's <code>selected</code> attribute.
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * @method _afterSelectionChange
69ce664b1e66d48ae3ae5be08488f38b4855fc8bSatyen Desai * @protected
57775f39a19dc392e5882d5217d5a9148688aa4aMatt Sweeney * @param {EventFacade} event The event facade for the attribute change.
if (selection) {
if (parent) {
var selection = null,
selected = [];
this.each(function (v) {
return selection;
Fn,
if (altType) {
else if (defaultType) {
if (FnConstructor) {
Y.error("Could not create a child instance because its constructor is either undefined or invalid.");
return child;
// (e.g. user passed in 10, and there are only 3 items, the actual index would be 3. We don't want to pass 10 around in the event facade).
var children,
children = [];
if (oChild) {
return returnVal;
add: function () {
return returnVal;
removeAll: function () {
var removed = [],
if (child) {
selectChild: function(i) {
selectAll: function () {
deselectAll: function () {
if (nextSibling) {
if (prevSibling) {
_bindUIParent: function () {
_renderChildren: function () {
_destroyChildren: function () {
// 1) It is unnecessary/inefficient at this point since we are doing