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 = 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..
135 public string mungeOut()
137 if (this.node.props.has_key("* xinclude")) {
138 this.addLine("Roo.apply(" + this.node.props.get("* xinclude") + "._tree(), {");
144 // output the items...
145 // work out remaining items...
146 var total_nodes = this.out_props.size +
147 this.out_props_array_plain.size +
148 (this.out_listeners.size > 0 ? 1 : 0) +
149 this.out_nodeprops.size +
150 this.out_props_array.size +
151 (this.out_children.size > 0 ? 1 : 0);
154 var iter = this.out_props.map_iterator();
157 suffix = total_nodes > 0 ? "," : "";
158 this.addLine(this.pad + iter.get_key() + " : " + iter.get_value() + suffix);
161 // out_props_array_plain
162 var paiter = this.out_props_array_plain.map_iterator();
164 while(paiter.next()) {
167 this.addLine(this.pad + paiter.get_key() + " : [");
168 var paliter = paiter.get_value().list_iterator();
169 while (paliter.next()) {
170 suffix = paliter.has_next() ? "," : "";
171 this.addMultiLine(this.pad + indent_str + paliter.get() + suffix);
174 suffix = total_nodes > 0 ? "," : "";
175 // this.mungeChild(this.pad + indent_str, niter.get_value())
176 this.addLine(this.pad + "]" + suffix);
182 if (this.out_listeners.size > 0 ) {
184 this.addLine(this.pad + "listeners : {");
185 iter = this.out_listeners.map_iterator();
186 var sz = this.out_listeners.size;
189 suffix = sz > 0 ? "," : "";
190 this.addMultiLine(this.pad + indent_str + iter.get_key() + " : " + iter.get_value() + suffix);
192 suffix = total_nodes > 0 ? "," : "";
193 this.addLine(this.pad + "}" + suffix);
198 var niter = this.out_nodeprops.map_iterator();
200 while(niter.next()) {
202 suffix = total_nodes > 0 ? "," : "";
203 this.addMultiLine(this.pad + niter.get_key() + " : " +
204 this.mungeChild(this.pad + indent_str, niter.get_value())
209 var piter = this.out_props_array.map_iterator();
211 while(piter.next()) {
214 this.addLine(this.pad + niter.get_key() + " : [");
215 var pliter = piter.get_value().list_iterator();
216 while (pliter.next()) {
217 suffix = pliter.has_next() ? "," : "";
218 this.addMultiLine(this.pad + indent_str +
219 this.mungeChild(this.pad + indent_str + indent_str, pliter.get()) + suffix);
222 suffix = total_nodes > 0 ? "," : "";
223 // this.mungeChild(this.pad + indent_str, niter.get_value())
224 this.addLine(this.pad + "]" + suffix);
228 if (this.out_children.size > 0) {
229 this.addLine(this.pad + "items : [");
230 var cniter = this.out_children.list_iterator();
231 while (cniter.next()) {
232 suffix = cniter.has_next() ? "," : "";
233 this.addMultiLine(this.pad +
234 this.mungeChild(this.pad + indent_str + indent_str, cniter.get()) + suffix
239 this.addLine(this.pad + indent_str + "]");
242 if (this.node.props.has_key("* xinclude")) {
243 this.addLine(this.pad + "})");
246 this.addLine(this.pad + "}");
258 public void addLine(string str= "")
261 this.ret += str+ "\n";
267 public void addMultiLine(string str= "")
270 this.cur_line += str.split("\n").length;
271 //this.ret += "/*%d*/ ".printf(l) + str + "\n";
272 this.ret += str + "\n";
275 string gLibStringListJoin( string sep, Gee.ArrayList<string> ar)
278 for (var i = 0; i < ar.size; i++) {
279 ret += i>0 ? sep : "";
285 public string mungeChild(string pad , Node cnode)
287 var x = new NodeToJs(cnode, this.doubleStringProps, pad, this);
294 public void checkChildren ()
298 // look throught he chilren == looking for * prop.. -- fixme might not work..
301 if (!this.node.hasChildren()) {
306 for (var ii =0; ii< this.node.items.size; ii++) {
307 var pl = this.node.items.get(ii);
308 if (!pl.props.has_key("* prop")) {
313 //print(JSON.stringify(pl,null,4));
315 //var prop = pl['*prop'] + '';
316 //delete pl['*prop'];
317 var prop = pl.get("* prop");
318 print("got prop "+ prop + "\n");
321 if (! Regex.match_simple("\\[\\]$", prop)) {
322 // it's a standard prop..
324 // munge property..??
326 this.out_nodeprops.set(prop, pl);
328 this.els.add( prop + " : " + this.mungeChild ( this.pad + indent_str, pl));
338 var sprop = prop.replace("[]", "");
339 print("sprop is : " + sprop + "\n");
341 // it's an array type..
343 if (!this.ar_props.has_key(sprop)) {
345 this.ar_props.set(sprop, "");
346 this.out_props_array.set(sprop, new Gee.ArrayList<Node>());
348 old = this.ar_props.get(sprop);
350 var nstr = old += old.length > 0 ? ",\n" : "";
351 nstr += this.mungeChild( this.pad + indent_str + indent_str + indent_str , pl);
352 this.out_props_array.get(sprop).add( pl);
353 this.ar_props.set(sprop, nstr);
360 * Standardize this crap...
362 * standard properties (use to set)
363 * If they are long values show the dialog..
366 * bool is_xxx :: can show a pulldown.. (true/false)
368 * $ string html = string with value interpolated eg. baseURL + ".."
369 * Clutter.ActorAlign x_align (typed) -- shows pulldowns if type is ENUM?
370 * $ untypedvalue = javascript untyped value...
371 * _ string html ... = translatable..
374 * object properties (not part of the GOjbect being wrapped?
375 * # Gee.ArrayList<Xcls_fileitem> fileitems
380 * methods -- always text editor..
388 * * init -- big string?
390 * event handlers (listeners)
395 * +XXXX -- indicates it's a instance property / not glob...
396 * *XXXX -- skip writing glob property (used as classes that can be created...)
400 public void readProps()
405 if (this.node.props.has_key("$ xns")) {
406 this.out_props.set("'|xns'", this.node.props.get("$ xns") );
408 this.els.add("'|xns' : '" + this.node.props.get("$ xns") + "'");
414 func_regex = new Regex("^\\s+|\\s+$");
416 print("failed to build regex");
419 // sort the key's so they always get rendered in the same order..
421 var keys = new Gee.ArrayList<string>();
422 var piter = this.node.props.map_iterator();
423 while (piter.next() ) {
427 this.node.normalize_key(piter.get_key(), out k, out kflag, out ktype);
432 keys.sort(( a, b) => {
433 return ((string)a).collate((string)b);
434 //if (a == b) return 0;
435 //return a < b ? -1 : 1;
440 for (var i = 0; i< keys.size; i++) {
441 var key = this.node.get_key(keys.get(i));
442 print("ADD KEY %s\n", key);
447 this.node.normalize_key(key, out k, out kflag, out ktype);
450 var v = this.node.get(key);
453 //if (this.skip.contains(k) ) {
456 if ( Regex.match_simple("\\[\\]$", k)) {
457 // array .. not supported... here?
463 // skip builder stuff. prefixed with '.' .. just like unix fs..
464 if (kflag == ".") { // |. or . -- do not output..
468 // ignore '* prop'; ???
473 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
474 left = "'" + leftv + "'";
475 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
476 var val = this.node.quoteString(leftv);
478 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
484 // next.. is it a function.. or a raw string..
492 // ??? any others that are raw output..
494 // does not hapepnd with arrays..
495 if (v.length < 1) { //if (typeof(el) == 'string' && !obj[i].length) { //skip empty.
502 str = func_regex.replace(v,v.length, 0, "");
504 print("regex failed");
510 var lines = str.split("\n");
512 if (lines.length > 0) {
513 nstr = string.joinv("\n" + this.pad, lines);
514 //nstr = string.joinv("\n", lines);
516 this.out_props.set(left, nstr);
517 //print("==> " + str + "\n");
518 this.els.add(left + " : "+ nstr);
529 ktype.down() == "boolean"
531 ktype.down() == "bool"
533 ktype.down() == "number"
535 ktype.down() == "int"
536 ) { // boolean or number...?
537 this.out_props.set(left, v.down());
538 this.els.add(left + " : " + v.down() );
542 // is it a translated string?
548 //if (this.doubleStringProps.size < 1) {
549 // this.els.add(left + this.node.quoteString(v));
553 if (this.doubleStringProps.index_of(k) > -1) {
554 // then use the translated version...
556 els.add(left + "_this._strings['" +
557 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
562 if (ktype.down() == "string" && k[0] == '_') {
563 els.add(left + "_this._strings['" +
564 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
569 // otherwise it needs to be encapsulated.. as single quotes..
571 var vv = this.node.quoteString(v);
572 // single quote.. v.substring(1, v.length-1).replace("'", "\\'") + "'";
573 this.els.add(left + " : " + "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
574 this.out_props.set(left, "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
581 public void readArrayProps()
584 // this is not needed in the new version
585 // as array props are handled more directly..
587 // handle the childitems that are arrays.. eg. button[] = { }...
589 // note this does not handle a mix of nodes and properties with the same
593 var iter = this.ar_props.map_iterator();
594 while (iter.next()) {
595 var k = iter.get_key();
596 var right = iter.get_value();
598 string leftv = k[0] == '|' ? k.substring(1) : k;
599 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
600 left = "'" + leftv + "'";
601 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
602 var val = this.node.quoteString(leftv);
604 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
610 if (right.length > 0){
611 //if (this.out_props_array_plain.has_key(left)) {
612 // this.out_props_array_plain.set(left, new Gee.ArrayList<string>());
614 //this.out_props_array_plain.get(left).add(right);
616 this.els.add(left + " : [\n" + this.pad + indent_str + indent_str +
617 right + "\n" + this.pad + "]");
624 public void readListeners()
627 if (this.node.listeners.size < 1) {
630 // munge the listeners.
631 //print("ADDING listeners?");
636 var keys = new Gee.ArrayList<string>();
637 var piter = this.node.listeners.map_iterator();
638 while (piter.next() ) {
640 keys.add(piter.get_key());
642 keys.sort(( a, b) => {
643 return ((string)a).collate((string)b);
644 //if (a == b) return 0;
645 //return a < b ? -1 : 1;
648 var itms = "listeners : {\n";
650 for (var i = 0; i< keys.size; i++) {
651 var key = keys.get(i);
652 var val = this.node.listeners.get(key);
655 itms += i >0 ? ",\n" : "";
657 var str = val.strip();
658 var lines = str.split("\n");
659 if (lines.length > 0) {
660 //str = string.joinv("\n" + this.pad + " ", lines);
661 str = string.joinv("\n" + this.pad + indent_str + indent_str , lines);
664 itms += this.pad + indent_str + key.replace("|", "") + " : " + str;
665 this.out_listeners.set(key.replace("|", "") ,str);
669 itms += "\n" + this.pad + "}";
670 //print ( "ADD " + itms);
675 public void iterChildren()
679 // finally munge the children...
680 if (this.node.items.size < 1) {
683 var itms = "items : [\n";
685 for(var i = 0; i < this.node.items.size;i++) {
686 var ele = this.node.items.get(i);
687 if (ele.props.has_key("* prop")) {
694 itms += this.pad + indent_str +
695 this.mungeChild( this.pad + indent_str + indent_str , ele);
696 this.out_children.add(ele);
699 itms += "\n"+ this.pad + "]" + "\n";
703 // finally output listeners...
705 public void xIncludeToString()