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