    /**
     * A mechanism for displaying data using custom layout templates and formatting.
     *
     * The View uses an {@link Ext.XTemplate} as its internal templating mechanism, and is bound to an
     * {@link Ext.data.Store} so that as the data in the store changes the view is automatically updated
     * to reflect the changes. The view also provides built-in behavior for many common events that can
     * occur for its contained items including click, doubleclick, mouseover, mouseout, etc. as well as a
     * built-in selection model. **In order to use these features, an {@link #itemSelector} config must
     * be provided for the View to determine what nodes it will be working with.**
     *
     * The example below binds a View to a {@link Ext.data.Store} and renders it into an {@link Ext.panel.Panel}.
     *
     *     @example
     *     Ext.define('Image', {
     *         extend: 'Ext.data.Model',
     *         fields: [
     *             { name:'src', type:'string' },
     *             { name:'caption', type:'string' }
     *         ]
     *     });
     *
     *     Ext.create('Ext.data.Store', {
     *         id:'imagesStore',
     *         model: 'Image',
     *         data: [
     *             { src:'http://www.sencha.com/img/20110215-feat-drawing.png', caption:'Drawing & Charts' },
     *             { src:'http://www.sencha.com/img/20110215-feat-data.png', caption:'Advanced Data' },
     *             { src:'http://www.sencha.com/img/20110215-feat-html5.png', caption:'Overhauled Theme' },
     *             { src:'http://www.sencha.com/img/20110215-feat-perf.png', caption:'Performance Tuned' }
     *         ]
     *     });
     *
     *     var imageTpl = new Ext.XTemplate(
     *         '<tpl for=".">',
     *             '<div style="margin-bottom: 10px;" class="thumb-wrap">',
     *               '<img src="{src}" />',
     *               '<br/><span>{caption}</span>',
     *             '</div>',
     *         '</tpl>'
     *     );
     *
     *     Ext.create('Ext.view.View', {
     *         store: Ext.data.StoreManager.lookup('imagesStore'),
     *         tpl: imageTpl,
     *         itemSelector: 'div.thumb-wrap',
     *         emptyText: 'No images available',
     *         renderTo: Ext.getBody()
     *     });
     */
    Ext.define('Ext.view.View', {
        extend: 'Ext.view.AbstractView',
        alternateClassName: 'Ext.DataView',
        alias: 'widget.dataview',

        // private delay to buffer row highlighting/unhighlighting on mouse move.
        // This is ignored if the public mouseOverOutBuffer remains a non-zero value
        deferHighlight: Ext.isIE7m ? 100 : 0,

        /**
         * @cfg {Number} [mouseOverOutBuffer=20]
         * The number of milliseconds to buffer mouseover and mouseout event handling on view items.
         *
         * Configure this as `false` to process mouseover and mouseout events immediately.
         */
        mouseOverOutBuffer: 20,

        inputTagRe: /^textarea$|^input$/i,

        inheritableStatics: {
            EventMap: {
                mousedown: 'MouseDown',
                mouseup: 'MouseUp',
                click: 'Click',
                dblclick: 'DblClick',
                contextmenu: 'ContextMenu',
                mouseover: 'MouseOver',
                mouseout: 'MouseOut',
                mouseenter: 'MouseEnter',
                mouseleave: 'MouseLeave',
                keydown: 'KeyDown',
                focus: 'Focus'
            }
        },

        initComponent: function() {
            var me = this;
            me.callParent();

            // Buffer the calls to handleMouseOver and handleMouseOut if configured to do so.
            if (me.mouseOverOutBuffer) {
                me.handleMouseOver =
                    Ext.Function.createBuffered(me.handleMouseOver, me.mouseOverOutBuffer, me);
                me.handleMouseOut =
                    Ext.Function.createBuffered(me.handleMouseOut, me.mouseOverOutBuffer, me);
                me.lastMouseOverEvent = new Ext.EventObjectImpl();
                me.lastMouseOutEvent = new Ext.EventObjectImpl();
            }

            // Not buffering mouse over/out handling - buffer item highlighting.
            else if (me.deferHighlight){
                me.setHighlightedItem =
                    Ext.Function.createBuffered(me.setHighlightedItem, me.deferHighlight, me);
            }
        },

        addCmpEvents: function() {
            this.addEvents(
                /**
                 * @event beforeitemmousedown
                 * Fires before the mousedown event on an item is processed. Returns false to cancel the default action.
                 * @param {Ext.view.View} this
                 * @param {Ext.data.Model} record The record that belongs to the item
                 * @param {HTMLElement} item The item's element
                 * @param {Number} index The item's index
                 * @param {Ext.EventObject} e The raw event object
                 */
                'beforeitemmousedown',
                /**
                 * @event beforeitemmouseup
                 * Fires before the mouseup event on an item is processed. Returns false to cancel the default action.
                 * @param {Ext.view.View} this
                 * @param {Ext.data.Model} record The record that belongs to the item
                 * @param {HTMLElement} item The item's element
                 * @param {Number} index The item's index
                 * @param {Ext.EventObject} e The raw event object
                 */
                'beforeitemmouseup',
                /**
                 * @event beforeitemmouseenter
                 * Fires before the mouseenter event on an item is processed. Returns false to cancel the default action.
                 * @param {Ext.view.View} this
                 * @param {Ext.data.Model} record The record that belongs to the item
                 * @param {HTMLElement} item The item's element
                 * @param {Number} index The item's index
                 * @param {Ext.EventObject} e The raw event object
                 */
                'beforeitemmouseenter',
                /**
                 * @event beforeitemmouseleave
                 * Fires before the mouseleave event on an item is processed. Returns false to cancel the default action.
                 * @param {Ext.view.View} this
                 * @param {Ext.data.Model} record The record that belongs to the item
                 * @param {HTMLElement} item The item's element
                 * @param {Number} index The item's index
                 * @param {Ext.EventObject} e The raw event object
                 */
                'beforeitemmouseleave',
                /**
                 * @event beforeitemclick
                 * Fires before the click event on an item is processed. Returns false to cancel the default action.
                 * @param {Ext.view.View} this
                 * @param {Ext.data.Model} record The record that belongs to the item
                 * @param {HTMLElement} item The item's element
                 * @param {Number} index The item's index
                 * @param {Ext.EventObject} e The raw event object
                 */
                'beforeitemclick',
                /**
                 * @event beforeitemdblclick
                 * Fires before the dblclick event on an item is processed. Returns false to cancel the default action.
                 * @param {Ext.view.View} this
                 * @param {Ext.data.Model} record The record that belongs to the item
                 * @param {HTMLElement} item The item's element
                 * @param {Number} index The item's index
                 * @param {Ext.EventObject} e The raw event object
                 */
                'beforeitemdblclick',
                /**
                 * @event beforeitemcontextmenu
                 * Fires before the contextmenu event on an item is processed. Returns false to cancel the default action.
                 * @param {Ext.view.View} this
                 * @param {Ext.data.Model} record The record that belongs to the item
                 * @param {HTMLElement} item The item's element
                 * @param {Number} index The item's index
                 * @param {Ext.EventObject} e The raw event object
                 */
                'beforeitemcontextmenu',
                /**
                 * @event beforeitemkeydown
                 * Fires before the keydown event on an item is processed. Returns false to cancel the default action.
                 * @param {Ext.view.View} this
                 * @param {Ext.data.Model} record The record that belongs to the item
                 * @param {HTMLElement} item The item's element
                 * @param {Number} index The item's index
                 * @param {Ext.EventObject} e The raw event object. Use {@link Ext.EventObject#getKey getKey()} to retrieve the key that was pressed.
                 */
                'beforeitemkeydown',
                /**
                 * @event itemmousedown
                 * Fires when there is a mouse down on an item
                 * @param {Ext.view.View} this
                 * @param {Ext.data.Model} record The record that belongs to the item
                 * @param {HTMLElement} item The item's element
                 * @param {Number} index The item's index
                 * @param {Ext.EventObject} e The raw event object
                 */
                'itemmousedown',
                /**
                 * @event itemmouseup
                 * Fires when there is a mouse up on an item
                 * @param {Ext.view.View} this
                 * @param {Ext.data.Model} record The record that belongs to the item
                 * @param {HTMLElement} item The item's element
                 * @param {Number} index The item's index
                 * @param {Ext.EventObject} e The raw event object
                 */
                'itemmouseup',
                /**
                 * @event itemmouseenter
                 * Fires when the mouse enters an item.
                 * @param {Ext.view.View} this
                 * @param {Ext.data.Model} record The record that belongs to the item
                 * @param {HTMLElement} item The item's element
                 * @param {Number} index The item's index
                 * @param {Ext.EventObject} e The raw event object
                 */
                'itemmouseenter',
                /**
                 * @event itemmouseleave
                 * Fires when the mouse leaves an item.
                 * @param {Ext.view.View} this
                 * @param {Ext.data.Model} record The record that belongs to the item
                 * @param {HTMLElement} item The item's element
                 * @param {Number} index The item's index
                 * @param {Ext.EventObject} e The raw event object
                 */
                'itemmouseleave',
                /**
                 * @event itemclick
                 * Fires when an item is clicked.
                 * @param {Ext.view.View} this
                 * @param {Ext.data.Model} record The record that belongs to the item
                 * @param {HTMLElement} item The item's element
                 * @param {Number} index The item's index
                 * @param {Ext.EventObject} e The raw event object
                 */
                'itemclick',
                /**
                 * @event itemdblclick
                 * Fires when an item is double clicked.
                 * @param {Ext.view.View} this
                 * @param {Ext.data.Model} record The record that belongs to the item
                 * @param {HTMLElement} item The item's element
                 * @param {Number} index The item's index
                 * @param {Ext.EventObject} e The raw event object
                 */
                'itemdblclick',
                /**
                 * @event itemcontextmenu
                 * Fires when an item is right clicked.
                 * @param {Ext.view.View} this
                 * @param {Ext.data.Model} record The record that belongs to the item
                 * @param {HTMLElement} item The item's element
                 * @param {Number} index The item's index
                 * @param {Ext.EventObject} e The raw event object
                 */
                'itemcontextmenu',
                /**
                 * @event itemkeydown
                 * Fires when a key is pressed while an item is currently selected.
                 * @param {Ext.view.View} this
                 * @param {Ext.data.Model} record The record that belongs to the item
                 * @param {HTMLElement} item The item's element
                 * @param {Number} index The item's index
                 * @param {Ext.EventObject} e The raw event object. Use {@link Ext.EventObject#getKey getKey()} to retrieve the key that was pressed.
                 */
                'itemkeydown',
                /**
                 * @event beforecontainermousedown
                 * Fires before the mousedown event on the container is processed. Returns false to cancel the default action.
                 * @param {Ext.view.View} this
                 * @param {Ext.EventObject} e The raw event object
                 */
                'beforecontainermousedown',
                /**
                 * @event beforecontainermouseup
                 * Fires before the mouseup event on the container is processed. Returns false to cancel the default action.
                 * @param {Ext.view.View} this
                 * @param {Ext.EventObject} e The raw event object
                 */
                'beforecontainermouseup',
                /**
                 * @event beforecontainermouseover
                 * Fires before the mouseover event on the container is processed. Returns false to cancel the default action.
                 * @param {Ext.view.View} this
                 * @param {Ext.EventObject} e The raw event object
                 */
                'beforecontainermouseover',
                /**
                 * @event beforecontainermouseout
                 * Fires before the mouseout event on the container is processed. Returns false to cancel the default action.
                 * @param {Ext.view.View} this
                 * @param {Ext.EventObject} e The raw event object
                 */
                'beforecontainermouseout',
                /**
                 * @event beforecontainerclick
                 * Fires before the click event on the container is processed. Returns false to cancel the default action.
                 * @param {Ext.view.View} this
                 * @param {Ext.EventObject} e The raw event object
                 */
                'beforecontainerclick',
                /**
                 * @event beforecontainerdblclick
                 * Fires before the dblclick event on the container is processed. Returns false to cancel the default action.
                 * @param {Ext.view.View} this
                 * @param {Ext.EventObject} e The raw event object
                 */
                'beforecontainerdblclick',
                /**
                 * @event beforecontainercontextmenu
                 * Fires before the contextmenu event on the container is processed. Returns false to cancel the default action.
                 * @param {Ext.view.View} this
                 * @param {Ext.EventObject} e The raw event object
                 */
                'beforecontainercontextmenu',
                /**
                 * @event beforecontainerkeydown
                 * Fires before the keydown event on the container is processed. Returns false to cancel the default action.
                 * @param {Ext.view.View} this
                 * @param {Ext.EventObject} e The raw event object. Use {@link Ext.EventObject#getKey getKey()} to retrieve the key that was pressed.
                 */
                'beforecontainerkeydown',
                /**
                 * @event containermouseup
                 * Fires when there is a mouse up on the container
                 * @param {Ext.view.View} this
                 * @param {Ext.EventObject} e The raw event object
                 */
                'containermouseup',
                /**
                 * @event containermouseover
                 * Fires when you move the mouse over the container.
                 * @param {Ext.view.View} this
                 * @param {Ext.EventObject} e The raw event object
                 */
                'containermouseover',
                /**
                 * @event containermouseout
                 * Fires when you move the mouse out of the container.
                 * @param {Ext.view.View} this
                 * @param {Ext.EventObject} e The raw event object
                 */
                'containermouseout',
                /**
                 * @event containerclick
                 * Fires when the container is clicked.
                 * @param {Ext.view.View} this
                 * @param {Ext.EventObject} e The raw event object
                 */
                'containerclick',
                /**
                 * @event containerdblclick
                 * Fires when the container is double clicked.
                 * @param {Ext.view.View} this
                 * @param {Ext.EventObject} e The raw event object
                 */
                'containerdblclick',
                /**
                 * @event containercontextmenu
                 * Fires when the container is right clicked.
                 * @param {Ext.view.View} this
                 * @param {Ext.EventObject} e The raw event object
                 */
                'containercontextmenu',
                /**
                 * @event containerkeydown
                 * Fires when a key is pressed while the container is focused, and no item is currently selected.
                 * @param {Ext.view.View} this
                 * @param {Ext.EventObject} e The raw event object. Use {@link Ext.EventObject#getKey getKey()} to retrieve the key that was pressed.
                 */
                'containerkeydown',

                /**
                 * @event
                 * @inheritdoc Ext.selection.DataViewModel#selectionchange
                 */
                'selectionchange',
                /**
                 * @event
                 * @inheritdoc Ext.selection.DataViewModel#beforeselect
                 */
                'beforeselect',
                /**
                 * @event
                 * @inheritdoc Ext.selection.DataViewModel#beforedeselect
                 */
                'beforedeselect',
                /**
                 * @event
                 * @inheritdoc Ext.selection.DataViewModel#select
                 */
                'select',
                /**
                 * @event
                 * @inheritdoc Ext.selection.DataViewModel#deselect
                 */
                'deselect',
                /**
                 * @event
                 * @inheritdoc Ext.selection.DataViewModel#focuschange
                 */
                'focuschange',

                /**
                 * @event highlightitem
                 * Fires when a node is highlighted using keyboard navigation, or mouseover.
                 * @param {Ext.view.View} view This View Component.
                 * @param {Ext.Element} node The highlighted node.
                 */
                'highlightitem',

                /**
                 * @event unhighlightitem
                 * Fires when a node is unhighlighted using keyboard navigation, or mouseout.
                 * @param {Ext.view.View} view This View Component.
                 * @param {Ext.Element} node The previously highlighted node.
                 */
                'unhighlightitem'
            );
        },

        getFocusEl: function() {
            return this.getTargetEl();
        },

        // @private
        afterRender: function() {
            var me = this,
                buffer = me.mouseOverOutBuffer;

            me.callParent();
            me.mon(me.getTargetEl(), {
                scope: me,
                /*
                 * We need to make copies of this since some of the events fired here will end up triggering
                 * a new event to be called and the shared event object will be mutated. In future we should
                 * investigate if there are any issues with creating a new event object for each event that
                 * is fired.
                 */
                freezeEvent: true,
                click: me.handleEvent,
                mousedown: me.handleEvent,
                mouseup: me.handleEvent,
                dblclick: me.handleEvent,
                contextmenu: me.handleEvent,
                keydown: me.handleEvent,
                mouseover: buffer ? me.onMouseOver : me.handleMouseOver,
                mouseout:  buffer ? me.onMouseOut : me.handleMouseOut
            });
        },

        onMouseOver: function(e) {
            var me = this;

            // mouseover events are deferred until mouse move churn settles down.
            // at that time, only the last mousover event will be fired.
            me.lastMouseOverEvent.setEvent(e.browserEvent, true);
            me.handleMouseOver(me.lastMouseOverEvent);
        },

        onMouseOut: function(e) {
            var me = this;

            // mouseout events are deferred until mouse move churn settles down.
            // at that time, only the first mousout event will be fired.
            if (!me._mouseOutPending) {
                me._mouseOutPending = true;
                me.lastMouseOutEvent.setEvent(e.browserEvent, true);
                me.handleMouseOut(me.lastMouseOutEvent);
            }
        },

        handleMouseOver: function(e) {
            var me = this,
                itemSelector = me.dataRowSelector || me.itemSelector,
                item = e.getTarget(itemSelector);

            // If mouseover/out handling is buffered, view might have been destyroyed during buffer time.
            if (!me.isDestroyed) {
                if (item) {
                    if (me.mouseOverItem !== item && me.el.contains(item)) {
                        me.mouseOverItem = e.item = item;
                        e.newType = 'mouseenter';
                        me.handleEvent(e);
                    }
                } else {
                    // not over a item, handle container event
                    e.item = e.newType = null;
                    me.handleEvent(e);
                }
            }
        },

        handleMouseOut: function(e) {
            var me = this,
                itemSelector = me.dataRowSelector || me.itemSelector,
                item = e.getTarget(itemSelector),
                sourceView;

            // If mouseover/out handling is buffered, view might have been destyroyed during buffer time.
            if (!me.isDestroyed) {
                me._mouseOutPending = false;

                if (item) {
                    if (e.getRelatedTarget(itemSelector) !== item && me.mouseOverItem === item) {
                        sourceView = me.self.getBoundView(item);
                        e.item = item;
                        e.newType = 'mouseleave';
                        sourceView.handleEvent(e);
                        sourceView.mouseOverItem = null;
                    }
                } else {
                    // not over a item, handle container event
                    e.item = e.newType = null;
                    me.handleEvent(e);
                }
            }

            // When not buffering mouseover events, the event is a singleton; clear for next usage.
            e.newType = e.item = null;
        },

        handleEvent: function(e) {
            var me = this,
                key = e.type == 'keydown' && e.getKey();

            if (me.processUIEvent(e) !== false) {
                me.processSpecialEvent(e);
            }

            // After all listeners have processed the event, then unless the user is typing into an input field,
            // prevent browser's default action on SPACE which is to focus the event's target element.
            // Focusing causes the browser to attempt to scroll the element into view.
            if (key === e.SPACE) {
                if (!me.inputTagRe.test(e.getTarget().tagName)) {
                    e.stopEvent();
                }
            }
        },

        // Private template method
        processItemEvent: Ext.emptyFn,
        processContainerEvent: Ext.emptyFn,
        processSpecialEvent: Ext.emptyFn,

        processUIEvent: function(e) {

            // If the target event has been removed from the body (data update causing view DOM to be updated),
            // do not process. isAncestor uses native methods to check.
            if (!Ext.getBody().isAncestor(e.target)) {
                return;
            }

            var me = this,
                item = e.getTarget(me.dataRowSelector || me.itemSelector, me.getTargetEl()),
                map = me.statics().EventMap,
                index, record,
                type = e.type,
                newType = e.type,
                sm;

            // If the event is a mouseover/mouseout event converted to a mouseenter/mouseleave,
            // use that event type and ensure that the item is correct.
            if (e.newType) {
                newType = e.newType;
                item = e.item;
            }

            // For keydown events, try to get either the last focused item or the selected item.
            // If we have not focused an item, we'll just fire a container keydown event.
            if (!item && type == 'keydown') {
                sm = me.getSelectionModel();
                record = sm.lastFocused || sm.getLastSelected();
                if (record) {
                    item = me.getNode(record, true);
                }
            }

            if (item) {
                if (!record) {
                    record = me.getRecord(item);
                }
                index = me.indexInStore ? me.indexInStore(record) : me.indexOf(item);

                // It is possible for an event to arrive for which there is no record... this
                // can happen with dblclick where the clicks are on removal actions (think a
                // grid w/"delete row" action column) or if the record was in a page that was
                // pruned by a buffered store.
                if (!record || me.processItemEvent(record, item, index, e) === false) {
                    return false;
                }

                if (
                    (me['onBeforeItem' + map[newType]](record, item, index, e) === false) ||
                    (me.fireEvent('beforeitem' + newType, me, record, item, index, e) === false) ||
                    (me['onItem' + map[newType]](record, item, index, e) === false)
                ) {
                    return false;
                }

                me.fireEvent('item' + newType, me, record, item, index, e);
            }
            else {
                if (
                    (me.processContainerEvent(e) === false) ||
                    (me['onBeforeContainer' + map[type]](e) === false) ||
                    (me.fireEvent('beforecontainer' + type, me, e) === false) ||
                    (me['onContainer' + map[type]](e) === false)
                ) {
                    return false;
                }

                me.fireEvent('container' + type, me, e);
            }

            return true;
        },

        // @private
        onItemMouseEnter: function(record, item, index, e) {
            if (this.trackOver) {
                this.highlightItem(item);
            }
        },

        // @private
        onItemMouseLeave : function(record, item, index, e) {
            if (this.trackOver) {
                this.clearHighlight();
            }
        },

        // private, template methods
        onItemMouseDown: Ext.emptyFn,
        onItemMouseUp: Ext.emptyFn,
        onItemFocus: Ext.emptyFn,
        onItemClick: Ext.emptyFn,
        onItemDblClick: Ext.emptyFn,
        onItemContextMenu: Ext.emptyFn,
        onItemKeyDown: Ext.emptyFn,
        onBeforeItemMouseDown: Ext.emptyFn,
        onBeforeItemMouseUp: Ext.emptyFn,
        onBeforeItemFocus: Ext.emptyFn,
        onBeforeItemMouseEnter: Ext.emptyFn,
        onBeforeItemMouseLeave: Ext.emptyFn,
        onBeforeItemClick: Ext.emptyFn,
        onBeforeItemDblClick: Ext.emptyFn,
        onBeforeItemContextMenu: Ext.emptyFn,
        onBeforeItemKeyDown: Ext.emptyFn,

        // private, template methods
        onContainerMouseDown: Ext.emptyFn,
        onContainerMouseUp: Ext.emptyFn,
        onContainerMouseOver: Ext.emptyFn,
        onContainerMouseOut: Ext.emptyFn,
        onContainerClick: Ext.emptyFn,
        onContainerDblClick: Ext.emptyFn,
        onContainerContextMenu: Ext.emptyFn,
        onContainerKeyDown: Ext.emptyFn,
        onBeforeContainerMouseDown: Ext.emptyFn,
        onBeforeContainerMouseUp: Ext.emptyFn,
        onBeforeContainerMouseOver: Ext.emptyFn,
        onBeforeContainerMouseOut: Ext.emptyFn,
        onBeforeContainerClick: Ext.emptyFn,
        onBeforeContainerDblClick: Ext.emptyFn,
        onBeforeContainerContextMenu: Ext.emptyFn,
        onBeforeContainerKeyDown: Ext.emptyFn,

        // @private
        setHighlightedItem: function(item){
            var me = this,
                highlighted = me.highlightedItem,
                overItemCls = me.overItemCls,
                beforeOverItemCls = me.beforeOverItemCls,
                previous;

            if (highlighted != item){
                if (highlighted) {
                    Ext.fly(highlighted).removeCls(overItemCls);
                    previous = highlighted.previousSibling;
                    if (beforeOverItemCls && previous) {
                        Ext.fly(previous).removeCls(beforeOverItemCls);
                    }
                    me.fireEvent('unhighlightitem', me, highlighted);
                }

                me.highlightedItem = item;

                if (item) {
                    Ext.fly(item).addCls(me.overItemCls);
                    previous = item.previousSibling;
                    if (beforeOverItemCls && previous) {
                        Ext.fly(previous).addCls(beforeOverItemCls);
                    }
                    me.fireEvent('highlightitem', me, item);
                }
            }
        },

        /**
         * Highlights a given item in the View. This is called by the mouseover handler if {@link #overItemCls}
         * and {@link #trackOver} are configured, but can also be called manually by other code, for instance to
         * handle stepping through the list via keyboard navigation.
         * @param {HTMLElement} item The item to highlight
         */
        highlightItem: function(item) {
            this.setHighlightedItem(item);
        },

        /**
         * Un-highlights the currently highlighted item, if any.
         */
        clearHighlight: function() {
            this.setHighlightedItem(undefined);
        },

        onUpdate: function(store, record){
            var me = this,
                node,
                newNode,
                highlighted;

            if (me.viewReady) {
                node = me.getNode(record);
                newNode = me.callParent(arguments);
                highlighted = me.highlightedItem;

                if (highlighted && highlighted === node) {
                    delete me.highlightedItem;
                    if (newNode) {
                        me.highlightItem(newNode);
                    }
                }
            }
        },

        refresh: function() {
            this.clearHighlight();
            this.callParent(arguments);
        },

        /**
         * Focuses a node in the view.
         * @param {Ext.data.Model} rec The record associated to the node that is to be focused.
         */
        focusNode: function(rec){
            var me          = this,
                node        = me.getNode(rec, true),
                el          = me.el,
                adjustmentY = 0,
                adjustmentX = 0,
                elRegion    = el.getRegion(),
                nodeRegion;

            // Viewable region must not include scrollbars, so use
            // DOM client dimensions
            elRegion.bottom = elRegion.top + el.dom.clientHeight;
            elRegion.right = elRegion.left + el.dom.clientWidth;
            if (node) {
                nodeRegion = Ext.fly(node).getRegion();
                // node is above
                if (nodeRegion.top < elRegion.top) {
                    adjustmentY = nodeRegion.top - elRegion.top;
                // node is below
                } else if (nodeRegion.bottom > elRegion.bottom) {
                    adjustmentY = nodeRegion.bottom - elRegion.bottom;
                }

                // node is left
                if (nodeRegion.left < elRegion.left) {
                    adjustmentX = nodeRegion.left - elRegion.left;
                // node is right
                } else if (nodeRegion.right > elRegion.right) {
                    adjustmentX = nodeRegion.right - elRegion.right;
                }

                if (adjustmentX || adjustmentY) {
                    me.scrollBy(adjustmentX, adjustmentY, false);
                }
                el.focus();
            }
        },

        bindStore: function (store, initial, propertyName) {
            // There could be different data sources (store or dataSource), so figure that out here.
            var dataSource = this[propertyName];

            if (dataSource && dataSource.isFeatureStore) {
                // Feature stores will call their own implementation of .bindStore().
                //
                // The passed 'store' function arg will be one of two types depending on the caller.
                //    1. regular data store
                //    2. grid feature store (data store is bound to it in featureStore.store).
                if (store.isFeatureStore) {
                    // The store listeners need to be bound to the feature store.
                    this.bindStoreListeners(store);
                    // Pass in the regular data store.
                    dataSource.bindStore(dataSource.store);
                } else {
                    dataSource.bindStore(store);
                }
            } else {
                this.callParent(arguments);
            }
        }
    });