major doc changes
[roojs1] / Roo / tree / TreePanel.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13 /**
14  * @class Roo.tree.TreePanel
15  * @extends Roo.data.Tree
16  * @cfg {Roo.tree.TreeNode} root The root node
17  * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
18  * @cfg {Boolean} lines false to disable tree lines (defaults to true)
19  * @cfg {Boolean} enableDD true to enable drag and drop
20  * @cfg {Boolean} enableDrag true to enable just drag
21  * @cfg {Boolean} enableDrop true to enable just drop
22  * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
23  * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
24  * @cfg {String} ddGroup The DD group this TreePanel belongs to
25  * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
26  * @cfg {Boolean} ddScroll true to enable YUI body scrolling
27  * @cfg {Boolean} containerScroll true to register this container with ScrollManager
28  * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
29  * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
30  * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
31  * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32  * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
33  * @cfg {Roo.tree.TreeLoader} loader A TreeLoader for use with this TreePanel
34  * @cfg {Roo.tree.TreeEditor} editor The TreeEditor to display when clicked.
35  * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
36  * @cfg {Function} renderer DEPRECATED - use TreeLoader:create event / Sets the rendering (formatting) function for the nodes. to return HTML markup for the tree view. The render function is called with  the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
37  * @cfg {Function} rendererTip DEPRECATED - use TreeLoader:create event / Sets the rendering (formatting) function for the nodes hovertip to return HTML markup for the tree view. The render function is called with  the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
38  * 
39  * @constructor
40  * @param {String/HTMLElement/Element} el The container element
41  * @param {Object} config
42  */
43 Roo.tree.TreePanel = function(el, config){
44     var root = false;
45     var loader = false;
46     if (config.root) {
47         root = config.root;
48         delete config.root;
49     }
50     if (config.loader) {
51         loader = config.loader;
52         delete config.loader;
53     }
54     
55     Roo.apply(this, config);
56     Roo.tree.TreePanel.superclass.constructor.call(this);
57     this.el = Roo.get(el);
58     this.el.addClass('x-tree');
59     //console.log(root);
60     if (root) {
61         this.setRootNode( Roo.factory(root, Roo.tree));
62     }
63     if (loader) {
64         this.loader = Roo.factory(loader, Roo.tree);
65     }
66    /**
67     * Read-only. The id of the container element becomes this TreePanel's id.
68     */
69     this.id = this.el.id;
70     this.addEvents({
71         /**
72         * @event beforeload
73         * Fires before a node is loaded, return false to cancel
74         * @param {Node} node The node being loaded
75         */
76         "beforeload" : true,
77         /**
78         * @event load
79         * Fires when a node is loaded
80         * @param {Node} node The node that was loaded
81         */
82         "load" : true,
83         /**
84         * @event textchange
85         * Fires when the text for a node is changed
86         * @param {Node} node The node
87         * @param {String} text The new text
88         * @param {String} oldText The old text
89         */
90         "textchange" : true,
91         /**
92         * @event beforeexpand
93         * Fires before a node is expanded, return false to cancel.
94         * @param {Node} node The node
95         * @param {Boolean} deep
96         * @param {Boolean} anim
97         */
98         "beforeexpand" : true,
99         /**
100         * @event beforecollapse
101         * Fires before a node is collapsed, return false to cancel.
102         * @param {Node} node The node
103         * @param {Boolean} deep
104         * @param {Boolean} anim
105         */
106         "beforecollapse" : true,
107         /**
108         * @event expand
109         * Fires when a node is expanded
110         * @param {Node} node The node
111         */
112         "expand" : true,
113         /**
114         * @event disabledchange
115         * Fires when the disabled status of a node changes
116         * @param {Node} node The node
117         * @param {Boolean} disabled
118         */
119         "disabledchange" : true,
120         /**
121         * @event collapse
122         * Fires when a node is collapsed
123         * @param {Node} node The node
124         */
125         "collapse" : true,
126         /**
127         * @event beforeclick
128         * Fires before click processing on a node. Return false to cancel the default action.
129         * @param {Node} node The node
130         * @param {Roo.EventObject} e The event object
131         */
132         "beforeclick":true,
133         /**
134         * @event checkchange
135         * Fires when a node with a checkbox's checked property changes
136         * @param {Node} this This node
137         * @param {Boolean} checked
138         */
139         "checkchange":true,
140         /**
141         * @event click
142         * Fires when a node is clicked
143         * @param {Node} node The node
144         * @param {Roo.EventObject} e The event object
145         */
146         "click":true,
147         /**
148         * @event dblclick
149         * Fires when a node is double clicked
150         * @param {Node} node The node
151         * @param {Roo.EventObject} e The event object
152         */
153         "dblclick":true,
154         /**
155         * @event contextmenu
156         * Fires when a node is right clicked
157         * @param {Node} node The node
158         * @param {Roo.EventObject} e The event object
159         */
160         "contextmenu":true,
161         /**
162         * @event beforechildrenrendered
163         * Fires right before the child nodes for a node are rendered
164         * @param {Node} node The node
165         */
166         "beforechildrenrendered":true,
167         /**
168         * @event startdrag
169         * Fires when a node starts being dragged
170         * @param {Roo.tree.TreePanel} this
171         * @param {Roo.tree.TreeNode} node
172         * @param {event} e The raw browser event
173         */ 
174        "startdrag" : true,
175        /**
176         * @event enddrag
177         * Fires when a drag operation is complete
178         * @param {Roo.tree.TreePanel} this
179         * @param {Roo.tree.TreeNode} node
180         * @param {event} e The raw browser event
181         */
182        "enddrag" : true,
183        /**
184         * @event dragdrop
185         * Fires when a dragged node is dropped on a valid DD target
186         * @param {Roo.tree.TreePanel} this
187         * @param {Roo.tree.TreeNode} node
188         * @param {DD} dd The dd it was dropped on
189         * @param {event} e The raw browser event
190         */
191        "dragdrop" : true,
192        /**
193         * @event beforenodedrop
194         * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
195         * passed to handlers has the following properties:<br />
196         * <ul style="padding:5px;padding-left:16px;">
197         * <li>tree - The TreePanel</li>
198         * <li>target - The node being targeted for the drop</li>
199         * <li>data - The drag data from the drag source</li>
200         * <li>point - The point of the drop - append, above or below</li>
201         * <li>source - The drag source</li>
202         * <li>rawEvent - Raw mouse event</li>
203         * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
204         * to be inserted by setting them on this object.</li>
205         * <li>cancel - Set this to true to cancel the drop.</li>
206         * </ul>
207         * @param {Object} dropEvent
208         */
209        "beforenodedrop" : true,
210        /**
211         * @event nodedrop
212         * Fires after a DD object is dropped on a node in this tree. The dropEvent
213         * passed to handlers has the following properties:<br />
214         * <ul style="padding:5px;padding-left:16px;">
215         * <li>tree - The TreePanel</li>
216         * <li>target - The node being targeted for the drop</li>
217         * <li>data - The drag data from the drag source</li>
218         * <li>point - The point of the drop - append, above or below</li>
219         * <li>source - The drag source</li>
220         * <li>rawEvent - Raw mouse event</li>
221         * <li>dropNode - Dropped node(s).</li>
222         * </ul>
223         * @param {Object} dropEvent
224         */
225        "nodedrop" : true,
226         /**
227         * @event nodedragover
228         * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
229         * passed to handlers has the following properties:<br />
230         * <ul style="padding:5px;padding-left:16px;">
231         * <li>tree - The TreePanel</li>
232         * <li>target - The node being targeted for the drop</li>
233         * <li>data - The drag data from the drag source</li>
234         * <li>point - The point of the drop - append, above or below</li>
235         * <li>source - The drag source</li>
236         * <li>rawEvent - Raw mouse event</li>
237         * <li>dropNode - Drop node(s) provided by the source.</li>
238         * <li>cancel - Set this to true to signal drop not allowed.</li>
239         * </ul>
240         * @param {Object} dragOverEvent
241         */
242        "nodedragover" : true,
243        /**
244         * @event appendnode
245         * Fires when append node to the tree
246         * @param {Roo.tree.TreePanel} this
247         * @param {Roo.tree.TreeNode} node
248         * @param {Number} index The index of the newly appended node
249         */
250        "appendnode" : true
251         
252     });
253     if(this.singleExpand){
254        this.on("beforeexpand", this.restrictExpand, this);
255     }
256     if (this.editor) {
257         this.editor.tree = this;
258         this.editor = Roo.factory(this.editor, Roo.tree);
259     }
260     
261     if (this.selModel) {
262         this.selModel = Roo.factory(this.selModel, Roo.tree);
263     }
264    
265 };
266 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
267     rootVisible : true,
268     animate: Roo.enableFx,
269     lines : true,
270     enableDD : false,
271     hlDrop : Roo.enableFx,
272   
273     renderer: false,
274     
275     rendererTip: false,
276     // private
277     restrictExpand : function(node){
278         var p = node.parentNode;
279         if(p){
280             if(p.expandedChild && p.expandedChild.parentNode == p){
281                 p.expandedChild.collapse();
282             }
283             p.expandedChild = node;
284         }
285     },
286
287     // private override
288     setRootNode : function(node){
289         Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
290         if(!this.rootVisible){
291             node.ui = new Roo.tree.RootTreeNodeUI(node);
292         }
293         return node;
294     },
295
296     /**
297      * Returns the container element for this TreePanel
298      */
299     getEl : function(){
300         return this.el;
301     },
302
303     /**
304      * Returns the default TreeLoader for this TreePanel
305      */
306     getLoader : function(){
307         return this.loader;
308     },
309
310     /**
311      * Expand all nodes
312      */
313     expandAll : function(){
314         this.root.expand(true);
315     },
316
317     /**
318      * Collapse all nodes
319      */
320     collapseAll : function(){
321         this.root.collapse(true);
322     },
323
324     /**
325      * Returns the selection model used by this TreePanel
326      */
327     getSelectionModel : function(){
328         if(!this.selModel){
329             this.selModel = new Roo.tree.DefaultSelectionModel();
330         }
331         return this.selModel;
332     },
333
334     /**
335      * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
336      * @param {String} attribute (optional) Defaults to null (return the actual nodes)
337      * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
338      * @return {Array}
339      */
340     getChecked : function(a, startNode){
341         startNode = startNode || this.root;
342         var r = [];
343         var f = function(){
344             if(this.attributes.checked){
345                 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
346             }
347         }
348         startNode.cascade(f);
349         return r;
350     },
351
352     /**
353      * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
354      * @param {String} path
355      * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
356      * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
357      * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
358      */
359     expandPath : function(path, attr, callback){
360         attr = attr || "id";
361         var keys = path.split(this.pathSeparator);
362         var curNode = this.root;
363         if(curNode.attributes[attr] != keys[1]){ // invalid root
364             if(callback){
365                 callback(false, null);
366             }
367             return;
368         }
369         var index = 1;
370         var f = function(){
371             if(++index == keys.length){
372                 if(callback){
373                     callback(true, curNode);
374                 }
375                 return;
376             }
377             var c = curNode.findChild(attr, keys[index]);
378             if(!c){
379                 if(callback){
380                     callback(false, curNode);
381                 }
382                 return;
383             }
384             curNode = c;
385             c.expand(false, false, f);
386         };
387         curNode.expand(false, false, f);
388     },
389
390     /**
391      * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
392      * @param {String} path
393      * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
394      * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
395      * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
396      */
397     selectPath : function(path, attr, callback){
398         attr = attr || "id";
399         var keys = path.split(this.pathSeparator);
400         var v = keys.pop();
401         if(keys.length > 0){
402             var f = function(success, node){
403                 if(success && node){
404                     var n = node.findChild(attr, v);
405                     if(n){
406                         n.select();
407                         if(callback){
408                             callback(true, n);
409                         }
410                     }else if(callback){
411                         callback(false, n);
412                     }
413                 }else{
414                     if(callback){
415                         callback(false, n);
416                     }
417                 }
418             };
419             this.expandPath(keys.join(this.pathSeparator), attr, f);
420         }else{
421             this.root.select();
422             if(callback){
423                 callback(true, this.root);
424             }
425         }
426     },
427
428     getTreeEl : function(){
429         return this.el;
430     },
431
432     /**
433      * Trigger rendering of this TreePanel
434      */
435     render : function(){
436         if (this.innerCt) {
437             return this; // stop it rendering more than once!!
438         }
439         
440         this.innerCt = this.el.createChild({tag:"ul",
441                cls:"x-tree-root-ct " +
442                (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
443
444         if(this.containerScroll){
445             Roo.dd.ScrollManager.register(this.el);
446         }
447         if((this.enableDD || this.enableDrop) && !this.dropZone){
448            /**
449             * The dropZone used by this tree if drop is enabled
450             * @type Roo.tree.TreeDropZone
451             */
452              this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
453                ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
454            });
455         }
456         if((this.enableDD || this.enableDrag) && !this.dragZone){
457            /**
458             * The dragZone used by this tree if drag is enabled
459             * @type Roo.tree.TreeDragZone
460             */
461             this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
462                ddGroup: this.ddGroup || "TreeDD",
463                scroll: this.ddScroll
464            });
465         }
466         this.getSelectionModel().init(this);
467         if (!this.root) {
468             Roo.log("ROOT not set in tree");
469             return this;
470         }
471         this.root.render();
472         if(!this.rootVisible){
473             this.root.renderChildren();
474         }
475         return this;
476     }
477 });