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")) {
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_props_array_plain.size +
145 (this.out_listeners.size > 0 ? 1 : 0) +
146 this.out_nodeprops.size +
147 this.out_props_array.size +
148 (this.out_children.size > 0 ? 1 : 0);
151 var iter = this.out_props.map_iterator();
154 suffix = total_nodes > 0 ? "," : "";
155 this.addLine(this.pad + iter.get_key() + " : " + iter.get_value() + suffix);
158 // out_props_array_plain
159 var paiter = this.out_props_array_plain.map_iterator();
161 while(paiter.next()) {
164 this.addLine(this.pad + paiter.get_key() + " : [");
165 var paliter = paiter.get_value().list_iterator();
166 while (paliter.next()) {
167 suffix = paliter.has_next() ? "," : "";
168 this.addMultiLine(this.pad + indent_str + paliter.get() + suffix);
171 suffix = total_nodes > 0 ? "," : "";
172 // this.mungeChild(this.pad + indent_str, niter.get_value())
173 this.addLine(this.pad + "]" + suffix);
179 if (this.out_listeners.size > 0 ) {
181 this.addLine(this.pad + "listeners : {");
182 iter = this.out_listeners.map_iterator();
183 var sz = this.out_listeners.size;
186 suffix = sz > 0 ? "," : "";
187 this.addMultiLine(this.pad + indent_str + iter.get_key() + " : " + iter.get_value() + suffix);
189 suffix = total_nodes > 0 ? "," : "";
190 this.addLine(this.pad + "}" + suffix);
195 var niter = this.out_nodeprops.map_iterator();
197 while(niter.next()) {
199 suffix = total_nodes > 0 ? "," : "";
200 this.addMultiLine(this.pad + niter.get_key() + " : " +
201 this.mungeChild(this.pad + indent_str, niter.get_value())
206 var piter = this.out_props_array.map_iterator();
208 while(piter.next()) {
211 this.addLine(this.pad + niter.get_key() + " : [");
212 var pliter = piter.get_value().list_iterator();
213 while (pliter.next()) {
214 suffix = pliter.has_next() ? "," : "";
215 this.addMultiLine(this.pad + indent_str +
216 this.mungeChild(this.pad + indent_str + indent_str, pliter.get()) + suffix);
219 suffix = total_nodes > 0 ? "," : "";
220 // this.mungeChild(this.pad + indent_str, niter.get_value())
221 this.addLine(this.pad + "]" + suffix);
225 if (this.out_children.size > 0) {
226 this.addLine(this.pad + "items : [");
227 var cniter = this.out_children.list_iterator();
228 while (cniter.next()) {
229 suffix = cniter.has_next() ? "," : "";
230 this.addMultiLine(this.pad +
231 this.mungeChild(this.pad + indent_str + indent_str, cniter.get()) + suffix
236 this.addLine(this.pad + indent_str + "]");
239 if (this.node.props.has_key("* xinclude")) {
240 this.addLine(this.pad + "})");
243 this.addLine(this.pad + "}");
255 public void addLine(string str= "")
258 this.ret += str+ "\n";
264 public void addMultiLine(string str= "")
267 this.cur_line += str.split("\n").length;
268 //this.ret += "/*%d*/ ".printf(l) + str + "\n";
269 this.ret += str + "\n";
272 string gLibStringListJoin( string sep, Gee.ArrayList<string> ar)
275 for (var i = 0; i < ar.size; i++) {
276 ret += i>0 ? sep : "";
282 public string mungeChild(string pad , Node cnode)
284 var x = new NodeToJs(cnode, this.doubleStringProps, pad, this);
291 public void checkChildren ()
295 // look throught he chilren == looking for * prop.. -- fixme might not work..
298 if (!this.node.hasChildren()) {
303 for (var ii =0; ii< this.node.items.size; ii++) {
304 var pl = this.node.items.get(ii);
305 if (!pl.props.has_key("* prop")) {
310 //print(JSON.stringify(pl,null,4));
312 //var prop = pl['*prop'] + '';
313 //delete pl['*prop'];
314 var prop = pl.get("* prop");
315 print("got prop "+ prop + "\n");
318 if (! Regex.match_simple("\\[\\]$", prop)) {
319 // it's a standard prop..
321 // munge property..??
323 this.out_nodeprops.set(prop, pl);
325 this.els.add( prop + " : " + this.mungeChild ( this.pad + indent_str, pl));
335 var sprop = prop.replace("[]", "");
336 print("sprop is : " + sprop + "\n");
338 // it's an array type..
340 if (!this.ar_props.has_key(sprop)) {
342 this.ar_props.set(sprop, "");
343 this.out_props_array.set(sprop, new Gee.ArrayList<Node>());
345 old = this.ar_props.get(sprop);
347 var nstr = old += old.length > 0 ? ",\n" : "";
348 nstr += this.mungeChild( this.pad + indent_str + indent_str + indent_str , pl);
349 this.out_props_array.get(sprop).add( pl);
350 this.ar_props.set(sprop, nstr);
357 * Standardize this crap...
359 * standard properties (use to set)
360 * If they are long values show the dialog..
363 * bool is_xxx :: can show a pulldown.. (true/false)
365 * $ string html = string with value interpolated eg. baseURL + ".."
366 * Clutter.ActorAlign x_align (typed) -- shows pulldowns if type is ENUM?
367 * $ untypedvalue = javascript untyped value...
368 * _ string html ... = translatable..
371 * object properties (not part of the GOjbect being wrapped?
372 * # Gee.ArrayList<Xcls_fileitem> fileitems
377 * methods -- always text editor..
385 * * init -- big string?
387 * event handlers (listeners)
392 * +XXXX -- indicates it's a instance property / not glob...
393 * *XXXX -- skip writing glob property (used as classes that can be created...)
397 public void readProps()
402 if (this.node.props.has_key("$ xns")) {
403 this.out_props.set("'|xns'", this.node.props.get("$ xns") );
405 this.els.add("'|xns' : '" + this.node.props.get("$ xns") + "'");
411 func_regex = new Regex("^\\s+|\\s+$");
413 print("failed to build regex");
416 // sort the key's so they always get rendered in the same order..
418 var keys = new Gee.ArrayList<string>();
419 var piter = this.node.props.map_iterator();
420 while (piter.next() ) {
424 this.node.normalize_key(piter.get_key(), out k, out kflag, out ktype);
429 keys.sort(( a, b) => {
430 return ((string)a).collate((string)b);
431 //if (a == b) return 0;
432 //return a < b ? -1 : 1;
437 for (var i = 0; i< keys.size; i++) {
438 var key = this.node.get_key(keys.get(i));
439 print("ADD KEY %s\n", key);
444 this.node.normalize_key(key, out k, out kflag, out ktype);
447 var v = this.node.get(key);
450 //if (this.skip.contains(k) ) {
453 if ( Regex.match_simple("\\[\\]$", k)) {
454 // array .. not supported... here?
460 // skip builder stuff. prefixed with '.' .. just like unix fs..
461 if (kflag == ".") { // |. or . -- do not output..
465 // ignore '* prop'; ???
470 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
471 left = "'" + leftv + "'";
472 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
473 var val = this.node.quoteString(leftv);
475 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
481 // next.. is it a function.. or a raw string..
489 // ??? any others that are raw output..
491 // does not hapepnd with arrays..
492 if (v.length < 1) { //if (typeof(el) == 'string' && !obj[i].length) { //skip empty.
499 str = func_regex.replace(v,v.length, 0, "");
501 print("regex failed");
507 var lines = str.split("\n");
509 if (lines.length > 0) {
510 nstr = string.joinv("\n" + this.pad, lines);
511 //nstr = string.joinv("\n", lines);
513 this.out_props.set(left, nstr);
514 //print("==> " + str + "\n");
515 this.els.add(left + " : "+ nstr);
526 ktype.down() == "boolean"
528 ktype.down() == "bool"
530 ktype.down() == "number"
532 ktype.down() == "int"
533 ) { // boolean or number...?
534 this.out_props.set(left, v.down());
535 this.els.add(left + " : " + v.down() );
539 // is it a translated string?
545 //if (this.doubleStringProps.size < 1) {
546 // this.els.add(left + this.node.quoteString(v));
550 if (this.doubleStringProps.index_of(k) > -1) {
551 // then use the translated version...
553 els.add(left + "_this._strings['" +
554 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
559 if (ktype.down() == "string" && k[0] == '_') {
560 els.add(left + "_this._strings['" +
561 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
566 // otherwise it needs to be encapsulated.. as single quotes..
568 var vv = this.node.quoteString(v);
569 // single quote.. v.substring(1, v.length-1).replace("'", "\\'") + "'";
570 this.els.add(left + " : " + "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
571 this.out_props.set(left, "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
578 public void readArrayProps()
581 // this is not needed in the new version
582 // as array props are handled more directly..
584 // handle the childitems that are arrays.. eg. button[] = { }...
586 // note this does not handle a mix of nodes and properties with the same
590 var iter = this.ar_props.map_iterator();
591 while (iter.next()) {
592 var k = iter.get_key();
593 var right = iter.get_value();
595 string leftv = k[0] == '|' ? k.substring(1) : k;
596 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
597 left = "'" + leftv + "'";
598 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
599 var val = this.node.quoteString(leftv);
601 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
607 if (right.length > 0){
608 //if (this.out_props_array_plain.has_key(left)) {
609 // this.out_props_array_plain.set(left, new Gee.ArrayList<string>());
611 //this.out_props_array_plain.get(left).add(right);
613 this.els.add(left + " : [\n" + this.pad + indent_str + indent_str +
614 right + "\n" + this.pad + "]");
621 public void readListeners()
624 if (this.node.listeners.size < 1) {
627 // munge the listeners.
628 //print("ADDING listeners?");
633 var keys = new Gee.ArrayList<string>();
634 var piter = this.node.listeners.map_iterator();
635 while (piter.next() ) {
637 keys.add(piter.get_key());
639 keys.sort(( a, b) => {
640 return ((string)a).collate((string)b);
641 //if (a == b) return 0;
642 //return a < b ? -1 : 1;
645 var itms = "listeners : {\n";
647 for (var i = 0; i< keys.size; i++) {
648 var key = keys.get(i);
649 var val = this.node.listeners.get(key);
652 itms += i >0 ? ",\n" : "";
654 var str = val.strip();
655 var lines = str.split("\n");
656 if (lines.length > 0) {
657 //str = string.joinv("\n" + this.pad + " ", lines);
658 str = string.joinv("\n" + this.pad + indent_str + indent_str , lines);
661 itms += this.pad + indent_str + key.replace("|", "") + " : " + str;
666 itms += "\n" + this.pad + "}";
667 //print ( "ADD " + itms);
672 public void iterChildren()
676 // finally munge the children...
677 if (this.node.items.size < 1) {
680 var itms = "items : [\n";
682 for(var i = 0; i < this.node.items.size;i++) {
683 var ele = this.node.items.get(i);
684 if (ele.props.has_key("* prop")) {
691 itms += this.pad + indent_str +
692 this.mungeChild( this.pad + indent_str + indent_str , ele);
693 this.out_children.add(ele);
696 itms += "\n"+ this.pad + "]" + "\n";
700 // finally output listeners...
702 public void xIncludeToString()