Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / View3.html
index 91c04c5..ae1c1f6 100644 (file)
@@ -3,8 +3,8 @@
 <head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   <title>The source code</title>
-  <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
-  <script type="text/javascript" src="../prettify/prettify.js"></script>
+  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
+  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
   <style type="text/css">
     .highlight { display: block; background-color: #ddd; }
   </style>
   </script>
 </head>
 <body onload="prettyPrint(); highlight();">
-  <pre class="prettyprint lang-js"><span id='Ext-tree-View'>/**
-</span> * @class Ext.tree.View
- * @extends Ext.view.Table
+  <pre class="prettyprint lang-js"><span id='Ext-view-View'>/**
+</span> * 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 DataView 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 &amp; 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(
+ *         '&lt;tpl for=&quot;.&quot;&gt;',
+ *             '&lt;div style=&quot;margin-bottom: 10px;&quot; class=&quot;thumb-wrap&quot;&gt;',
+ *               '&lt;img src=&quot;{src}&quot; /&gt;',
+ *               '&lt;br/&gt;&lt;span&gt;{caption}&lt;/span&gt;',
+ *             '&lt;/div&gt;',
+ *         '&lt;/tpl&gt;'
+ *     );
+ *
+ *     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.tree.View', {
-    extend: 'Ext.view.Table',
-    alias: 'widget.treeview',
-
-    loadingCls: Ext.baseCSSPrefix + 'grid-tree-loading',
-    expandedCls: Ext.baseCSSPrefix + 'grid-tree-node-expanded',
-
-    expanderSelector: '.' + Ext.baseCSSPrefix + 'tree-expander',
-    checkboxSelector: '.' + Ext.baseCSSPrefix + 'tree-checkbox',
-    expanderIconOverCls: Ext.baseCSSPrefix + 'tree-expander-over',
-
-    blockRefresh: true,
-
-<span id='Ext-tree-View-cfg-rootVisible'>    /** 
-</span>     * @cfg {Boolean} rootVisible &lt;tt&gt;false&lt;/tt&gt; to hide the root node (defaults to &lt;tt&gt;true&lt;/tt&gt;)
-     */
-    rootVisible: true,
-
-<span id='Ext-tree-View-cfg-animate'>    /** 
-</span>     * @cfg {Boolean} animate &lt;tt&gt;true&lt;/tt&gt; to enable animated expand/collapse (defaults to the value of {@link Ext#enableFx Ext.enableFx})
-     */
-
-    expandDuration: 250,
-    collapseDuration: 250,
-    
-    toggleOnDblClick: true,
-
-    initComponent: function() {
-        var me = this;
-        
-        if (me.initialConfig.animate === undefined) {
-            me.animate = Ext.enableFx;
-        }
-        
-        me.store = Ext.create('Ext.data.NodeStore', {
-            recursive: true,
-            rootVisible: me.rootVisible,
-            listeners: {
-                beforeexpand: me.onBeforeExpand,
-                expand: me.onExpand,
-                beforecollapse: me.onBeforeCollapse,
-                collapse: me.onCollapse,
-                scope: me
-            }
-        });
-        
-        if (me.node) {
-            me.setRootNode(me.node);
+Ext.define('Ext.view.View', {
+    extend: 'Ext.view.AbstractView',
+    alternateClassName: 'Ext.DataView',
+    alias: 'widget.dataview',
+
+    inheritableStatics: {
+        EventMap: {
+            mousedown: 'MouseDown',
+            mouseup: 'MouseUp',
+            click: 'Click',
+            dblclick: 'DblClick',
+            contextmenu: 'ContextMenu',
+            mouseover: 'MouseOver',
+            mouseout: 'MouseOut',
+            mouseenter: 'MouseEnter',
+            mouseleave: 'MouseLeave',
+            keydown: 'KeyDown',
+            focus: 'Focus'
         }
-        me.animQueue = {};
-        me.callParent(arguments);
-    },
-    
-    onClear: function(){
-        this.store.removeAll();    
     },
 
-    setRootNode: function(node) {
-        var me = this;        
-        me.store.setNode(node);
-        me.node = node;
-        if (!me.rootVisible) {
-            node.expand();
-        }
+    addCmpEvents: function() {
+        this.addEvents(
+<span id='Ext-view-View-event-beforeitemmousedown'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-beforeitemmouseup'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-beforeitemmouseenter'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-beforeitemmouseleave'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-beforeitemclick'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-beforeitemdblclick'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-beforeitemcontextmenu'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-beforeitemkeydown'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-itemmousedown'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-itemmouseup'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-itemmouseenter'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-itemmouseleave'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-itemclick'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-itemdblclick'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-itemcontextmenu'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-itemkeydown'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-beforecontainermousedown'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-beforecontainermouseup'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-beforecontainermouseover'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-beforecontainermouseout'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-beforecontainerclick'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-beforecontainerdblclick'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-beforecontainercontextmenu'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-beforecontainerkeydown'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-containermouseup'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-containermouseover'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-containermouseout'>            /**
+</span>             * @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',
+<span id='Ext-view-View-event-containerclick'>            /**
+</span>             * @event containerclick
+             * Fires when the container is clicked.
+             * @param {Ext.view.View} this
+             * @param {Ext.EventObject} e The raw event object
+             */
+            'containerclick',
+<span id='Ext-view-View-event-containerdblclick'>            /**
+</span>             * @event containerdblclick
+             * Fires when the container is double clicked.
+             * @param {Ext.view.View} this
+             * @param {Ext.EventObject} e The raw event object
+             */
+            'containerdblclick',
+<span id='Ext-view-View-event-containercontextmenu'>            /**
+</span>             * @event containercontextmenu
+             * Fires when the container is right clicked.
+             * @param {Ext.view.View} this
+             * @param {Ext.EventObject} e The raw event object
+             */
+            'containercontextmenu',
+<span id='Ext-view-View-event-containerkeydown'>            /**
+</span>             * @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',
+
+<span id='Ext-view-View-event-selectionchange'>            /**
+</span>             * @event selectionchange
+             * Fires when the selected nodes change. Relayed event from the underlying selection model.
+             * @param {Ext.view.View} this
+             * @param {HTMLElement[]} selections Array of the selected nodes
+             */
+            'selectionchange',
+<span id='Ext-view-View-event-beforeselect'>            /**
+</span>             * @event beforeselect
+             * Fires before a selection is made. If any handlers return false, the selection is cancelled.
+             * @param {Ext.view.View} this
+             * @param {HTMLElement} node The node to be selected
+             * @param {HTMLElement[]} selections Array of currently selected nodes
+             */
+            'beforeselect'
+        );
     },
-    
-    onRender: function() {
+    // private
+    afterRender: function(){
         var me = this,
-            opts = {delegate: me.expanderSelector},
-            el;
+            listeners;
 
-        me.callParent(arguments);
+        me.callParent();
 
-        el = me.el;
-        el.on({
-            scope: me,
-            delegate: me.expanderSelector,
-            mouseover: me.onExpanderMouseOver,
-            mouseout: me.onExpanderMouseOut
-        });
-        el.on({
+        listeners = {
             scope: me,
-            delegate: me.checkboxSelector,
-            click: me.onCheckboxChange
-        });
-    },
+            /*
+             * 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,
+            mouseover: me.handleEvent,
+            mouseout: me.handleEvent,
+            keydown: me.handleEvent
+        };
 
-    onCheckboxChange: function(e, t) {
-        var item = e.getTarget(this.getItemSelector(), this.getTargetEl()),
-            record, value;
-            
-        if (item) {
-            record = this.getRecord(item);
-            value = !record.get('checked');
-            record.set('checked', value);
-            this.fireEvent('checkchange', record, value);
-        }
-    },
+        me.mon(me.getTargetEl(), listeners);
 
-    getChecked: function() {
-        var checked = [];
-        this.node.cascadeBy(function(rec){
-            if (rec.get('checked')) {
-                checked.push(rec);
-            }
-        });
-        return checked;
-    },
-    
-    isItemChecked: function(rec){
-        return rec.get('checked');
+        if (me.store) {
+            me.bindStore(me.store, true);
+        }
     },
 
-    createAnimWrap: function(record, index) {
-        var thHtml = '',
-            headerCt = this.panel.headerCt,
-            headers = headerCt.getGridColumns(),
-            i = 0, len = headers.length, item,
-            node = this.getNode(record),
-            tmpEl, nodeEl;
-
-        for (; i &lt; len; i++) {
-            item = headers[i];
-            thHtml += '&lt;th style=&quot;width: ' + (item.hidden ? 0 : item.getDesiredWidth()) + 'px; height: 0px;&quot;&gt;&lt;/th&gt;';
+    handleEvent: function(e) {
+        if (this.processUIEvent(e) !== false) {
+            this.processSpecialEvent(e);
         }
-
-        nodeEl = Ext.get(node);        
-        tmpEl = nodeEl.insertSibling({
-            tag: 'tr',
-            html: [
-                '&lt;td colspan=&quot;' + headerCt.getColumnCount() + '&quot;&gt;',
-                    '&lt;div class=&quot;' + Ext.baseCSSPrefix + 'tree-animator-wrap' + '&quot;&gt;',
-                        '&lt;table class=&quot;' + Ext.baseCSSPrefix + 'grid-table&quot; style=&quot;width: ' + headerCt.getFullWidth() + 'px;&quot;&gt;&lt;tbody&gt;',
-                            thHtml,
-                        '&lt;/tbody&gt;&lt;/table&gt;',
-                    '&lt;/div&gt;',
-                '&lt;/td&gt;'
-            ].join('')
-        }, 'after');
-
-        return {
-            record: record,
-            node: node,
-            el: tmpEl,
-            expanding: false,
-            collapsing: false,
-            animating: false,
-            animateEl: tmpEl.down('div'),
-            targetEl: tmpEl.down('tbody')
-        };
     },
 
-    getAnimWrap: function(parent) {
-        if (!this.animate) {
-            return null;
-        }
+    // Private template method
+    processItemEvent: Ext.emptyFn,
+    processContainerEvent: Ext.emptyFn,
+    processSpecialEvent: Ext.emptyFn,
 
-        // We are checking to see which parent is having the animation wrap
-        while (parent) {
-            if (parent.animWrap) {
-                return parent.animWrap;
-            }
-            parent = parent.parentNode;
+    /*
+     * Returns true if this mouseover/out event is still over the overItem.
+     */
+    stillOverItem: function (event, overItem) {
+        var nowOver;
+
+        // There is this weird bug when you hover over the border of a cell it is saying
+        // the target is the table.
+        // BrowserBug: IE6 &amp; 7. If me.mouseOverItem has been removed and is no longer
+        // in the DOM then accessing .offsetParent will throw an &quot;Unspecified error.&quot; exception.
+        // typeof'ng and checking to make sure the offsetParent is an object will NOT throw
+        // this hard exception.
+        if (overItem &amp;&amp; typeof(overItem.offsetParent) === &quot;object&quot;) {
+            // mouseout : relatedTarget == nowOver, target == wasOver
+            // mouseover: relatedTarget == wasOver, target == nowOver
+            nowOver = (event.type == 'mouseout') ? event.getRelatedTarget() : event.getTarget();
+            return Ext.fly(overItem).contains(nowOver);
         }
-        return null;
+
+        return false;
     },
 
-    doAdd: function(nodes, records, index) {
-        // If we are adding records which have a parent that is currently expanding
-        // lets add them to the animation wrap
+    processUIEvent: function(e) {
         var me = this,
-            record = records[0],
-            parent = record.parentNode,
-            a = me.all.elements,
-            relativeIndex = 0,
-            animWrap = me.getAnimWrap(parent),
-            targetEl, children, len;
-
-        if (!animWrap || !animWrap.expanding) {
-            me.resetScrollers();
-            return me.callParent(arguments);
-        }
+            item = e.getTarget(me.getItemSelector(), me.getTargetEl()),
+            map = this.statics().EventMap,
+            index, record,
+            type = e.type,
+            overItem = me.mouseOverItem,
+            newType;
+
+        if (!item) {
+            if (type == 'mouseover' &amp;&amp; me.stillOverItem(e, overItem)) {
+                item = overItem;
+            }
 
-        // We need the parent that has the animWrap, not the nodes parent
-        parent = animWrap.record;
-        
-        // If there is an anim wrap we do our special magic logic
-        targetEl = animWrap.targetEl;
-        children = targetEl.dom.childNodes;
-        
-        // We subtract 1 from the childrens length because we have a tr in there with the th'es
-        len = children.length - 1;
-        
-        // The relative index is the index in the full flat collection minus the index of the wraps parent
-        relativeIndex = index - me.indexOf(parent) - 1;
-        
-        // If we are adding records to the wrap that have a higher relative index then there are currently children
-        // it means we have to append the nodes to the wrap
-        if (!len || relativeIndex &gt;= len) {
-            targetEl.appendChild(nodes);
-        }
-        // If there are already more children then the relative index it means we are adding child nodes of
-        // some expanded node in the anim wrap. In this case we have to insert the nodes in the right location
-        else {
-            // +1 because of the tr with th'es that is already there
-            Ext.fly(children[relativeIndex + 1]).insertSibling(nodes, 'before', true);
+            // Try to get the selected item to handle the keydown event, otherwise we'll just fire a container keydown event
+            if (type == 'keydown') {
+                record = me.getSelectionModel().getLastSelected();
+                if (record) {
+                    item = me.getNode(record);
+                }
+            }
         }
 
-        // We also have to update the CompositeElementLite collection of the DataView
-        Ext.Array.insert(a, index, nodes);
-        
-        // If we were in an animation we need to now change the animation
-        // because the targetEl just got higher.
-        if (animWrap.isAnimating) {
-            me.onExpand(parent);
-        }
-    },
-    
-    doRemove: function(record, index) {
-        // If we are adding records which have a parent that is currently expanding
-        // lets add them to the animation wrap
-        var me = this,
-            parent = record.parentNode,
-            all = me.all,
-            animWrap = me.getAnimWrap(record),
-            node = all.item(index).dom;
-
-        if (!animWrap || !animWrap.collapsing) {
-            me.resetScrollers();
-            return me.callParent(arguments);
-        }
+        if (item) {
+            index = me.indexOf(item);
+            if (!record) {
+                record = me.getRecord(item);
+            }
 
-        animWrap.targetEl.appendChild(node);
-        all.removeElement(index);
-    },
+            if (me.processItemEvent(record, item, index, e) === false) {
+                return false;
+            }
 
-    onBeforeExpand: function(parent, records, index) {
-        var me = this,
-            animWrap;
-            
-        if (!me.rendered || !me.animate) {
-            return;
-        }
+            newType = me.isNewItemEvent(item, e);
+            if (newType === false) {
+                return false;
+            }
 
-        if (me.getNode(parent)) {
-            animWrap = me.getAnimWrap(parent);
-            if (!animWrap) {
-                animWrap = parent.animWrap = me.createAnimWrap(parent);
-                animWrap.animateEl.setHeight(0);
+            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;
             }
-            else if (animWrap.collapsing) {
-                // If we expand this node while it is still expanding then we
-                // have to remove the nodes from the animWrap.
-                animWrap.targetEl.select(me.itemSelector).remove();
-            } 
-            animWrap.expanding = true;
-            animWrap.collapsing = false;
-        }
-    },
 
-    onExpand: function(parent) {
-        var me = this,
-            queue = me.animQueue,
-            id = parent.getId(),
-            animWrap,
-            animateEl, 
-            targetEl,
-            queueItem;        
-        
-        if (me.singleExpand) {
-            me.ensureSingleExpand(parent);
+            me.fireEvent('item' + newType, me, record, item, index, e);
         }
-        
-        animWrap = me.getAnimWrap(parent);
+        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;
+            }
 
-        if (!animWrap) {
-            me.resetScrollers();
-            return;
+            me.fireEvent('container' + type, me, e);
         }
-        
-        animateEl = animWrap.animateEl;
-        targetEl = animWrap.targetEl;
-
-        animateEl.stopAnimation();
-        // @TODO: we are setting it to 1 because quirks mode on IE seems to have issues with 0
-        queue[id] = true;
-        animateEl.slideIn('t', {
-            duration: me.expandDuration,
-            listeners: {
-                scope: me,
-                lastframe: function() {
-                    // Move all the nodes out of the anim wrap to their proper location
-                    animWrap.el.insertSibling(targetEl.query(me.itemSelector), 'before');
-                    animWrap.el.remove();
-                    me.resetScrollers();
-                    delete animWrap.record.animWrap;
-                    delete queue[id];
-                }
-            }
-        });
-        
-        animWrap.isAnimating = true;
-    },
-    
-    resetScrollers: function(){
-        var panel = this.panel;
-        
-        panel.determineScrollbars();
-        panel.invalidateScroller();
+
+        return true;
     },
 
-    onBeforeCollapse: function(parent, records, index) {
+    isNewItemEvent: function (item, e) {
         var me = this,
-            animWrap;
-            
-        if (!me.rendered || !me.animate) {
-            return;
-        }
+            overItem = me.mouseOverItem,
+            type = e.type;
 
-        if (me.getNode(parent)) {
-            animWrap = me.getAnimWrap(parent);
-            if (!animWrap) {
-                animWrap = parent.animWrap = me.createAnimWrap(parent, index);
-            }
-            else if (animWrap.expanding) {
-                // If we collapse this node while it is still expanding then we
-                // have to remove the nodes from the animWrap.
-                animWrap.targetEl.select(this.itemSelector).remove();
-            }
-            animWrap.expanding = false;
-            animWrap.collapsing = true;
+        switch (type) {
+            case 'mouseover':
+                if (item === overItem) {
+                    return false;
+                }
+                me.mouseOverItem = item;
+                return 'mouseenter';
+
+            case 'mouseout':
+                // If the currently mouseovered item contains the mouseover target, it's *NOT* a mouseleave
+                if (me.stillOverItem(e, overItem)) {
+                    return false;
+                }
+                me.mouseOverItem = null;
+                return 'mouseleave';
         }
+        return type;
     },
-    
-    onCollapse: function(parent) {
-        var me = this,
-            queue = me.animQueue,
-            id = parent.getId(),
-            animWrap = me.getAnimWrap(parent),
-            animateEl, targetEl;
-
-        if (!animWrap) {
-            me.resetScrollers();
-            return;
+
+    // private
+    onItemMouseEnter: function(record, item, index, e) {
+        if (this.trackOver) {
+            this.highlightItem(item);
         }
-        
-        animateEl = animWrap.animateEl;
-        targetEl = animWrap.targetEl;
-
-        queue[id] = true;
-        
-        // @TODO: we are setting it to 1 because quirks mode on IE seems to have issues with 0
-        animateEl.stopAnimation();
-        animateEl.slideOut('t', {
-            duration: me.collapseDuration,
-            listeners: {
-                scope: me,
-                lastframe: function() {
-                    animWrap.el.remove();
-                    delete animWrap.record.animWrap;
-                    me.resetScrollers();
-                    delete queue[id];
-                }             
-            }
-        });
-        animWrap.isAnimating = true;
     },
-    
-<span id='Ext-tree-View-method-isAnimating'>    /**
-</span>     * Checks if a node is currently undergoing animation
-     * @private
-     * @param {Ext.data.Model} node The node
-     * @return {Boolean} True if the node is animating
-     */
-    isAnimating: function(node) {
-        return !!this.animQueue[node.getId()];    
-    },
-    
-    collectData: function(records) {
-        var data = this.callParent(arguments),
-            rows = data.rows,
-            len = rows.length,
-            i = 0,
-            row, record;
-            
-        for (; i &lt; len; i++) {
-            row = rows[i];
-            record = records[i];
-            if (record.get('qtip')) {
-                row.rowAttr = 'data-qtip=&quot;' + record.get('qtip') + '&quot;';
-                if (record.get('qtitle')) {
-                    row.rowAttr += ' ' + 'data-qtitle=&quot;' + record.get('qtitle') + '&quot;';
-                }
-            }
-            if (record.isExpanded()) {
-                row.rowCls = (row.rowCls || '') + ' ' + this.expandedCls;
-            }
-            if (record.isLoading()) {
-                row.rowCls = (row.rowCls || '') + ' ' + this.loadingCls;
-            }
+
+    // private
+    onItemMouseLeave : function(record, item, index, e) {
+        if (this.trackOver) {
+            this.clearHighlight();
         }
-        
-        return data;
-    },
-    
-<span id='Ext-tree-View-method-expand'>    /**
-</span>     * Expand a record that is loaded in the view.
-     * @param {Ext.data.Model} record The record to expand
-     * @param {Boolean} deep (optional) True to expand nodes all the way down the tree hierarchy.
-     * @param {Function} callback (optional) The function to run after the expand is completed
-     * @param {Object} scope (optional) The scope of the callback function.
-     */
-    expand: function(record, deep, callback, scope) {
-        return record.expand(deep, callback, scope);
     },
-    
-<span id='Ext-tree-View-method-collapse'>    /**
-</span>     * Collapse a record that is loaded in the view.
-     * @param {Ext.data.Model} record The record to collapse
-     * @param {Boolean} deep (optional) True to collapse nodes all the way up the tree hierarchy.
-     * @param {Function} callback (optional) The function to run after the collapse is completed
-     * @param {Object} scope (optional) The scope of the callback function.
+
+    // @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,
+
+<span id='Ext-view-View-method-highlightItem'>    /**
+</span>     * Highlights a given item in the DataView. 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
      */
-    collapse: function(record, deep, callback, scope) {
-        return record.collapse(deep, callback, scope);
+    highlightItem: function(item) {
+        var me = this;
+        me.clearHighlight();
+        me.highlightedItem = item;
+        Ext.fly(item).addCls(me.overItemCls);
     },
-    
-<span id='Ext-tree-View-method-toggle'>    /**
-</span>     * Toggle a record between expanded and collapsed.
-     * @param {Ext.data.Record} recordInstance
+
+<span id='Ext-view-View-method-clearHighlight'>    /**
+</span>     * Un-highlights the currently highlighted item, if any.
      */
-    toggle: function(record) {
-        this[record.isExpanded() ? 'collapse' : 'expand'](record);
-    },
-    
-    onItemDblClick: function(record, item, index) {
-        this.callParent(arguments);
-        if (this.toggleOnDblClick) {
-            this.toggle(record);
-        }
-    },
-    
-    onBeforeItemMouseDown: function(record, item, index, e) {
-        if (e.getTarget(this.expanderSelector, item)) {
-            return false;
-        }
-        return this.callParent(arguments);
-    },
-    
-    onItemClick: function(record, item, index, e) {
-        if (e.getTarget(this.expanderSelector, item)) {
-            this.toggle(record);
-            return false;
+    clearHighlight: function() {
+        var me = this,
+            highlighted = me.highlightedItem;
+
+        if (highlighted) {
+            Ext.fly(highlighted).removeCls(me.overItemCls);
+            delete me.highlightedItem;
         }
-        return this.callParent(arguments);
-    },
-    
-    onExpanderMouseOver: function(e, t) {
-        e.getTarget(this.cellSelector, 10, true).addCls(this.expanderIconOverCls);
-    },
-    
-    onExpanderMouseOut: function(e, t) {
-        e.getTarget(this.cellSelector, 10, true).removeCls(this.expanderIconOverCls);
     },
-    
-<span id='Ext-tree-View-method-getTreeStore'>    /**
-</span>     * Gets the base TreeStore from the bound TreePanel.
-     */
-    getTreeStore: function() {
-        return this.panel.store;
-    },    
-    
-    ensureSingleExpand: function(node) {
-        var parent = node.parentNode;
-        if (parent) {
-            parent.eachChild(function(child) {
-                if (child !== node &amp;&amp; child.isExpanded()) {
-                    child.collapse();
-                }
-            });
+
+    refresh: function() {
+        var me = this;
+        me.clearHighlight();
+        me.callParent(arguments);
+        if (!me.isFixedHeight()) {
+            me.doComponentLayout();
         }
     }
 });</pre>