| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to You under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| |
| package spark.components.supportClasses |
| { |
| |
| import flash.display.DisplayObject; |
| import flash.events.Event; |
| import flash.events.FocusEvent; |
| import flash.events.KeyboardEvent; |
| import flash.events.MouseEvent; |
| import flash.geom.Point; |
| |
| import mx.collections.IList; |
| import mx.core.InteractionMode; |
| import mx.events.CollectionEvent; |
| import mx.events.FlexEvent; |
| |
| import spark.components.List; |
| import spark.core.NavigationUnit; |
| import spark.events.DropDownEvent; |
| import spark.events.IndexChangeEvent; |
| |
| import mx.core.mx_internal; |
| use namespace mx_internal; |
| |
| //-------------------------------------- |
| // Styles |
| //-------------------------------------- |
| |
| /** |
| * The radius of the corners for this component. |
| * |
| * @default 4 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| [Style(name="cornerRadius", type="Number", format="Length", inherit="no", theme="spark")] |
| |
| /** |
| * Controls the visibility of the drop shadow for this component. |
| * |
| * @default true |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| [Style(name="dropShadowVisible", type="Boolean", inherit="no", theme="spark")] |
| |
| //-------------------------------------- |
| // Events |
| //-------------------------------------- |
| |
| /** |
| * Dispatched when the drop-down list closes for any reason, such when |
| * the user: |
| * <ul> |
| * <li>Selects an item in the drop-down list.</li> |
| * <li>Clicks outside of the drop-down list.</li> |
| * <li>Clicks the anchor button while the drop-down list is |
| * displayed.</li> |
| * </ul> |
| * |
| * @eventType spark.events.DropDownEvent.CLOSE |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| [Event(name="close", type="spark.events.DropDownEvent")] |
| |
| /** |
| * Dispatched when the user clicks the anchor button |
| * to display the drop-down list. |
| * It is also dispatched if the user |
| * uses Control-Down to open the dropDown. |
| * |
| * @eventType spark.events.DropDownEvent.OPEN |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| [Event(name="open", type="spark.events.DropDownEvent")] |
| |
| //-------------------------------------- |
| // SkinStates |
| //-------------------------------------- |
| |
| /** |
| * Skin state for the open state of the DropDownListBase control. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| [SkinState("open")] |
| |
| //-------------------------------------- |
| // Excluded APIs |
| //-------------------------------------- |
| |
| [Exclude(name="allowMultipleSelection", kind="property")] |
| [Exclude(name="dragEnabled", kind="property")] |
| [Exclude(name="dragMoveEnabled", kind="property")] |
| [Exclude(name="dropEnabled", kind="property")] |
| [Exclude(name="selectedIndices", kind="property")] |
| [Exclude(name="selectedItems", kind="property")] |
| |
| //-------------------------------------- |
| // Other metadata |
| //-------------------------------------- |
| |
| [AccessibilityClass(implementation="spark.accessibility.DropDownListBaseAccImpl")] |
| |
| /** |
| * The DropDownListBase control contains a drop-down list |
| * from which the user can select a single value. |
| * Its functionality is very similar to that of the |
| * SELECT form element in HTML. |
| * |
| * <p>The DropDownListBase control consists of the anchor button, |
| * and drop-down-list. |
| * Use the anchor button to open and close the drop-down-list. |
| * </p> |
| * |
| * <p>When the drop-down list is open:</p> |
| * <ul> |
| * <li>Clicking the anchor button closes the drop-down list |
| * and commits the currently selected data item.</li> |
| * <li>Clicking outside of the drop-down list closes the drop-down list |
| * and commits the currently selected data item.</li> |
| * <li>Clicking on a data item selects that item and closes the drop-down list.</li> |
| * <li>If the <code>requireSelection</code> property is <code>false</code>, |
| * clicking on a data item while pressing the Control key deselects |
| * the item and closes the drop-down list.</li> |
| * </ul> |
| * |
| * @mxml <p>The <code><s:DropDownListBase></code> tag inherits all of the tag |
| * attributes of its superclass and adds the following attributes:</p> |
| * |
| * <pre> |
| * <s:DropDownListBase |
| * <strong>Styles</strong> |
| * cornerRadius="4" |
| * dropShadowVisible="true" |
| * |
| * <strong>Events</strong> |
| * closed="<i>No default</i>" |
| * open="<i>No default</i>" |
| * /> |
| * </pre> |
| * |
| * @see spark.skins.spark.DropDownListSkin |
| * @see spark.components.supportClasses.DropDownController |
| * |
| * @includeExample examples/DropDownListExample.mxml |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public class DropDownListBase extends List |
| { |
| include "../../core/Version.as"; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Class mixins |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * Placeholder for mixin by DropDownListBaseAccImpl. |
| */ |
| mx_internal static var createAccessibilityImplementation:Function; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function DropDownListBase() |
| { |
| super(); |
| |
| dropDownController = new DropDownController(); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Skin parts |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // dropDown |
| //---------------------------------- |
| |
| [SkinPart(required="false")] |
| |
| /** |
| * A skin part that defines the drop-down list area. When the DropDownListBase is open, |
| * clicking anywhere outside of the dropDown skin part closes the |
| * drop-down list. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public var dropDown:DisplayObject; |
| |
| //---------------------------------- |
| // openButton |
| //---------------------------------- |
| |
| [SkinPart(required="true")] |
| |
| /** |
| * A skin part that defines the anchor button. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public var openButton:ButtonBase; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| private var labelChanged:Boolean = false; |
| // Stores the user selected index until the dropDown closes |
| |
| /** |
| * @private |
| */ |
| mx_internal static var PAGE_SIZE:int = 5; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // allowMultipleSelection |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| override public function set allowMultipleSelection(value:Boolean):void |
| { |
| // Don't allow this value to be set. If the multiple |
| // selection related properties are set and |
| // allowMultipleSelection is false, List will |
| // select the first item passed in. |
| return; |
| } |
| |
| //---------------------------------- |
| // dataProvider |
| //---------------------------------- |
| |
| [Inspectable(category="Data")] |
| |
| /** |
| * @private |
| * Update the label if the dataProvider has changed |
| */ |
| override public function set dataProvider(value:IList):void |
| { |
| if (dataProvider === value) |
| return; |
| |
| super.dataProvider = value; |
| labelChanged = true; |
| invalidateProperties(); |
| } |
| |
| //---------------------------------- |
| // dragEnabled |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Excluded property |
| */ |
| override public function set dragEnabled(value:Boolean):void |
| { |
| } |
| |
| //---------------------------------- |
| // dragMoveEnabled |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Excluded property |
| */ |
| override public function set dragMoveEnabled(value:Boolean):void |
| { |
| } |
| |
| //---------------------------------- |
| // dropEnabled |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Excluded property |
| */ |
| override public function set dropEnabled(value:Boolean):void |
| { |
| } |
| |
| //---------------------------------- |
| // labelField |
| //---------------------------------- |
| |
| [Inspectable(category="Data", defaultValue="label")] |
| |
| /** |
| * @private |
| */ |
| override public function set labelField(value:String):void |
| { |
| if (labelField == value) |
| return; |
| |
| super.labelField = value; |
| labelChanged = true; |
| invalidateProperties(); |
| } |
| |
| //---------------------------------- |
| // labelFunction |
| //---------------------------------- |
| |
| [Inspectable(category="Data")] |
| |
| /** |
| * @private |
| */ |
| override public function set labelFunction(value:Function):void |
| { |
| if (labelFunction == value) |
| return; |
| |
| super.labelFunction = value; |
| labelChanged = true; |
| invalidateProperties(); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // dropDownController |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| private var _dropDownController:DropDownController; |
| |
| /** |
| * Instance of the DropDownController class that handles all of the mouse, keyboard |
| * and focus user interactions. |
| * |
| * Flex calls the <code>initializeDropDownController()</code> method after |
| * the DropDownController instance is created in the constructor. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| protected function get dropDownController():DropDownController |
| { |
| return _dropDownController; |
| } |
| |
| /** |
| * @private |
| */ |
| protected function set dropDownController(value:DropDownController):void |
| { |
| if (_dropDownController == value) |
| return; |
| |
| _dropDownController = value; |
| |
| _dropDownController.addEventListener(DropDownEvent.OPEN, dropDownController_openHandler); |
| _dropDownController.addEventListener(DropDownEvent.CLOSE, dropDownController_closeHandler); |
| |
| _dropDownController.closeOnResize = _closeDropDownOnResize; |
| |
| if (openButton) |
| _dropDownController.openButton = openButton; |
| if (dropDown) |
| _dropDownController.dropDown = dropDown; |
| } |
| |
| //---------------------------------- |
| // isDropDownOpen |
| //---------------------------------- |
| |
| /** |
| * @copy spark.components.supportClasses.DropDownController#isOpen |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function get isDropDownOpen():Boolean |
| { |
| if (dropDownController) |
| return dropDownController.isOpen; |
| else |
| return false; |
| } |
| |
| //---------------------------------- |
| // closeDropDownOnResize |
| //---------------------------------- |
| |
| /** |
| * @private |
| * |
| * cached value: getStyle("interactionMode") == InteractionMode.TOUCH |
| */ |
| private var isTouchInteractionMode:Boolean = false; |
| |
| /** |
| * @private |
| * |
| * do not know what default value for closeDropDownOnResize will be until styles have been applied, |
| * but user may set property before that. this flag indicates whether property has been explicitly set, |
| * and so will not need to be determined from css when stylesInitialized() or styleChanged() is called. |
| */ |
| private var isCloseDropDownOnResizeExplicitlySet:Boolean = false; |
| |
| /** |
| * @private |
| */ |
| protected var _closeDropDownOnResize:Boolean = true; |
| |
| [Inspectable(category="General", enumeration="true,false", defaultValue="true")] |
| |
| /** |
| * When <code>true</code>, resizing the system manager |
| * closes the drop down. |
| * For mobile applications, this property is set |
| * to <code>false</code> so that the drop down stays open when the |
| * page orientation changes. |
| * |
| * @default true |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4.12 |
| */ |
| public function get closeDropDownOnResize():Boolean |
| { |
| return _closeDropDownOnResize; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set closeDropDownOnResize(value:Boolean):void |
| { |
| setCloseDropDownOnResize(value, true); |
| } |
| |
| /** |
| * @private |
| */ |
| private function setCloseDropDownOnResize(value:Boolean, explicitlySet:Boolean):void |
| { |
| _closeDropDownOnResize = value; |
| isCloseDropDownOnResizeExplicitlySet ||= explicitlySet; |
| if (dropDownController) |
| dropDownController.closeOnResize = _closeDropDownOnResize; |
| } |
| |
| //---------------------------------- |
| // userProposedSelectedIndex |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| private var _userProposedSelectedIndex:Number = NO_SELECTION; |
| |
| /** |
| * @private |
| */ |
| mx_internal function set userProposedSelectedIndex(value:Number):void |
| { |
| _userProposedSelectedIndex = value; |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal function get userProposedSelectedIndex():Number |
| { |
| return _userProposedSelectedIndex; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4.12 |
| */ |
| override public function stylesInitialized():void |
| { |
| super.stylesInitialized(); |
| setInteractionMode(); |
| } |
| |
| /** |
| * @private |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4.12 |
| */ |
| override public function styleChanged(styleProp:String):void |
| { |
| super.styleChanged(styleProp); |
| if (!styleProp || styleProp == "styleName" || styleProp == "interactionMode") |
| setInteractionMode(); |
| } |
| |
| /** |
| * @private |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4.12 |
| */ |
| private function setInteractionMode():void |
| { |
| isTouchInteractionMode = getStyle("interactionMode") == InteractionMode.TOUCH; |
| if (!isCloseDropDownOnResizeExplicitlySet) |
| setCloseDropDownOnResize(!isTouchInteractionMode, false); |
| } |
| |
| /** |
| * @private |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4.12 |
| */ |
| override public function setSelectedIndex(rowIndex:int, dispatchChangeEvent:Boolean = false, changeCaret:Boolean = true):void |
| { |
| super.setSelectedIndex(rowIndex, dispatchChangeEvent, changeCaret); |
| if (isTouchInteractionMode) |
| { |
| userProposedSelectedIndex = rowIndex; |
| closeDropDown(true); |
| } |
| } |
| |
| |
| /** |
| * @private |
| * Called by the initialize() method of UIComponent |
| * to hook in the accessibility code. |
| */ |
| override protected function initializeAccessibility():void |
| { |
| if (DropDownListBase.createAccessibilityImplementation != null) |
| DropDownListBase.createAccessibilityImplementation(this); |
| } |
| /** |
| * @private |
| */ |
| override protected function commitProperties():void |
| { |
| super.commitProperties(); |
| |
| if (labelChanged) |
| { |
| labelChanged = false; |
| updateLabelDisplay(); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function partAdded(partName:String, instance:Object):void |
| { |
| super.partAdded(partName, instance); |
| |
| if (instance == openButton) |
| { |
| if (dropDownController) |
| dropDownController.openButton = openButton; |
| } |
| else if (instance == dropDown && dropDownController) |
| { |
| dropDownController.dropDown = dropDown; |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function partRemoved(partName:String, instance:Object):void |
| { |
| if (dropDownController) |
| { |
| if (instance == openButton) |
| dropDownController.openButton = null; |
| |
| if (instance == dropDown) |
| dropDownController.dropDown = null; |
| } |
| |
| super.partRemoved(partName, instance); |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function getCurrentSkinState():String |
| { |
| return !enabled ? "disabled" : isDropDownOpen ? "open" : "normal"; |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function commitSelection(dispatchChangedEvents:Boolean = true):Boolean |
| { |
| var retVal:Boolean = super.commitSelection(dispatchChangedEvents); |
| updateLabelDisplay(); |
| return retVal; |
| } |
| |
| /** |
| * @private |
| * In updateRenderer, we want to select the proposedSelectedIndex |
| */ |
| override mx_internal function isItemIndexSelected(index:int):Boolean |
| { |
| return userProposedSelectedIndex == index; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Open the drop-down list and dispatch |
| * a <code>DropdownEvent.OPEN</code> event. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function openDropDown():void |
| { |
| dropDownController.openDropDown(); |
| } |
| |
| /** |
| * Close the drop-down list and dispatch a <code>DropDownEvent.CLOSE</code> event. |
| * |
| * @param commit If <code>true</code>, commit the selected |
| * data item. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function closeDropDown(commit:Boolean):void |
| { |
| dropDownController.closeDropDown(commit); |
| } |
| |
| /** |
| * @private |
| * Called whenever we need to update the text passed to the labelDisplay skin part |
| */ |
| // TODO (jszeto): Make this protected and make the name more generic (passing data to skin) |
| mx_internal function updateLabelDisplay(displayItem:* = undefined):void |
| { |
| // DropDownList and ComboBox will override this function |
| } |
| |
| /** |
| * @private |
| * Called whenever we need to change the highlighted selection while the dropDown is open |
| * ComboBox overrides this behavior |
| */ |
| mx_internal function changeHighlightedSelection(newIndex:int, scrollToTop:Boolean = false):void |
| { |
| // Store the selection in userProposedSelectedIndex because we |
| // don't want to update selectedIndex until the dropdown closes |
| itemSelected(userProposedSelectedIndex, false); |
| userProposedSelectedIndex = newIndex; |
| itemSelected(userProposedSelectedIndex, true); |
| |
| positionIndexInView(userProposedSelectedIndex, scrollToTop ? 0 : NaN); |
| |
| var e:IndexChangeEvent = new IndexChangeEvent(IndexChangeEvent.CARET_CHANGE); |
| e.oldIndex = caretIndex; |
| setCurrentCaretIndex(userProposedSelectedIndex); |
| e.newIndex = caretIndex; |
| dispatchEvent(e); |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal function positionIndexInView(index:int, topOffset:Number = NaN, |
| bottomOffset:Number = NaN, |
| leftOffset:Number = NaN, |
| rightOffset:Number = NaN):void |
| { |
| if (!layout || dataGroup == null) |
| return; |
| |
| var spDelta:Point = |
| dataGroup.layout.getScrollPositionDeltaToElementHelper(index, topOffset, bottomOffset, |
| leftOffset, rightOffset); |
| |
| if (spDelta) |
| { |
| dataGroup.horizontalScrollPosition += spDelta.x; |
| dataGroup.verticalScrollPosition += spDelta.y; |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override mx_internal function findKey(eventCode:int):Boolean |
| { |
| if (!dataProvider || dataProvider.length == 0) |
| return false; |
| |
| if (eventCode >= 33 && eventCode <= 126) |
| { |
| var matchingIndex:Number; |
| var keyString:String = String.fromCharCode(eventCode); |
| var startIndex:int = isDropDownOpen ? userProposedSelectedIndex + 1 : selectedIndex + 1; |
| startIndex = Math.max(0, startIndex); |
| |
| matchingIndex = findStringLoop(keyString, startIndex, dataProvider.length); |
| |
| // We didn't find the item, loop back to the top |
| if (matchingIndex == -1) |
| { |
| matchingIndex = findStringLoop(keyString, 0, startIndex); |
| } |
| |
| |
| if (matchingIndex != -1) |
| { |
| if (isDropDownOpen) |
| changeHighlightedSelection(matchingIndex); |
| else |
| setSelectedIndex(matchingIndex, true); |
| |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Event handlers |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| override protected function dataProvider_collectionChangeHandler(event:Event):void |
| { |
| super.dataProvider_collectionChangeHandler(event); |
| |
| if (event is CollectionEvent) |
| { |
| labelChanged = true; |
| invalidateProperties(); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function item_mouseDownHandler(event:MouseEvent):void |
| { |
| super.item_mouseDownHandler(event); |
| if (!isTouchInteractionMode) |
| { |
| userProposedSelectedIndex = selectedIndex; |
| closeDropDown(true); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function keyDownHandler(event:KeyboardEvent) : void |
| { |
| if (!enabled) |
| return; |
| |
| if (!dropDownController.processKeyDown(event)) |
| { |
| // If rtl layout, need to swap Keyboard.LEFT and Keyboard.RIGHT. |
| var navigationUnit:uint = mapKeycodeForLayoutDirection(event); |
| |
| if (findKey(event.charCode)) |
| { |
| event.preventDefault(); |
| return; |
| } |
| |
| if (!NavigationUnit.isNavigationUnit(navigationUnit)) |
| return; |
| |
| var proposedNewIndex:int = NO_SELECTION; |
| var currentIndex:int; |
| |
| if (isDropDownOpen) |
| { |
| // Normalize the proposed index for getNavigationDestinationIndex |
| currentIndex = userProposedSelectedIndex < NO_SELECTION ? NO_SELECTION : userProposedSelectedIndex; |
| proposedNewIndex = layout.getNavigationDestinationIndex(currentIndex, navigationUnit, arrowKeysWrapFocus); |
| |
| if (proposedNewIndex != NO_SELECTION) |
| { |
| changeHighlightedSelection(proposedNewIndex); |
| event.preventDefault(); |
| } |
| } |
| else if (dataProvider) |
| { |
| var maxIndex:int = dataProvider.length - 1; |
| |
| // Normalize the proposed index for getNavigationDestinationIndex |
| currentIndex = caretIndex < NO_SELECTION ? NO_SELECTION : caretIndex; |
| |
| switch (navigationUnit) |
| { |
| case NavigationUnit.UP: |
| { |
| if (arrowKeysWrapFocus && |
| (currentIndex == 0 || |
| currentIndex == NO_SELECTION || |
| currentIndex == CUSTOM_SELECTED_ITEM)) |
| proposedNewIndex = maxIndex; |
| else |
| proposedNewIndex = currentIndex - 1; |
| event.preventDefault(); |
| break; |
| } |
| |
| case NavigationUnit.DOWN: |
| { |
| if (arrowKeysWrapFocus && |
| (currentIndex == maxIndex || |
| currentIndex == NO_SELECTION || |
| currentIndex == CUSTOM_SELECTED_ITEM)) |
| proposedNewIndex = 0; |
| else |
| proposedNewIndex = currentIndex + 1; |
| event.preventDefault(); |
| break; |
| } |
| |
| case NavigationUnit.PAGE_UP: |
| { |
| proposedNewIndex = currentIndex == NO_SELECTION ? |
| NO_SELECTION : Math.max(currentIndex - PAGE_SIZE, 0); |
| event.preventDefault(); |
| break; |
| } |
| |
| case NavigationUnit.PAGE_DOWN: |
| { |
| proposedNewIndex = currentIndex == NO_SELECTION ? |
| PAGE_SIZE : (currentIndex + PAGE_SIZE); |
| event.preventDefault(); |
| break; |
| } |
| |
| case NavigationUnit.HOME: |
| { |
| proposedNewIndex = 0; |
| event.preventDefault(); |
| break; |
| } |
| |
| case NavigationUnit.END: |
| { |
| proposedNewIndex = maxIndex; |
| event.preventDefault(); |
| break; |
| } |
| |
| } |
| |
| proposedNewIndex = Math.min(proposedNewIndex, maxIndex); |
| |
| if (proposedNewIndex >= 0) |
| { |
| userProposedSelectedIndex = proposedNewIndex; |
| setSelectedIndex(proposedNewIndex, true); |
| } |
| } |
| } |
| else |
| { |
| event.preventDefault(); |
| } |
| |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function focusOutHandler(event:FocusEvent):void |
| { |
| if (isOurFocus(DisplayObject(event.target))) |
| dropDownController.processFocusOut(event); |
| |
| super.focusOutHandler(event); |
| } |
| |
| /** |
| * @private |
| * Event handler for the <code>dropDownController</code> |
| * <code>DropDownEvent.OPEN</code> event. Updates the skin's state and |
| * ensures that the selectedItem is visible. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| mx_internal function dropDownController_openHandler(event:DropDownEvent):void |
| { |
| addEventListener(FlexEvent.UPDATE_COMPLETE, open_updateCompleteHandler); |
| userProposedSelectedIndex = selectedIndex; |
| invalidateSkinState(); |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal function open_updateCompleteHandler(event:FlexEvent):void |
| { |
| removeEventListener(FlexEvent.UPDATE_COMPLETE, open_updateCompleteHandler); |
| positionIndexInView(selectedIndex, 0); |
| |
| dispatchEvent(new DropDownEvent(DropDownEvent.OPEN)); |
| } |
| |
| /** |
| * @private |
| * Event handler for the <code>dropDownController</code> |
| * <code>DropDownEvent.CLOSE</code> event. Updates the skin's state. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| protected function dropDownController_closeHandler(event:DropDownEvent):void |
| { |
| addEventListener(FlexEvent.UPDATE_COMPLETE, close_updateCompleteHandler); |
| invalidateSkinState(); |
| |
| if (!event.isDefaultPrevented()) |
| { |
| // Even if the dropDown was programmatically closed, assume the selection |
| // changed as a result of a previous user interaction |
| setSelectedIndex(userProposedSelectedIndex, true); |
| } |
| else |
| { |
| changeHighlightedSelection(selectedIndex); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| private function close_updateCompleteHandler(event:FlexEvent):void |
| { |
| removeEventListener(FlexEvent.UPDATE_COMPLETE, close_updateCompleteHandler); |
| |
| dispatchEvent(new DropDownEvent(DropDownEvent.CLOSE)); |
| } |
| } |
| |
| } |