4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5 <title>The source code</title>
6 <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7 <script type="text/javascript" src="../prettify/prettify.js"></script>
8 <style type="text/css">
9 .highlight { display: block; background-color: #ddd; }
11 <script type="text/javascript">
12 function highlight() {
13 document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
17 <body onload="prettyPrint(); highlight();">
18 <pre class="prettyprint lang-js"><span id='Ext-tree-View'>/**
19 </span> * @class Ext.tree.View
20 * @extends Ext.view.Table
22 Ext.define('Ext.tree.View', {
23 extend: 'Ext.view.Table',
24 alias: 'widget.treeview',
26 loadingCls: Ext.baseCSSPrefix + 'grid-tree-loading',
27 expandedCls: Ext.baseCSSPrefix + 'grid-tree-node-expanded',
29 expanderSelector: '.' + Ext.baseCSSPrefix + 'tree-expander',
30 checkboxSelector: '.' + Ext.baseCSSPrefix + 'tree-checkbox',
31 expanderIconOverCls: Ext.baseCSSPrefix + 'tree-expander-over',
35 <span id='Ext-tree-View-cfg-rootVisible'> /**
36 </span> * @cfg {Boolean} rootVisible <tt>false</tt> to hide the root node (defaults to <tt>true</tt>)
40 <span id='Ext-tree-View-cfg-animate'> /**
41 </span> * @cfg {Boolean} animate <tt>true</tt> to enable animated expand/collapse (defaults to the value of {@link Ext#enableFx Ext.enableFx})
45 collapseDuration: 250,
47 toggleOnDblClick: true,
49 initComponent: function() {
52 if (me.initialConfig.animate === undefined) {
53 me.animate = Ext.enableFx;
56 me.store = Ext.create('Ext.data.NodeStore', {
58 rootVisible: me.rootVisible,
60 beforeexpand: me.onBeforeExpand,
62 beforecollapse: me.onBeforeCollapse,
63 collapse: me.onCollapse,
69 me.setRootNode(me.node);
72 me.callParent(arguments);
76 this.store.removeAll();
79 setRootNode: function(node) {
81 me.store.setNode(node);
83 if (!me.rootVisible) {
88 onRender: function() {
90 opts = {delegate: me.expanderSelector},
93 me.callParent(arguments);
98 delegate: me.expanderSelector,
99 mouseover: me.onExpanderMouseOver,
100 mouseout: me.onExpanderMouseOut
104 delegate: me.checkboxSelector,
105 click: me.onCheckboxChange
109 onCheckboxChange: function(e, t) {
110 var item = e.getTarget(this.getItemSelector(), this.getTargetEl()),
114 record = this.getRecord(item);
115 value = !record.get('checked');
116 record.set('checked', value);
117 this.fireEvent('checkchange', record, value);
121 getChecked: function() {
123 this.node.cascadeBy(function(rec){
124 if (rec.get('checked')) {
131 isItemChecked: function(rec){
132 return rec.get('checked');
135 createAnimWrap: function(record, index) {
137 headerCt = this.panel.headerCt,
138 headers = headerCt.getGridColumns(),
139 i = 0, len = headers.length, item,
140 node = this.getNode(record),
143 for (; i < len; i++) {
145 thHtml += '<th style="width: ' + (item.hidden ? 0 : item.getDesiredWidth()) + 'px; height: 0px;"></th>';
148 nodeEl = Ext.get(node);
149 tmpEl = nodeEl.insertSibling({
152 '<td colspan="' + headerCt.getColumnCount() + '">',
153 '<div class="' + Ext.baseCSSPrefix + 'tree-animator-wrap' + '">',
154 '<table class="' + Ext.baseCSSPrefix + 'grid-table" style="width: ' + headerCt.getFullWidth() + 'px;"><tbody>',
156 '</tbody></table>',
169 animateEl: tmpEl.down('div'),
170 targetEl: tmpEl.down('tbody')
174 getAnimWrap: function(parent) {
179 // We are checking to see which parent is having the animation wrap
181 if (parent.animWrap) {
182 return parent.animWrap;
184 parent = parent.parentNode;
189 doAdd: function(nodes, records, index) {
190 // If we are adding records which have a parent that is currently expanding
191 // lets add them to the animation wrap
194 parent = record.parentNode,
197 animWrap = me.getAnimWrap(parent),
198 targetEl, children, len;
200 if (!animWrap || !animWrap.expanding) {
202 return me.callParent(arguments);
205 // We need the parent that has the animWrap, not the nodes parent
206 parent = animWrap.record;
208 // If there is an anim wrap we do our special magic logic
209 targetEl = animWrap.targetEl;
210 children = targetEl.dom.childNodes;
212 // We subtract 1 from the childrens length because we have a tr in there with the th'es
213 len = children.length - 1;
215 // The relative index is the index in the full flat collection minus the index of the wraps parent
216 relativeIndex = index - me.indexOf(parent) - 1;
218 // If we are adding records to the wrap that have a higher relative index then there are currently children
219 // it means we have to append the nodes to the wrap
220 if (!len || relativeIndex >= len) {
221 targetEl.appendChild(nodes);
223 // If there are already more children then the relative index it means we are adding child nodes of
224 // some expanded node in the anim wrap. In this case we have to insert the nodes in the right location
226 // +1 because of the tr with th'es that is already there
227 Ext.fly(children[relativeIndex + 1]).insertSibling(nodes, 'before', true);
230 // We also have to update the CompositeElementLite collection of the DataView
231 Ext.Array.insert(a, index, nodes);
233 // If we were in an animation we need to now change the animation
234 // because the targetEl just got higher.
235 if (animWrap.isAnimating) {
240 doRemove: function(record, index) {
241 // If we are adding records which have a parent that is currently expanding
242 // lets add them to the animation wrap
244 parent = record.parentNode,
246 animWrap = me.getAnimWrap(record),
247 node = all.item(index).dom;
249 if (!animWrap || !animWrap.collapsing) {
251 return me.callParent(arguments);
254 animWrap.targetEl.appendChild(node);
255 all.removeElement(index);
258 onBeforeExpand: function(parent, records, index) {
262 if (!me.rendered || !me.animate) {
266 if (me.getNode(parent)) {
267 animWrap = me.getAnimWrap(parent);
269 animWrap = parent.animWrap = me.createAnimWrap(parent);
270 animWrap.animateEl.setHeight(0);
272 else if (animWrap.collapsing) {
273 // If we expand this node while it is still expanding then we
274 // have to remove the nodes from the animWrap.
275 animWrap.targetEl.select(me.itemSelector).remove();
277 animWrap.expanding = true;
278 animWrap.collapsing = false;
282 onExpand: function(parent) {
284 queue = me.animQueue,
291 if (me.singleExpand) {
292 me.ensureSingleExpand(parent);
295 animWrap = me.getAnimWrap(parent);
302 animateEl = animWrap.animateEl;
303 targetEl = animWrap.targetEl;
305 animateEl.stopAnimation();
306 // @TODO: we are setting it to 1 because quirks mode on IE seems to have issues with 0
308 animateEl.slideIn('t', {
309 duration: me.expandDuration,
312 lastframe: function() {
313 // Move all the nodes out of the anim wrap to their proper location
314 animWrap.el.insertSibling(targetEl.query(me.itemSelector), 'before');
315 animWrap.el.remove();
317 delete animWrap.record.animWrap;
323 animWrap.isAnimating = true;
326 resetScrollers: function(){
327 var panel = this.panel;
329 panel.determineScrollbars();
330 panel.invalidateScroller();
333 onBeforeCollapse: function(parent, records, index) {
337 if (!me.rendered || !me.animate) {
341 if (me.getNode(parent)) {
342 animWrap = me.getAnimWrap(parent);
344 animWrap = parent.animWrap = me.createAnimWrap(parent, index);
346 else if (animWrap.expanding) {
347 // If we collapse this node while it is still expanding then we
348 // have to remove the nodes from the animWrap.
349 animWrap.targetEl.select(this.itemSelector).remove();
351 animWrap.expanding = false;
352 animWrap.collapsing = true;
356 onCollapse: function(parent) {
358 queue = me.animQueue,
360 animWrap = me.getAnimWrap(parent),
368 animateEl = animWrap.animateEl;
369 targetEl = animWrap.targetEl;
373 // @TODO: we are setting it to 1 because quirks mode on IE seems to have issues with 0
374 animateEl.stopAnimation();
375 animateEl.slideOut('t', {
376 duration: me.collapseDuration,
379 lastframe: function() {
380 animWrap.el.remove();
381 delete animWrap.record.animWrap;
387 animWrap.isAnimating = true;
390 <span id='Ext-tree-View-method-isAnimating'> /**
391 </span> * Checks if a node is currently undergoing animation
393 * @param {Ext.data.Model} node The node
394 * @return {Boolean} True if the node is animating
396 isAnimating: function(node) {
397 return !!this.animQueue[node.getId()];
400 collectData: function(records) {
401 var data = this.callParent(arguments),
407 for (; i < len; i++) {
410 if (record.get('qtip')) {
411 row.rowAttr = 'data-qtip="' + record.get('qtip') + '"';
412 if (record.get('qtitle')) {
413 row.rowAttr += ' ' + 'data-qtitle="' + record.get('qtitle') + '"';
416 if (record.isExpanded()) {
417 row.rowCls = (row.rowCls || '') + ' ' + this.expandedCls;
419 if (record.isLoading()) {
420 row.rowCls = (row.rowCls || '') + ' ' + this.loadingCls;
427 <span id='Ext-tree-View-method-expand'> /**
428 </span> * Expand a record that is loaded in the view.
429 * @param {Ext.data.Model} record The record to expand
430 * @param {Boolean} deep (optional) True to expand nodes all the way down the tree hierarchy.
431 * @param {Function} callback (optional) The function to run after the expand is completed
432 * @param {Object} scope (optional) The scope of the callback function.
434 expand: function(record, deep, callback, scope) {
435 return record.expand(deep, callback, scope);
438 <span id='Ext-tree-View-method-collapse'> /**
439 </span> * Collapse a record that is loaded in the view.
440 * @param {Ext.data.Model} record The record to collapse
441 * @param {Boolean} deep (optional) True to collapse nodes all the way up the tree hierarchy.
442 * @param {Function} callback (optional) The function to run after the collapse is completed
443 * @param {Object} scope (optional) The scope of the callback function.
445 collapse: function(record, deep, callback, scope) {
446 return record.collapse(deep, callback, scope);
449 <span id='Ext-tree-View-method-toggle'> /**
450 </span> * Toggle a record between expanded and collapsed.
451 * @param {Ext.data.Record} recordInstance
453 toggle: function(record) {
454 this[record.isExpanded() ? 'collapse' : 'expand'](record);
457 onItemDblClick: function(record, item, index) {
458 this.callParent(arguments);
459 if (this.toggleOnDblClick) {
464 onBeforeItemMouseDown: function(record, item, index, e) {
465 if (e.getTarget(this.expanderSelector, item)) {
468 return this.callParent(arguments);
471 onItemClick: function(record, item, index, e) {
472 if (e.getTarget(this.expanderSelector, item)) {
476 return this.callParent(arguments);
479 onExpanderMouseOver: function(e, t) {
480 e.getTarget(this.cellSelector, 10, true).addCls(this.expanderIconOverCls);
483 onExpanderMouseOut: function(e, t) {
484 e.getTarget(this.cellSelector, 10, true).removeCls(this.expanderIconOverCls);
487 <span id='Ext-tree-View-method-getTreeStore'> /**
488 </span> * Gets the base TreeStore from the bound TreePanel.
490 getTreeStore: function() {
491 return this.panel.store;
494 ensureSingleExpand: function(node) {
495 var parent = node.parentNode;
497 parent.eachChild(function(child) {
498 if (child !== node && child.isExpanded()) {