3 * Code to convert node tree to Javascript...
5 * usage : x = (new JsRender.NodeToJs(node)).munge();
12 public class JsRender.NodeToJs : Object {
14 static uint indent = 1;
15 static string indent_str = " ";
18 Gee.ArrayList<string> doubleStringProps; // need to think if this is a good idea like this
21 Gee.ArrayList<string> els;
22 //Gee.ArrayList<string> skip;
23 Gee.HashMap<string,string> ar_props;
25 Gee.HashMap<string,string> out_props;
26 Gee.HashMap<string,string> out_listeners;
27 Gee.HashMap<string,Node> out_nodeprops;
28 Gee.ArrayList<Node> out_children;
29 Gee.HashMap<string,Gee.ArrayList<Node>> out_props_array;
37 public NodeToJs( Node node, Gee.ArrayList<string> doubleStringProps, string pad, NodeToJs? parent)
40 this.doubleStringProps = doubleStringProps;
43 this.els = new Gee.ArrayList<string>();
44 this.ar_props = new Gee.HashMap<string,string>();
47 this.out_props = new Gee.HashMap<string,string>();
48 this.out_listeners = new Gee.HashMap<string,string>();
49 this.out_nodeprops = new Gee.HashMap<string,Node>() ;
50 this.out_children = new Gee.ArrayList<Node> ();
51 this.out_props_array = new Gee.HashMap<string,Gee.ArrayList<Node>>() ;
57 this.cur_line = parent == null ? 0 : parent.cur_line;
59 this.top = parent == null ? this : parent.top;
68 public string munge ( )
70 //return this.mungeToString(this.node);
72 this.node.line_start = this.cur_line;
76 this.readArrayProps();
79 if (!this.node.props.has_key("* xinclude")) {
86 if (this.els.size < 1) {
91 var spad = pad.substring(0, this.pad.length-indent);
94 var str_props = gLibStringListJoin(",\n" + this.pad , this.els) ;
95 //print ("STR PROPS: " + str_props);
99 if (!this.node.props.has_key("* xinclude")) {
101 this.pad + str_props +
107 return "Roo.apply(" + this.node.props.get("* xinclude") + "._tree(), "+
109 this.pad + str_props +
115 This currently works by creating a key/value array of this.els, which is just an array of properties..
116 this is so that join() works...
120 b) output plan properties.
121 c) output listeners..
123 g) output prop_arrays..
132 public string mungeOut()
134 if (this.node.props.has_key("* xinclude")) {
135 this.addLine("Roo.apply(" + this.node.props.get("* xinclude") + "._tree(), {");
141 // output the items...
142 // work out remaining items...
143 var total_nodes = this.out_props.size +
144 (this.out_listeners.size > 0 ? 1 : 0) +
145 this.out_nodeprops.size +
146 this.out_props_array.size +
147 (this.out_children.size > 0 ? 1 : 0);
150 var iter = this.out_props.map_iterator();
153 suffix = total_nodes > 0 ? "," : "";
154 this.addLine(this.pad + iter.get_key() + " : " + iter.get_value() + suffix);
158 if (this.out_listeners.size > 0 ) {
160 this.addLine(this.pad + "listeners : {");
161 iter = this.out_listeners.map_iterator();
162 var sz = this.out_listeners.size;
165 suffix = sz > 0 ? "," : "";
166 this.addMultiLine(this.pad + indent_str + iter.get_key() + " : " + iter.get_value() + suffix);
168 suffix = total_nodes > 0 ? "," : "";
169 this.addLine(this.pad + "}" + suffix);
174 var niter = this.out_nodeprops.map_iterator();
176 while(niter.next()) {
178 suffix = total_nodes > 0 ? "," : "";
179 this.addMultiLine(this.pad + niter.get_key() + " : " +
180 this.mungeChild(this.pad + indent_str, niter.get_value())
185 var piter = this.out_props_array.map_iterator();
187 while(piter.next()) {
190 this.addLine(this.pad + niter.get_key() + " : [");
191 var pliter = piter.get_value().list_iterator();
192 while (pliter.next()) {
193 suffix = pliter.has_next() ? "," : "";
194 this.addMultiLine(this.pad + indent_str +
195 this.mungeChild(this.pad + indent_str + indent_str, pliter.get()) + suffix);
198 suffix = total_nodes > 0 ? "," : "";
199 // this.mungeChild(this.pad + indent_str, niter.get_value())
200 this.addLine(this.pad + "]" + suffix);
204 if (this.out_children.size > 0) {
205 this.addLine(this.pad + "items : [");
206 var cniter = this.out_children.list_iterator();
207 while (cniter.next()) {
208 suffix = cniter.has_next() ? "," : "";
209 this.addMultiLine(this.pad +
210 this.mungeChild(this.pad + indent_str + indent_str, cniter.get()) + suffix
215 this.addLine(this.pad + "]");
218 if (this.node.props.has_key("* xinclude")) {
234 public void addLine(string str= "")
237 this.ret += str+ "\n";
243 public void addMultiLine(string str= "")
246 this.cur_line += str.split("\n").length;
247 //this.ret += "/*%d*/ ".printf(l) + str + "\n";
248 this.ret += str + "\n";
251 string gLibStringListJoin( string sep, Gee.ArrayList<string> ar)
254 for (var i = 0; i < ar.size; i++) {
255 ret += i>0 ? sep : "";
261 public string mungeChild(string pad , Node cnode)
263 var x = new NodeToJs(cnode, this.doubleStringProps, pad, this);
270 public void checkChildren ()
274 // look throught he chilren == looking for * prop.. -- fixme might not work..
277 if (!this.node.hasChildren()) {
282 for (var ii =0; ii< this.node.items.size; ii++) {
283 var pl = this.node.items.get(ii);
284 if (!pl.props.has_key("* prop")) {
289 //print(JSON.stringify(pl,null,4));
291 //var prop = pl['*prop'] + '';
292 //delete pl['*prop'];
293 var prop = pl.get("* prop");
294 print("got prop "+ prop + "\n");
297 if (! Regex.match_simple("\\[\\]$", prop)) {
298 // it's a standard prop..
300 // munge property..??
302 this.out_nodeprops.set(prop, pl);
304 this.els.add( prop + " : " + this.mungeChild ( this.pad + indent_str, pl));
314 var sprop = prop.replace("[]", "");
315 print("sprop is : " + sprop + "\n");
317 // it's an array type..
319 if (!this.ar_props.has_key(sprop)) {
321 this.ar_props.set(sprop, "");
322 this.out_props_array.set(sprop, new Gee.ArrayList<Node>());
324 old = this.ar_props.get(sprop);
326 var nstr = old += old.length > 0 ? ",\n" : "";
327 nstr += this.mungeChild( this.pad + indent_str + indent_str + indent_str , pl);
328 this.out_props_array.get(sprop).add( pl);
329 this.ar_props.set(sprop, nstr);
336 * Standardize this crap...
338 * standard properties (use to set)
339 * If they are long values show the dialog..
342 * bool is_xxx :: can show a pulldown.. (true/false)
344 * $ string html = string with value interpolated eg. baseURL + ".."
345 * Clutter.ActorAlign x_align (typed) -- shows pulldowns if type is ENUM?
346 * $ untypedvalue = javascript untyped value...
347 * _ string html ... = translatable..
350 * object properties (not part of the GOjbect being wrapped?
351 * # Gee.ArrayList<Xcls_fileitem> fileitems
356 * methods -- always text editor..
364 * * init -- big string?
366 * event handlers (listeners)
371 * +XXXX -- indicates it's a instance property / not glob...
372 * *XXXX -- skip writing glob property (used as classes that can be created...)
376 public void readProps()
381 if (this.node.props.has_key("$ xns")) {
382 this.out_props.set("'|xns'", this.node.props.get("$ xns") );
384 this.els.add("'|xns' : '" + this.node.props.get("$ xns") + "'");
390 func_regex = new Regex("^\\s+|\\s+$");
392 print("failed to build regex");
395 // sort the key's so they always get rendered in the same order..
397 var keys = new Gee.ArrayList<string>();
398 var piter = this.node.props.map_iterator();
399 while (piter.next() ) {
403 this.node.normalize_key(piter.get_key(), out k, out kflag, out ktype);
408 keys.sort(( a, b) => {
409 return ((string)a).collate((string)b);
410 //if (a == b) return 0;
411 //return a < b ? -1 : 1;
416 for (var i = 0; i< keys.size; i++) {
417 var key = this.node.get_key(keys.get(i));
418 print("ADD KEY %s\n", key);
423 this.node.normalize_key(key, out k, out kflag, out ktype);
426 var v = this.node.get(key);
429 //if (this.skip.contains(k) ) {
432 if ( Regex.match_simple("\\[\\]$", k)) {
433 // array .. not supported... here?
439 // skip builder stuff. prefixed with '.' .. just like unix fs..
440 if (kflag == ".") { // |. or . -- do not output..
444 // ignore '* prop'; ???
449 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
450 left = "'" + leftv + "'";
451 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
452 var val = this.node.quoteString(leftv);
454 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
462 // next.. is it a function.. or a raw string..
470 // ??? any others that are raw output..
472 // does not hapepnd with arrays..
473 if (v.length < 1) { //if (typeof(el) == 'string' && !obj[i].length) { //skip empty.
480 str = func_regex.replace(v,v.length, 0, "");
482 print("regex failed");
488 var lines = str.split("\n");
490 if (lines.length > 0) {
491 nstr = string.joinv("\n" + this.pad, lines);
492 //nstr = string.joinv("\n", lines);
494 //print("==> " + str + "\n");
495 this.els.add(left + nstr);
506 ktype.down() == "boolean"
508 ktype.down() == "bool"
510 ktype.down() == "number"
512 ktype.down() == "int"
513 ) { // boolean or number...?
514 this.els.add(left + v.down() );
518 // is it a translated string?
524 //if (this.doubleStringProps.size < 1) {
525 // this.els.add(left + this.node.quoteString(v));
529 if (this.doubleStringProps.index_of(k) > -1) {
530 // then use the translated version...
532 els.add(left + "_this._strings['" +
533 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
538 if (ktype.down() == "string" && k[0] == '_') {
539 els.add(left + "_this._strings['" +
540 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
545 // otherwise it needs to be encapsulated.. as single quotes..
547 var vv = this.node.quoteString(v);
548 // single quote.. v.substring(1, v.length-1).replace("'", "\\'") + "'";
549 this.els.add(left + "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
557 public void readArrayProps()
560 // handle the childitems that are arrays.. eg. button[] = { }...
564 var iter = this.ar_props.map_iterator();
565 while (iter.next()) {
566 var k = iter.get_key();
567 var right = iter.get_value();
569 string leftv = k[0] == '|' ? k.substring(1) : k;
570 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
571 left = "'" + leftv + "'";
572 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
573 var val = this.node.quoteString(leftv);
575 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
584 if (right.length > 0){
585 this.els.add(left + "[\n" + this.pad + indent_str + indent_str +
586 right + "\n" + this.pad + "]");
593 public void readListeners()
596 if (this.node.listeners.size < 1) {
599 // munge the listeners.
600 //print("ADDING listeners?");
602 var liter = this.node.listeners.map_iterator();
606 var keys = new Gee.ArrayList<string>();
607 var piter = this.node.listeners.map_iterator();
608 while (piter.next() ) {
610 keys.add(piter.get_key());
612 keys.sort(( a, b) => {
613 return ((string)a).collate((string)b);
614 //if (a == b) return 0;
615 //return a < b ? -1 : 1;
618 var itms = "listeners : {\n";
620 for (var i = 0; i< keys.size; i++) {
621 var key = keys.get(i);
622 var val = this.node.listeners.get(key);
625 itms += i >0 ? ",\n" : "";
627 var str = val.strip();
628 var lines = str.split("\n");
629 if (lines.length > 0) {
630 //str = string.joinv("\n" + this.pad + " ", lines);
631 str = string.joinv("\n" + this.pad + indent_str + indent_str , lines);
634 itms += this.pad + indent_str + key.replace("|", "") + " : " + str;
639 itms += "\n" + this.pad + "}";
640 //print ( "ADD " + itms);
645 public void iterChildren()
649 // finally munge the children...
650 if (this.node.items.size < 1) {
653 var itms = "items : [\n";
655 for(var i = 0; i < this.node.items.size;i++) {
656 var ele = this.node.items.get(i);
657 if (ele.props.has_key("* prop")) {
664 itms += this.pad + indent_str +
665 this.mungeChild( this.pad + indent_str + indent_str , ele);
669 itms += "\n"+ this.pad + "]" + "\n";
673 // finally output listeners...
675 public void xIncludeToString()