﻿// Name:        AjaxControlToolkit.ComboBox.ComboBox.debug.js
// Assembly:    AjaxControlToolkit
// Version:     3.0.30930.28736
// FileVersion: 3.0.30930.0
/// <reference name="MicrosoftAjax.js"/>

// Problem in MicrosoftAjax.js for Safari 3 release -- see http://forums.asp.net/p/1252014/2392110.aspx 
// Uncomment the next 8 lines to force correct behavior in Safari 3 release:
//if (typeof(Sys.Browser.WebKit) === 'undefined') {
//    Sys.Browser.WebKit = {};
//    if (navigator.userAgent.indexOf('WebKit/') > -1) {
//        Sys.Browser.agent = Sys.Browser.WebKit;
//        Sys.Browser.version = parseFloat(navigator.userAgent.match(/WebKit\/(\d+(\.\d+)?)/)[1]);
//        Sys.Browser.name = 'WebKit';
//    }
//}

Type.registerNamespace('AjaxControlToolkit');

AjaxControlToolkit.ComboBoxAutoCompleteMode = function() { };
AjaxControlToolkit.ComboBoxAutoCompleteMode.prototype =
{
    None: 0,
    Append: 1,
    Suggest: 2,
    SuggestAppend: 3
}

AjaxControlToolkit.ComboBoxAutoCompleteMode.registerEnum(
    'AjaxControlToolkit.ComboBoxAutoCompleteMode', false);

AjaxControlToolkit.ComboBoxStyle = function() { };
AjaxControlToolkit.ComboBoxStyle.prototype =
{
    DropDownList: 0,
    DropDown: 1,
    Simple: 2
}

AjaxControlToolkit.ComboBoxStyle.registerEnum(
    'AjaxControlToolkit.ComboBoxStyle', false);

AjaxControlToolkit.ComboBoxTextSelectionStrategy = function() { };
AjaxControlToolkit.ComboBoxTextSelectionStrategy.prototype =
{
    Unknown: 0,
    Microsoft: 1,
    W3C: 2
}

AjaxControlToolkit.ComboBoxTextSelectionStrategy.registerEnum(
    "AjaxControlToolkit.ComboBoxTextSelectionStrategy", false);


AjaxControlToolkit.ComboBox = function(element) {

    AjaxControlToolkit.ComboBox.initializeBase(this, [element]);

    this._comboTableControl = null;
    this._textBoxControl = null;
    this._optionListControl = null;
    this._buttonControl = null;
    this._hiddenFieldControl = null;
    this._autoPostBack = false;
    this._autoCompleteMode = null;
    this._dropDownStyle = null;
    this._caseSensitive = false;
    this._originalSelectedIndex = null;
    this._listItemHoverCssClass = null;

    this._popupBehavior = null;
    this._supressFocusHide = true;
    this._doingPostBack = false;
    this._textSelectionStrategy = null;
    this._highlightSuggestedItem = false;
    this._highlightedIndex = null;

    this._optionListItems = null;
    this._optionListItemHeight = null;
    this._optionListHeight = null;
    this._optionListWidth = null;

    this.clearDelegates();

}

AjaxControlToolkit.ComboBox.prototype = {

    initialize: function() {

        AjaxControlToolkit.ComboBox.callBaseMethod(this, 'initialize');
        this.createDelegates();
        this.initializeTextBox();
        this.initializeButton();
        this.initializeOptionList();
        this.addHandlers();

    },
    dispose: function() {

        // dispose of popup extender
        if (this._popupBehavior) {
            this._popupBehavior.remove_showing(this._popupShowingHandler);
            this._popupBehavior.remove_shown(this._popupShownHandler);
            this._popupBehavior.remove_hiding(this._popupHidingHandler);
            this._popupBehavior.dispose();
            this._popupBehavior = null;
        }

        this.clearHandlers();
        this.clearDelegates();

        AjaxControlToolkit.ComboBox.callBaseMethod(this, 'dispose');

    },
    createDelegates: function() {

        this._listMouseOverHandler = Function.createDelegate(this, this._onListMouseOver);
        this._listMouseOutHandler = Function.createDelegate(this, this._onListMouseOut);
        this._listMouseDownHandler = Function.createDelegate(this, this._onListMouseDown);
        this._listClickHandler = Function.createDelegate(this, this._onListClick);
        this._listDragHandler = Function.createDelegate(this, this._onListDrag);
        this._listSelectStartHandler = Function.createDelegate(this, this._onListSelectStart);
        this._listMouseWheelHandler = Function.createDelegate(this, this._onListMouseWheel);
        this._textBoxClickHandler = Function.createDelegate(this, this._onTextBoxClick);
        this._textBoxFocusHandler = Function.createDelegate(this, this._onTextBoxFocus);
        this._textBoxBlurHandler = Function.createDelegate(this, this._onTextBoxBlur);
        this._textBoxKeyPressHandler = Function.createDelegate(this, this._onTextBoxKeyPress);
        this._textBoxKeyDownHandler = Function.createDelegate(this, this._onTextBoxKeyDown);
        this._buttonClickHandler = Function.createDelegate(this, this._onButtonClick);
        this._buttonBlurHandler = Function.createDelegate(this, this._onButtonBlur);
        this._buttonKeyDownHandler = Function.createDelegate(this, this._onButtonKeyDown);
        this._buttonKeyPressHandler = Function.createDelegate(this, this._onButtonKeyPress);
        this._documentClickHandler = Function.createDelegate(this, this._onDocumentClick);
        this._documentMouseWheelHandler = Function.createDelegate(this, this._onDocumentMouseWheel);
        this._popupShowingHandler = Function.createDelegate(this, this._popupShowing);
        this._popupShownHandler = Function.createDelegate(this, this._popupShown);
        this._popupHidingHandler = Function.createDelegate(this, this._popupHiding);

    },
    clearDelegates: function() {

        this._listMouseOverHandler = null;
        this._listMouseOutHandler = null;
        this._listMouseDownHandler = null;
        this._listClickHandler = null;
        this._listDragHandler = null;
        this._listSelectStartHandler = null;
        this._listMouseWheelHandler = null;
        this._textBoxClickHandler = null;
        this._textBoxFocusHandler = null;
        this._textBoxBlurHandler = null;
        this._textBoxKeyPressHandler = null;
        this._textBoxKeyDownHandler = null;
        this._buttonClickHandler = null;
        this._buttonBlurHandler = null;
        this._buttonKeyDownHandler = null;
        this._buttonKeyPressHandler = null;
        this._documentClickHandler = null;
        this._documentMouseWheelHandler = null;
        this._popupShowingHandler = null;
        this._popupShownHandler = null;
        this._popupHidingHandler = null;

    },
    addHandlers: function() {

        $addHandlers(this.get_optionListControl(),
		{
		    'mouseover': this._listMouseOverHandler,
		    'mouseout': this._listMouseOutHandler,
		    'mousedown': this._listMouseDownHandler,
		    'click': this._listClickHandler,
		    'drag': this._listDragHandler,
		    'selectstart': this._listSelectStartHandler,
		    'mousewheel': this._listMouseWheelHandler
		}, this);

        $addHandlers(this.get_textBoxControl(),
        {
            "click": this._textBoxClickHandler,
            "focus": this._textBoxFocusHandler,
            "blur": this._textBoxBlurHandler,
            "keypress": this._textBoxKeyPressHandler
        }, this);
        if (Sys.Browser.agent == Sys.Browser.InternetExplorer || Sys.Browser.agent === Sys.Browser.Safari
            || Sys.Browser.agent === Sys.Browser.WebKit) {
            $addHandler(this.get_textBoxControl(), "keydown", this._textBoxKeyDownHandler);
        }

        $addHandlers(this.get_buttonControl(),
		{
		    'click': this._buttonClickHandler,
		    'blur': this._buttonBlurHandler,
		    'keydown': this._buttonKeyDownHandler,
		    'keypress': this._buttonKeyPressHandler
		}, this);

        $addHandlers(document,
        {
            'click': this._documentClickHandler,
            'mousewheel': this._documentMouseWheelHandler
        }, this);

        // FF doesn't have an onmousewheel event
        if (typeof (this.get_optionListControl().onmousewheel) === 'undefined') {

            this.get_optionListControl()._thisPrototype = this;
            if (typeof (document.ajax__combobox_prototypes) === 'undefined') {
                document.ajax__combobox_prototypes = new Array();
            }
            Array.add(document.ajax__combobox_prototypes, this);

            this.get_optionListControl().addEventListener('DOMMouseScroll', this._onListMouseWheel, false);
            document.addEventListener('DOMMouseScroll', this._onDocumentMouseWheel, false);
        }

    },
    clearHandlers: function() {

        $clearHandlers(this.get_optionListControl());
        $clearHandlers(this.get_textBoxControl());
        $clearHandlers(this.get_buttonControl());
        $clearHandlers(document);

    },
    initializeTextBox: function() {

        // initialize style
        var style = this.get_textBoxControl().style;

        // default browser margins interfere with button alignment
        if (style.margin == '')
            style.margin = '0px';

    },
    initializeButton: function() {

        // initialize style
        var style = this.get_buttonControl().style;

        // container height is based on the textbox's offsetHeight
        if (style.height == '' && this.get_textBoxControl().offsetHeight >= 0)
            style.height = this.get_textBoxControl().offsetHeight + 'px';
        if (style.width == '')
            style.width = style.height;

        // zero margins & padding (helps particularly in firefox)
        if (style.margin == '')
            style.margin = '0px';
        if (style.padding == '')
            style.padding = '0px';

        // button is originally hidden to reduce screen flicker
        this._buttonControl.style.visibility = 'visible';

    },
    initializeOptionList: function() {

        // when there are no option items, server does not render a UL element. 
        if (this.get_optionListControl() == null) {
            var optionList = document.createElement('ul');
            this.get_element().appendChild(optionList);
            this.set_optionListControl(optionList);
        }

        // force inline display on Safari by moving the list to the bottom of the form.
        if (Sys.Browser.agent === Sys.Browser.Safari || Sys.Browser.agent === Sys.Browser.WebKit) {
            this.get_element().removeChild(this.get_optionListControl());
            var parent = this.get_element().parentNode;
            while (typeof (parent) != typeof (document.forms[0])) {
                parent = parent.parentNode
            }
            var safariListContainer = document.createElement('div');
            safariListContainer.className = this.get_element().className;
            safariListContainer.appendChild(this.get_optionListControl());
            parent.appendChild(safariListContainer);
        }

        // initialize style
        var style = this.get_optionListControl().style;

        // option list is originally display-none to force inline rendering
        style.display = 'block';
        style.zIndex = '10000';

        // build an array of list items
        this._optionListItems = new Array();
        var children = this.get_optionListControl().childNodes;
        for (var i = 0; i < children.length; i++) {

            // evaluate the current node to see if it should be added to the list items array
            var child = children[i];

            // there may be more childNodes than items in the list -- remove non-li elements
            if (child.tagName == undefined || child.tagName.toUpperCase() != 'LI') {
                // remove the child, then re-evaluate this index
                this.get_optionListControl().removeChild(child);
                i--;
                continue;
            }

            // add the item to the internal collection
            var item = new Object();
            var text = child.innerHTML.trim();

            // remove carriage returns
            var indexOfCarriageReturn = text.indexOf('\r');
            while (indexOfCarriageReturn >= 0) {
                text = text.substring(0, indexOfCarriageReturn).trim()
                    + ' ' + text.substring(indexOfCarriageReturn + 1, text.length).trim();
                indexOfCarriageReturn = text.indexOf('\r');
            }

            // remove newlines
            var indexOfNewline = text.indexOf('\n');
            while (indexOfNewline >= 0) {
                text = text.substring(0, indexOfNewline).trim()
                    + ' ' + text.substring(indexOfNewline + 1, text.length).trim();
                indexOfNewline = text.indexOf('\n');
            }

            // replace HTML entities with character equivalents
            text = text.replace('&amp;', '&')
                .replace('&quot;', '"')
                .replace('&gt;', '>')
                .replace('&lt;', '<');

            item.text = text.trim();
            Array.add(this._optionListItems, item);

            // style the ListItem with default skin
            this.initializeOptionListItem(child);
        }

        // initialize list width
        style.width = this._getOptionListBounds().width + 'px';
        style.width = '0px';

        // add the popup behavior to the master container, targeting the option list
        this._popupBehavior = $create(AjaxControlToolkit.PopupBehavior,
		{
		    'id': this.get_id() + '_PopupBehavior'
			, 'parentElement': this.get_textBoxControl()
			, "positioningMode": AjaxControlToolkit.PositioningMode.BottomLeft
		}, null, null, this.get_optionListControl());
        this._popupBehavior.add_showing(this._popupShowingHandler);
        this._popupBehavior.add_shown(this._popupShownHandler);
        this._popupBehavior.add_hiding(this._popupHidingHandler);

        // highlight the default item and set the default text
        if (this.get_selectedIndex() >= 0) {
            this._highlightListItem(this.get_selectedIndex());
            this.get_textBoxControl().value = this._optionListItems[this.get_selectedIndex()].text;
        }
        else {
            this.get_textBoxControl().text = '';
        }

        // show and hide the popup behavior to initialize dimensions and overflow
        this._popupShowing();
        this.get_optionListControl().style.display = "none";

    },
    initializeOptionListItem: function(liElement) {

        // ensure empty text appears in the list
        liElement._textIsEmpty = false;
        if (liElement.innerHTML.length < 1) {
            liElement.innerHTML = '&nbsp;';
            liElement._textIsEmpty = true;
        }

    },
    _popupShowing: function() {

        // find out what dimensions and positioning we are working with
        var windowBounds = this._getWindowBounds();
        var tableBounds = Sys.UI.DomElement.getBounds(this.get_comboTableControl());
        var optionListBounds = this._getOptionListBounds();
        var safetyDimension = 30;

        // determine placement
        var yThreshold = windowBounds.y + (windowBounds.height / 2);
        var yFlopPoint = tableBounds.y + tableBounds.height;
        var xThreshold = windowBounds.x + (windowBounds.width / 2);
        var xFlopPoint = tableBounds.x + (tableBounds.width / 2);

        // vertical alignment & height
        var maxHeight = tableBounds.y - windowBounds.y;
        var yAlign = 'Top';
        if (yFlopPoint <= yThreshold) {
            yAlign = 'Bottom';
            maxHeight = windowBounds.height - tableBounds.height - maxHeight;
        }

        // when the list contains few enough items, maxHeight may be too large
        var itemHeight = this._getOptionListItemHeight();
        if (maxHeight >= optionListBounds.height) {
            maxHeight = optionListBounds.height;
        }
        else {
            // adjust maxHeight to be a multiple of listItemHeight
            maxHeight = itemHeight * ((Math.floor(maxHeight / itemHeight)) - 2);
        }
        var visibleItems = maxHeight / itemHeight;
        var yScrollbar = (visibleItems < this._optionListItems.length);
        var scrollbarWidth = 20;

        // when the list will fit safely, give it default alignment
        if (yAlign == "Top" && maxHeight < (windowBounds.height - tableBounds.y)) {
            yAlign = "Bottom";
        }

        // horizontal alignment & width
        var maxWidth = tableBounds.x - windowBounds.x;
        var xAlign = 'Left';
        if (xFlopPoint <= xThreshold) {
            maxWidth = windowBounds.width - maxWidth;
        }
        else {
            xAlign = 'Right';
            maxWidth = tableBounds.width + maxWidth;
        }

        // subtract safety dimension
        maxWidth -= safetyDimension;

        // when the list contains short items, maxWidth may be too large.
        var bestWidth = optionListBounds.width;
        if (yScrollbar) {
            bestWidth += scrollbarWidth;
            if (maxWidth >= bestWidth) {
                maxWidth = bestWidth;
            }
        }
        else if (maxWidth >= bestWidth) {
            maxWidth = bestWidth;
        }

        // when the list will fit safely, give it default alignment
        if (xAlign == "Right" && maxWidth < (windowBounds.width - tableBounds.x)) {
            xAlign = "Left";
        }

        // when list is empty, maxheight is -Infinity
        if (maxHeight < 0) {
            maxHeight = 0;
        }
        if (maxWidth < 0) {
            maxWidth = 0;
        }

        // set width & height
        var style = this.get_optionListControl().style;
        style.height = maxHeight + 'px';
        style.width = maxWidth + 'px';

        // account for scrollbars
        if (yScrollbar) {
            style.overflow = 'auto';
            style.overflowX = 'hidden';
        }
        else {
            style.overflow = 'hidden';
        }

        // set positioning mode
        var compositeAlign = yAlign + xAlign;
        if (compositeAlign == 'BottomLeft')
            this._popupBehavior.set_positioningMode(AjaxControlToolkit.PositioningMode.BottomLeft);
        else if (compositeAlign == 'BottomRight')
            this._popupBehavior.set_positioningMode(AjaxControlToolkit.PositioningMode.BottomRight);
        else if (compositeAlign == 'TopLeft')
            this._popupBehavior.set_positioningMode(AjaxControlToolkit.PositioningMode.TopLeft);
        else if (compositeAlign == 'TopRight')
            this._popupBehavior.set_positioningMode(AjaxControlToolkit.PositioningMode.TopRight);
        this.get_optionListControl().style.visibility = 'hidden';

    },
    _popupShown: function() {

        this.get_optionListControl().style.display = 'block';

        // check and enforce correct positioning.
        var tableBounds = Sys.UI.DomElement.getBounds(this.get_comboTableControl());
        var listBounds = Sys.UI.DomElement.getBounds(this.get_optionListControl());
        var textBoxBounds = Sys.UI.DomElement.getBounds(this.get_textBoxControl());
        var y = listBounds.y;
        var x;

        if (this._popupBehavior.get_positioningMode() === AjaxControlToolkit.PositioningMode.BottomLeft
            || this._popupBehavior.get_positioningMode() === AjaxControlToolkit.PositioningMode.TopLeft) {
            x = textBoxBounds.x;
        }
        else if (this._popupBehavior.get_positioningMode() === AjaxControlToolkit.PositioningMode.BottomRight
            || this._popupBehavior.get_positioningMode() === AjaxControlToolkit.PositioningMode.TopRight) {
            x = textBoxBounds.x - (listBounds.width - textBoxBounds.width);
        }

        Sys.UI.DomElement.setLocation(this.get_optionListControl(), x, y);

        // enforce default scroll
        this._ensureHighlightedIndex();
        this._ensureScrollTop();

        // show the option list
        this.get_optionListControl().style.visibility = 'visible';

    },
    _popupHiding: function() {

        // hide the option list
        this._highlightSuggestedItem = false;
        this.get_optionListControl().style.display = 'none';
        this.get_optionListControl().style.visibility = 'hidden';

    },
    _onButtonClick: function(e) {

        // in Simple mode, always display the list
        if (this.get_dropDownStyle() == AjaxControlToolkit.ComboBoxStyle.Simple) {
            this._popupBehavior.show();
        }

        // show / hide the option list
        else if (this._popupBehavior._visible) {
            this._popupBehavior.hide();
        }
        else {
            this._popupBehavior.show();
        }

        e.preventDefault();
        e.stopPropagation();
        return false;

    },
    _onButtonBlur: function(e) {

        // optionally trigger postback
        if (this.get_autoPostBack() == true && !this._doingPostBack && this._originalSelectedIndex != this.get_selectedIndex()) {
            this._doingPostBack = true;
            __doPostBack(this.get_element().id, '');
        }

    },
    _onButtonKeyDown: function(e) {

        // sometimes user can type while the button has focus
        if (e.keyCode == Sys.UI.Key.tab || e.keyCode == 16) { // 16==SHIFT key
            return true;
        }

        if (!this._popupBehavior._visible && (e.keyCode == Sys.UI.Key.enter || e.keyCode == Sys.UI.Key.down)) {
            this._popupBehavior.show();
        }
        else if (this._popupBehavior._visible && (e.keyCode == Sys.UI.Key.enter || e.keyCode == Sys.UI.Key.up)) {
            this._popupBehavior.hide();
        }

        e.stopPropagation();
        e.preventDefault();

        // give focus to the text box
        var textBoxID = this.get_textBoxControl().id;
        setTimeout(function() { document.getElementById(textBoxID).focus(); }, 0);
        return false;

    },
    _onButtonKeyPress: function(e) {

        // sometimes user can type while the button has focus
        if (e.charCode == Sys.UI.Key.tab || e.charCode == 16) { // 16==SHIFT key
            return true;
        }
        e.stopPropagation();
        e.preventDefault();
        return false;

    },
    _onListMouseWheel: function(e) {

        // event is invoked by either this prototype or the DOM option list object
        var _this = this._thisPrototype;
        if (typeof (_this) === 'undefined') {
            _this = this;
        }

        // enforce mousewheel scrolling
        var direction;
        if (typeof (this._thisPrototype) === 'undefined') {
            // not firefox
            direction = (e.rawEvent.wheelDelta > 1) ? -1 : 1;
        }
        else {
            // firefox
            direction = (e.detail >= 1) ? 1 : -1;
        }

        // each event scrolls approximately 1 list item up or down
        var scrollStep = _this._getOptionListItemHeight() * direction;
        var newScrollTop = _this.get_optionListControl().scrollTop + scrollStep;
        _this.get_optionListControl().scrollTop = newScrollTop;

        // tell parents we have handled this event
        e.stopPropagation();
        e.preventDefault();
        return false;

    },
    _onListMouseOver: function(e) {

        // do not highlight unless an LI is being hovered
        if (e.target !== this.get_optionListControl()) {
            var target = e.target;
            var children = this.get_optionListControl().childNodes;

            // loop through children to find a match with the target
            for (var i = 0; i < children.length; ++i) {
                // match found, highlight item and break loop
                if (target === children[i]) {
                    this._highlightListItem(i, true);
                    break;
                }
            }
        }

    },
    _onListMouseOut: function(e) {

        // unhighlight the highlighted item if the list is open in suggestappend mode
        // prevents overriding user-typed text when determining the selectedindex
        if (this._popupBehavior._visible
            && this.get_autoCompleteMode() == AjaxControlToolkit.ComboBoxAutoCompleteMode.SuggestAppend) {
            this._highlightListItem(this._highlightedIndex, false);
        }

    },
    _onListMouseDown: function(e) {

        if (e.target == this.get_optionListControl() || e.target.tagName == 'scrollbar') {
            return true;
        }

        // set the TextBox to the highlighted ListItem's text and update selectedIndex
        if (e.target !== this.get_optionListControl()) {
            var highlightedItem = this.get_optionListControl().
				childNodes[this._highlightedIndex];
            var text = this._optionListItems[this._highlightedIndex].text;
            this.get_textBoxControl().value = text;
            this.set_selectedIndex(this._highlightedIndex);

            // return focus to the TextBox
            this._supressFocusHide = false;
            //this.get_textBoxControl().focus(); // danludwig, see http://ajaxcontroltoolkit.codeplex.com/WorkItem/View.aspx?WorkItemId=22392
            this._handleTextBoxFocus(null);

        }
        else {
            return true;
        }
        e.preventDefault();
        e.stopPropagation();
        return false;

    },
    _onListClick: function(e) {

        if (e.target == this.get_optionListControl()) {
            return true;
        }

        // prevent ItemList clicks from triggering document clicks
        e.preventDefault();
        e.stopPropagation();
        return false;

    },
    _onListDrag: function(e) {

        // prevent selection of ListItem text
        e.preventDefault();
        e.stopPropagation();
        return false;

    },
    _onListSelectStart: function(e) {

        // prevent selection of ListItem text
        e.preventDefault();
        e.stopPropagation();
        return false;

    },
    _onTextBoxClick: function(e) {

        // in Simple mode, always display the list
        if (this.get_dropDownStyle() == AjaxControlToolkit.ComboBoxStyle.Simple) {
            this._popupBehavior.show();
        }

        // prevent TextBox clicks from triggering document clicks
        e.preventDefault();
        e.stopPropagation();
        return false;

    },
    _onTextBoxFocus: function(e) {

        this._handleTextBoxFocus(e);

    },
    _onTextBoxBlur: function(e) {

        // select the correct index based on text box value
        var textBoxValue = this.get_textBoxControl().value.trim();
        var matchedIndex = -3;

        // search items
        for (var i = 0; i < this._optionListItems.length; i++) {
            var item = this._optionListItems[i];
            if (this._isExactMatch(item.text, textBoxValue)) {
                matchedIndex = i;
                break;
            }
        }

        // when in suggest mode, a suggested index may already be set
        if (this._highlightSuggestedItem == true && this._highlightedIndex != null && this._highlightedIndex >= 0) {
            this.set_selectedIndex(this._highlightedIndex);
            this.get_textBoxControl().value = this._optionListItems[this.get_selectedIndex()].text;
        }

        // selected index is -2 when custom text is entered in dropdownlist mode
        else if (matchedIndex == -3 && textBoxValue.length > 0
            && this.get_dropDownStyle() != AjaxControlToolkit.ComboBoxStyle.DropDownList) {
            this.set_selectedIndex(-2);
        }

        // selected index is -1 when there are no items in the list and there is no custom text
        else if (this._optionListItems.length < 1 && (textBoxValue == ''
            || this.get_dropDownStyle() == AjaxControlToolkit.ComboBoxStyle.DropDownList)) {
            this.set_selectedIndex(-1);
            this.get_textBoxControl().value = '';
        }

        // when list contains items but none matched, select the first item by default
        else if (this._optionListItems.length >= 0 && matchedIndex == -3
            && this.get_dropDownStyle() == AjaxControlToolkit.ComboBoxStyle.DropDownList) {
            this.set_selectedIndex(0);
            this.get_textBoxControl().value = this._optionListItems[0].text;
        }

        // when list contains a matchable item, set the selected index
        else if (matchedIndex >= 0) {
            this.set_selectedIndex(matchedIndex);
            this.get_textBoxControl().value = this._optionListItems[matchedIndex].text;
        }

        // hide the option list and optionally trigger postback
        this._popupBehavior.hide();
        if (this.get_autoPostBack() == true && !this._doingPostBack && this._originalSelectedIndex != this.get_selectedIndex()) {
            this._doingPostBack = true;
            __doPostBack(this.get_element().id, '');
        }

    },
    _onTextBoxKeyDown: function(e) {

        // keydown is not fired in ff or opera. keypress is fired instead.
        // in ie and safari, keydown is fired before keypress for character keys and the ENTER key.
        // in ie and safari, keydown is fired instead of keypress for ARROWS, BACKSPACE, and DELETE keys.
        // only keyCodes are sent to this event: charCodes are always undefined here.

        // user presses ENTER while text box has focus
        var enterResult = this._handleEnterKey(e);
        if (enterResult != null) {
            return enterResult;
        }

        this._handleArrowKey(e);

        // handle backspace and delete keystrokes
        var erasureKeyResult = this._handleErasureKeys(e);
        if (erasureKeyResult != null) {
            return erasureKeyResult;
        }

        return true;

    },
    _onTextBoxKeyPress: function(e) {

        // user presses ENTER while text box has focus
        var enterResult = this._handleEnterKey(e);
        if (enterResult != null) {
            return enterResult;
        }

        // some browsers, like ff and Opera, send arrow strokes here instead of keydown 
        var arrowResult = this._handleArrowKey(e);
        if (arrowResult != null) {
            return arrowResult;
        }

        // do not prevent all keypresses, only character keypresses.
        var nonCharacterKeyResult = this._handleNonCharacterKey(e);
        if (nonCharacterKeyResult != null) {
            return nonCharacterKeyResult;
        }

        // always show list in simple mode
        if (this.get_dropDownStyle() == AjaxControlToolkit.ComboBoxStyle.Simple && !this._popupBehavior._visible) {
            this._popupBehavior.show();
        }

        // prevent typing when there are no items in the list
        if (this.get_selectedIndex() == -1 && this.get_dropDownStyle() == AjaxControlToolkit.ComboBoxStyle.DropDownList) {
            this.get_textBoxControl().value = '';
            e.preventDefault();
            e.stopPropagation();
            return false;
        }

        // get info about the text and selection
        var info = this._getTextSelectionInfo(this.get_textBoxControl(), e);
        var newSelectionStart = info.selectionStart;
        var newSelectionEnd = info.selectionEnd;
        var allText = info.selectionPrefix + info.typedCharacter
            + info.selectionText.substring(1) + info.selectionSuffix;
        var userText = info.selectionPrefix + info.typedCharacter;
        var suggestedIndex = this._suggestIndex(allText, userText);

        // setup suggest behavior
        if (this.get_autoCompleteMode() == AjaxControlToolkit.ComboBoxAutoCompleteMode.Suggest
                || this.get_autoCompleteMode() == AjaxControlToolkit.ComboBoxAutoCompleteMode.SuggestAppend) {
            this._highlightSuggestedItem = true;
            if (!this._popupBehavior._visible) {
                this._popupBehavior.show();
            }
        }

        // suggestedIndex can be a valid index or -1.
        if (suggestedIndex >= 0) {

            // handle append behavior
            if (this.get_autoCompleteMode() == AjaxControlToolkit.ComboBoxAutoCompleteMode.Append
                    || this.get_autoCompleteMode() == AjaxControlToolkit.ComboBoxAutoCompleteMode.SuggestAppend) {
                this.get_textBoxControl().value = this._optionListItems[suggestedIndex].text;
                newSelectionStart = info.selectionStart + 1;
                newSelectionEnd = this.get_textBoxControl().value.length;
            }
            // do not append suggestion
            else {
                this.get_textBoxControl().value = this._optionListItems[suggestedIndex].text.substring(0, userText.length);
                newSelectionStart = this.get_textBoxControl().value.length;
                newSelectionEnd = this.get_textBoxControl().value.length;
            }
        }

        // when suggestedIndex is -1, there is no match.
        else if (this.get_dropDownStyle() == AjaxControlToolkit.ComboBoxStyle.Simple
                || this.get_dropDownStyle() == AjaxControlToolkit.ComboBoxStyle.DropDown) {
            this.get_textBoxControl().value = userText;
            newSelectionStart = userText.length;
            newSelectionEnd = userText.length;
        }

        // handle backspace and delete keystrokes
        var erasureKeyResult = this._handleErasureKeys(e);
        if (erasureKeyResult != null) {
            return erasureKeyResult;
        }

        // automatically highlight and scroll based on typing
        this._ensureHighlightedIndex();
        this._ensureScrollTop();
        this._setTextSelectionRange(this.get_textBoxControl(), newSelectionStart, newSelectionEnd);

        e.preventDefault();
        e.stopPropagation();
        return false;

    },
    _onDocumentClick: function(e) {

        // hide the option list when users click document
        if (this._popupBehavior._visible) {
            this._popupBehavior.hide();
        }

    },
    _onDocumentMouseWheel: function(e) {

        // event is invoked by either 'this' prototype or the DOM document object
        var _this = this.ajax__combobox_prototypes;
        if (typeof (_this) === 'undefined') {
            _this = this;
        }

        // hide the option list when user mousewheel scrolls outside of it
        if (typeof (this.ajax__combobox_prototypes) === 'undefined') {
            this._popupBehavior.hide();
        }
        else {
            for (var i = 0; i < this.ajax__combobox_prototypes.length; i++) {
                this.ajax__combobox_prototypes[i]._popupBehavior.hide();
            }
        }

        return true;

    },
    _handleTextBoxFocus: function(e) {

        // hide the option list and optionally trigger postback
        if (!this._supressFocusHide && this._popupBehavior._visible) {
            this._popupBehavior.hide();
            this._supressFocusHide = true;
            if (this.get_autoPostBack() && !this._doingPostBack && this._originalSelectedIndex != this.get_selectedIndex()) {
                this._doingPostBack = true;
                __doPostBack(this.get_element().id, '');
            }
        }

        // in Simple mode, always display the list
        if (this.get_dropDownStyle() == AjaxControlToolkit.ComboBoxStyle.Simple) {
            this._popupBehavior.show();
        }

        // select the entire string in the text box
        this._setTextSelectionRange(
            this.get_textBoxControl(),
            0,
            this.get_textBoxControl().value.length);

        if (e != null) {
            e.preventDefault();
            e.stopPropagation();
        }

    },
    _highlightListItem: function(index, isHighlighted) {

        // only highlight valid indices
        if (index == undefined || index < 0) {
            if (this._highlightedIndex != undefined && this._highlightedIndex >= 0) {
                this._highlightListItem(this._highlightedIndex, false);
            }
            return;
        }

        var children = this.get_optionListControl().childNodes;
        var liElement = children[index];

        // item is being hovered
        if (isHighlighted == true) {

            // skip if already highlighted
            if (this._highlightedIndex == index)
                return;

            // apply hover css class
            if (index >= 0) {
                // to avoid scrollbar flickering during scrolls in IE, do not set className unless it is provided
                if (this.get_listItemHoverCssClass() == undefined || this.get_listItemHoverCssClass() == '') {
                    liElement.style.backgroundColor = 'Highlight';
                    liElement.style.color = 'HighlightText'
                }
                else {
                    liElement.className = this.get_listItemHoverCssClass;
                }
            }

            // unselect previously highlighted item
            if (this._highlightedIndex != null && this._highlightedIndex != index && this._highlightedIndex >= 0) {
                this._highlightListItem(this._highlightedIndex, false);
            }

            // update control state
            this._highlightedIndex = index;
        }

        // item is not being hovered
        else {
            if (this.get_listItemHoverCssClass() == undefined || this.get_listItemHoverCssClass() == '') {
                liElement.style.backgroundColor = '';
                liElement.style.color = ''
            }
            else {
                liElement.className = '';
            }

            if (index == this._highlightedIndex) {
                this._highlightedIndex = -1;
            }
        }

    },
    _suggestIndex: function(allText, userText) {

        // suggest closest option list match based on user's typing
        var suggestedIndex = -1;
        var firstMatch = false;
        var exactMatch = false;

        // loop through all options in the list
        for (var i = 0; i < this._optionListItems.length; i++) {
            itemText = this._optionListItems[i].text;

            // skip empty elements
            if (itemText.length < 1)
                continue;

            // skip elements that don't match on first character
            if (itemText.substring(0, 1).toLowerCase() != userText.substring(0, 1).toLowerCase())
                continue;

            // first, check if strings are exact match
            var allCandidate = itemText.substring(0, allText.length);
            exactMatch = (allCandidate == allText);
            if (!exactMatch && !this.get_caseSensitive()) {
                exactMatch = (allCandidate.toLowerCase() == allText.toLowerCase());
            }

            // always return exact matches before first matches
            if (exactMatch) {
                suggestedIndex = i;
                break;
            }

            // otherwise, look for a partial match and keep going
            else if (!firstMatch) {
                var userCandidate = itemText.substring(0, userText.length);
                firstMatch = (userCandidate == userText);
                if (!firstMatch && !this.get_caseSensitive())
                    firstMatch = (userCandidate.toLowerCase() == userText.toLowerCase());
                if (firstMatch)
                    suggestedIndex = i;
            }
        }
        return suggestedIndex;

    },
    _getKeyboardCode: function(e) {

        if (e.type == 'keypress') {
            return e.charCode;
        } else if (e.type == 'keydown') {
            return e.keyCode;
        }
        return undefined;

    },
    _handleArrowKey: function(e) {

        // when shift key is pressed, ignore arrow codes
        if (e.shiftKey == true) {
            return null;
        }

        var code = this._getKeyboardCode(e);

        // cycle through items when up & down arrow keys are used
        if (code == Sys.UI.Key.up || code == Sys.UI.Key.down) {
            if (this._popupBehavior._visible) {
                var vector = code - 39;
                if ((vector == -1 && this._highlightedIndex > 0) || (vector == 1 && this._highlightedIndex < this._optionListItems.length - 1)) {
                    var newIndex = (this._highlightedIndex + vector);
                    this.get_textBoxControl().value = this._optionListItems[newIndex].text;
                    this._highlightListItem(newIndex, true);
                    this.set_selectedIndex(newIndex);
                    this._ensureScrollTop();
                }
            }
            else {
                this._popupBehavior.show();
            }

            if (e.type == 'keypress') {
                e.preventDefault();
                e.stopPropagation();
                return false;
            }
            return true;
        }
        return null;

    },
    _handleEnterKey: function(e) {

        var code = this._getKeyboardCode(e);

        if (code == Sys.UI.Key.enter) {
            // if the dropdown is open, close it.
            if (this._popupBehavior._visible) {
                if (this._highlightedIndex >= 0) {
                    this.get_textBoxControl().value = this._optionListItems[this._highlightedIndex].text
                    this.set_selectedIndex(this._highlightedIndex);
                }
                this._popupBehavior.hide();
                e.preventDefault();
                e.stopPropagation();
                return false;
            }

            // allow form submits for free text
            else if (this.get_dropDownStyle() == AjaxControlToolkit.ComboBoxStyle.Simple
                || this.get_dropDownStyle() == AjaxControlToolkit.ComboBoxStyle.DropDown) {
                return true;
            }

            // allow form submits for valid selected indices
            else if (this._highlightedIndex == this.get_selectedIndex()) {
                return true;
            }

            e.preventDefault();
            e.stopPropagation();
            return false;
        }
        return null;

    },
    _handleErasureKeys: function(e) {

        var code = this._getKeyboardCode(e);

        var isBackspaceKey = (code == Sys.UI.Key.backspace);
        var isDeleteKey = (code == Sys.UI.Key.del);
        if (typeof (window.event) === 'undefined' && e.type == 'keypress') {
            isDeleteKey = (e.rawEvent.keyCode == 46);
        }

        if (isBackspaceKey || isDeleteKey) {

            var info = this._getTextSelectionInfo(this.get_textBoxControl(), e);
            var newSelectionStart, newSelectionEnd;

            // always delete selected characters
            if (info.selectionStart < info.selectionEnd) {
                this.get_textBoxControl().value = info.selectionPrefix + info.selectionSuffix;
                newSelectionStart = info.selectionStart;
                newSelectionEnd = info.selectionStart;
            }

            // otherwise, there is no selection -- only a carat
            else if (info.selectionStart == info.selectionEnd) {
                var newValue;
                if (isBackspaceKey && info.selectionStart > 0) {
                    var trimSize = 1;
                    if (info.selectionPrefix.charCodeAt(info.selectionPrefix.length - 1) == 8) {
                        trimSize = 2;
                    }
                    newValue = info.selectionPrefix.substr(0, info.selectionPrefix.length - trimSize);
                    newValue += info.selectionSuffix;
                    this.get_textBoxControl().value = newValue;
                    newSelectionStart = info.selectionStart - 1;
                    newSelectionEnd = info.selectionStart - 1;
                }
                else if (isDeleteKey && info.selectionStart < info.textBoxValue.length) {
                    newValue = info.selectionSuffix;
                    newValue = info.selectionPrefix + newValue.substr(1, info.selectionSuffix.length - 1);
                    this.get_textBoxControl().value = newValue;
                    newSelectionStart = info.selectionStart;
                    newSelectionEnd = info.selectionStart;
                    this._setTextSelectionRange(this.get_textBoxControl(), info.selectionStart, info.selectionStart);
                }
            }

            this._ensureHighlightedIndex();
            this._ensureScrollTop();
            this._setTextSelectionRange(this.get_textBoxControl(), newSelectionStart, newSelectionEnd);

            // in custom text modes with suggestion, need to re-check the highlighted item
            if ((this.get_dropDownStyle() == AjaxControlToolkit.ComboBoxStyle.Simple
                || this.get_dropDownStyle() == AjaxControlToolkit.ComboBoxStyle.DropDown)
                && (this.get_autoCompleteMode() == AjaxControlToolkit.ComboBoxAutoCompleteMode.Suggest
                || this.get_autoCompleteMode() == AjaxControlToolkit.ComboBoxAutoCompleteMode.SuggestAppend)
                && this._highlightedIndex >= 0) {
                var _isExactMatch = this._isExactMatch(this._optionListItems[this._highlightedIndex].text, this.get_textBoxControl().value);
                if (!_isExactMatch) {
                    this._highlightListItem(this._highlightedIndex, false);
                }
            }

            e.preventDefault();
            e.stopPropagation();
            return false;
        }
        return null;

    },
    _handleNonCharacterKey: function(e) {

        var code = this._getKeyboardCode(e);

        var isBackspaceKey = (code == Sys.UI.Key.backspace);
        var isDeleteKey = (code == Sys.UI.Key.del);
        if (e.type == 'keypress') {
            isDeleteKey = (code == 46);
        }

        if (isBackspaceKey || isDeleteKey) {

            return null;
        }

        if (this._isNonCharacterKey(e)) {
            // prevent event validation errors when ESC is hit twice
            if (code == Sys.UI.Key.esc) {
                this._popupBehavior.hide();
                this.get_textBoxControl().blur();
                e.preventDefault();
                e.stopPropagation();
                return false;
            }
            return true;
        }
        return null;
    },
    _isNonCharacterKey: function(e) {

        // MS Ajax uses following codes for Key enumeration
        // backspace:8,tab:9,enter:13,esc:27,space:32,pageUp:33,pageDown:34,end:35,home:36,left:37,up:38,right:39,down:40,del:127
        var code = this._getKeyboardCode(e);

        // return true if keypress actions should be allowed
        if (code == Sys.UI.Key.enter || code == Sys.UI.Key.esc) { // allow RETURN/ENTER and ESC keys for all browsers

            return true;
        }
        else if (Sys.Browser.agent == Sys.Browser.Safari && Sys.Browser.version < 500) {

            // allow special funky apple keypresses
            if (code == 8           // BACKSPACE in Safari 2
                || code == 9        // TAB in Safari 2
                || code == 63272    // DELETE in Safari 2
                || code == 63276    // PAGEUP in Safari 2
                || code == 63277    // PAGEDOWN in Safari 2
                || code == 63275    // END in Safari 2
                || code == 63273    // HOME in Safari 2
                || code == 63234    // ARROWLEFT in Safari 2
                || code == 63235    // ARROWRIGHT in Safari 2
                || (code >= 63236 && code <= 63243) // FUNCTION keys in Safari 2
                || code == 63248       // F13 key in Safari 2
            ) {
                return true;
            }
        }
        else if (Sys.Browser.agent == Sys.Browser.WebKit) {

            // allow special funky apple webkit keypresses
            if (code == 8            // BACKSPACE in Safari 3
                || code == 9         // TAB in Safari 3
                || code == 19        // PAUSE BREAK Safari 3
                || code == 33        // PAGEUP in Safari 3
                || code == 34        // PAGEDOWN in Safari 3
                || code == 35        // END in Safari 3
                || code == 36        // HOME in Safari 3
                || code == 37        // ARROWLEFT in Safari 3
                || code == 39        // ARROWRIGHT in Safari 3
                || code == 45        // INSERT in Safari 3
                || code == 46        // DELETE in Safari 3
                || code == 91        // WINDOWS LEFT Safari 3
                || code == 92        // WINDOWS RIGHT Safari 3
                || code == 93        // MENU Safari 3
                || code == 113       // F2 Safari 3
                || code == 115       // F4 Safari 3
                || code == 118       // F7 Safari 3
                || code == 119       // F8 Safari 3
                || code == 120       // F9 Safari 3
                || code == 122       // F11 Safari 3
                || code == 145       // SCROLL LOCK Safari 3
            )
                return true;
        }
        else if (Sys.Browser.agent != Sys.Browser.InternetExplorer) {

            // allow kepress events triggered by FF & Opera
            if (code == 8           // BACKSPACE in non-microsoft browsers
                || code == 9        // TAB in non-microsoft browsers
                || code == 33       // PAGEUP in non-microsoft browsers
                || code == 34       // PAGEDOWN in non-microsoft browsers
                || code == 35       // END in non-microsoft browsers
                || code == 36       // HOME in non-microsoft browsers
                || code == 37       // ARROWLEFT in non-microsoft browsers
                || code == 39       // ARROWRIGHT in non-microsoft browsers
                || code == 45       // INSERT in non-microsoft browsers
                || code == 46       // DELETE in non-microsoft browsers
            //|| (code >= 112 && code <= 123) // FUNCTION keys in non-microsoft browsers
            ) {
                if (!e.shiftKey)
                    return true;
            }
            else if (code == 145) {

                // allow SCROLL LOCK events triggered by weird combos
                return true;

            }
            else if (code == 19) {

                // allow PAUSE BREAK events triggered by weird combos
                return true;

            }
            else if (Sys.Browser.agent == Sys.Browser.Opera) {

                // allow kepress events triggered only by Opera
                if (code == 0       // MENU key in Opera
                    || code == 16   // SHIFT key in Opera
                    || code == 17   // CONTROL key in Opera
                ) {
                    return true;
                }
            }
            else if (Sys.Browser.agent == Sys.Browser.Firefox) {

                // allow kepress events triggered only by Firefox
                if (code == 91      // WINDOWS LEFT key in Firefox
                    || code == 92   // WINDOWS RIGHT key in Firefox
                    || code == 93   // MENU key in Firefox
                ) {
                    return true;
                }
            }
        }
        return false;

    },
    _ensureScrollTop: function() {

        // automatically scroll if the highlighted index is not visible. 
        if (this._highlightedIndex >= 0) {
            var itemHeight = this._getOptionListItemHeight();
            var itemTop = itemHeight * this._highlightedIndex;
            var scrollBottom = this.get_optionListControl().scrollTop + this.get_optionListControl().clientHeight;

            if (itemTop <= this.get_optionListControl().scrollTop || itemTop >= scrollBottom)
                this.get_optionListControl().scrollTop = this._highlightedIndex * itemHeight;
        }

    },
    _ensureSelectedIndex: function() {

        // server may not always invoke set_selectedIndex(), need to make sure this is always an integer
        var selectedIndex = this.get_hiddenFieldControl().value;
        if (selectedIndex == '') {
            selectedIndex = (this._optionListItems.length > 0) ? 0 : -1;
            this.get_hiddenFieldControl().value = selectedIndex.toString();
        }
        if (this._originalSelectedIndex == null) {
            this._originalSelectedIndex = parseInt(selectedIndex);
        }


    },
    _ensureHighlightedIndex: function() {

        // highlight an index according to textbox value
        var textBoxValue = this.get_textBoxControl().value;

        // first, check the current highlighted index
        if (this._highlightedIndex != null && this._highlightedIndex >= 0
            && this._isExactMatch(this._optionListItems[this._highlightedIndex].text, textBoxValue)) {
            return;
        }

        // need to find the correct index
        var firstMatch = -1;
        var ensured = false;
        for (var i = 0; i < this._optionListItems.length; i++) {
            var itemText = this._optionListItems[i].text;
            if (this._isExactMatch(itemText, textBoxValue)) {
                this._highlightListItem(i, true);
                ensured = true;
                break;
            }

            // if in DropDownList mode, save first match.
            else if (firstMatch < 0 && this._highlightSuggestedItem) {
                if (this._isPrefixMatch(itemText, textBoxValue)) {
                    firstMatch = i;
                }
            }
        }

        if (!ensured) {
            this._highlightListItem(firstMatch, true);
        }

    },
    _isExactMatch: function(itemText, userText) {

        // whether strings match exactly, depending on case sensitivity
        var exactMatch = (itemText == userText);
        if (!exactMatch && !this.get_caseSensitive())
            exactMatch = (itemText.toLowerCase() == userText.toLowerCase())

        return exactMatch;

    },
    _isPrefixMatch: function(itemText, userText) {

        // whether the user-typed text matches as the prefix of an option in the list
        return this._isExactMatch(itemText.substring(0, userText.length), userText);

    },
    _setTextSelectionRange: function(textBox, selectionStart, selectionEnd) {

        // set the selection range on the text box
        var strategy = this._getTextSelectionStrategy();
        if (strategy == AjaxControlToolkit.ComboBoxTextSelectionStrategy.Microsoft) {
            var range = textBox.createTextRange();
            range.collapse(true);
            range.moveEnd('character', selectionEnd);
            range.moveStart('character', selectionStart);
            range.select();

            // opera wants to also invoke the W3C setSelectionRange method
            if (Sys.Browser.agent == Sys.Browser.Opera) {
                textBox.setSelectionRange(selectionStart, selectionEnd)
            }
        }
        else if (strategy == AjaxControlToolkit.ComboBoxTextSelectionStrategy.W3C) {
            textBox.setSelectionRange(selectionStart, selectionEnd)
        }

    },
    _getTextSelectionStrategy: function() {

        // different browsers have different API's for selecting text
        if (this._textSelectionStrategy == null) {
            if (this.get_textBoxControl().createTextRange) {
                this._textSelectionStrategy =
                    AjaxControlToolkit.ComboBoxTextSelectionStrategy.Microsoft;
            }
            else if (this.get_textBoxControl().setSelectionRange) {
                this._textSelectionStrategy =
                    AjaxControlToolkit.ComboBoxTextSelectionStrategy.W3C;
            }
            else {
                this._textSelectionStrategy =
                    AjaxControlToolkit.ComboBoxTextSelectionStrategy.Unknown;
            }
        }

        return this._textSelectionStrategy;

    },
    _getTextSelectionInfo: function(textBox, e) {

        // returns a helper object with information about textbox selection
        var info = new Object();

        // strategy
        info.strategy = this._getTextSelectionStrategy();

        // selectionStart & selectionEnd
        if (info.strategy == AjaxControlToolkit.ComboBoxTextSelectionStrategy.Microsoft) {
            var userRange = document.selection.createRange();
            info.selectionStart = 0;
            info.selectionEnd = textBox.value.length;
            while (userRange.moveStart('character', -1) != 0) {
                info.selectionStart++;
            }
            while (userRange.moveEnd('character', 1) != 0) {
                info.selectionEnd--;
            }
        }
        else if (info.strategy == AjaxControlToolkit.ComboBoxTextSelectionStrategy.W3C) {
            info.selectionStart = textBox.selectionStart;
            info.selectionEnd = textBox.selectionEnd;
        }

        // typedCharacter, textBoxValue, selectionPrefix, selectionSuffix, selectionTextFirst
        info.typedCharacter = String.fromCharCode(e.charCode);
        info.textBoxValue = textBox.value;
        info.selectionPrefix = (info.textBoxValue.length >= info.selectionStart)
            ? info.textBoxValue.substring(0, info.selectionStart)
            : '';
        info.selectionText = (info.textBoxValue.length >= info.selectionEnd)
            ? info.textBoxValue.substring(info.selectionStart, info.selectionEnd)
            : '';
        info.selectionSuffix = (info.textBoxValue.length >= info.selectionEnd)
            ? info.textBoxValue.substring(info.selectionEnd, info.textBoxValue.length)
            : '';
        info.selectionTextFirst = info.selectionText.substring(0, 1);

        return info;

    },
    _getOptionListItemHeight: function() {

        // gets the height of an individual option list item
        if (this._optionListItemHeight == null && this.get_optionListControl().scrollHeight > 0) {
            this._optionListItemHeight = Math.round(this.get_optionListControl().scrollHeight / this._optionListItems.length);
        }
        else if (Sys.Browser.agent === Sys.Browser.InternetExplorer && Sys.Browser.version < 7
            && Math.round(this.get_optionListControl().scrollHeight / this._optionListItems.length) < this._optionListItemHeight) {
            this._optionListItemHeight = Math.round(this.get_optionListControl().scrollHeight / this._optionListItems.length);
        }
        return this._optionListItemHeight;

    },
    _getOptionListBounds: function() {

        var bounds = {
            width: this._getOptionListWidth(),
            height: this._getOptionListHeight()
        };
        return bounds;

    },
    _getOptionListHeight: function() {

        // gets the total height of the option list
        if (this._optionListHeight == null || (this._getOptionListItemHeight() * this._optionListItems.length) < this._optionListHeight) {
            // multiply the height of one item by the total number of items
            this._optionListHeight = this._getOptionListItemHeight() * this._optionListItems.length;
        }

        // protect against negative dimensions
        if (this._optionListHeight < 0) {
            this._optionListHeight = 0;
        }

        return this._optionListHeight;

    },
    _getOptionListWidth: function() {

        // gets the width of the option list
        if (this._optionListWidth == null) {
            var leftBorder = 1;
            var rightBorder = 1;
            var leftPadding = 0;
            var rightPadding = 0;
            var style = this.get_optionListControl().style;


            // before doing anything, make sure overflow is auto
            style.overflow = 'auto';

            // first, default to the clientWidth of the container
            var bestWidth = this.get_comboTableControl().offsetWidth;

            // subtract borders from the offsetWidth
            bestWidth -= (leftBorder + rightBorder);
            if (bestWidth < 0) {
                bestWidth = 0;
            }

            // in order for ths list's scrollWidth to be correct, must set its width
            var originalWidth = style.width;
            style.width = bestWidth + 'px';

            // now compare the list's scrollWidth to the box width
            if (this.get_comboTableControl().offsetWidth < this.get_optionListControl().scrollWidth) {
                // allow the list to extend as wide as necessary according to its contents
                bestWidth = this.get_optionListControl().scrollWidth + rightPadding + leftPadding;
            }

            // hide the overflow, as there shouldn't be any scrollbars needed now
            style.overflow = 'hidden';

            // reset the list's width style to its original setting
            style.width = originalWidth;

            this._optionListWidth = bestWidth;
        }

        // protect against negative dimensions
        if (this._optionListWidth < 0) {
            this._optionListWidth = 0;
        }

        return this._optionListWidth;

    },
    _getWindowBounds: function() {

        var bounds = {
            x: this._getScrollLeft(),
            y: this._getScrollTop(),
            width: this._getWindowWidth(),
            height: this._getWindowHeight()
        };
        return bounds;

    },
    _getWindowHeight: function() {

        var windowHeight = 0;
        if (typeof (window.innerHeight) == 'number') {
            windowHeight = window.innerHeight;
        }
        else if (document.documentElement && document.documentElement.clientHeight) {
            windowHeight = document.documentElement.clientHeight;
        }
        else if (document.body && document.body.clientHeight) {
            windowHeight = document.body.clientHeight;
        }
        return windowHeight;

    },
    _getWindowWidth: function() {

        var windowWidth = 0;
        if (typeof (window.innerWidth) == 'number') {
            windowWidth = window.innerWidth;
        }
        else if (document.documentElement && document.documentElement.clientWidth) {
            windowWidth = document.documentElement.clientWidth;
        }
        else if (document.body && document.body.clientWidth) {
            windowWidth = document.body.clientWidth;
        }
        return windowWidth;

    },
    _getScrollTop: function() {

        var scrollTop = 0;
        if (typeof (window.pageYOffset) == 'number') {
            scrollTop = window.pageYOffset;
        }
        if (document.body && document.body.scrollTop) {
            scrollTop = document.body.scrollTop;
        }
        else if (document.documentElement && document.documentElement.scrollTop) {
            scrollTop = document.documentElement.scrollTop;
        }
        return scrollTop;

    },
    _getScrollLeft: function() {

        var scrollLeft = 0;
        if (typeof (window.pageXOffset) == 'number') {
            scrollLeft = window.pageXOffset;
        }
        else if (document.body && document.body.scrollLeft) {
            scrollLeft = document.body.scrollLeft;
        }
        else if (document.documentElement && document.documentElement.scrollLeft) {
            scrollLeft = document.documentElement.scrollLeft;
        }
        return scrollLeft;

    },
    set_comboTableControl: function(value) {

        if (this._comboTableControl !== value) {
            this._comboTableControl = value;
            this.raisePropertyChanged('comboTableControl');
        }

    },
    get_comboTableControl: function() {

        return this._comboTableControl;

    },
    set_textBoxControl: function(value) {

        if (this._textBoxControl !== value) {
            this._textBoxControl = value;
            this.raisePropertyChanged('textBoxControl');
        }

    },
    get_textBoxControl: function() {

        return this._textBoxControl;

    },
    set_buttonControl: function(value) {

        if (this._buttonControl !== value) {
            this._buttonControl = value;
            this.raisePropertyChanged('buttonControl');
        }

    },
    get_buttonControl: function() {
        return this._buttonControl;
    },
    set_optionListControl: function(value) {

        if (this._optionListControl !== value) {
            this._optionListControl = value;
            this.raisePropertyChanged('optionListControl');
        }

    },
    get_optionListControl: function() {

        return this._optionListControl;

    },
    set_hiddenFieldControl: function(value) {

        if (this._hiddenFieldControl !== value) {
            this._hiddenFieldControl = value;
            this.raisePropertyChanged('hiddenFieldControl');
        }

    },
    get_hiddenFieldControl: function() {

        return this._hiddenFieldControl;

    },
    set_selectedIndex: function(value) {

        if (this.get_hiddenFieldControl().value !== value.toString()) {
            this.get_hiddenFieldControl().value = value.toString();
            this._ensureSelectedIndex();
            this.raisePropertyChanged('selectedIndex');
        }

    },
    get_selectedIndex: function() {

        this._ensureSelectedIndex();
        var selectedIndex = this.get_hiddenFieldControl().value;
        return parseInt(selectedIndex);

    },
    set_autoPostBack: function(value) {

        if (this._autoPostBack !== value) {
            this._autoPostBack = value;
            this.raisePropertyChanged('autoPostBack');
        }

    },
    get_autoPostBack: function() {

        return this._autoPostBack;

    },
    set_autoCompleteMode: function(value) {

        if (this._autoCompleteMode !== value) {
            this._autoCompleteMode = value;
            this.raisePropertyChanged('autoCompleteMode');
        }

    },
    get_autoCompleteMode: function() {

        return this._autoCompleteMode;

    },
    set_dropDownStyle: function(value) {

        if (this._dropDownStyle !== value) {
            this._dropDownStyle = value;
            this.raisePropertyChanged('dropDownStyle');
        }

    },
    get_dropDownStyle: function() {

        return this._dropDownStyle;

    },
    set_caseSensitive: function(value) {

        if (this._caseSensitive !== value) {
            this._caseSensitive = value;
            this.raisePropertyChanged('caseSensitive');
        }

    },
    get_caseSensitive: function() {

        return this._caseSensitive;

    },
    set_listItemHoverCssClass: function(value) {

        if (this._listItemHoverCssClass !== value) {
            this._listItemHoverCssClass = value;
            this.raisePropertyChanged('listItemHoverCssClass');
        }

    },
    get_listItemHoverCssClass: function() {

        return this._listItemHoverCssClass;

    }

}

AjaxControlToolkit.ComboBox.registerClass('AjaxControlToolkit.ComboBox', Sys.UI.Control);

//if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();


if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();