X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/3789b528d8dd8aad4558e38e22d775bcab1cbd36..6746dc89c47ed01b165cc1152533605f97eb8e8d:/docs/source/View3.html diff --git a/docs/source/View3.html b/docs/source/View3.html index a9d033f7..91c04c5a 100644 --- a/docs/source/View3.html +++ b/docs/source/View3.html @@ -15,587 +15,491 @@
-/** - * @class Ext.view.View - * @extends Ext.view.AbstractView - * - * A mechanism for displaying data using custom layout templates and formatting. DataView 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. <b>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.</b> - * - * The example below binds a DataView to a {@link Ext.data.Store} and renders it into an {@link Ext.panel.Panel}. - * - * {@img Ext.DataView/Ext.DataView.png Ext.DataView component} - * - * Ext.regModel('Image', { - * 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="thumb-wrap">', - * '<img src="{src}" />', - * '<br/><span>{caption}</span>', - * '</div>', - * '</tpl>' - * ); - * - * Ext.create('Ext.DataView', { - * store: Ext.data.StoreManager.lookup('imagesStore'), - * tpl: imageTpl, - * itemSelector: 'div.thumb-wrap', - * emptyText: 'No images available', - * renderTo: Ext.getBody() - * }); - * - * @xtype dataview +/** + * @class Ext.tree.View + * @extends Ext.view.Table */ -Ext.define('Ext.view.View', { - extend: 'Ext.view.AbstractView', - alternateClassName: 'Ext.view.View', - 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' - } - }, +Ext.define('Ext.tree.View', { + extend: 'Ext.view.Table', + alias: 'widget.treeview', - 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 selectionchange - * Fires when the selected nodes change. Relayed event from the underlying selection model. - * @param {Ext.view.View} this - * @param {Array} selections Array of the selected nodes - */ - 'selectionchange', - /** - * @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 {Array} selections Array of currently selected nodes - */ - 'beforeselect' - ); - }, - // private - afterRender: function(){ - var me = this, - listeners; + loadingCls: Ext.baseCSSPrefix + 'grid-tree-loading', + expandedCls: Ext.baseCSSPrefix + 'grid-tree-node-expanded', - me.callParent(); + expanderSelector: '.' + Ext.baseCSSPrefix + 'tree-expander', + checkboxSelector: '.' + Ext.baseCSSPrefix + 'tree-checkbox', + expanderIconOverCls: Ext.baseCSSPrefix + 'tree-expander-over', - listeners = { - scope: me, - click: me.handleEvent, - mousedown: me.handleEvent, - mouseup: me.handleEvent, - dblclick: me.handleEvent, - contextmenu: me.handleEvent, - mouseover: me.handleEvent, - mouseout: me.handleEvent, - keydown: me.handleEvent - }; + blockRefresh: true, - me.mon(me.getTargetEl(), listeners); + /** + * @cfg {Boolean} rootVisible <tt>false</tt> to hide the root node (defaults to <tt>true</tt>) + */ + rootVisible: true, + + /** + * @cfg {Boolean} animate <tt>true</tt> to enable animated expand/collapse (defaults to the value of {@link Ext#enableFx Ext.enableFx}) + */ - if (me.store) { - me.bindStore(me.store, true); + 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); + } + me.animQueue = {}; + me.callParent(arguments); + }, + + onClear: function(){ + this.store.removeAll(); }, - handleEvent: function(e) { - if (this.processUIEvent(e) !== false) { - this.processSpecialEvent(e); + setRootNode: function(node) { + var me = this; + me.store.setNode(node); + me.node = node; + if (!me.rootVisible) { + node.expand(); } }, + + onRender: function() { + var me = this, + opts = {delegate: me.expanderSelector}, + el; - // Private template method - processItemEvent: Ext.emptyFn, - processContainerEvent: Ext.emptyFn, - processSpecialEvent: Ext.emptyFn, + me.callParent(arguments); - /* - * 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 & 7. If me.mouseOverItem has been removed and is no longer - // in the DOM then accessing .offsetParent will throw an "Unspecified error." exception. - // typeof'ng and checking to make sure the offsetParent is an object will NOT throw - // this hard exception. - if (overItem && typeof(overItem.offsetParent) === "object") { - // mouseout : relatedTarget == nowOver, target == wasOver - // mouseover: relatedTarget == wasOver, target == nowOver - nowOver = (event.type == 'mouseout') ? event.getRelatedTarget() : event.getTarget(); - return Ext.fly(overItem).contains(nowOver); - } + el = me.el; + el.on({ + scope: me, + delegate: me.expanderSelector, + mouseover: me.onExpanderMouseOver, + mouseout: me.onExpanderMouseOut + }); + el.on({ + scope: me, + delegate: me.checkboxSelector, + click: me.onCheckboxChange + }); + }, - return false; + 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); + } }, - processUIEvent: function(e) { - var me = this, - 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' && me.stillOverItem(e, overItem)) { - item = overItem; + 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'); + }, - // 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); - } - } + 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 < len; i++) { + item = headers[i]; + thHtml += '<th style="width: ' + (item.hidden ? 0 : item.getDesiredWidth()) + 'px; height: 0px;"></th>'; } - if (item) { - index = me.indexOf(item); - if (!record) { - record = me.getRecord(item); - } + nodeEl = Ext.get(node); + tmpEl = nodeEl.insertSibling({ + tag: 'tr', + html: [ + '<td colspan="' + headerCt.getColumnCount() + '">', + '<div class="' + Ext.baseCSSPrefix + 'tree-animator-wrap' + '">', + '<table class="' + Ext.baseCSSPrefix + 'grid-table" style="width: ' + headerCt.getFullWidth() + 'px;"><tbody>', + thHtml, + '</tbody></table>', + '</div>', + '</td>' + ].join('') + }, 'after'); + + return { + record: record, + node: node, + el: tmpEl, + expanding: false, + collapsing: false, + animating: false, + animateEl: tmpEl.down('div'), + targetEl: tmpEl.down('tbody') + }; + }, - if (me.processItemEvent(record, item, index, e) === false) { - return false; - } + getAnimWrap: function(parent) { + if (!this.animate) { + return null; + } - newType = me.isNewItemEvent(item, e); - if (newType === false) { - return false; + // We are checking to see which parent is having the animation wrap + while (parent) { + if (parent.animWrap) { + return parent.animWrap; } + parent = parent.parentNode; + } + return null; + }, - 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; - } + 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 + 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); + } - me.fireEvent('item' + newType, me, record, item, index, e); + // 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 >= 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 { - 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; - } + // +1 because of the tr with th'es that is already there + Ext.fly(children[relativeIndex + 1]).insertSibling(nodes, 'before', true); + } - me.fireEvent('container' + type, me, e); + // 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); } - return true; + animWrap.targetEl.appendChild(node); + all.removeElement(index); }, - isNewItemEvent: function (item, e) { + onBeforeExpand: function(parent, records, index) { var me = this, - overItem = me.mouseOverItem, - type = e.type; - - switch (type) { - case 'mouseover': - if (item === overItem) { - return false; - } - me.mouseOverItem = item; - return 'mouseenter'; + animWrap; + + if (!me.rendered || !me.animate) { + return; + } - 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'; + if (me.getNode(parent)) { + animWrap = me.getAnimWrap(parent); + if (!animWrap) { + animWrap = parent.animWrap = me.createAnimWrap(parent); + animWrap.animateEl.setHeight(0); + } + 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; } - return type; }, - // private - onItemMouseEnter: function(record, item, index, e) { - if (this.trackOver) { - this.highlightItem(item); + onExpand: function(parent) { + var me = this, + queue = me.animQueue, + id = parent.getId(), + animWrap, + animateEl, + targetEl, + queueItem; + + if (me.singleExpand) { + me.ensureSingleExpand(parent); } - }, + + animWrap = me.getAnimWrap(parent); - // private - onItemMouseLeave : function(record, item, index, e) { - if (this.trackOver) { - this.clearHighlight(); + if (!animWrap) { + me.resetScrollers(); + return; } + + 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; }, - - // @private, template methods - onItemMouseDown: Ext.emptyFn, - onItemMouseUp: Ext.emptyFn, - onItemClick: Ext.emptyFn, - onItemDblClick: Ext.emptyFn, - onItemContextMenu: Ext.emptyFn, - onItemKeyDown: Ext.emptyFn, - onBeforeItemMouseDown: Ext.emptyFn, - onBeforeItemMouseUp: 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, - - /** - * Highlight 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 - */ - highlightItem: function(item) { - var me = this; - me.clearHighlight(); - me.highlightedItem = item; - Ext.fly(item).addCls(me.overItemCls); + + resetScrollers: function(){ + var panel = this.panel; + + panel.determineScrollbars(); + panel.invalidateScroller(); }, - /** - * Un-highlight the currently highlighted item, if any. - */ - clearHighlight: function() { + onBeforeCollapse: function(parent, records, index) { var me = this, - highlighted = me.highlightedItem; + animWrap; + + if (!me.rendered || !me.animate) { + return; + } - if (highlighted) { - Ext.fly(highlighted).removeCls(me.overItemCls); - delete me.highlightedItem; + 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; } }, - - refresh: function() { - this.clearHighlight(); + + onCollapse: function(parent) { + var me = this, + queue = me.animQueue, + id = parent.getId(), + animWrap = me.getAnimWrap(parent), + animateEl, targetEl; + + if (!animWrap) { + me.resetScrollers(); + return; + } + + 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; + }, + + /** + * 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 < len; i++) { + row = rows[i]; + record = records[i]; + if (record.get('qtip')) { + row.rowAttr = 'data-qtip="' + record.get('qtip') + '"'; + if (record.get('qtitle')) { + row.rowAttr += ' ' + 'data-qtitle="' + record.get('qtitle') + '"'; + } + } + if (record.isExpanded()) { + row.rowCls = (row.rowCls || '') + ' ' + this.expandedCls; + } + if (record.isLoading()) { + row.rowCls = (row.rowCls || '') + ' ' + this.loadingCls; + } + } + + return data; + }, + + /** + * 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); + }, + + /** + * 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. + */ + collapse: function(record, deep, callback, scope) { + return record.collapse(deep, callback, scope); + }, + + /** + * Toggle a record between expanded and collapsed. + * @param {Ext.data.Record} recordInstance + */ + 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; + } + 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); + }, + + /** + * 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 && child.isExpanded()) { + child.collapse(); + } + }); + } } });