Gumbo ItemsComponent and Selector - Functional and Design Specification
Summary and Background
ItemsComponent is the base class for all skinnable components that have content. For example, Panel is a subclass of ItemsComponent that has a border, header, and footer. This is a pure model class that does not make any assumptions about the presentation or behavior of the items.
Selector is a subclass of ItemsComponent that is the base class for any skinnable component that supports selection. List, TabBar, ComboBox, and RadioButtonGroup are all subclasses of Selector. Selector is also a pure model class.
Usage Scenario
The ItemsComponent and Selector classes are not typically instantiated using MXML. These classes are primarily used as a base class for a new component, or as a SkinPart.
The first example extends ItemsComponent. The second example has a SkinPart that is typed as Selector.
Example 1: Panel Component
public class Panel extends ItemsComponent {
[SkinPart(required="false")]
public var headerGroup:Group;
[SkinPart(required="false")]
public var footerGroup:Group;
public var header:*;
public var footer:*;
override protected function partAdded(partName:String, instance:*):void
{
switch (partName)
{
case "headerGroup":
headerGroup.content = header;
break;
case "footerGroup":
footerGroup.content = footer;
break;
default:
super.partAdded(partName, instance);
break;
}
}
}
Example 2: Media Browser
public class MediaBrowser extends SkinnableComponent {
[SkinPart]
public var mediaTypeSelector: Selector;
private static const mediaTypes:Array = ["Music", "Photos", "Video"];
override protected function partAdded(partName:String, instance:*):void
{
if (instance == mediaTypeSelector)
{
mediaTypeSelector.content = mediaTypes;
mediaTypeSelector.addEventListener("selectionChanged",
mediaTypeSelector_selectionChangedHandler);
}
else
{
super.partAdded(partName, instance);
}
}
private function mediaTypeSelector_selectionChangedHandler(event:Event):void
{
showMedia(mediaTypeSelector.selectedItem);
}
private function showMedia(mediaType:String):void
{
...
}
}
Detailed Description
ItemsComponent
The ItemsComponent class is basically a skinnable Group. It has one SkinPart named contentGroup, and it proxies the content, layout, and item renderer functionality of the contentGroup skin part. See the API Description section for details.
Selector
The Selector class is a subclass of ItemsComponent that supports simple single selection. Multiple selection is handled in a subclass.
API Description
ItemsComponent
Most of the ItemsComponent APIs are proxies to the contentGroup skin part. Details on these APIs can be found in the Gumbo Group Spec.
package flex.component
{
/**
* Dispatched when an item is added to the component.
* event.relatedObject is the item that was added.
*/
[Event(name="itemAdd", type="flex.events.ItemExistenceChangedEvent")]
/**
* Dispatched when an item is removed from the component.
* event.relatedObject is the item that was removed.
*/
[Event(name="itemRemove", type="flex.events.ItemExistenceChangedEvent")]
[DefaultProperty("content")]
class ItemsComponent extends SkinnableComponent
{
/**
* The Group that displays the content of this component. The content,
* layout, itemRenderer, and itemRendererFunction properties of the
* component are assigned to this skin part.
*/
[SkinPart]
public var contentGroup:Group;
public var content;
public var layout;
public var itemRenderer;
public var itemRendererFunction;
public function get numItems();
public function getItemAt();
public function addItem();
public function addItemAt();
public function removeItem();
public function removeItemAt();
public function getItemIndex();
public function setItemIndex();
public function swapItems();
public function swapItemsAt();
}
}
Selector
package flex.component {
/**
* Dispatched when the selection is going to change. Calling preventDefault()
* on the event will prevent the selection from changing.
*/
Event(name="selectionChanging", type="mx.events.IndexChangeEvent")]
/**
* Dispatched after the selection has changed.
*/
[Event(name="selectionChanged", type="mx.events.IndexChangeEvent")]
public class Selector extends ItemsComponent
{
/**
* The 0-based index of the selected item, or -1 if no item is selected.
* Setting the selectedIndex property de-selects the currently selected
* item and selects the item at the specified index.
*
* The value of selectedIndex is always pinned between -1 and
* (numItems - 1). If items at a lower index than selectedIndex are
* removed from the component, the selected index is adjusted downward
* accordingly. If the selected item is removed, selected index is
* set to -1 (if requireSelection = false or there are no remaining items)
* or 0 (if requireSelection = true and there is at least one item).
*
* @default -1
*/
public var selectedIndex:int;
/**
* The item that is currently selected. Setting the selectedItem property
* de-selects the currently selected item and selects the specified item.
*
* Setting selectedItem to an item that is not in this component results in
* no selection, and selectedItem being set to undefined. If the selected
* item is removed, the selected item is set to undefined (if requireSelection
* = false or there are no remaining items) or the first item (if
* requireSelection = true and there is at least one item).
*
* @default undefined
*/
public var selectedItem:*;
/**
* Specifies whether an item must always be selected.
* If the value is true, the selectedIndex property will always be
* set to a value between 0 and (numItems - 1), or -1 if there are
* no items.
*
* @default false
*/
public var requiresSelection:Boolean = false;
/**
* Called when an item is selected or de-selected. Subclasses must override
* this method to display the selection.
*/
protected function itemSelected(item:Object, selected:Boolean):void;
}
}
Prototype Work
Very basic implementations of ItemsComponent and Selector have been prototyped and checked in.
Compiler Work
None.
Web Tier Compiler Impact
None.
Flex Feature Dependencies
Group - ItemsComponent has a very tight connection with the Group class, and must keep the API's in sync.
ItemsComponent and Selector are the base class for numerous components. As these components are developed, some core functionality may be pushed back down into these classes.
Backwards Compatibility
Syntax changes
None. These are new classes.
Behavior
None. These are new classes.
Warnings/Deprecation
None.
Accessibility
The selectionChanged event will be the main accessibility hook for Selector. Due to the abstract nature of an item, we may need a general mechanism for determining the item type, and passing the item label to the accessibility implementation.
Performance
These classes are bound by the performance of the Group class.
Globalization
Not Applicable.
Localization
Compiler Features
None.
Framework Features
None.
Issues and Recommendations
Should the selection mechanism be moved to a separate object? The current thinking is single-selection is provided by the Selector class and multiple selection is provided by the List class. Are there other classes that need the concept of a selection?
QA
These are base classes, so testing should be API-focused.
|
 |
It might be nice if a selection was able to be applied to any set of items in a Group. For example if I didn't want to use a list but rather just make some Group that had an unknown number of content items and allow a single or multiple selection to be managed, it might be nice to have the Selection class(es) available for such a thing.
It might also be nice if I can take a selection from one List/Group/Whatever and then assign it to another and have it be applied if the same items where in there. Perhaps something like this would be useful for binding?
Just throwing out ideas to hopefully get some conversations started here! Thanks!