package gov.va.med.edp.widget
{
import gov.va.med.edp.util.KeyUtils;
import flash.events.Event;
import flash.events.FocusEvent;
import flash.events.KeyboardEvent;
import flash.net.SharedObject;
import flash.ui.Keyboard;
import mx.events.FlexEvent;
import mx.collections.ArrayCollection;
import mx.collections.ListCollectionView;
import mx.controls.ComboBox;
import mx.core.UIComponent;
import mx.core.mx_internal;
use namespace mx_internal;
//--------------------------------------
// Events
//--------------------------------------
/**
* Dispatched when the filterFunction
property changes.
*
* You can listen for this event and update the component
* when the filterFunction
property changes.
typedText
property changes.
*
* You can listen for this event and update the component
* when the typedText
property changes.
*
* @eventType flash.events.Event
*/
[Event(name="typedTextChange", type="flash.events.Event")]
//--------------------------------------
// Excluded APIs
//--------------------------------------
[Exclude(name="editable", kind="property")]
// added by jtorreno
// created accessibility class
[AccessibilityClass(implementation="gov.va.med.edp.widget.accessibility.AutoCompleteAccImpl")]
/**
* The AutoComplete control is an enhanced
* TextInput control which pops up a list of suggestions
* based on characters entered by the user. These suggestions
* are to be provided by setting the dataProvider
*
property of the control.
* @mxml
*
* The <fc:AutoComplete>
tag inherits all the tag attributes
* of its superclass, and adds the following tag attributes:
* <fc:AutoComplete * Properties * keepLocalHistory="false" * lookAhead="false" * typedText="" * filterFunction="Internal filter function" * * Events * filterFunctionChange="No default" * typedTextChange="No default" * /> ** * @includeExample ../../../../../../docs/com/adobe/flex/extras/controls/example/AutoCompleteCountriesData/AutoCompleteCountriesData.mxml * * @see mx.controls.ComboBox * */ public class AutoComplete extends ComboBox { // added by jtorreno 05.16.2008 mx_internal static var createAccessibilityImplementation:Function; //-------------------------------------------------------------------------- // // Constructor // //-------------------------------------------------------------------------- public function AutoComplete() { super(); // added by jtorreno tabChildren=true; //Make ComboBox look like a normal text field editable = true; if(keepLocalHistory) addEventListener("focusOut",focusOutHandler); setStyle("arrowButtonWidth",0); setStyle("fontWeight","normal"); setStyle("cornerRadius",0); setStyle("paddingLeft",0); setStyle("paddingRight",0); rowCount = 7; } //-------------------------------------------------------------------------- // // Variables // //-------------------------------------------------------------------------- /** * @private */ private var cursorPosition:Number=0; /** * @private */ private var prevIndex:Number = -1; /** * @private */ private var removeHighlight:Boolean = false; /** * @private */ private var showDropdown:Boolean=false; /** * @private */ private var showingDropdown:Boolean=false; /** * @private */ private var tempCollection:Object; /** * @private */ private var usingLocalHistory:Boolean=false; /** * @private */ private var dropdownClosed:Boolean=true; //-------------------------------------------------------------------------- // // Overridden Properties // //-------------------------------------------------------------------------- //---------------------------------- // editable //---------------------------------- /** * @private */ override public function set editable(value:Boolean):void { //This is done to prevent user from resetting the value to false super.editable = true; } /** * @private */ override public function set dataProvider(value:Object):void { super.dataProvider = value; if(!usingLocalHistory) tempCollection = value; } //---------------------------------- // labelField //---------------------------------- /** * @private */ override public function set labelField(value:String):void { super.labelField = value; invalidateProperties(); invalidateDisplayList(); } //-------------------------------------------------------------------------- // // Properties // //-------------------------------------------------------------------------- //---------------------------------- // filterFunction //---------------------------------- /** * @private * Storage for the filterFunction property. */ private var _filterFunction:Function = defaultFilterFunction; /** * @private */ private var filterFunctionChanged:Boolean = true; [Bindable("filterFunctionChange")] [Inspectable(category="General")] /** * A function that is used to select items that match the * function's criteria. * A filterFunction is expected to have the following signature: * *
f(item:~~, text:String):Boolean* * where the return value is
true
if the specified item
* should displayed as a suggestion.
* Whenever there is a change in text in the AutoComplete control, this
* filterFunction is run on each item in the dataProvider
.
*
* The default implementation for filterFunction works as follows:
* If "AB" has been typed, it will display all the items matching
* "AB~~" (ABaa, ABcc, abAc etc.).
An example usage of a customized filterFunction is when text typed * is a regular expression and we want to display all the * items which come in the set.
* * @example ** public function myFilterFunction(item:~~, text:String):Boolean * { * public var regExp:RegExp = new RegExp(text,""); * return regExp.test(item); * } ** */ public function get filterFunction():Function { return _filterFunction; } /** * @private */ public function set filterFunction(value:Function):void { //An empty filterFunction is allowed but not a null filterFunction if(value!=null) { _filterFunction = value; filterFunctionChanged = true; invalidateProperties(); invalidateDisplayList(); dispatchEvent(new Event("filterFunctionChange")); } else _filterFunction = defaultFilterFunction; } //---------------------------------- // filterFunction //---------------------------------- /** * @private * Storage for the keepLocalHistory property. */ private var _keepLocalHistory:Boolean = false; /** * @private */ private var keepLocalHistoryChanged:Boolean = true; [Bindable("keepLocalHistoryChange")] [Inspectable(category="General")] /** * When true, this causes the control to keep track of the * entries that are typed into the control, and saves the * history as a local shared object. When true, the * completionFunction and dataProvider are ignored. * * @default "false" */ public function get keepLocalHistory():Boolean { return _keepLocalHistory; } /** * @private */ public function set keepLocalHistory(value:Boolean):void { _keepLocalHistory = value; } //---------------------------------- // lookAhead //---------------------------------- /** * @private * Storage for the lookAhead property. */ private var _lookAhead:Boolean=false; /** * @private */ private var lookAheadChanged:Boolean; [Bindable("lookAheadChange")] [Inspectable(category="Data")] /** * lookAhead decides whether to auto complete the text in the text field * with the first item in the drop down list or not. * * @default "false" */ public function get lookAhead():Boolean { return _lookAhead; } /** * @private */ public function set lookAhead(value:Boolean):void { _lookAhead = value; lookAheadChanged = true; } //---------------------------------- // typedText //---------------------------------- /** * @private * Storage for the typedText property. */ private var _typedText:String=""; /** * @private */ private var typedTextChanged:Boolean; [Bindable("typedTextChange")] [Inspectable(category="Data")] /** * A String to keep track of the text changed as * a result of user interaction. */ public function get typedText():String { return _typedText; } /** * @private */ public function set typedText(input:String):void { _typedText = input; typedTextChanged = true; invalidateProperties(); invalidateDisplayList(); dispatchEvent(new Event("typedTextChange")); } //-------------------------------------------------------------------------- // // Overridden methods // //-------------------------------------------------------------------------- override protected function createChildren():void { super.createChildren(); textInput.addEventListener(KeyboardEvent.KEY_DOWN, textInput_keyHandler); textInput.restrict = textInput.restrict + " "; // restrict space characters from being entered } /** * @private */ override protected function commitProperties():void { super.commitProperties(); if(!dropdown) selectedIndex=-1; if(dropdown) { if(typedTextChanged) { cursorPosition = textInput.selectionBeginIndex; updateDataProvider(); //In case there are no suggestions there is no need to show the dropdown if(collection.length==0 || typedText==""|| typedText==null) { dropdownClosed=true; showDropdown=false; //added by jtorreno //reset selected index if autocomplete field is empty selectedIndex = -1; } else { showDropdown = true; //selectedIndex = 0; // revised by jtorreno // removes default higlighted item on list selectedIndex = -1; } } } } /** * @private */ override protected function focusOutHandler(event:FocusEvent):void { super.focusOutHandler(event) if(keepLocalHistory && dataProvider.length==0) addToLocalHistory(); } /** * @private */ override public function getStyle(styleProp:String):* { if(styleProp != "openDuration") return super.getStyle(styleProp); else { if(dropdownClosed) return super.getStyle(styleProp); else return 0; } } /** * @private */ override protected function keyDownHandler(event:KeyboardEvent):void { super.keyDownHandler(event); if(!event.ctrlKey) { //An UP "keydown" event on the top-most item in the drop-down //or an ESCAPE "keydown" event should change the text in text // field to original text if(event.keyCode == Keyboard.UP && prevIndex==0) { textInput.text = _typedText; textInput.setSelection(textInput.text.length, textInput.text.length); selectedIndex = -1; } else if(event.keyCode==Keyboard.ESCAPE && showingDropdown) { textInput.text = _typedText; textInput.setSelection(textInput.text.length, textInput.text.length); showingDropdown = false; dropdownClosed=true; } else if (event.keyCode == Keyboard.SPACE && showingDropdown) { showingDropdown = false; dropdownClosed=true; } else if(event.keyCode == Keyboard.ENTER) { if(keepLocalHistory && dataProvider.length==0) addToLocalHistory(); } else if(lookAhead && KeyUtils.isRemoveKey(event)) removeHighlight = true; } else if(event.ctrlKey && event.keyCode == Keyboard.UP) dropdownClosed=true; prevIndex = selectedIndex; } /** * @private */ override protected function measure():void { super.measure(); measuredWidth = mx.core.UIComponent.DEFAULT_MEASURED_WIDTH; } /** * @private */ override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void { super.updateDisplayList(unscaledWidth, unscaledHeight); //An UP "keydown" event on the top-most item in the drop //down list otherwise changes the text in the text field to "" if(selectedIndex == -1) textInput.text = typedText; if(dropdown) { if(typedTextChanged) { //This is needed because a call to super.updateDisplayList() set the text // in the textInput to "" and thus the value //typed by the user losts if(lookAhead && showDropdown && typedText!="" && !removeHighlight) { var label:String = itemToLabel(collection[0]); var index:Number = label.toLowerCase().indexOf(_typedText.toLowerCase()); if(index==0) { textInput.text = _typedText+label.substr(_typedText.length); textInput.setSelection(textInput.text.length,_typedText.length); } else { textInput.text = _typedText; textInput.setSelection(cursorPosition, cursorPosition); removeHighlight = false; } } else { textInput.text = _typedText; textInput.setSelection(cursorPosition, cursorPosition); removeHighlight = false; } typedTextChanged= false; } else if(typedText) //Sets the selection when user navigates the suggestion list through //arrows keys. textInput.setSelection(_typedText.length,textInput.text.length); } if(showDropdown && !dropdown.visible) { //This is needed to control the open duration of the dropdown super.open(); showDropdown = false; showingDropdown = true; if(dropdownClosed) dropdownClosed=false; } } /** * @private */ override protected function textInput_changeHandler(event:Event):void { super.textInput_changeHandler(event); //Stores the text typed by the user in a variable typedText=text; if (text.charAt(text.length - 1) == ' ') { typedText = text.slice(0, text.length - 1); } } protected function textInput_keyHandler(event:KeyboardEvent):void { if (event.keyCode == Keyboard.SPACE && showingDropdown && selectedIndex != -1 && !event.ctrlKey) { // event.preventDefault(); dispatchEvent(new FlexEvent(FlexEvent.ENTER)); } } //-------------------------------------------------------------------------- // // Methods // //-------------------------------------------------------------------------- /** * @private * If keepLocalHistory is enabled, stores the text typed * by the user in the local history on the client machine */ private function addToLocalHistory():void { if (id != null && id != "" && text != null && text != "") { var so:SharedObject = SharedObject.getLocal("AutoCompleteData"); var savedData : Array = so.data.suggestions; //No shared object has been created so far if (savedData == null) savedData = new Array(); var i:Number=0; var flag:Boolean=false; //Check if this entry is there in the previously saved shared object data for(i=0;i