Wednesday, 14 September 2011

Auto Intelligent Combobox



package
{
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.TimerEvent;
import flash.ui.Keyboard;
import flash.utils.Timer;

import mx.controls.ComboBox;
import mx.utils.ArrayUtil;


public class ComboBoxItemRenderer extends ComboBox
{
//--------------------------------------------------------------------------
//
//  Constructor
//
//--------------------------------------------------------------------------

public function ComboBoxItemRenderer()
{
super();

_searchString = '';
_clearTimer = new Timer( 1000, 1 );
_clearTimer.addEventListener( TimerEvent.TIMER_COMPLETE, clearTimerCompleteHandler );
}

//--------------------------------------------------------------------------
//
//  Variables
//
//--------------------------------------------------------------------------

/**
* The string that is added to as the user types to use as the search string
*/
private var _searchString:String;

/**
* The timer that we use to clear the search string after a period of inactivity
*/
private var _clearTimer:Timer;

/**
* Keys we don't want to be bothered about handling
*/
private var _keysSuperHandles:Array = [ Keyboard.DOWN, Keyboard.UP, Keyboard.ESCAPE, Keyboard.ENTER, Keyboard.PAGE_UP, Keyboard.PAGE_DOWN ];

/**
* Used to keep track of whether we're inside the keyDownHandler or not, this
* allows us to stop the close() method from executing (default behaviour on
* selecting an item) when we're selecting an item as type.
*/
protected var _selectingItemAsTyping:Boolean = false;

//--------------------------------------------------------------------------
//
//  Properties
//
//--------------------------------------------------------------------------

/**
* The time, in milliseconds, of keyboard inactivity before the search string
* is reset
*
* @tiptext Time, in milliseconds, of keyboard inactivity before the search string is reset
* @default 1000
*/
public var inactivityResetTimeout:int = 1000;

//--------------------------------------------------------------------------
//
//  Methods
//
//--------------------------------------------------------------------------

/**
* Override the close function to take account of us changing
* the selected item (see keyDownHandler & _foxyInKeyDown)
*
* @see mx.controls.ComboBox::close()
*/
override public function close(trigger:Event = null):void
{
if( !_selectingItemAsTyping )
{
super.close();
}
}

//--------------------------------------------------------------------------
//
//  Overridden event handlers
//
//--------------------------------------------------------------------------

override protected function keyDownHandler(event:KeyboardEvent):void
{
var tmpCode:int = event.keyCode;
/*
* Note: In an ideal world the best place to do this work would be within a sub class
* of the List, but for some reason if the user doesn't open the drop down and
* starts typing (e.g. tabs to the ComboBox and starts typing) then the ComboBox
* keeps getting a new List from the factory. This stops us from keeping any sort
* of state within our List sub class, and having the feature only when the user
* has opened the drop down AND typed while it's open is not really very nice.
*
* So rather than going into overkill, by sub classing a few things and overriding
* far much more than I would like to, this compromise seemed the best option.
*/
if( ArrayUtil.getItemIndex( tmpCode, _keysSuperHandles ) != -1 )
{
// it's one of the keys we don't want to handle, let the parent handle it
super.keyDownHandler( event );
}
else if(( tmpCode >= 33 && tmpCode <= 126 ) || tmpCode == Keyboard.SPACE )
{
// Internally the ComboBox uses a private variable called
// bInKeyDown to make sure not to close the dropdown (if open)
// in this situation (where we have changed the selected item
// ourselves), we have to do something similar with a variable
// we have access to (see the overridden close() method for more details)
_selectingItemAsTyping = true;

// it's one of the keys we want to handle
_searchString += String.fromCharCode( tmpCode );

// backup the selected index incase the findString doesn't find any matches
var prevSelectedIndex:int = dropdown.selectedIndex;

// reset the selectedIndex stops from cycling through values as your typing, e.g.
// if there were the values united kingdom and united states then while typing united
// the selected item would cycle between the two (which isn't very attractive)
dropdown.selectedIndex = -1;

var matchedString:Boolean = dropdown.findString( _searchString );

if( !matchedString )
{
// if we didn't find a match we put the selection back to where it was
// as it was us that removed the selection (when we set it to -1 above)
dropdown.selectedIndex = prevSelectedIndex;
}

// kick off the clear timer
_clearTimer.reset();
_clearTimer.start();

_selectingItemAsTyping = false;
}
else
{
/*
it's another key that we don't care about (but not one we've explicitally
said we don't care about), so let the parent handle it
*/
super.keyDownHandler( event );
}
}

//--------------------------------------------------------------------------
//
//  Event handlers
//
//--------------------------------------------------------------------------

private function clearTimerCompleteHandler( event:TimerEvent ):void
{
this._searchString = '';
}

}
}

No comments:

Post a Comment