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