Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / docs / source / Panel5.html
1 <!DOCTYPE html>
2 <html>
3 <head>
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; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
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. 
22  * 
23  * Simple TreePanel using inline data.
24  *
25  * {@img Ext.tree.Panel/Ext.tree.Panel1.png Ext.tree.Panel component}
26  * 
27  * Code:
28  *
29  *     var store = Ext.create('Ext.data.TreeStore', {
30  *         root: {
31  *             expanded: true, 
32  *             children: [
33  *                 { text: &quot;detention&quot;, leaf: true },
34  *                 { text: &quot;homework&quot;, expanded: true, children: [
35  *                     { text: &quot;book report&quot;, leaf: true },
36  *                     { text: &quot;alegrbra&quot;, leaf: true}
37  *                 ] },
38  *                 { text: &quot;buy lottery tickets&quot;, leaf: true }
39  *             ]
40  *         }
41  *     });     
42  *
43  *     Ext.create('Ext.tree.Panel', {
44  *         title: 'Simple Tree',
45  *         width: 200,
46  *         height: 150,
47  *         store: store,
48  *         rootVisible: false,        
49  *         renderTo: Ext.getBody()
50  *     });
51  */
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'],
57     viewType: 'treeview',
58     selType: 'treemodel',
59     
60     treeCls: Ext.baseCSSPrefix + 'tree-panel',
61
62     deferRowRender: false,
63
64 <span id='Ext-tree-Panel-cfg-lines'>    /**
65 </span>     * @cfg {Boolean} lines False to disable tree lines. Defaults to true.
66      */
67     lines: true,
68     
69 <span id='Ext-tree-Panel-cfg-useArrows'>    /**
70 </span>     * @cfg {Boolean} useArrows True to use Vista-style arrows in the tree. Defaults to false.
71      */
72     useArrows: false,
73     
74 <span id='Ext-tree-Panel-cfg-singleExpand'>    /**
75 </span>     * @cfg {Boolean} singleExpand True if only 1 node per branch may be expanded. Defaults to false.
76      */
77     singleExpand: false,
78     
79     ddConfig: {
80         enableDrag: true,
81         enableDrop: true
82     },
83     
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}.
86      */
87             
88 <span id='Ext-tree-Panel-cfg-rootVisible'>    /** 
89 </span>     * @cfg {Boolean} rootVisible False to hide the root node. Defaults to true.
90      */
91     rootVisible: true,
92     
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. Defaults to 'text'.
95      */    
96     displayField: 'text',
97
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:
103      *
104      *     Ext.create('Ext.tree.Panel', {
105      *         title: 'Simple Tree',
106      *         root: {
107      *             text: &quot;Root node&quot;,
108      *             expanded: true,
109      *             children: [
110      *                 { text: &quot;Child 1&quot;, leaf: true },
111      *                 { text: &quot;Child 2&quot;, leaf: true }
112      *             ]
113      *         },
114      *         renderTo: Ext.getBody()
115      *     });
116      */
117     root: null,
118     
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'],
123
124 <span id='Ext-tree-Panel-cfg-hideHeaders'>    /**
125 </span>     * @cfg {Boolean} hideHeaders True to hide the headers. Defaults to `undefined`.
126      */
127     
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`.
130      */ 
131     
132     constructor: function(config) {
133         config = config || {};
134         if (config.animate === undefined) {
135             config.animate = Ext.enableFx;
136         }
137         this.enableAnimations = config.animate;
138         delete config.animate;
139         
140         this.callParent([config]);
141     },
142     
143     initComponent: function() {
144         var me = this,
145             cls = [me.treeCls];
146
147         if (me.useArrows) {
148             cls.push(Ext.baseCSSPrefix + 'tree-arrows');
149             me.lines = false;
150         }
151         
152         if (me.lines) {
153             cls.push(Ext.baseCSSPrefix + 'tree-lines');
154         } else if (!me.useArrows) {
155             cls.push(Ext.baseCSSPrefix + 'tree-no-lines');
156         }
157         
158         if (Ext.isString(me.store)) {
159             me.store = Ext.StoreMgr.lookup(me.store);
160         } else if (!me.store || Ext.isObject(me.store) &amp;&amp; !me.store.isStore) {
161             me.store = Ext.create('Ext.data.TreeStore', Ext.apply({}, me.store || {}, {
162                 root: me.root,
163                 fields: me.fields,
164                 model: me.model,
165                 folderSort: me.folderSort
166             }));
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;
172                 me.store.sort();
173             }            
174         }
175         
176         // I'm not sure if we want to this. It might be confusing
177         // if (me.initialConfig.rootVisible === undefined &amp;&amp; !me.getRootNode()) {
178         //     me.rootVisible = false;
179         // }
180         
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
187         });
188         
189         me.mon(me.store, {
190             scope: me,
191             rootchange: me.onRootChange,
192             clear: me.onClear
193         });
194     
195         me.relayEvents(me.store, [
196 <span id='Ext-tree-Panel-event-beforeload'>            /**
197 </span>             * @event beforeload
198              * Event description
199              * @param {Ext.data.Store} store This Store
200              * @param {Ext.data.Operation} operation The Ext.data.Operation object that will be passed to the Proxy to load the Store
201              */
202             'beforeload',
203
204 <span id='Ext-tree-Panel-event-load'>            /**
205 </span>             * @event load
206              * Fires whenever the store reads data from a remote data source.
207              * @param {Ext.data.store} this
208              * @param {Array} records An array of records
209              * @param {Boolean} successful True if the operation was successful.
210              */
211             'load'   
212         ]);
213         
214         me.store.on({
215 <span id='Ext-tree-Panel-event-itemappend'>            /**
216 </span>             * @event itemappend
217              * Fires when a new child node is appended to a node in the tree.
218              * @param {Tree} tree The owner tree
219              * @param {Node} parent The parent node
220              * @param {Node} node The newly appended node
221              * @param {Number} index The index of the newly appended node
222              */
223             append: me.createRelayer('itemappend'),
224             
225 <span id='Ext-tree-Panel-event-itemremove'>            /**
226 </span>             * @event itemremove
227              * Fires when a child node is removed from a node in the tree
228              * @param {Tree} tree The owner tree
229              * @param {Node} parent The parent node
230              * @param {Node} node The child node removed
231              */
232             remove: me.createRelayer('itemremove'),
233             
234 <span id='Ext-tree-Panel-event-itemmove'>            /**
235 </span>             * @event itemmove
236              * Fires when a node is moved to a new location in the tree
237              * @param {Tree} tree The owner tree
238              * @param {Node} node The node moved
239              * @param {Node} oldParent The old parent of this node
240              * @param {Node} newParent The new parent of this node
241              * @param {Number} index The index it was moved to
242              */
243             move: me.createRelayer('itemmove'),
244             
245 <span id='Ext-tree-Panel-event-iteminsert'>            /**
246 </span>             * @event iteminsert
247              * Fires when a new child node is inserted in a node in tree
248              * @param {Tree} tree The owner tree
249              * @param {Node} parent The parent node
250              * @param {Node} node The child node inserted
251              * @param {Node} refNode The child node the node was inserted before
252              */
253             insert: me.createRelayer('iteminsert'),
254             
255 <span id='Ext-tree-Panel-event-beforeitemappend'>            /**
256 </span>             * @event beforeitemappend
257              * Fires before a new child is appended to a node in this tree, return false to cancel the append.
258              * @param {Tree} tree The owner tree
259              * @param {Node} parent The parent node
260              * @param {Node} node The child node to be appended
261              */
262             beforeappend: me.createRelayer('beforeitemappend'),
263             
264 <span id='Ext-tree-Panel-event-beforeitemremove'>            /**
265 </span>             * @event beforeitemremove
266              * Fires before a child is removed from a node in this tree, return false to cancel the remove.
267              * @param {Tree} tree The owner tree
268              * @param {Node} parent The parent node
269              * @param {Node} node The child node to be removed
270              */
271             beforeremove: me.createRelayer('beforeitemremove'),
272             
273 <span id='Ext-tree-Panel-event-beforeitemmove'>            /**
274 </span>             * @event beforeitemmove
275              * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
276              * @param {Tree} tree The owner tree
277              * @param {Node} node The node being moved
278              * @param {Node} oldParent The parent of the node
279              * @param {Node} newParent The new parent the node is moving to
280              * @param {Number} index The index it is being moved to
281              */
282             beforemove: me.createRelayer('beforeitemmove'),
283             
284 <span id='Ext-tree-Panel-event-beforeiteminsert'>            /**
285 </span>             * @event beforeiteminsert
286              * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
287              * @param {Tree} tree The owner tree
288              * @param {Node} parent The parent node
289              * @param {Node} node The child node to be inserted
290              * @param {Node} refNode The child node the node is being inserted before
291              */
292             beforeinsert: me.createRelayer('beforeiteminsert'),
293              
294 <span id='Ext-tree-Panel-event-itemexpand'>            /**
295 </span>             * @event itemexpand
296              * Fires when a node is expanded.
297              * @param {Node} this The expanding node
298              */
299             expand: me.createRelayer('itemexpand'),
300              
301 <span id='Ext-tree-Panel-event-itemcollapse'>            /**
302 </span>             * @event itemcollapse
303              * Fires when a node is collapsed.
304              * @param {Node} this The collapsing node
305              */
306             collapse: me.createRelayer('itemcollapse'),
307              
308 <span id='Ext-tree-Panel-event-beforeitemexpand'>            /**
309 </span>             * @event beforeitemexpand
310              * Fires before a node is expanded.
311              * @param {Node} this The expanding node
312              */
313             beforeexpand: me.createRelayer('beforeitemexpand'),
314              
315 <span id='Ext-tree-Panel-event-beforeitemcollapse'>            /**
316 </span>             * @event beforeitemcollapse
317              * Fires before a node is collapsed.
318              * @param {Node} this The collapsing node
319              */
320             beforecollapse: me.createRelayer('beforeitemcollapse')
321         });
322         
323         // If the user specifies the headers collection manually then dont inject our own
324         if (!me.columns) {
325             if (me.initialConfig.hideHeaders === undefined) {
326                 me.hideHeaders = true;
327             }
328             me.columns = [{
329                 xtype    : 'treecolumn',
330                 text     : 'Name',
331                 flex     : 1,
332                 dataIndex: me.displayField         
333             }];
334         }
335         
336         if (me.cls) {
337             cls.push(me.cls);
338         }
339         me.cls = cls.join(' ');
340         me.callParent();
341         
342         me.relayEvents(me.getView(), [
343 <span id='Ext-tree-Panel-event-checkchange'>            /**
344 </span>             * @event checkchange
345              * Fires when a node with a checkbox's checked property changes
346              * @param {Ext.data.Model} node The node who's checked property was changed
347              * @param {Boolean} checked The node's new checked state
348              */
349             'checkchange'
350         ]);
351             
352         // If the root is not visible and there is no rootnode defined, then just lets load the store
353         if (!me.getView().rootVisible &amp;&amp; !me.getRootNode()) {
354             me.setRootNode({
355                 expanded: true
356             });
357         }
358     },
359     
360     onClear: function(){
361         this.view.onClear();
362     },
363     
364     setRootNode: function() {
365         return this.store.setRootNode.apply(this.store, arguments);
366     },
367     
368     getRootNode: function() {
369         return this.store.getRootNode();
370     },
371     
372     onRootChange: function(root) {
373         this.view.setRootNode(root);
374     },
375
376 <span id='Ext-tree-Panel-method-getChecked'>    /**
377 </span>     * Retrieve an array of checked records.
378      * @return {Array} An array containing the checked records
379      */
380     getChecked: function() {
381         return this.getView().getChecked();
382     },
383     
384     isItemChecked: function(rec) {
385         return rec.get('checked');
386     },
387         
388 <span id='Ext-tree-Panel-method-expandAll'>    /**
389 </span>     * Expand all nodes
390      * @param {Function} callback (optional) A function to execute when the expand finishes.
391      * @param {Object} scope (optional) The scope of the callback function
392      */
393     expandAll : function(callback, scope) {
394         var root = this.getRootNode();
395         if (root) {
396             root.expand(true, callback, scope);
397         }
398     },
399
400 <span id='Ext-tree-Panel-method-collapseAll'>    /**
401 </span>     * Collapse all nodes
402      * @param {Function} callback (optional) A function to execute when the collapse finishes.
403      * @param {Object} scope (optional) The scope of the callback function
404      */
405     collapseAll : function(callback, scope) {
406         var root = this.getRootNode();
407         if (root) {
408             if (this.getView().rootVisible) {
409                 root.collapse(true, callback, scope);
410             }
411             else {
412                 root.collapseChildren(true, callback, scope);
413             }
414         }
415     },
416
417 <span id='Ext-tree-Panel-method-expandPath'>    /**
418 </span>     * Expand the tree to the path of a particular node.
419      * @param {String} path The path to expand. The path should include a leading separator.
420      * @param {String} field (optional) The field to get the data from. Defaults to the model idProperty.
421      * @param {String} separator (optional) A separator to use. Defaults to `'/'`.
422      * @param {Function} callback (optional) A function to execute when the expand finishes. The callback will be called with
423      * (success, lastNode) where success is if the expand was successful and lastNode is the last node that was expanded.
424      * @param {Object} scope (optional) The scope of the callback function
425      */
426     expandPath: function(path, field, separator, callback, scope) {
427         var me = this,
428             current = me.getRootNode(),
429             index = 1,
430             view = me.getView(),
431             keys,
432             expander;
433         
434         field = field || me.getRootNode().idProperty;
435         separator = separator || '/';
436         
437         if (Ext.isEmpty(path)) {
438             Ext.callback(callback, scope || me, [false, null]);
439             return;
440         }
441         
442         keys = path.split(separator);
443         if (current.get(field) != keys[1]) {
444             // invalid root
445             Ext.callback(callback, scope || me, [false, current]);
446             return;
447         }
448         
449         expander = function(){
450             if (++index === keys.length) {
451                 Ext.callback(callback, scope || me, [true, current]);
452                 return;
453             }
454             var node = current.findChild(field, keys[index]);
455             if (!node) {
456                 Ext.callback(callback, scope || me, [false, current]);
457                 return;
458             }
459             current = node;
460             current.expand(false, expander);
461         };
462         current.expand(false, expander);
463     },
464     
465 <span id='Ext-tree-Panel-method-selectPath'>    /**
466 </span>     * Expand the tree to the path of a particular node, then selecti t.
467      * @param {String} path The path to select. The path should include a leading separator.
468      * @param {String} field (optional) The field to get the data from. Defaults to the model idProperty.
469      * @param {String} separator (optional) A separator to use. Defaults to `'/'`.
470      * @param {Function} callback (optional) A function to execute when the select finishes. The callback will be called with
471      * (bSuccess, oLastNode) where bSuccess is if the select was successful and oLastNode is the last node that was expanded.
472      * @param {Object} scope (optional) The scope of the callback function
473      */
474     selectPath: function(path, field, separator, callback, scope) {
475         var me = this,
476             keys,
477             last;
478         
479         field = field || me.getRootNode().idProperty;
480         separator = separator || '/';
481         
482         keys = path.split(separator);
483         last = keys.pop();
484         
485         me.expandPath(keys.join(separator), field, separator, function(success, node){
486             var doSuccess = false;
487             if (success &amp;&amp; node) {
488                 node = node.findChild(field, last);
489                 if (node) {
490                     me.getSelectionModel().select(node);
491                     Ext.callback(callback, scope || me, [true, node]);
492                     doSuccess = true;
493                 }
494             } else if (node === me.getRootNode()) {
495                 doSuccess = true;
496             }
497             Ext.callback(callback, scope || me, [doSuccess, node]);
498         }, me);
499     }
500 });
501 </pre>
502 </body>
503 </html>