Show:
                            /**
                             * The Textboxlist Utility - Full documentation coming soon.
                             *
                             * @module aui-textboxlist
                             */
                            
                            var Lang = A.Lang,
                            
                                getClassName = A.getClassName,
                            
                                ENTRY_NAME = 'textboxlistentry',
                                NAME = 'textboxlist',
                            
                                BOUNDING_BOX = 'boundingBox',
                                CONTENT_BOX = 'contentBox',
                            
                                CONFIG_ANIM = {
                                    from: {
                                        opacity: 1
                                    },
                                    to: {
                                        opacity: 0.3
                                    },
                                    duration: 0.1,
                                    on: {
                                        end: function(event) {
                                            var instance = this;
                            
                                            var reverse = instance.get('reverse');
                            
                                            if (!reverse) {
                                                instance.run();
                                            }
                            
                                            instance.set('reverse', !reverse);
                                        }
                                    }
                                },
                            
                                CSS_CLEARFIX = getClassName('helper', 'clearfix'),
                            
                                CSS_ENTRY_REMOVE = getClassName(ENTRY_NAME, 'remove'),
                                CSS_ENTRY_HOLDER = getClassName(ENTRY_NAME, 'holder'),
                                CSS_ENTRY_ITEM = getClassName(ENTRY_NAME, 'item'),
                                CSS_ENTRY_TEXT = getClassName(ENTRY_NAME, 'text'),
                                CSS_ICON = getClassName('icon'),
                                CSS_ICON_REMOVE = getClassName('icon', 'remove'),
                                CSS_ICON_REMOVE_HOVER = getClassName(ENTRY_NAME, 'remove', 'hover'),
                            
                                CSS_INPUT_CONTAINER = getClassName(NAME, 'input', 'container'),
                            
                                BACKSPACE = 'BACKSPACE',
                                ENTER = 'ENTER',
                                LEFT = 'LEFT',
                                RIGHT = 'RIGHT',
                            
                                TPL_ENTRY_HOLDER = '<ul class="' + [CSS_CLEARFIX, CSS_ENTRY_HOLDER, 'unstyled'].join(' ') + '"></ul>',
                                TPL_ENTRY_REMOVE = '<span class="' + CSS_ENTRY_REMOVE + '"><i class="' + [CSS_ICON, CSS_ICON_REMOVE].join(' ') +
                                    '"></i></span>',
                                TPL_ENTRY_TEXT = '<span class="' + CSS_ENTRY_TEXT + '"></span>',
                            
                                TPL_INPUT_CONTAINER = '<li class="' + CSS_INPUT_CONTAINER + '"></li>';
                            
                            /**
                             * A base class for Textboxlist, providing:
                             * <ul>
                             *    <li>Widget Lifecycle (initializer, renderUI, bindUI, syncUI, destructor)</li>
                             *    <li>Text box list</li>
                             * </ul>
                             *
                             * Check the list of <a href="Textboxlist.html#configattributes">Configuration Attributes</a> available for
                             * Textboxlist.
                             *
                             * @param config {Object} Object literal specifying widget configuration properties.
                             *
                             * @class Textboxlist
                             * @constructor
                             * @extends AutoComplete
                             */
                            var TextboxList = A.Component.create({
                                /**
                                 * Static property provides a string to identify the class.
                                 *
                                 * @property Textboxlist.NAME
                                 * @type String
                                 * @static
                                 */
                                NAME: NAME,
                            
                                /**
                                 * Static property used to define the default attribute
                                 * configuration for the Textboxlist.
                                 *
                                 * @property Textboxlist.ATTRS
                                 * @type Object
                                 * @static
                                 */
                                ATTRS: {
                                    allowAnyEntry: {
                                        value: false
                                    },
                                    delimChar: {
                                        value: ''
                                    },
                                    tabIndex: {
                                        value: 0
                                    }
                                },
                            
                                EXTENDS: A.AutoCompleteDeprecated,
                            
                                prototype: {
                                    /**
                                     * Construction logic executed during Textboxlist instantiation. Lifecycle.
                                     *
                                     * @method initializer
                                     * @protected
                                     */
                                    initializer: function(config) {
                                        var instance = this;
                            
                                        var matchKey = instance.get('matchKey');
                            
                                        instance.entries = new A.DataSet({
                                            getKey: function(obj) {
                                                var instance = this;
                            
                                                return obj[matchKey];
                                            }
                                        });
                            
                                        instance._lastSelectedEntry = -1;
                                    },
                            
                                    /**
                                     * Create the DOM structure for the Textboxlist. Lifecycle.
                                     *
                                     * @method renderUI
                                     * @protected
                                     */
                                    renderUI: function() {
                                        var instance = this;
                            
                                        instance._renderEntryHolder();
                            
                                        TextboxList.superclass.renderUI.apply(instance, arguments);
                            
                                        instance._overlayAlign.node = instance.get(BOUNDING_BOX);
                                    },
                            
                                    /**
                                     * Bind the events on the Textboxlist UI. Lifecycle.
                                     *
                                     * @method bindUI
                                     * @protected
                                     */
                                    bindUI: function() {
                                        var instance = this;
                            
                                        TextboxList.superclass.bindUI.apply(instance, arguments);
                            
                                        instance.after('itemSelect', instance._afterItemSelect);
                                        instance.after('focusedChange', instance._afterTBLFocusedChange);
                                        instance.on('click', instance._onBoundingBoxClick);
                            
                                        var entries = instance.entries;
                                        var entryHolder = instance.entryHolder;
                                        var closeSelector = '.' + CSS_ICON_REMOVE;
                            
                                        entries.after('add', instance._updateEntryHolder, instance);
                                        entries.after('replace', instance._updateEntryHolder, instance);
                                        entries.after('remove', instance._updateEntryHolder, instance);
                            
                                        entryHolder.delegate('click', A.bind(instance._removeItem, instance), closeSelector);
                                        entryHolder.delegate('mouseenter', A.bind(instance._onCloseIconMouseOver, instance), closeSelector);
                                        entryHolder.delegate('mouseleave', A.bind(instance._onCloseIconMouseOut, instance), closeSelector);
                            
                                        A.on(
                                            'key',
                                            instance._onTBLKeypress,
                                            instance.get(BOUNDING_BOX),
                                            'down:39,40,37,38,8,13',
                                            instance
                                        );
                            
                                        instance.inputNode.on('focus', instance._onInputNodeFocus, instance);
                            
                                        instance.inputField.after('focusedChange', function(event) {
                                            instance._set('focused', event.newVal, {src: 'inputfield'});
                                        });
                                    },
                            
                                    add: function(label) {
                                        var instance = this;
                            
                                        var entry = instance._prepareEntry(label);
                            
                                        instance.entries.add(entry);
                                    },
                            
                                    addEntries: function(instance) {
                                        var instance = this;
                                        var inputNode = instance.inputNode;
                            
                                        instance.entries.add(inputNode.val(), {});
                                    },
                            
                                    insert: function(index, label) {
                                        var instance = this;
                            
                                        var entry = instance._prepareEntry(label);
                            
                                        return instance.entries.insert(index, entry);
                                    },
                            
                                    remove: function(label) {
                                        var instance = this;
                            
                                        return instance.entries.removeKey(label);
                                    },
                            
                                    _afterItemSelect: function(elListItem) {
                                        var instance = this;
                            
                                        instance.entries.add(elListItem._resultData);
                            
                                    },
                            
                                    _afterTBLFocusedChange: function(event) {
                                        var instance = this;
                            
                                        if (event.type.indexOf('textboxlistentry') > -1) {
                                            if (event.newVal) {
                                                var entryBoundingBox = event.target.get(BOUNDING_BOX);
                            
                                                instance._lastSelectedEntry = instance.entryHolder.all('li').indexOf(entryBoundingBox);
                                            }
                                        }
                                    },
                            
                                    _onBoundingBoxClick: function(event) {
                                        var instance = this;
                            
                                        instance.inputNode.focus();
                                    },
                            
                                    _onCloseIconMouseOut: function(event) {
                                        var instance = this;
                            
                                        event.currentTarget.removeClass(CSS_ICON_REMOVE_HOVER);
                                    },
                            
                                    _onCloseIconMouseOver: function(event) {
                                        var instance = this;
                            
                                        event.currentTarget.addClass(CSS_ICON_REMOVE_HOVER);
                                    },
                            
                                    _onInputNodeFocus: function(event) {
                                        var instance = this;
                            
                                        instance._lastSelectedEntry = -1;
                                    },
                            
                                    _onTBLKeypress: function(event) {
                                        var instance = this;
                            
                                        var inputNode = instance.inputNode;
                            
                                        if (!inputNode.val()) {
                                            var lastSelectedEntry = instance._lastSelectedEntry;
                                            var currentSelectedEntry = -1;
                            
                                            var unselected = (lastSelectedEntry == -1);
                            
                                            var deleteEntry = event.isKey(BACKSPACE);
                                            var deleteBack = (deleteEntry && unselected);
                                            var moveBack = event.isKey(LEFT) || deleteBack;
                                            var moveForward = event.isKey(RIGHT);
                            
                                            var entries = instance.entries;
                            
                                            var entriesSize = entries.size();
                                            var lastEntryIndex = entriesSize - 1;
                            
                                            if (moveBack) {
                                                if (unselected) {
                                                    currentSelectedEntry = lastEntryIndex;
                                                }
                                                else if (lastSelectedEntry == 0) {
                                                    currentSelectedEntry = lastSelectedEntry;
                                                }
                                                else {
                                                    currentSelectedEntry = lastSelectedEntry - 1;
                                                }
                                            }
                                            else if (moveForward) {
                                                if (unselected || (lastSelectedEntry == lastEntryIndex)) {
                                                    currentSelectedEntry = -1;
                                                }
                                                else {
                                                    currentSelectedEntry = lastSelectedEntry + 1;
                                                }
                                            }
                                            else if (deleteEntry) {
                                                entries.removeAt(lastSelectedEntry);
                            
                                                entriesSize = entries.size();
                            
                                                if (lastSelectedEntry == entriesSize) {
                                                    currentSelectedEntry = -1;
                                                }
                                                else {
                                                    currentSelectedEntry = lastSelectedEntry;
                                                }
                                            }
                            
                                            if (deleteBack || deleteEntry) {
                                                event.halt();
                                            }
                            
                                            if (currentSelectedEntry != -1) {
                                                entries.item(currentSelectedEntry).entry.focus();
                                            }
                                            else {
                                                inputNode.focus();
                                            }
                            
                                            instance._lastSelectedEntry = currentSelectedEntry;
                                        }
                                        else {
                                            if (event.isKey(ENTER) && instance.get('allowAnyEntry')) {
                                                instance.addEntries();
                                            }
                                        }
                                    },
                            
                                    _onTextboxKeyPress: function(event) {
                                        var instance = this;
                            
                                        TextboxList.superclass._onTextboxKeyPress.apply(instance, arguments);
                            
                                        if (event.isKey(ENTER)) {
                                            event.halt();
                                        }
                                    },
                            
                                    _prepareEntry: function(label) {
                                        var instance = this;
                            
                                        var entry = {};
                                        var matchKey = instance.get('matchKey');
                            
                                        entry[matchKey] = label;
                            
                                        return entry;
                                    },
                            
                                    _realignContainer: function(event) {
                                        var instance = this;
                            
                                        instance.overlay.set('width', instance.get(BOUNDING_BOX).get('offsetWidth'));
                            
                                        TextboxList.superclass._realignContainer.apply(instance, arguments);
                                    },
                            
                                    _removeItem: function(event) {
                                        var instance = this;
                            
                                        var entry = A.Widget.getByNode(event.currentTarget);
                            
                                        entry = entry.get(BOUNDING_BOX);
                            
                                        var currentIndex = instance.entryHolder.all('li').indexOf(entry);
                            
                                        instance.entries.removeAt(currentIndex);
                                    },
                            
                                    _renderEntryHolder: function() {
                                        var instance = this;
                            
                                        var contentBox = instance.get(CONTENT_BOX);
                                        var entryHolder = A.Node.create(TPL_ENTRY_HOLDER);
                            
                                        contentBox.prepend(entryHolder);
                            
                                        instance.entryHolder = entryHolder;
                                    },
                            
                                    _renderInput: function() {
                                        var instance = this;
                            
                                        var contentBox = instance.get(CONTENT_BOX);
                                        var input = instance.get('input');
                            
                                        var fieldConfig = {
                                            labelText: false
                                        };
                            
                                        var inputParent = null;
                            
                                        if (input) {
                                            input = A.one(input);
                            
                                            fieldConfig.node = input;
                            
                                            inputParent = input.get('parentNode');
                                        }
                            
                                        var inputContainer = A.Node.create(TPL_INPUT_CONTAINER);
                            
                                        instance.entryHolder.append(inputContainer);
                            
                                        var inputField = new A.Textfield(fieldConfig).render(inputContainer);
                                        var inputBoundingBox = inputField.get(BOUNDING_BOX);
                            
                                        if (inputBoundingBox.get('parentNode') != inputContainer) {
                                            inputContainer.appendChild(inputBoundingBox);
                                        }
                            
                                        instance.inputContainer = inputContainer;
                                        instance.inputField = inputField;
                                        instance.inputNode = inputField.get('node');
                                        instance.button = new A.ButtonItem();
                            
                                        instance.set('uniqueName', A.stamp(instance.inputNode));
                                    },
                            
                                    _updateEntryHolder: function(event) {
                                        var instance = this;
                            
                                        var eventType = event.type;
                                        var inputNode = instance.inputNode;
                                        var entryHolder = instance.entryHolder;
                                        var item = event.item;
                                        var index = event.index;
                            
                                        var matchKey = instance.get('matchKey');
                            
                                        var key = item[matchKey] || event.attrName;
                            
                                        if (key) {
                                            if (eventType == 'dataset:add') {
                                                var entry = new TextboxListEntry({
                                                    labelText: key
                                                });
                            
                                                entry.addTarget(instance);
                            
                                                var entryNode = entry.get(BOUNDING_BOX);
                            
                                                entry.render(entryHolder);
                            
                                                entryHolder.all('li').item(index).placeBefore(entryNode);
                            
                                                entryNode.plug(A.Plugin.NodeFX, CONFIG_ANIM);
                            
                                                item.entry = entry;
                            
                                                inputNode.val('');
                                            }
                                            else if (eventType == 'dataset:replace') {
                                                inputNode.val('');
                            
                                                var entry = event.prevVal.entry;
                            
                                                item.entry = entry;
                            
                                                entry.get(BOUNDING_BOX).fx.run();
                                            }
                                            else if (eventType == 'dataset:remove') {
                                                var entryNodes = entryHolder.all('li');
                            
                                                if (entryNodes) {
                                                    entryNodes.item(index).remove();
                                                }
                                            }
                                        }
                                        else {
                                            instance.entries.removeAt(index);
                                        }
                                    }
                                }
                            });
                            
                            var TextboxListEntry = A.Component.create({
                                NAME: ENTRY_NAME,
                            
                                ATTRS: {
                                    labelText: {
                                        value: ''
                                    },
                                    tabIndex: {
                                        value: 0
                                    }
                                },
                            
                                prototype: {
                                    BOUNDING_TEMPLATE: '<li></li>',
                                    CONTENT_TEMPLATE: '<span></span>',
                                    renderUI: function() {
                                        var instance = this;
                            
                                        var contentBox = instance.get(CONTENT_BOX);
                            
                                        var text = A.Node.create(TPL_ENTRY_TEXT);
                                        var close = A.Node.create(TPL_ENTRY_REMOVE);
                            
                                        var labelText = A.Escape.html(instance.get('labelText'));
                            
                                        text.set('innerHTML', labelText);
                            
                                        contentBox.appendChild(text);
                                        contentBox.appendChild(close);
                                    }
                                }
                            });
                            
                            A.TextboxList = TextboxList;
                            A.TextboxListEntry = TextboxListEntry;