php7 fixes
[Pman.Builder] / Pman.Builder.JsRender.js
1 /**
2  * This is baed on the code in the app builder..
3  *
4  *
5  * usage:
6  *
7 <pre><code>
8    render = new Pman.Builder.JsRender(
9           Pman.Builder.Tree.toJS()
10      );
11     
12     var source = render.toSource();
13 </code></pre>    
14  * 
15  * @cfg {Array} items - the array of items..
16  * @cfg {String} name - eg. Pman.Tab.XXXXyyyyy
17  
18  * @cfg {String} path - needs the full path << we only have the class name..
19  * @cfg {String} region - ?? needed anymore?
20  * @cfg {String} parent
21  * @cfg {String}  title
22  * @cfg {String}  disable? function call to disable it?
23  * @cfg {String} permname
24  * @cfg {Number} modOrder
25   * @cfg {Number} modkey ???
26  * 
27  *
28  */ 
29 Pman.Builder.JsRender = function(cfg) {
30     Roo.apply(this, cfg);
31 }
32
33 Pman.Builder.JsRender.prototype =  {
34     
35         
36     name : '',
37     path : '', // the file path..
38     modOrder : '001', /// sequence id that this uses.
39     region : 'center',
40     parent : '',
41     title : '', // the title on displayed when loading.
42     disable : '', // use a function to that returns false to disable this..
43     permname: '', /// permission name
44     
45     items: false,
46     
47     /**
48      * @type {Object} the properties that have to be double quoted to enable translation
49      */
50     doubleStringProps : [ 
51         'title',
52         'legend',
53         'loadingText',
54         'emptyText',
55         'qtip',
56         'value',
57         'text',
58         'emptyMsg',
59         'displayMsg'
60     ],
61     
62   
63     /**
64      * 
65      * munge JSON tree into Javascript code.
66      * 
67      * FIXME: + or / prefixes to properties hide it from renderer.
68      * FIXME: '*props' - not supported by this.. ?? - upto rendering code..
69      * FIXME: needs to understand what properties might be translatable (eg. double quotes)
70      * 
71      * @arg {object} obj the object or array to munge..
72      * @arg {boolean} isListener - is the array being sent a listener..
73      * @arg {string} pad - the padding to indent with. 
74      */
75     
76     
77     mungeToString:  function(obj, isListener, pad)
78     {
79         
80          
81         pad = pad || '    ';
82         var keys = [];
83         var isArray = false;
84         isListener = isListener || false;
85          
86         // am I munging a object or array...
87         if (obj.constructor.toString() === Array.toString()) {
88             for (var i= 0; i < obj.length; i++) {
89                 keys.push(i);
90             }
91             isArray = true;
92         } else {
93             for (var i in obj) {
94                 keys.push(i);
95             }
96         }
97         
98         
99         var els = []; 
100         var skip = [];
101         if (!isArray && 
102                 typeof(obj['|xns']) != 'undefined' &&
103                 typeof(obj['xtype']) != 'undefined'
104             ) {
105                 this.mungeXtype(obj['|xns'] + '.' + obj['xtype'], els);
106                 //els.push('xtype: '+ obj['|xns'] + '.' + obj['xtype']);
107                 skip.push('|xns','xtype');
108             }
109         
110         
111         if (!isArray && obj.items && obj.items.length) {
112             // look for props..
113             var newitems = [];
114             obj.items.forEach(function(pl) {
115                 if (typeof(pl['*prop']) == 'undefined') {
116                     newitems.push(pl);
117                     return;
118                 }
119                 
120                 //print(JSON.stringify(pl,null,4));
121                 // we have a prop...
122                 var prop = pl['*prop'] + '';
123                 delete pl['*prop'];
124                 if (!prop.match(/\[\]$/)) {
125                     // it's a standard prop..
126                     
127                     // munge property..??
128                     
129                     obj[prop] = pl;
130                     
131                     keys.push(prop);
132                     return;
133                 }
134                 prop  = prop.substring(0, prop.length -2); //strip []
135                 // it's an array type..
136                 obj[prop] = obj[prop]  || [];
137                 obj[prop].push(pl);
138               //  print("ADDNG PROP:" + prop + ' ' + keys.indexOf(prop) );
139                 if (keys.indexOf(prop) < 0) {
140                     keys.push(prop);
141                 }
142                 
143                 
144                 
145             });
146             obj.items = newitems;
147             if (!obj.items.length) {
148                 delete obj.items;
149             }
150             
151         }
152          
153         
154         //if (isArray) { print(JSON.stringify(keys, null,4)); }
155         // keys is just the real keys of the object.
156         var _this = this;
157         
158         var left =  '';
159         
160         keys.forEach(function(i) {
161             
162             if (i[0] == '.') { // skip builder data.
163                 return;
164             }
165             
166             if (typeof(obj[i]) == 'undefined') { // empty or removed.
167                 return;
168             }
169             var el = obj[i];
170             if (!isArray && skip.indexOf(i) > -1) { // things we do not write..
171                 return;
172             }
173             if (!isArray) {
174                 // set the key to be quoted with singel quotes..
175                 var leftv = i[0] == '|' ? i.substring(1) : i;
176                 if (Pman.Builder.Lang.isKeyword(leftv) || Pman.Builder.Lang.isBuiltin(leftv)) {
177                     left = "'" + leftv + "'";
178                 } else if (leftv.match(/[^A-Z_]+/i)) { // not plain a-z... - quoted.
179                     var val = JSON.stringify(leftv);
180                     left = "'" + val.substring(1, val.length-1).replace(/'/g, "\\'") + "'";
181                 } else {
182                     left = '' + leftv;
183                 }
184                 left += ' : ';
185                 
186             }
187             
188             
189             if (isListener) {
190                 // change the lines...
191                 var str= ('' + obj[i]).replace(/^\s+|\s+$/g,""); // remove bar.
192                 var lines = str.split("\n");
193                 if (lines.length > 1) {
194                     str = lines.join("\n" + pad);
195                 }
196                 
197                 els.push(left  + str);
198                 return;
199             }
200              
201             
202             
203             //var left = isArray ? '' : (JSON.stringify(i) + " : " )
204             
205             if (i[0] == '|') {
206                 // does not hapepnd with arrays..
207                 if (typeof(el) == 'string' && !obj[i].length) { //skip empty.
208                     return;
209                 }
210                 // this needs to go...
211                 //if (typeof(el) == 'string'  && obj[i].match(new RegExp("Gtk.main" + "_quit"))) { // we can not handle this very well..
212                 //    return;
213                 //}
214                 
215                 var str= ('' + obj[i]).replace(/^\s+|\s+$/g,"");;
216                 var lines = str.split("\n");
217                 if (lines.length > 1) {
218                     str = lines.join("\n" + pad);
219                 }
220                 
221                 els.push(left + str);
222                 return;
223             }
224             
225             
226             
227             
228             if (typeof(el) == 'object') {
229                 
230                 // we can skip empty items lists and empty listeners..
231                 //if (!isArray && i == 'items' && !el.length) {
232                 //    return; 
233                 //}
234                // 
235                 var right = _this.mungeToString(el, i == 'listeners', pad + '    ');
236                 
237                 //if (!left.length && isArray) print(right);
238                 
239                 if ((typeof(right) != 'undefined') && right.length){
240                     els.push(left + right);
241                 }
242             
243                 return;
244             }
245             // standard. .
246             if (typeof(obj[i]) != 'string') {
247                 els.push(left + JSON.stringify(obj[i]));
248                 return;
249             }
250             // strings..
251             if (!_this.doubleStringProps) {
252                 els.push(left + JSON.stringify(obj[i]));
253                 return;
254             }
255             if (_this.doubleStringProps.indexOf(i) > -1) {
256                 els.push(left + JSON.stringify(obj[i]));
257                 return;
258             }
259             // single quote..
260             els.push(left + "'" + obj[i].replace(/'/g, "\\'") + "'");
261             
262
263         });
264         
265         if (!isArray && !els.length) {
266             return '';
267         }
268         //output the thing.
269         var spad = pad.substring(0, pad.length-4);
270         return (isArray ? '[' : '{') + "\n" +
271             pad  + els.join(",\n" + pad ) + 
272             "\n" + spad + (isArray ? ']' : '}');
273            
274         
275         
276     },
277     
278     
279     setNSID : function(id)
280     {
281         
282         this.items[0]['|module'] = id;
283    
284         
285     },
286     
287     
288     getType: function() {
289         return 'Roo';
290     },
291    
292    
293     /**
294      * old code had broken xtypes and used arrays differently,
295      * this code should try and clean it up..
296      * 
297      * 
298      */
299     fixItems : function(node, fixthis)
300     {
301         if (fixthis) {
302             // fix xtype.
303             var fn = this.guessName(node);
304             //print("guessname got " + fn);
305             if (fn) {
306                 var bits = fn.split('.');
307                 node.xtype = bits.pop();
308                 node['|xns'] = bits.join('.');
309                 
310             }
311             // fix array???
312              
313             
314         }
315         if (!node.items || !node.items.length) {
316             return;
317         }
318         var _this = this;
319         var aitems = [];
320         var nitems = [];
321         node.items.forEach(function(i) {
322             
323             
324             
325             _this.fixItems(i, true);
326             if (i.xtype == 'Array') {
327                 aitems.push(i);
328                 return;
329             }    
330             nitems.push(i);
331         });
332         node.items = nitems; 
333         
334         if (!aitems.length) {
335             return;
336         }
337         
338         aitems.forEach(function(i) {
339             
340             if (!i.items || !i.items.length) {
341                 return;
342             }
343             var prop = i['*prop'] + '[]';
344             // colModel to cm?
345             i.items.forEach(function(c) {
346                 c['*prop']  = prop;
347                 node.items.push(c);
348                 
349             });
350             
351             
352         });
353         
354         
355         // array handling.. 
356         
357         
358         
359         
360         
361     },
362      
363      /**
364      * convert xtype for munged output..
365      * 
366      */
367     mungeXtype : function(xtype, els)
368     {
369         var bits = xtype.split('.');
370         // assume it has lenght!
371         
372         els.push("xtype: '"+ bits.pop()+"'");
373         els.push('xns: '+ bits.join('.'));
374     },
375     
376     /**
377      * This needs to use some options on the project
378      * to determine how the file is output..
379      * 
380      * At present we are hard coding it..
381      * 
382      * 
383      */
384     toSource: function()
385     {
386         // dump the file tree back out to a string.
387         
388         // we have 2 types = dialogs and components
389         // 
390         var top = this.guessName(this.items[0]);
391         
392         if (!top) {
393             return false;
394         }
395         if (top.match(/Dialog/) || top.match(/Modal/)) {
396             return this.toSourceDialog();
397         }
398         return this.toSourceLayout();
399         
400         /*
401         eventually support 'classes??'
402          return this.toSourceStdClass();
403         */
404           
405     },
406    
407     outputHeader : function()
408     {
409         return [
410             "//<script type=\"text/javascript\">",
411             "",
412             "// Auto generated file - created by app.Builder.js- do not edit directly (at present!)",
413             ""
414         ].join("\n");
415         
416    
417     },
418     // a standard dialog module.
419     // fixme - this could be alot neater..
420     toSourceDialog : function() 
421     {
422         var items = JSON.parse(JSON.stringify(this.items[0]));
423         var o = this.mungeToString(items, false, '            ');
424         
425         return [
426             this.outputHeader(),
427             this.name + " = {",
428             "",
429             "    dialog : false,",
430             "    callback:  false,",
431             "",   
432             "    show : function(data, cb)",
433             "    {",
434             "        if (!this.dialog) {",
435             "            this.create();",
436             "        }",
437             "",
438             "        this.callback = cb;",
439             "        this.data = data;",
440             "        this.dialog.show(this.data._el);",
441             "        if (this.form) {",
442             "           this.form.reset();",
443             "           this.form.setValues(data);",
444             "           this.form.fireEvent('actioncomplete', this.form,  { type: 'setdata', data: data });",
445             "        }",
446             "",   
447             "    },",
448             "",
449             "    create : function()",
450             "    {",
451             "        var _this = this;",
452             "        this.dialog = Roo.factory(" + o +  ");",
453             "    }",
454             "};",
455             ""
456             
457          ].join("\n");
458          
459          
460          
461     },
462     
463     /**
464      * try to remove Pman.Tab.XXXXXYYYY
465      * where XXXX= the project name..
466      *
467      */
468     pathToPart : function()
469     {
470         
471         
472         var modname = this.name.split('.').pop();
473         
474         var ret = modname.match(/([A-Z][a-z]+)/g);
475         var mm = ret.shift();
476         return [ mm, ret.join('')];
477         
478         //return [ modname , npart];
479         
480         
481         
482         
483     },
484     
485     // a layout compoent 
486     toSourceLayout : function() 
487     {
488         var items = JSON.parse(JSON.stringify(this.items[0]));
489         var o = this.mungeToString(items, false, '            ');   
490          
491         var modkey = this.modkey + '-' + this.name.replace(/[^A-Z.]+/ig, '-');
492         
493         var name = this.name.replace(/[^a-z_]+/i, '_');
494         
495     
496         return [
497             this.outputHeader(),
498             
499             name  +  " = new Roo.XComponent({",
500             "    order    : '" +modkey+"',",
501             "    region   : '" + this.region   +"',",
502             "    parent   : "+ (this.parent ?  "'" + this.parent + "'" :  'false') + ",",
503             "    name     : " + JSON.stringify(this.title  || "unnamed module") + ",",
504             "    disabled : " + (this.disabled || 'false') +", ",
505             "    tree : function()",
506             "    {",
507             "        var _this = this;", // bc
508             "        var MODULE = this;", /// this looks like a better name.
509             "        return " + o + ';',
510             "    }",
511             "});",
512             ""
513              
514          ].join("\n");
515         
516     },
517         
518     guessName : function(ar) // turns the object into full name.
519     {
520          // eg. xns: Roo, xtype: XXX -> Roo.xxx
521         if (!ar) {
522             return false;
523         }
524         var ret = [];
525         ret.push(typeof( ar['|xns'] ) == 'undefined' ? 'Roo' : ar['|xns'] );
526         
527         
528         
529         if (typeof( ar['xtype'] ) == 'undefined' || !ar['xtype'].length) {
530             return false;
531         }
532         var xtype = ar['xtype'] + '';
533         if (xtype[0] == '*') { // prefixes????
534             xtype  = xtype.substring(1);
535         }
536         if (xtype.match(/^Roo/)) {
537             // already starts with roo...
538             ret = [];
539         }
540         ret.push(xtype);
541         return   ret.join('.');
542         
543          
544                         
545                              
546     }
547    
548     
549 };
550