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;
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;
151 public string mungeOut()
154 var spad = this.pad.substring(0, this.pad.length-indent);
156 if (this.node.props.has_key("* xinclude")) {
157 this.addLine("Roo.apply(" + this.node.props.get("* xinclude") + "._tree(), {");
163 // output the items...
164 // work out remaining items...
165 var total_nodes = this.out_props.size +
166 this.out_props_array_plain.size +
167 (this.out_listeners.size > 0 ? 1 : 0) +
168 this.out_nodeprops.size +
169 this.out_props_array.size +
170 (this.out_children.size > 0 ? 1 : 0);
175 var niter = this.out_nodeprops.map_iterator();
177 while(niter.next()) {
179 suffix = total_nodes > 0 ? "," : "";
180 this.addMultiLine(this.pad + niter.get_key() + " : " +
181 this.mungeChildNew(this.pad + indent_str, niter.get_value()) + suffix
186 var iter = this.orderedPropKeys().list_iterator();
189 suffix = total_nodes > 0 ? "," : "";
191 var v = this.out_props.get(k);
193 this.addLine(this.pad + k + " : " + v + suffix);
196 // out_props_array_plain -- not used?
197 var paiter = this.out_props_array_plain.map_iterator();
199 while(paiter.next()) {
202 this.addLine(this.pad + paiter.get_key() + " : [");
203 var paliter = paiter.get_value().list_iterator();
204 while (paliter.next()) {
205 suffix = paliter.has_next() ? "," : "";
206 this.addMultiLine(this.pad + indent_str + paliter.get() + suffix);
209 suffix = total_nodes > 0 ? "," : "";
210 // this.mungeChild(this.pad + indent_str, niter.get_value())
211 this.addLine(this.pad + "]" + suffix);
219 var piter = this.out_props_array.map_iterator();
221 while(piter.next()) {
224 this.addLine(this.pad + piter.get_key() + " : [");
225 var pliter = piter.get_value().list_iterator();
226 while (pliter.next()) {
227 suffix = pliter.has_next() ? "," : "";
228 this.addMultiLine(this.pad + indent_str +
229 this.mungeChildNew(this.pad + indent_str + indent_str, pliter.get()) + suffix);
232 suffix = total_nodes > 0 ? "," : "";
234 this.addLine(this.pad + "]" + suffix);
238 if (this.out_listeners.size > 0 ) {
240 this.addLine(this.pad + "listeners : {");
241 var lis_iter = this.out_listeners.map_iterator();
242 var sz = this.out_listeners.size;
243 while(lis_iter.next()) {
245 suffix = sz > 0 ? "," : "";
246 this.addMultiLine(this.pad + indent_str + lis_iter.get_key() + " : " + lis_iter.get_value() + suffix);
248 suffix = total_nodes > 0 ? "," : "";
249 this.addLine(this.pad + "}" + suffix);
253 if (this.out_children.size > 0) {
254 this.addLine(this.pad + "items : [" );
255 var cniter = this.out_children.list_iterator();
256 while (cniter.next()) {
257 suffix = cniter.has_next() ? "," : "";
258 this.addMultiLine(this.pad + indent_str +
259 this.mungeChildNew(this.pad + indent_str + indent_str, cniter.get()) + suffix
264 this.addLine(this.pad + "]");
267 if (this.node.props.has_key("* xinclude")) {
268 this.ret += spad + "})";
271 this.ret += spad + "}";
283 public void addLine(string str= "")
286 this.ret += str+ "\n";
292 public void addMultiLine(string str= "")
295 this.cur_line += str.split("\n").length;
296 //this.ret += "/*%d*/ ".printf(l) + str + "\n";
297 this.ret += str + "\n";
300 string gLibStringListJoin( string sep, Gee.ArrayList<string> ar)
303 for (var i = 0; i < ar.size; i++) {
304 ret += i>0 ? sep : "";
310 public string mungeChild(string pad , Node cnode)
312 var x = new NodeToJs(cnode, this.doubleStringProps, pad, this);
316 public string mungeChildNew(string pad , Node cnode)
318 var x = new NodeToJs(cnode, this.doubleStringProps, pad, this);
325 public void checkChildren ()
329 // look throught he chilren == looking for * prop.. -- fixme might not work..
332 if (!this.node.hasChildren()) {
337 for (var ii =0; ii< this.node.items.size; ii++) {
338 var pl = this.node.items.get(ii);
339 if (!pl.props.has_key("* prop")) {
344 //print(JSON.stringify(pl,null,4));
346 //var prop = pl['*prop'] + '';
347 //delete pl['*prop'];
348 var prop = pl.get("* prop");
349 print("got prop "+ prop + "\n");
352 if (! Regex.match_simple("\\[\\]$", prop)) {
353 // it's a standard prop..
355 // munge property..??
357 this.out_nodeprops.set(prop, pl);
359 this.els.add( prop + " : " + this.mungeChild ( this.pad + indent_str, pl));
369 var sprop = prop.replace("[]", "");
370 print("sprop is : " + sprop + "\n");
372 // it's an array type..
374 if (!this.ar_props.has_key(sprop)) {
376 this.ar_props.set(sprop, "");
377 this.out_props_array.set(sprop, new Gee.ArrayList<Node>());
379 old = this.ar_props.get(sprop);
381 var nstr = old += old.length > 0 ? ",\n" : "";
382 nstr += this.mungeChild( this.pad + indent_str + indent_str + indent_str , pl);
383 this.out_props_array.get(sprop).add( pl);
384 this.ar_props.set(sprop, nstr);
391 * Standardize this crap...
393 * standard properties (use to set)
394 * If they are long values show the dialog..
397 * bool is_xxx :: can show a pulldown.. (true/false)
399 * $ string html = string with value interpolated eg. baseURL + ".."
400 * Clutter.ActorAlign x_align (typed) -- shows pulldowns if type is ENUM?
401 * $ untypedvalue = javascript untyped value...
402 * _ string html ... = translatable..
405 * object properties (not part of the GOjbect being wrapped?
406 * # Gee.ArrayList<Xcls_fileitem> fileitems
411 * methods -- always text editor..
419 * * init -- big string?
421 * event handlers (listeners)
426 * +XXXX -- indicates it's a instance property / not glob...
427 * *XXXX -- skip writing glob property (used as classes that can be created...)
431 public void readProps()
436 if (this.node.props.has_key("$ xns")) {
437 this.out_props.set("'|xns'", this.node.props.get("$ xns") );
439 this.els.add("'|xns' : '" + this.node.props.get("$ xns") + "'");
445 func_regex = new Regex("^\\s+|\\s+$");
447 print("failed to build regex");
450 // sort the key's so they always get rendered in the same order..
452 var keys = new Gee.ArrayList<string>();
453 var piter = this.node.props.map_iterator();
454 while (piter.next() ) {
458 this.node.normalize_key(piter.get_key(), out k, out kflag, out ktype);
463 keys.sort(( a, b) => {
464 return ((string)a).collate((string)b);
465 //if (a == b) return 0;
466 //return a < b ? -1 : 1;
471 for (var i = 0; i< keys.size; i++) {
472 var key = this.node.get_key(keys.get(i));
473 print("ADD KEY %s\n", key);
478 this.node.normalize_key(key, out k, out kflag, out ktype);
481 var v = this.node.get(key);
484 //if (this.skip.contains(k) ) {
487 if ( Regex.match_simple("\\[\\]$", k)) {
488 // array .. not supported... here?
494 // skip builder stuff. prefixed with '.' .. just like unix fs..
495 if (kflag == ".") { // |. or . -- do not output..
499 // ignore '* prop'; ???
504 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
505 left = "'" + leftv + "'";
506 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
507 var val = this.node.quoteString(leftv);
509 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
515 // next.. is it a function.. or a raw string..
523 // ??? any others that are raw output..
525 // does not hapepnd with arrays..
526 if (v.length < 1) { //if (typeof(el) == 'string' && !obj[i].length) { //skip empty.
533 str = func_regex.replace(v,v.length, 0, "");
535 print("regex failed");
541 var lines = str.split("\n");
543 if (lines.length > 0) {
544 nstr = string.joinv("\n" + this.pad, lines);
545 //nstr = string.joinv("\n", lines);
547 this.out_props.set(left, nstr);
548 //print("==> " + str + "\n");
549 this.els.add(left + " : "+ nstr);
560 ktype.down() == "boolean"
562 ktype.down() == "bool"
564 ktype.down() == "number"
566 ktype.down() == "int"
567 ) { // boolean or number...?
568 this.out_props.set(left, v.down());
569 this.els.add(left + " : " + v.down() );
573 // is it a translated string?
579 //if (this.doubleStringProps.size < 1) {
580 // this.els.add(left + this.node.quoteString(v));
584 if (this.doubleStringProps.index_of(k) > -1) {
585 // then use the translated version...
587 this.els.add(left + " : _this._strings['" +
588 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
591 this.out_props.set(left, "_this._strings['" +
592 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
596 if (ktype.down() == "string" && k[0] == '_') {
597 this.els.add(left + " : _this._strings['" +
598 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
601 this.out_props.set(left, " _this._strings['" +
602 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
609 // otherwise it needs to be encapsulated.. as single quotes..
611 var vv = this.node.quoteString(v);
612 // single quote.. v.substring(1, v.length-1).replace("'", "\\'") + "'";
613 this.els.add(left + " : " + "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
614 this.out_props.set(left, "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
621 public void readArrayProps()
624 // this is not needed in the new version
625 // as array props are handled more directly..
627 // handle the childitems that are arrays.. eg. button[] = { }...
629 // note this does not handle a mix of nodes and properties with the same
633 var iter = this.ar_props.map_iterator();
634 while (iter.next()) {
635 var k = iter.get_key();
636 var right = iter.get_value();
638 string leftv = k[0] == '|' ? k.substring(1) : k;
639 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
640 left = "'" + leftv + "'";
641 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
642 var val = this.node.quoteString(leftv);
644 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
650 if (right.length > 0){
651 //if (this.out_props_array_plain.has_key(left)) {
652 // this.out_props_array_plain.set(left, new Gee.ArrayList<string>());
654 //this.out_props_array_plain.get(left).add(right);
656 this.els.add(left + " : [\n" + this.pad + indent_str + indent_str +
657 right + "\n" + this.pad + "]");
664 public void readListeners()
667 if (this.node.listeners.size < 1) {
670 // munge the listeners.
671 //print("ADDING listeners?");
676 var keys = new Gee.ArrayList<string>();
677 var piter = this.node.listeners.map_iterator();
678 while (piter.next() ) {
680 keys.add(piter.get_key());
682 keys.sort(( a, b) => {
683 return ((string)a).collate((string)b);
684 //if (a == b) return 0;
685 //return a < b ? -1 : 1;
688 var itms = "listeners : {\n";
690 for (var i = 0; i< keys.size; i++) {
691 var key = keys.get(i);
692 var val = this.node.listeners.get(key);
695 itms += i >0 ? ",\n" : "";
697 var str = val.strip();
698 var lines = str.split("\n");
699 if (lines.length > 0) {
700 //str = string.joinv("\n" + this.pad + " ", lines);
701 str = string.joinv("\n" + this.pad + indent_str + indent_str , lines);
704 itms += this.pad + indent_str + key.replace("|", "") + " : " + str;
705 this.out_listeners.set(key.replace("|", "") ,str);
709 itms += "\n" + this.pad + "}";
710 //print ( "ADD " + itms);
715 public void iterChildren()
719 // finally munge the children...
720 if (this.node.items.size < 1) {
723 var itms = "items : [\n";
725 for(var i = 0; i < this.node.items.size;i++) {
726 var ele = this.node.items.get(i);
727 if (ele.props.has_key("* prop")) {
734 itms += this.pad + indent_str +
735 this.mungeChild( this.pad + indent_str + indent_str , ele);
736 this.out_children.add(ele);
739 itms += "\n"+ this.pad + "]" + "\n";
743 // finally output listeners...
745 public void xIncludeToString()