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;
30 Gee.HashMap<string,Gee.ArrayList<string>> out_props_array_plain;
38 public NodeToJs( Node node, Gee.ArrayList<string> doubleStringProps, string pad, NodeToJs? parent)
41 this.doubleStringProps = doubleStringProps;
44 this.els = new Gee.ArrayList<string>();
45 this.ar_props = new Gee.HashMap<string,string>();
48 this.out_props = new Gee.HashMap<string,string>();
49 this.out_listeners = new Gee.HashMap<string,string>();
50 this.out_nodeprops = new Gee.HashMap<string,Node>() ;
51 this.out_children = new Gee.ArrayList<Node> ();
52 this.out_props_array = new Gee.HashMap<string,Gee.ArrayList<Node>>() ;
53 this.out_props_array_plain = new Gee.HashMap<string,Gee.ArrayList<string>>() ;
57 this.cur_line = parent == null ? 0 : parent.cur_line ; //-1 as we usuall concat onto the existin gline?
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")) {
85 // no properties to output...
86 if (this.els.size < 1) {
94 var spad = this.pad.substring(0, this.pad.length-indent);
97 var str_props = gLibStringListJoin(",\n" + this.pad , this.els) ;
98 //print ("STR PROPS: " + str_props);
102 if (!this.node.props.has_key("* xinclude")) {
104 this.pad + str_props +
110 return "Roo.apply(" + this.node.props.get("* xinclude") + "._tree(), "+
112 this.pad + str_props +
118 This currently works by creating a key/value array of this.els, which is just an array of properties..
119 this is so that join() works...
123 b) output plan properties.
124 c) output listeners..
126 g) output prop_arrays..
134 public Gee.ArrayList<string> orderedPropKeys() {
136 var ret = new Gee.ArrayList<string> ();
137 var niter = this.out_props.map_iterator();
138 while(niter.next()) {
139 ret.add(niter.get_key());
142 ret.sort(( a, b) => {
143 return ((string)a).collate((string)b);
144 //if (a == b) return 0;
145 //return a < b ? -1 : 1;
149 public Gee.ArrayList<string> orderedListenerKeys() {
151 var ret = new Gee.ArrayList<string> ();
152 var niter = this.out_listeners.map_iterator();
153 while(niter.next()) {
154 ret.add(niter.get_key());
157 ret.sort(( a, b) => {
158 return ((string)a).collate((string)b);
159 //if (a == b) return 0;
160 //return a < b ? -1 : 1;
166 public string mungeOut()
169 var spad = this.pad.substring(0, this.pad.length-indent);
171 if (this.node.props.has_key("* xinclude")) {
172 this.addLine("Roo.apply(" + this.node.props.get("* xinclude") + "._tree(), {");
178 // output the items...
179 // work out remaining items...
180 var total_nodes = this.out_props.size +
181 this.out_props_array_plain.size +
182 (this.out_listeners.size > 0 ? 1 : 0) +
183 this.out_nodeprops.size +
184 this.out_props_array.size +
185 (this.out_children.size > 0 ? 1 : 0);
190 var niter = this.out_nodeprops.map_iterator();
192 while(niter.next()) {
194 suffix = total_nodes > 0 ? "," : "";
195 var l = this.pad + niter.get_key() + " : " +
196 this.mungeChildNew(this.pad + indent_str, niter.get_value(), -1) + suffix;
197 this.addMultiLine(l);
201 var iter = this.orderedPropKeys().list_iterator();
204 suffix = total_nodes > 0 ? "," : "";
206 var v = this.out_props.get(k);
208 this.addMultiLine(this.pad + k + " : " + v + suffix);
211 // out_props_array_plain -- not used?
212 var paiter = this.out_props_array_plain.map_iterator();
214 while(paiter.next()) {
217 this.addLine(this.pad + paiter.get_key() + " : [");
218 var paliter = paiter.get_value().list_iterator();
219 while (paliter.next()) {
220 suffix = paliter.has_next() ? "," : "";
221 this.addMultiLine(this.pad + indent_str + paliter.get() + suffix);
224 suffix = total_nodes > 0 ? "," : "";
225 // this.mungeChild(this.pad + indent_str, niter.get_value())
226 this.addLine(this.pad + "]" + suffix);
234 var piter = this.out_props_array.map_iterator();
236 while(piter.next()) {
239 this.addLine(this.pad + piter.get_key() + " : [");
240 var pliter = piter.get_value().list_iterator();
241 while (pliter.next()) {
242 suffix = pliter.has_next() ? "," : "";
243 this.addMultiLine(this.pad + indent_str +
244 this.mungeChildNew(this.pad + indent_str + indent_str, pliter.get()) + suffix);
247 suffix = total_nodes > 0 ? "," : "";
249 this.addLine(this.pad + "]" + suffix);
253 if (this.out_listeners.size > 0 ) {
255 this.addLine(this.pad + "listeners : {");
256 iter = this.orderedListenerKeys().list_iterator();
258 var sz = this.out_listeners.size;
261 suffix = sz > 0 ? "," : "";
263 var v = this.out_listeners.get(k);
264 this.addMultiLine(this.pad + indent_str + k + " : " + v + suffix);
266 suffix = total_nodes > 0 ? "," : "";
267 this.addLine(this.pad + "}" + suffix);
271 if (this.out_children.size > 0) {
272 this.addLine(this.pad + "items : [" );
273 var cniter = this.out_children.list_iterator();
274 while (cniter.next()) {
275 suffix = cniter.has_next() ? "," : "";
276 this.addMultiLine(this.pad + indent_str +
277 this.mungeChildNew(this.pad + indent_str + indent_str, cniter.get()) + suffix
282 this.addLine(this.pad + "]");
285 if (this.node.props.has_key("* xinclude")) {
286 this.ret += spad + "})";
289 this.ret += spad + "}";
301 public void addLine(string str= "")
304 //this.ret += str+ "\n";
305 this.ret += "/*%d*/ ".printf(this.cur_line) + str + "\n";
310 public void addMultiLine(string str= "")
313 this.cur_line += str.split("\n").length;
314 this.ret += "/*%d*/ ".printf(this.cur_line) + str + "\n";
315 //this.ret += str + "\n";
318 string gLibStringListJoin( string sep, Gee.ArrayList<string> ar)
321 for (var i = 0; i < ar.size; i++) {
322 ret += i>0 ? sep : "";
328 public string mungeChild(string pad , Node cnode)
330 var x = new NodeToJs(cnode, this.doubleStringProps, pad, this);
334 public string mungeChildNew(string pad , Node cnode, int offset = 0)
336 var x = new NodeToJs(cnode, this.doubleStringProps, pad, this);
337 x.cur_line -= offset;
344 public void checkChildren ()
348 // look throught he chilren == looking for * prop.. -- fixme might not work..
351 if (!this.node.hasChildren()) {
356 for (var ii =0; ii< this.node.items.size; ii++) {
357 var pl = this.node.items.get(ii);
358 if (!pl.props.has_key("* prop")) {
363 //print(JSON.stringify(pl,null,4));
365 //var prop = pl['*prop'] + '';
366 //delete pl['*prop'];
367 var prop = pl.get("* prop");
368 print("got prop "+ prop + "\n");
371 if (! Regex.match_simple("\\[\\]$", prop)) {
372 // it's a standard prop..
374 // munge property..??
376 this.out_nodeprops.set(prop, pl);
378 this.els.add( prop + " : " + this.mungeChild ( this.pad + indent_str, pl));
388 var sprop = prop.replace("[]", "");
389 print("sprop is : " + sprop + "\n");
391 // it's an array type..
393 if (!this.ar_props.has_key(sprop)) {
395 this.ar_props.set(sprop, "");
396 this.out_props_array.set(sprop, new Gee.ArrayList<Node>());
398 old = this.ar_props.get(sprop);
400 var nstr = old += old.length > 0 ? ",\n" : "";
401 nstr += this.mungeChild( this.pad + indent_str + indent_str + indent_str , pl);
402 this.out_props_array.get(sprop).add( pl);
403 this.ar_props.set(sprop, nstr);
410 * Standardize this crap...
412 * standard properties (use to set)
413 * If they are long values show the dialog..
416 * bool is_xxx :: can show a pulldown.. (true/false)
418 * $ string html = string with value interpolated eg. baseURL + ".."
419 * Clutter.ActorAlign x_align (typed) -- shows pulldowns if type is ENUM?
420 * $ untypedvalue = javascript untyped value...
421 * _ string html ... = translatable..
424 * object properties (not part of the GOjbect being wrapped?
425 * # Gee.ArrayList<Xcls_fileitem> fileitems
430 * methods -- always text editor..
438 * * init -- big string?
440 * event handlers (listeners)
445 * +XXXX -- indicates it's a instance property / not glob...
446 * *XXXX -- skip writing glob property (used as classes that can be created...)
450 public void readProps()
455 if (this.node.props.has_key("$ xns")) {
456 this.out_props.set("'|xns'", "'" + this.node.props.get("$ xns") + "'" );
458 this.els.add("'|xns' : '" + this.node.props.get("$ xns") + "'");
464 func_regex = new Regex("^\\s+|\\s+$");
466 print("failed to build regex");
469 // sort the key's so they always get rendered in the same order..
471 var keys = new Gee.ArrayList<string>();
472 var piter = this.node.props.map_iterator();
473 while (piter.next() ) {
477 this.node.normalize_key(piter.get_key(), out k, out kflag, out ktype);
482 keys.sort(( a, b) => {
483 return ((string)a).collate((string)b);
484 //if (a == b) return 0;
485 //return a < b ? -1 : 1;
490 for (var i = 0; i< keys.size; i++) {
491 var key = this.node.get_key(keys.get(i));
492 print("ADD KEY %s\n", key);
497 this.node.normalize_key(key, out k, out kflag, out ktype);
500 var v = this.node.get(key);
503 //if (this.skip.contains(k) ) {
506 if ( Regex.match_simple("\\[\\]$", k)) {
507 // array .. not supported... here?
513 // skip builder stuff. prefixed with '.' .. just like unix fs..
514 if (kflag == ".") { // |. or . -- do not output..
518 // ignore '* prop'; ???
523 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
524 left = "'" + leftv + "'";
525 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
526 var val = this.node.quoteString(leftv);
528 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
534 // next.. is it a function.. or a raw string..
542 // ??? any others that are raw output..
544 // does not hapepnd with arrays..
545 if (v.length < 1) { //if (typeof(el) == 'string' && !obj[i].length) { //skip empty.
552 str = func_regex.replace(v,v.length, 0, "");
554 print("regex failed");
560 var lines = str.split("\n");
562 if (lines.length > 0) {
563 nstr = string.joinv("\n" + this.pad, lines);
564 //nstr = string.joinv("\n", lines);
566 this.out_props.set(left, nstr);
567 //print("==> " + str + "\n");
568 this.els.add(left + " : "+ nstr);
579 ktype.down() == "boolean"
581 ktype.down() == "bool"
583 ktype.down() == "number"
585 ktype.down() == "int"
586 ) { // boolean or number...?
587 this.out_props.set(left, v.down());
588 this.els.add(left + " : " + v.down() );
592 // is it a translated string?
598 //if (this.doubleStringProps.size < 1) {
599 // this.els.add(left + this.node.quoteString(v));
603 if ((this.doubleStringProps.index_of(k) > -1) ||
604 (ktype.down() == "string" && k[0] == '_')
607 // then use the translated version...
610 (v.split("\n").length > 1 ?
611 ("\n" + string.joinv(this.pad + "\n", v.split("\n")).replace("*/", "* - /") + "\n" + this.pad + "*/ ") :
612 (v.replace("*/", "* - /") + " */")
615 this.els.add(left + " : _this._strings['" +
616 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
619 this.out_props.set(left, "_this._strings['" +
620 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
625 // otherwise it needs to be encapsulated.. as single quotes..
627 var vv = this.node.quoteString(v);
628 // single quote.. v.substring(1, v.length-1).replace("'", "\\'") + "'";
629 this.els.add(left + " : " + "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
630 this.out_props.set(left, "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
637 public void readArrayProps()
640 // this is not needed in the new version
641 // as array props are handled more directly..
643 // handle the childitems that are arrays.. eg. button[] = { }...
645 // note this does not handle a mix of nodes and properties with the same
649 var iter = this.ar_props.map_iterator();
650 while (iter.next()) {
651 var k = iter.get_key();
652 var right = iter.get_value();
654 string leftv = k[0] == '|' ? k.substring(1) : k;
655 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
656 left = "'" + leftv + "'";
657 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
658 var val = this.node.quoteString(leftv);
660 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
666 if (right.length > 0){
667 //if (this.out_props_array_plain.has_key(left)) {
668 // this.out_props_array_plain.set(left, new Gee.ArrayList<string>());
670 //this.out_props_array_plain.get(left).add(right);
672 this.els.add(left + " : [\n" + this.pad + indent_str + indent_str +
673 right + "\n" + this.pad + "]");
680 public void readListeners()
683 if (this.node.listeners.size < 1) {
686 // munge the listeners.
687 //print("ADDING listeners?");
692 var keys = new Gee.ArrayList<string>();
693 var piter = this.node.listeners.map_iterator();
694 while (piter.next() ) {
696 keys.add(piter.get_key());
698 keys.sort(( a, b) => {
699 return ((string)a).collate((string)b);
700 //if (a == b) return 0;
701 //return a < b ? -1 : 1;
704 var itms = "listeners : {\n";
706 for (var i = 0; i< keys.size; i++) {
707 var key = keys.get(i);
708 var val = this.node.listeners.get(key);
711 itms += i >0 ? ",\n" : "";
713 var str = val.strip();
714 var lines = str.split("\n");
715 if (lines.length > 0) {
716 //str = string.joinv("\n" + this.pad + " ", lines);
717 str = string.joinv("\n" + this.pad + indent_str + indent_str , lines);
720 itms += this.pad + indent_str + key.replace("|", "") + " : " + str;
721 this.out_listeners.set(key.replace("|", "") ,str);
725 itms += "\n" + this.pad + "}";
726 //print ( "ADD " + itms);
731 public void iterChildren()
735 // finally munge the children...
736 if (this.node.items.size < 1) {
739 var itms = "items : [\n";
741 for(var i = 0; i < this.node.items.size;i++) {
742 var ele = this.node.items.get(i);
743 if (ele.props.has_key("* prop")) {
750 itms += this.pad + indent_str +
751 this.mungeChild( this.pad + indent_str + indent_str , ele);
752 this.out_children.add(ele);
755 itms += "\n"+ this.pad + "]" + "\n";
759 // finally output listeners...
761 public void xIncludeToString()