Pman.Builder.Tree.js
[Pman.Builder] / Pman.Builder.Tree.js
1 /**
2  * The code that manages the tree...
3  *
4  * used to be inside the Interface, but has proved to be to difficult to manage.
5  *
6  * In principle, simple event handling code is put in the interface, and any hard
7  * lifting is done in nice files...
8  *
9  * It might be better to just extend 'tree', and use the extended class..
10  * 
11  */
12
13 Pman.Builder.Tree = {
14     
15     currentNode: false,
16     dragProp: '',
17     
18     appendNode : function(parent, inConfig, point) {
19                                 
20                                     
21         var tree = Pman.Tab.BuilderTree.tree;
22         
23         
24         var items = [];
25         if (inConfig.items) { // loading!
26             items = inConfig.items;
27             delete inConfig.items;
28         }
29         
30         var config = this.cloneConfig(inConfig);
31         
32         if (!parent) {
33             parent = tree.root;
34         }
35               
36         var newNode = new Roo.tree.TreeNode({
37                 text: this.configToText(config)
38         });
39                 
40         
41         newNode.elConfig = config;
42         //if (markUndo === true) {
43         //Pman.Tab.Builder.markUndo("Add " + newNode.text);
44         //
45             // appends to our tree...
46         console.log("APPEND NODE: " + point);    
47         switch(point) {
48             case 'above':
49                 parent.parentNode.insertBefore(newNode, parent);
50                 break;
51             case 'below':
52                 // if it's the last node.. then we append..
53                 var ix = parent.parentNode.indexOf(parent) + 1;
54                 if (parent.parentNode.childNodes.length == ix) {
55                      parent.parentNode.appendChild(newNode);
56                      break;
57                 }
58                 var bef = parent.parentNode.childNodes[ix];
59                 parent.parentNode.insertBefore(newNode, bef);
60                 break;
61             
62             case 'append':
63             default:    
64                 parent.appendChild(newNode);
65                 break;
66         }
67             
68         if (items.length) {
69             Roo.each(items, function(i) {
70                 this.appendNode(newNode, i);
71             },this);
72             
73         }
74             
75             
76             /*
77             -- panels with panes...
78                 if (items && items.length) {
79                         for (var i = 0; i < items.length; i++) {
80                                         this.appendConfig(items[i], newNode, false);
81                         }
82                 }
83                 if (opts.doUpdate !== false) {
84                         this.updateForm(false, newNode);
85                 }
86             */
87         return newNode;
88         
89          
90     },
91     clearAll : function() {
92         var tree = Pman.Tab.BuilderTree.tree;
93         
94         var rt = tree.root;
95          if (rt.childNodes.length) {
96             rt.removeChild(rt.childNodes[0]);
97         }
98         
99         tree.root.elConfig  = Roo.apply({ }, this.defaultElConfig());  
100         //var btop = Pman.Tab.BuilderTop;
101         //if (btop.modsel && btop.modsel.lastData) {
102         //    this.tree.root.elConfig.app = btop.modsel.lastData.app;
103         //}
104         
105         this.setCurrentNode(tree.root,true);
106         
107     },
108     cloneConfig : function(config) {
109         if (!config) { return null; }
110         var newConfig = {};
111         
112         for (var i in config) {
113             if (typeof config[i] == 'object') {
114                  newConfig[i] = this.cloneConfig(config[i]);
115             } else if (typeof config[i] != 'function') { // should this happen?
116                  newConfig[i] = config[i];
117             }
118         }
119         return newConfig;
120     },
121     configToText : function(c) {
122          
123         var txt = [];
124         c = c || {};
125               var sr = (typeof(c['+buildershow']) != 'undefined') &&  !c['+buildershow'] ? true : false;
126             if (sr) txt.push('<s>');
127             if (typeof(c['*prop']) != 'undefined')   { txt.push(c['*prop']+ ':'); }
128         if (c.xtype)      { txt.push(c.xtype); }
129         if (c.fieldLabel) { txt.push('[' + c.fieldLabel + ']'); }
130         if (c.boxLabel)   { txt.push('[' + c.boxLabel + ']'); }
131         
132         
133         if (c.layout)     { txt.push('<i>' + c.layout + '</i>'); }
134         if (c.title)      { txt.push('<b>' + c.title + '</b>'); }
135             if (c.header)    { txt.push('<b>' + c.header + '</b>'); }
136             if (c.legend)      { txt.push('<b>' + c.legend + '</b>'); }
137         if (c.text)       { txt.push('<b>' + c.text + '</b>'); }
138             if (c.name)       { txt.push('<b>' + c.name+ '</b>'); }
139         if (c.region)     { txt.push('<i>(' + c.region + ')</i>'); }
140             if (c.dataIndex) { txt.push('[' + c.dataIndex+ ']'); }
141             if (sr) txt.push('</s>');
142         return (txt.length == 0 ? "Element" : txt.join(" "));
143         
144         
145     },
146     currentNodeType : function() {
147         return this.nodeXtype(this.currentNode);
148         
149     },
150     defaultElConfig : function() {
151         return {
152            xtype : '*top',
153             
154             module : 'TestApp',
155             part:   'Partname',
156             modkey : 0,
157             region : 'center',
158             parent : 'Pman',
159             name : 'Module Name',
160             items: [] 
161         };
162     },
163     deleteCurrent : function()
164     {
165         if (this.currentNode == tree.root) {
166             return false;
167         }
168         var cfg = this.currentNode.elConfig;
169         // things that can not be deleted...
170         
171         
172         var pn = this.currentNode.parentNode;
173         
174         
175         var ix = pn.indexOf(this.currentNode);
176         //  console.log(ix);
177         pn.removeChild(this.currentNode);
178         if (pn.childNodes.length) {
179             ix = Math.min(pn.childNodes.length-1, ix);
180         }
181         this.setCurrentNode(pn.childNodes.length ? pn.childNodes[ix] : pn  ,true);
182         return true;
183     },
184     dupeNode : function(node)
185         {
186             var cfg = this.cloneConfig(node.elConfig);
187             
188             var newNode = new Roo.tree.TreeNode(
189             {
190                     id: Roo.id(),
191                     text: this.configToText(cfg)
192             });
193             
194             newNode.elConfig = cfg;
195             node.eachChild(function(n) {
196                 newNode.appendChild(this.dupeNode(n));
197             },this);
198             
199             return newNode;
200                 
201     },
202     loadBJS : function(module, part) {
203         var _t = this;
204         new Pman.Request({
205             url : baseURL + '/Roo/Builder_part.php',
206             method : 'GET',
207             params : {
208                _id : part
209             },
210             success : function(res)         
211             {
212                 // data is in.. 
213                 Roo.log(res);
214                 
215                 if (!res.data.json.length) {
216                     var cfg = _t.defaultElConfig();
217                     cfg.name = Pman.Tab.BuilderTop.filesel.lastData.name;
218                     cfg.part = Pman.Tab.BuilderTop.filesel.lastData.name;
219                     cfg.module = '';
220                     _t.loadTree(cfg);
221                     return;
222                 
223                 }
224                 
225                 _t.loadTree(JSON.parse(res.data.json));
226                 
227              
228             }
229         
230          })  
231             
232         
233         
234     },
235     loadTree : function(o)
236     {
237         var tree = Pman.Tab.BuilderTree.tree;
238         this.clearAll();
239         tree.root.elConfig = o;
240         if (typeof(o.xtype) == 'undefined') {
241             o.xtype = '*top';
242         }
243         tree.root.setText(this.configToText(tree.root.elConfig));
244         this.appendNode(tree.root, o.items[0]);
245         tree.root.expand(true);
246         Pman.Tab.BuilderView.panel.redraw();
247         this.setCurrentNode(tree.root,true);
248     },
249     nodeXtype : function(n)
250     {
251         var tree = Pman.Tab.BuilderTree.tree;
252         if (!n) {return ''; }
253         var xt = n.elConfig.xtype ||  '';
254         var xns= n.elConfig['|xns'] ||   '';
255         xns += xns.length ? '.' : '';
256         return xns + xt;
257     },
258     setCurrentNode : function(node,select)
259     {
260         var tree = Pman.Tab.BuilderTree.tree;
261         
262         this.currentNode = node || tree.root;
263             
264         //Pman.Tab.BuilderView.highlightElement(this.currentNode);
265     
266         var p = Pman.Tab.BuilderProps.grid;
267         if (p) { //may not be ready yet..
268             p.setCurrrentNode(this.currentNode);
269         }
270         
271       
272         this.currentNode.setText(this.configToText(this.currentNode.elConfig));
273         
274         if (select) { //&& node !== this.tree.root) {
275             if (this.currentNode !== tree.root)  {
276                      this.currentNode.ensureVisible();
277               }   
278              this.currentNode.expand(false,false);
279             this.currentNode.select();
280         }
281         // update palete..
282         Pman.Tab.BuilderPalette.grid.getSelectionModel().clearSelections();
283         Pman.Tab.BuilderPalette.grid.view.refresh();
284         
285     },
286     toJS : function(n)
287     {
288         if (!n) {
289             var tree = Pman.Tab.BuilderTree.tree;
290             return this.toJS(tree.root);
291         }
292         var _this = this;
293         var ret = this.cloneConfig(n.elConfig);
294         if (n.childNodes.length) {
295             ret.items = [];
296             n.eachChild(function(cn) {
297                 ret.items.push(_this.toJS(cn));
298             });
299                 
300         }
301         return ret;
302           
303          
304     },
305     
306     /**
307      * handle dropNode
308      */
309     
310     handleDropNode : function (e)
311     {
312         // nodedragover handles the allow/disallow..
313         
314         /*
315         tree - The TreePanel
316         target - The node being targeted for the drop
317         data - The drag data from the drag source
318         point - The point of the drop - append, above or below
319         source - The drag source
320         rawEvent - Raw mouse event
321         dropNode - Drop node(s) provided by the source OR you can supply node(s) to be inserted by setting them on this object.
322         cancel - Set this to true to cancel the drop.
323         */
324         
325         var _t = this;
326         var np = e.point == 'append' ? e.target : e.target.parentNode ; // new parent
327           
328         if (!e.tree || !e.dropNode) {
329         
330             // form palete...
331             var data  = e.source.dragData.selections[0].data;
332     
333             var xar = data.name.split('.');
334     
335             var cfg = {
336                 'xtype' : xar.pop(),
337                 '|xns' : xar.join('.')
338                 
339             };
340             if (this.dragProp.length > 1) {
341                 cfg['*prop'] = this.dragProp;
342             }
343             // at this point it should of a set of options...
344              var cls = cfg['|xns'] + '.' + cfg['xtype'];
345                 
346     
347             if (typeof(Pman.Builder[cls]) != 'undefined') {
348                 Pman.Dialog.BuilderAdd.show( cfg , function(fdata ) {
349     
350                 
351                     _t.appendNode(e.target, fdata , e.point);
352     
353                  });
354                  return false;
355              }
356              this.appendNode(e.target, cfg, e.point);
357               Pman.Tab.BuilderView.panel.redraw();
358              
359             return false; // fixme drop of elements from palete..
360         }
361     
362         // always drop onto own parent
363         if (np == e.dropNode.parentNode) {
364             if (e.rawEvent.ctrlKey) {
365                 e.dropNode = this.dupeNode(e.dropNode);
366             }
367             return true;
368         }
369         // can append has to use palete...
370         // this code should be in nodedragover.
371         
372         Roo.log("move checks need moving");
373         return false;
374         
375         if (_this.canAppend(np, e.dropNode.elConfig)) {
376             if (e.rawEvent.ctrlKey) {
377                 e.dropNode = _this.dupeNode(e.dropNode);
378                   
379                 if (np.elConfig.xtype == 'GridEditor') {
380                     e.dropNode.elConfig['*prop'] = 'field';
381                 }
382                 
383             }
384             return true;
385         }  
386         Roo.log('can not drop ' + e.dropNode.elConfig.xtype + ' ontop of ' + np.elConfig.xtype);
387         
388         
389         
390         return false;
391                             
392     
393     },
394     handleDragOver : function(e)
395     {
396         Roo.log('nodedragover');
397         Roo.log(e);
398         // e.cancel..
399         // if we have within the same tree:
400           // dropNode (the node being dragged !!important!!) 
401           // point: below, append
402           // target - node 
403        // for palete
404            // dropNode = false;
405            // grid = the grid...
406            // source.dragData.selections[..] 
407       
408        
409        // we can only check parents... (we in theory can check dupe properties.. but let's ignore that for the time being.)
410        
411        // ok off we go.
412        
413        if (!e.dropNode) {
414            // drag from palete..
415            if (!e.source.dragData.selections.length) {
416                e.cancel = true;
417                return;
418            }
419            var drop_rec = e.source.dragData.selections[0];
420            var drop_xtype = drop_rec.data.name;
421            var ok_parents = drop_rec.json.parents;
422            
423            Roo.log("TEST PARENTS: " + ok_parents.join(', '));
424            var new_parent = this.nodeXtype((e.point == 'append') ? e.target :  e.target.parentNode);
425            Roo.log("NEW PARENT: " + e.point + " = " + new_parent);
426            
427            // see if the new_parent is actually in the list of ok_parents
428            e.cancel = true;
429            this.dragProp = '';
430            var _t = this;
431            Roo.each(ok_parents, function(n) {
432                if (n == new_parent || n.split(':').shift() == new_parent) {
433                    Roo.log("got match!");
434                    e.cancel = false;
435                    _t.dragProp = (n == new_parent) ?  '' : n.split(':').pop();
436                    return true;
437                }
438                return false;
439             });
440    
441            // done all the checks...
442            return;
443            
444        }
445         
446     },
447     save : function() 
448     {
449        // first see if first element has a name.. - we can not save otherwise..
450         var t = Pman.Tab.BuilderTree.tree;
451         if (!t.root.elConfig.name.length) {
452             Roo.MessageBox.alert("Error", "No name set for form");
453             return;
454         }
455      
456         var  sid = (typeof(sid) == 'undefined') ? 
457              (Pman.Tab.BuilderTop.filesel.lastData ? Pman.Tab.BuilderTop.filesel.lastData.id : 0) : sid;
458         
459
460         var js = this.toJS();
461         var render = new Pman.Builder.JsRender(js); 
462          
463         // console.log(js);
464         // console.log(json);
465         
466         // check the select box to see if that has been set... - save it with that id..
467         
468         //var _this = this;
469         
470         Pman.request({
471             url: baseURL + '/Roo/Builder_part.php',
472             method : 'POST',
473             params : {
474                 json : Roo.encode(js, null, 4),
475                 jsource : render.toSource(),
476                 name : js.name,
477                 module_id : _this.modsel.getValue(),
478                 id : sid
479             }, 
480             success : function(data) {
481                 // set the fileSel!!
482                 console.log(data);
483                 //if (data) {
484                 //    _this.filesel.setFromData(data);
485 //                    if (cb) {
486 //                        cb.call(_this,data);
487   //                  }
488 //                    _this.postCode(data);
489 //                }
490             }
491         });
492 }
493
494     
495     
496 }