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 if (index < a.length) {
232 a.splice.apply(a, [index, 0].concat(nodes));
235 a.push.apply(a, nodes);
238 // If we were in an animation we need to now change the animation
239 // because the targetEl just got higher.
240 if (animWrap.isAnimating) {
245 doRemove: function(record, index) {
246 // If we are adding records which have a parent that is currently expanding
247 // lets add them to the animation wrap
249 parent = record.parentNode,
251 animWrap = me.getAnimWrap(record),
252 node = all.item(index).dom;
254 if (!animWrap || !animWrap.collapsing) {
256 return me.callParent(arguments);
259 animWrap.targetEl.appendChild(node);
260 all.removeElement(index);
263 onBeforeExpand: function(parent, records, index) {
267 if (!me.rendered || !me.animate) {
271 if (me.getNode(parent)) {
272 animWrap = me.getAnimWrap(parent);
274 animWrap = parent.animWrap = me.createAnimWrap(parent);
275 animWrap.animateEl.setHeight(0);
277 else if (animWrap.collapsing) {
278 // If we expand this node while it is still expanding then we
279 // have to remove the nodes from the animWrap.
280 animWrap.targetEl.select(me.itemSelector).remove();
282 animWrap.expanding = true;
283 animWrap.collapsing = false;
287 onExpand: function(parent) {
289 queue = me.animQueue,
296 if (me.singleExpand) {
297 me.ensureSingleExpand(parent);
300 animWrap = me.getAnimWrap(parent);
307 animateEl = animWrap.animateEl;
308 targetEl = animWrap.targetEl;
310 animateEl.stopAnimation();
311 // @TODO: we are setting it to 1 because quirks mode on IE seems to have issues with 0
313 animateEl.slideIn('t', {
314 duration: me.expandDuration,
317 lastframe: function() {
318 // Move all the nodes out of the anim wrap to their proper location
319 animWrap.el.insertSibling(targetEl.query(me.itemSelector), 'before');
320 animWrap.el.remove();
322 delete animWrap.record.animWrap;
328 animWrap.isAnimating = true;
331 resetScrollers: function(){
332 var panel = this.panel;
334 panel.determineScrollbars();
335 panel.invalidateScroller();
338 onBeforeCollapse: function(parent, records, index) {
342 if (!me.rendered || !me.animate) {
346 if (me.getNode(parent)) {
347 animWrap = me.getAnimWrap(parent);
349 animWrap = parent.animWrap = me.createAnimWrap(parent, index);
351 else if (animWrap.expanding) {
352 // If we collapse this node while it is still expanding then we
353 // have to remove the nodes from the animWrap.
354 animWrap.targetEl.select(this.itemSelector).remove();
356 animWrap.expanding = false;
357 animWrap.collapsing = true;
361 onCollapse: function(parent) {
363 queue = me.animQueue,
365 animWrap = me.getAnimWrap(parent),
373 animateEl = animWrap.animateEl;
374 targetEl = animWrap.targetEl;
378 // @TODO: we are setting it to 1 because quirks mode on IE seems to have issues with 0
379 animateEl.stopAnimation();
380 animateEl.slideOut('t', {
381 duration: me.collapseDuration,
384 lastframe: function() {
385 animWrap.el.remove();
386 delete animWrap.record.animWrap;
392 animWrap.isAnimating = true;
395 <span id='Ext-tree-View-method-isAnimating'> /**
396 </span> * Checks if a node is currently undergoing animation
398 * @param {Ext.data.Model} node The node
399 * @return {Boolean} True if the node is animating
401 isAnimating: function(node) {
402 return !!this.animQueue[node.getId()];
405 collectData: function(records) {
406 var data = this.callParent(arguments),
412 for (; i < len; i++) {
415 if (record.get('qtip')) {
416 row.rowAttr = 'data-qtip="' + record.get('qtip') + '"';
417 if (record.get('qtitle')) {
418 row.rowAttr += ' ' + 'data-qtitle="' + record.get('qtitle') + '"';
421 if (record.isExpanded()) {
422 row.rowCls = (row.rowCls || '') + ' ' + this.expandedCls;
424 if (record.isLoading()) {
425 row.rowCls = (row.rowCls || '') + ' ' + this.loadingCls;
432 <span id='Ext-tree-View-method-expand'> /**
433 </span> * Expand a record that is loaded in the view.
434 * @param {Ext.data.Model} record The record to expand
435 * @param {Boolean} deep (optional) True to expand nodes all the way down the tree hierarchy.
436 * @param {Function} callback (optional) The function to run after the expand is completed
437 * @param {Object} scope (optional) The scope of the callback function.
439 expand: function(record, deep, callback, scope) {
440 return record.expand(deep, callback, scope);
443 <span id='Ext-tree-View-method-collapse'> /**
444 </span> * Collapse a record that is loaded in the view.
445 * @param {Ext.data.Model} record The record to collapse
446 * @param {Boolean} deep (optional) True to collapse nodes all the way up the tree hierarchy.
447 * @param {Function} callback (optional) The function to run after the collapse is completed
448 * @param {Object} scope (optional) The scope of the callback function.
450 collapse: function(record, deep, callback, scope) {
451 return record.collapse(deep, callback, scope);
454 <span id='Ext-tree-View-method-toggle'> /**
455 </span> * Toggle a record between expanded and collapsed.
456 * @param {Ext.data.Record} recordInstance
458 toggle: function(record) {
459 this[record.isExpanded() ? 'collapse' : 'expand'](record);
462 onItemDblClick: function(record, item, index) {
463 this.callParent(arguments);
464 if (this.toggleOnDblClick) {
469 onBeforeItemMouseDown: function(record, item, index, e) {
470 if (e.getTarget(this.expanderSelector, item)) {
473 return this.callParent(arguments);
476 onItemClick: function(record, item, index, e) {
477 if (e.getTarget(this.expanderSelector, item)) {
481 return this.callParent(arguments);
484 onExpanderMouseOver: function(e, t) {
485 e.getTarget(this.cellSelector, 10, true).addCls(this.expanderIconOverCls);
488 onExpanderMouseOut: function(e, t) {
489 e.getTarget(this.cellSelector, 10, true).removeCls(this.expanderIconOverCls);
492 <span id='Ext-tree-View-method-getTreeStore'> /**
493 </span> * Gets the base TreeStore from the bound TreePanel.
495 getTreeStore: function() {
496 return this.panel.store;
499 ensureSingleExpand: function(node) {
500 var parent = node.parentNode;
502 parent.eachChild(function(child) {
503 if (child !== node && child.isExpanded()) {