4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5 <title>The source code</title>
6 <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
7 <script type="text/javascript" src="../resources/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-Panel'>/**
19 </span> * The TreePanel provides tree-structured UI representation of tree-structured data.
20 * A TreePanel must be bound to a {@link Ext.data.TreeStore}. TreePanel's support
21 * multiple columns through the {@link #columns} configuration.
23 * Simple TreePanel using inline data:
26 * var store = Ext.create('Ext.data.TreeStore', {
30 * { text: "detention", leaf: true },
31 * { text: "homework", expanded: true, children: [
32 * { text: "book report", leaf: true },
33 * { text: "alegrbra", leaf: true}
35 * { text: "buy lottery tickets", leaf: true }
40 * Ext.create('Ext.tree.Panel', {
41 * title: 'Simple Tree',
46 * renderTo: Ext.getBody()
49 * For the tree node config options (like `text`, `leaf`, `expanded`), see the documentation of
50 * {@link Ext.data.NodeInterface NodeInterface} config options.
52 Ext.define('Ext.tree.Panel', {
53 extend: 'Ext.panel.Table',
54 alias: 'widget.treepanel',
55 alternateClassName: ['Ext.tree.TreePanel', 'Ext.TreePanel'],
56 requires: ['Ext.tree.View', 'Ext.selection.TreeModel', 'Ext.tree.Column'],
60 treeCls: Ext.baseCSSPrefix + 'tree-panel',
62 deferRowRender: false,
64 <span id='Ext-tree-Panel-cfg-lines'> /**
65 </span> * @cfg {Boolean} lines False to disable tree lines.
69 <span id='Ext-tree-Panel-cfg-useArrows'> /**
70 </span> * @cfg {Boolean} useArrows True to use Vista-style arrows in the tree.
74 <span id='Ext-tree-Panel-cfg-singleExpand'> /**
75 </span> * @cfg {Boolean} singleExpand True if only 1 node per branch may be expanded.
84 <span id='Ext-tree-Panel-cfg-animate'> /**
85 </span> * @cfg {Boolean} animate True to enable animated expand/collapse. Defaults to the value of {@link Ext#enableFx}.
88 <span id='Ext-tree-Panel-cfg-rootVisible'> /**
89 </span> * @cfg {Boolean} rootVisible False to hide the root node.
93 <span id='Ext-tree-Panel-cfg-displayField'> /**
94 </span> * @cfg {Boolean} displayField The field inside the model that will be used as the node's text.
98 <span id='Ext-tree-Panel-cfg-root'> /**
99 </span> * @cfg {Ext.data.Model/Ext.data.NodeInterface/Object} root
100 * Allows you to not specify a store on this TreePanel. This is useful for creating a simple tree with preloaded
101 * data without having to specify a TreeStore and Model. A store and model will be created and root will be passed
102 * to that store. For example:
104 * Ext.create('Ext.tree.Panel', {
105 * title: 'Simple Tree',
107 * text: "Root node",
110 * { text: "Child 1", leaf: true },
111 * { text: "Child 2", leaf: true }
114 * renderTo: Ext.getBody()
119 // Required for the Lockable Mixin. These are the configurations which will be copied to the
120 // normal and locked sub tablepanels
121 normalCfgCopy: ['displayField', 'root', 'singleExpand', 'useArrows', 'lines', 'rootVisible', 'scroll'],
122 lockedCfgCopy: ['displayField', 'root', 'singleExpand', 'useArrows', 'lines', 'rootVisible'],
124 <span id='Ext-tree-Panel-cfg-hideHeaders'> /**
125 </span> * @cfg {Boolean} hideHeaders True to hide the headers. Defaults to `undefined`.
128 <span id='Ext-tree-Panel-cfg-folderSort'> /**
129 </span> * @cfg {Boolean} folderSort True to automatically prepend a leaf sorter to the store. Defaults to `undefined`.
132 constructor: function(config) {
133 config = config || {};
134 if (config.animate === undefined) {
135 config.animate = Ext.enableFx;
137 this.enableAnimations = config.animate;
138 delete config.animate;
140 this.callParent([config]);
143 initComponent: function() {
148 cls.push(Ext.baseCSSPrefix + 'tree-arrows');
153 cls.push(Ext.baseCSSPrefix + 'tree-lines');
154 } else if (!me.useArrows) {
155 cls.push(Ext.baseCSSPrefix + 'tree-no-lines');
158 if (Ext.isString(me.store)) {
159 me.store = Ext.StoreMgr.lookup(me.store);
160 } else if (!me.store || Ext.isObject(me.store) && !me.store.isStore) {
161 me.store = Ext.create('Ext.data.TreeStore', Ext.apply({}, me.store || {}, {
165 folderSort: me.folderSort
167 } else if (me.root) {
168 me.store = Ext.data.StoreManager.lookup(me.store);
169 me.store.setRootNode(me.root);
170 if (me.folderSort !== undefined) {
171 me.store.folderSort = me.folderSort;
176 // I'm not sure if we want to this. It might be confusing
177 // if (me.initialConfig.rootVisible === undefined && !me.getRootNode()) {
178 // me.rootVisible = false;
181 me.viewConfig = Ext.applyIf(me.viewConfig || {}, {
182 rootVisible: me.rootVisible,
183 animate: me.enableAnimations,
184 singleExpand: me.singleExpand,
185 node: me.store.getRootNode(),
186 hideHeaders: me.hideHeaders
191 rootchange: me.onRootChange,
195 me.relayEvents(me.store, [
196 <span id='Ext-tree-Panel-event-beforeload'> /**
197 </span> * @event beforeload
198 * @alias Ext.data.Store#beforeload
202 <span id='Ext-tree-Panel-event-load'> /**
203 </span> * @event load
204 * @alias Ext.data.Store#load
210 <span id='Ext-tree-Panel-event-itemappend'> /**
211 </span> * @event itemappend
212 * @alias Ext.data.TreeStore#append
214 append: me.createRelayer('itemappend'),
216 <span id='Ext-tree-Panel-event-itemremove'> /**
217 </span> * @event itemremove
218 * @alias Ext.data.TreeStore#remove
220 remove: me.createRelayer('itemremove'),
222 <span id='Ext-tree-Panel-event-itemmove'> /**
223 </span> * @event itemmove
224 * @alias Ext.data.TreeStore#move
226 move: me.createRelayer('itemmove'),
228 <span id='Ext-tree-Panel-event-iteminsert'> /**
229 </span> * @event iteminsert
230 * @alias Ext.data.TreeStore#insert
232 insert: me.createRelayer('iteminsert'),
234 <span id='Ext-tree-Panel-event-beforeitemappend'> /**
235 </span> * @event beforeitemappend
236 * @alias Ext.data.TreeStore#beforeappend
238 beforeappend: me.createRelayer('beforeitemappend'),
240 <span id='Ext-tree-Panel-event-beforeitemremove'> /**
241 </span> * @event beforeitemremove
242 * @alias Ext.data.TreeStore#beforeremove
244 beforeremove: me.createRelayer('beforeitemremove'),
246 <span id='Ext-tree-Panel-event-beforeitemmove'> /**
247 </span> * @event beforeitemmove
248 * @alias Ext.data.TreeStore#beforemove
250 beforemove: me.createRelayer('beforeitemmove'),
252 <span id='Ext-tree-Panel-event-beforeiteminsert'> /**
253 </span> * @event beforeiteminsert
254 * @alias Ext.data.TreeStore#beforeinsert
256 beforeinsert: me.createRelayer('beforeiteminsert'),
258 <span id='Ext-tree-Panel-event-itemexpand'> /**
259 </span> * @event itemexpand
260 * @alias Ext.data.TreeStore#expand
262 expand: me.createRelayer('itemexpand'),
264 <span id='Ext-tree-Panel-event-itemcollapse'> /**
265 </span> * @event itemcollapse
266 * @alias Ext.data.TreeStore#collapse
268 collapse: me.createRelayer('itemcollapse'),
270 <span id='Ext-tree-Panel-event-beforeitemexpand'> /**
271 </span> * @event beforeitemexpand
272 * @alias Ext.data.TreeStore#beforeexpand
274 beforeexpand: me.createRelayer('beforeitemexpand'),
276 <span id='Ext-tree-Panel-event-beforeitemcollapse'> /**
277 </span> * @event beforeitemcollapse
278 * @alias Ext.data.TreeStore#beforecollapse
280 beforecollapse: me.createRelayer('beforeitemcollapse')
283 // If the user specifies the headers collection manually then dont inject our own
285 if (me.initialConfig.hideHeaders === undefined) {
286 me.hideHeaders = true;
289 xtype : 'treecolumn',
292 dataIndex: me.displayField
299 me.cls = cls.join(' ');
302 me.relayEvents(me.getView(), [
303 <span id='Ext-tree-Panel-event-checkchange'> /**
304 </span> * @event checkchange
305 * Fires when a node with a checkbox's checked property changes
306 * @param {Ext.data.Model} node The node who's checked property was changed
307 * @param {Boolean} checked The node's new checked state
312 // If the root is not visible and there is no rootnode defined, then just lets load the store
313 if (!me.getView().rootVisible && !me.getRootNode()) {
324 <span id='Ext-tree-Panel-method-setRootNode'> /**
325 </span> * Sets root node of this tree.
326 * @param {Ext.data.Model/Ext.data.NodeInterface/Object} root
327 * @return {Ext.data.NodeInterface} The new root
329 setRootNode: function() {
330 return this.store.setRootNode.apply(this.store, arguments);
333 <span id='Ext-tree-Panel-method-getRootNode'> /**
334 </span> * Returns the root node for this tree.
335 * @return {Ext.data.NodeInterface}
337 getRootNode: function() {
338 return this.store.getRootNode();
341 onRootChange: function(root) {
342 this.view.setRootNode(root);
345 <span id='Ext-tree-Panel-method-getChecked'> /**
346 </span> * Retrieve an array of checked records.
347 * @return {Ext.data.Model[]} An array containing the checked records
349 getChecked: function() {
350 return this.getView().getChecked();
353 isItemChecked: function(rec) {
354 return rec.get('checked');
357 <span id='Ext-tree-Panel-method-expandAll'> /**
358 </span> * Expand all nodes
359 * @param {Function} callback (optional) A function to execute when the expand finishes.
360 * @param {Object} scope (optional) The scope of the callback function
362 expandAll : function(callback, scope) {
363 var root = this.getRootNode(),
364 animate = this.enableAnimations,
365 view = this.getView();
368 view.beginBulkUpdate();
370 root.expand(true, callback, scope);
372 view.endBulkUpdate();
377 <span id='Ext-tree-Panel-method-collapseAll'> /**
378 </span> * Collapse all nodes
379 * @param {Function} callback (optional) A function to execute when the collapse finishes.
380 * @param {Object} scope (optional) The scope of the callback function
382 collapseAll : function(callback, scope) {
383 var root = this.getRootNode(),
384 animate = this.enableAnimations,
385 view = this.getView();
389 view.beginBulkUpdate();
391 if (view.rootVisible) {
392 root.collapse(true, callback, scope);
394 root.collapseChildren(true, callback, scope);
397 view.endBulkUpdate();
402 <span id='Ext-tree-Panel-method-expandPath'> /**
403 </span> * Expand the tree to the path of a particular node.
404 * @param {String} path The path to expand. The path should include a leading separator.
405 * @param {String} field (optional) The field to get the data from. Defaults to the model idProperty.
406 * @param {String} separator (optional) A separator to use. Defaults to `'/'`.
407 * @param {Function} callback (optional) A function to execute when the expand finishes. The callback will be called with
408 * (success, lastNode) where success is if the expand was successful and lastNode is the last node that was expanded.
409 * @param {Object} scope (optional) The scope of the callback function
411 expandPath: function(path, field, separator, callback, scope) {
413 current = me.getRootNode(),
419 field = field || me.getRootNode().idProperty;
420 separator = separator || '/';
422 if (Ext.isEmpty(path)) {
423 Ext.callback(callback, scope || me, [false, null]);
427 keys = path.split(separator);
428 if (current.get(field) != keys[1]) {
430 Ext.callback(callback, scope || me, [false, current]);
434 expander = function(){
435 if (++index === keys.length) {
436 Ext.callback(callback, scope || me, [true, current]);
439 var node = current.findChild(field, keys[index]);
441 Ext.callback(callback, scope || me, [false, current]);
445 current.expand(false, expander);
447 current.expand(false, expander);
450 <span id='Ext-tree-Panel-method-selectPath'> /**
451 </span> * Expand the tree to the path of a particular node, then select it.
452 * @param {String} path The path to select. The path should include a leading separator.
453 * @param {String} field (optional) The field to get the data from. Defaults to the model idProperty.
454 * @param {String} separator (optional) A separator to use. Defaults to `'/'`.
455 * @param {Function} callback (optional) A function to execute when the select finishes. The callback will be called with
456 * (bSuccess, oLastNode) where bSuccess is if the select was successful and oLastNode is the last node that was expanded.
457 * @param {Object} scope (optional) The scope of the callback function
459 selectPath: function(path, field, separator, callback, scope) {
464 field = field || me.getRootNode().idProperty;
465 separator = separator || '/';
467 keys = path.split(separator);
470 me.expandPath(keys.join(separator), field, separator, function(success, node){
471 var doSuccess = false;
472 if (success && node) {
473 node = node.findChild(field, last);
475 me.getSelectionModel().select(node);
476 Ext.callback(callback, scope || me, [true, node]);
479 } else if (node === me.getRootNode()) {
482 Ext.callback(callback, scope || me, [doSuccess, node]);