initial import
[roojs1] / examples / tree / dependency.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  */\r
11 Roo.onReady(function(){\r
12     var xt = Roo.tree;\r
13     // seeds for the new node suffix\r
14     var cseed = 0, oseed = 0;\r
15 \r
16     // turn on quick tips\r
17     Roo.QuickTips.init();\r
18 \r
19     var cview = Roo.DomHelper.append('main-ct',\r
20         {cn:[{id:'main-tb'},{id:'cbody'}]}\r
21     );\r
22 \r
23 \r
24     // create the primary toolbar\r
25     var tb = new Roo.Toolbar('main-tb');\r
26     tb.add({\r
27         id:'save',\r
28         text:'Save',\r
29         disabled:true,\r
30         handler:save,\r
31         cls:'x-btn-text-icon save',\r
32         tooltip:'Saves all components to the server'\r
33     },'-', {\r
34         id:'add',\r
35         text:'Component',\r
36         handler:addComponent,\r
37         cls:'x-btn-text-icon add-cmp',\r
38         tooltip:'Add a new Component to the dependency builder'\r
39     }, {\r
40         id:'option',\r
41         text:'Option',\r
42         disabled:true,\r
43         handler:addOption,\r
44         cls:'x-btn-text-icon add-opt',\r
45         tooltip:'Add a new optional dependency to the selected component'\r
46     },'-',{\r
47         id:'remove',\r
48         text:'Remove',\r
49         disabled:true,\r
50         handler:removeNode,\r
51         cls:'x-btn-text-icon remove',\r
52         tooltip:'Remove the selected item'\r
53     });\r
54     // for enabling and disabling\r
55     var btns = tb.items.map;\r
56 \r
57 \r
58 \r
59     // create our layout\r
60     var layout = new Roo.BorderLayout('main-ct', {\r
61         west: {\r
62             split:true,\r
63             initialSize: 200,\r
64             minSize: 175,\r
65             maxSize: 400,\r
66             titlebar: true,\r
67             margins:{left:5,right:0,bottom:5,top:5}\r
68         },\r
69         center: {\r
70             title:'Components',\r
71             margins:{left:0,right:5,bottom:5,top:5}\r
72         }\r
73     }, 'main-ct');\r
74 \r
75     layout.batchAdd({\r
76        west: {\r
77            id: 'source-files',\r
78            autoCreate:true,\r
79            title:'Ext Source Files',\r
80            autoScroll:true,\r
81            fitToFrame:true\r
82        },\r
83        center : {\r
84            el: cview,\r
85            autoScroll:true,\r
86            fitToFrame:true,\r
87            toolbar: tb,\r
88            resizeEl:'cbody'\r
89        }\r
90     });\r
91 \r
92 \r
93 \r
94     // this is the source code tree\r
95     var stree = new xt.TreePanel('source-files', {\r
96         animate:true,\r
97         loader: new xt.TreeLoader({dataUrl:'dependency.php'}),\r
98         enableDrag:true,\r
99         containerScroll: true\r
100     });\r
101 \r
102     new xt.TreeSorter(stree, {folderSort:true});\r
103 \r
104     var sroot = new xt.AsyncTreeNode({\r
105         text: 'Ext JS',\r
106         draggable:false,\r
107         id:'source'\r
108     });\r
109     stree.setRootNode(sroot);\r
110     stree.render();\r
111     sroot.expand(false, false);\r
112 \r
113 \r
114     // the component tree\r
115     var ctree = new xt.TreePanel('cbody', {\r
116         animate:true,\r
117         enableDD:true,\r
118         containerScroll: true,\r
119         lines:false,\r
120         rootVisible:false,\r
121         loader: new Roo.tree.TreeLoader()\r
122     });\r
123 \r
124     ctree.el.addKeyListener(Roo.EventObject.DELETE, removeNode);\r
125 \r
126     var croot = new xt.AsyncTreeNode({\r
127         allowDrag:false,\r
128         allowDrop:true,\r
129         id:'croot',\r
130         text:'Packages and Components',\r
131         cls:'croot',\r
132         loader:new Roo.tree.TreeLoader({\r
133             dataUrl:'dep-tree.json',\r
134             createNode: readNode\r
135         })\r
136     });\r
137     ctree.setRootNode(croot);\r
138     ctree.render();\r
139     croot.expand();\r
140 \r
141     // some functions to determine whether is not the drop is allowed\r
142     function hasNode(t, n){\r
143         return (t.attributes.type == 'fileCt' && t.findChild('id', n.id)) ||\r
144             (t.leaf === true && t.parentNode.findChild('id', n.id));\r
145     };\r
146 \r
147     function isSourceCopy(e, n){\r
148         var a = e.target.attributes;\r
149         return n.getOwnerTree() == stree && !hasNode(e.target, n) &&\r
150            ((e.point == 'append' && a.type == 'fileCt') || a.leaf === true);\r
151     };\r
152 \r
153     function isReorder(e, n){\r
154         return n.parentNode == e.target.parentNode && e.point != 'append';\r
155     };\r
156 \r
157     // handle drag over and drag drop\r
158     ctree.on('nodedragover', function(e){\r
159         var n = e.dropNode;\r
160         return isSourceCopy(e, n) || isReorder(e, n);\r
161     });\r
162 \r
163     ctree.on('beforenodedrop', function(e){\r
164         var n = e.dropNode;\r
165 \r
166         // copy node from source tree\r
167         if(isSourceCopy(e, n)){\r
168             var copy = new xt.TreeNode(\r
169                 Roo.apply({allowDelete:true,expanded:true}, n.attributes)\r
170             );\r
171             copy.loader = undefined;\r
172             if(e.target.attributes.options){\r
173                 e.target = createOption(e.target, copy.text);\r
174                 //return false;\r
175             }\r
176             e.dropNode = copy;\r
177             return true;\r
178         }\r
179 \r
180         return isReorder(e, n);\r
181     });\r
182 \r
183     ctree.on('contextmenu', prepareCtx);\r
184 \r
185     // track whether save is allowed\r
186     ctree.on('append', trackSave);\r
187     ctree.on('remove', trackSave);\r
188     ctree.el.swallowEvent('contextmenu', true);\r
189     ctree.el.on('keypress', function(e){\r
190         if(e.isNavKeyPress()){\r
191             e.stopEvent();\r
192         }\r
193     });\r
194     // when the tree selection changes, enable/disable the toolbar buttons\r
195     var sm = ctree.getSelectionModel();\r
196     sm.on('selectionchange', function(){\r
197         var n = sm.getSelectedNode();\r
198         if(!n){\r
199             btns.remove.disable();\r
200             btns.option.disable();\r
201             return;\r
202         }\r
203         var a = n.attributes;\r
204         btns.remove.setDisabled(!a.allowDelete);\r
205         btns.option.setDisabled(!a.cmpId);\r
206     });\r
207 \r
208 \r
209 \r
210     // create the editor for the component tree\r
211     var ge = new xt.TreeEditor(ctree, {\r
212         allowBlank:false,\r
213         blankText:'A name is required',\r
214         selectOnFocus:true\r
215     });\r
216     \r
217     ge.on('beforestartedit', function(){\r
218         if(!ge.editNode.attributes.allowEdit){\r
219             return false;\r
220         }\r
221     });\r
222 \r
223 \r
224     // add component handler\r
225     function addComponent(){\r
226         var id = guid('c-');\r
227         var text = 'Component '+(++cseed);\r
228         var node = createComponent(id, text);\r
229         node.expand(false, false);\r
230         node.select();\r
231         node.lastChild.ensureVisible();\r
232         ge.triggerEdit(node);\r
233     }\r
234 \r
235     function createComponent(id, text, cfiles, cdep, coptions){\r
236         var node = new xt.TreeNode({\r
237             text: text,\r
238             iconCls:'cmp',\r
239             cls:'cmp',\r
240             type:'cmp',\r
241             id: id,\r
242             cmpId:id,\r
243             allowDelete:true,\r
244             allowEdit:true\r
245         });\r
246         croot.appendChild(node);\r
247 \r
248         var files = new xt.AsyncTreeNode({\r
249             text: 'Files',\r
250             allowDrag:false,\r
251             allowDrop:true,\r
252             iconCls:'folder',\r
253             type:'fileCt',\r
254             cmpId:id,\r
255             allowDelete:false,\r
256             children:cfiles||[],\r
257             expanded:true\r
258         });\r
259 \r
260         var dep = new xt.AsyncTreeNode({\r
261             text: 'Dependencies',\r
262             allowDrag:false,\r
263             allowDrop:true,\r
264             iconCls:'folder',\r
265             type:'fileCt',\r
266             cmpId:id,\r
267             allowDelete:false,\r
268             children:cdep||[],\r
269             expanded:true,\r
270             allowCopy:true\r
271         });\r
272 \r
273         var options = new xt.AsyncTreeNode({\r
274             text: 'Optional Dependencies',\r
275             allowDrag:false,\r
276             allowDrop:true,\r
277             iconCls:'folder',\r
278             type:'fileCt',\r
279             options:true,\r
280             cmpId:id,\r
281             allowDelete:false,\r
282             children:coptions||[],\r
283             expanded:true,\r
284             allowCopy:true\r
285         });\r
286 \r
287         node.appendChild(files);\r
288         node.appendChild(dep);\r
289         node.appendChild(options);\r
290 \r
291         return node;\r
292     }\r
293 \r
294     // remove handler\r
295     function removeNode(){\r
296         var n = sm.getSelectedNode();\r
297         if(n && n.attributes.allowDelete){\r
298             ctree.getSelectionModel().selectPrevious();\r
299             n.parentNode.removeChild(n);\r
300         }\r
301     }\r
302 \r
303 \r
304     // add option handler\r
305     function addOption(){\r
306         var n = sm.getSelectedNode();\r
307         if(n){\r
308             var node = createOption(n, 'Option'+(++oseed));\r
309             node.select();\r
310             ge.triggerEdit(node);\r
311         }\r
312     }\r
313 \r
314     function createOption(n, text){\r
315         var cnode = ctree.getNodeById(n.attributes.cmpId);\r
316 \r
317         var node = new xt.TreeNode({\r
318             text: text,\r
319             cmpId:cnode.id,\r
320             iconCls:'folder',\r
321             type:'fileCt',\r
322             allowDelete:true,\r
323             allowEdit:true,\r
324             id:guid('o-')\r
325         });\r
326         cnode.childNodes[2].appendChild(node);\r
327         cnode.childNodes[2].expand(false, false);\r
328 \r
329         return node;\r
330     }\r
331 \r
332     // semi unique ids across edits\r
333     function guid(prefix){\r
334         return prefix+(new Date().getTime());\r
335     }\r
336 \r
337 \r
338     function trackSave(){\r
339         btns.save.setDisabled(!croot.hasChildNodes());\r
340     }\r
341 \r
342     function storeChildren(cmp, n, name){\r
343         if(n.childrenRendered){\r
344             cmp[name] = [];\r
345             n.eachChild(function(f){\r
346                 cmp[name].push(f.attributes);\r
347             });\r
348         }else{\r
349             cmp[name] = n.attributes.children || [];\r
350         }\r
351     }\r
352 \r
353     // save to the server in a format usable in PHP\r
354     function save(){\r
355         var ch = [];\r
356         croot.eachChild(function(c){\r
357             var cmp = {\r
358                 text:c.text,\r
359                 id: c.id,\r
360                 options:[]\r
361             };\r
362 \r
363             storeChildren(cmp, c.childNodes[0], 'files');\r
364             storeChildren(cmp, c.childNodes[1], 'dep');\r
365 \r
366             var onode = c.childNodes[2];\r
367             if(!onode.childrenRendered){\r
368                 cmp.options = onode.attributes.children || [];\r
369             }else{\r
370                 onode.eachChild(function(o){\r
371                     var opt = Roo.apply({}, o.attributes);\r
372                     storeChildren(opt, o, 'children');\r
373                     cmp.options.push(opt);\r
374                 });\r
375             }\r
376             ch.push(cmp);\r
377         });\r
378 \r
379         layout.el.mask('Sending data to server...', 'x-mask-loading');\r
380         var hide = layout.el.unmask.createDelegate(layout.el);\r
381         Roo.lib.Ajax.request(\r
382             'POST',\r
383             'save-dep.php',\r
384             {success:hide,failure:hide},\r
385             'data='+encodeURIComponent(Roo.encode(ch))\r
386         );\r
387     }\r
388 \r
389     function readNode(o){\r
390         createComponent(o.id, o.text, o.files, o.dep, o.options);\r
391     }\r
392 \r
393     // context menus\r
394 \r
395     var ctxMenu = new Roo.menu.Menu({\r
396         id:'copyCtx',\r
397         items: [{\r
398                 id:'expand',\r
399                 handler:expandAll,\r
400                 cls:'expand-all',\r
401                 text:'Expand All'\r
402             },{\r
403                 id:'collapse',\r
404                 handler:collapseAll,\r
405                 cls:'collapse-all',\r
406                 text:'Collapse All'\r
407             },'-',{\r
408                 id:'remove',\r
409                 handler:removeNode,\r
410                 cls:'remove-mi',\r
411                 text: 'Remove Item'\r
412         }]\r
413     });\r
414 \r
415     function prepareCtx(node, e){\r
416         node.select();\r
417         ctxMenu.items.get('remove')[node.attributes.allowDelete ? 'enable' : 'disable']();\r
418         ctxMenu.showAt(e.getXY());\r
419     }\r
420 \r
421     function collapseAll(){\r
422         ctxMenu.hide();\r
423         setTimeout(function(){\r
424             croot.eachChild(function(n){\r
425                n.collapse(false, false);\r
426             });\r
427         }, 10);\r
428     }\r
429 \r
430     function expandAll(){\r
431         ctxMenu.hide();\r
432         setTimeout(function(){\r
433             croot.eachChild(function(n){\r
434                n.expand(false, false);\r
435             });\r
436         }, 10);\r
437     }\r
438 });