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.out_props.map_iterator();
189 suffix = total_nodes > 0 ? "," : "";
190 this.addLine(this.pad + iter.get_key() + " : " + iter.get_value() + suffix);
193 // out_props_array_plain -- not used?
194 var paiter = this.out_props_array_plain.map_iterator();
196 while(paiter.next()) {
199 this.addLine(this.pad + paiter.get_key() + " : [");
200 var paliter = paiter.get_value().list_iterator();
201 while (paliter.next()) {
202 suffix = paliter.has_next() ? "," : "";
203 this.addMultiLine(this.pad + indent_str + paliter.get() + suffix);
206 suffix = total_nodes > 0 ? "," : "";
207 // this.mungeChild(this.pad + indent_str, niter.get_value())
208 this.addLine(this.pad + "]" + suffix);
216 var piter = this.out_props_array.map_iterator();
218 while(piter.next()) {
221 this.addLine(this.pad + piter.get_key() + " : [");
222 var pliter = piter.get_value().list_iterator();
223 while (pliter.next()) {
224 suffix = pliter.has_next() ? "," : "";
225 this.addMultiLine(this.pad + indent_str +
226 this.mungeChildNew(this.pad + indent_str + indent_str, pliter.get()) + suffix);
229 suffix = total_nodes > 0 ? "," : "";
231 this.addLine(this.pad + "]" + suffix);
235 if (this.out_listeners.size > 0 ) {
237 this.addLine(this.pad + "listeners : {");
238 iter = this.out_listeners.map_iterator();
239 var sz = this.out_listeners.size;
242 suffix = sz > 0 ? "," : "";
243 this.addMultiLine(this.pad + indent_str + iter.get_key() + " : " + iter.get_value() + suffix);
245 suffix = total_nodes > 0 ? "," : "";
246 this.addLine(this.pad + "}" + suffix);
250 if (this.out_children.size > 0) {
251 this.addLine(this.pad + "items : [" );
252 var cniter = this.out_children.list_iterator();
253 while (cniter.next()) {
254 suffix = cniter.has_next() ? "," : "";
255 this.addMultiLine(this.pad + indent_str +
256 this.mungeChildNew(this.pad + indent_str + indent_str, cniter.get()) + suffix
261 this.addLine(this.pad + "]");
264 if (this.node.props.has_key("* xinclude")) {
265 this.ret += spad + "})";
268 this.ret += spad + "}";
280 public void addLine(string str= "")
283 this.ret += str+ "\n";
289 public void addMultiLine(string str= "")
292 this.cur_line += str.split("\n").length;
293 //this.ret += "/*%d*/ ".printf(l) + str + "\n";
294 this.ret += str + "\n";
297 string gLibStringListJoin( string sep, Gee.ArrayList<string> ar)
300 for (var i = 0; i < ar.size; i++) {
301 ret += i>0 ? sep : "";
307 public string mungeChild(string pad , Node cnode)
309 var x = new NodeToJs(cnode, this.doubleStringProps, pad, this);
313 public string mungeChildNew(string pad , Node cnode)
315 var x = new NodeToJs(cnode, this.doubleStringProps, pad, this);
322 public void checkChildren ()
326 // look throught he chilren == looking for * prop.. -- fixme might not work..
329 if (!this.node.hasChildren()) {
334 for (var ii =0; ii< this.node.items.size; ii++) {
335 var pl = this.node.items.get(ii);
336 if (!pl.props.has_key("* prop")) {
341 //print(JSON.stringify(pl,null,4));
343 //var prop = pl['*prop'] + '';
344 //delete pl['*prop'];
345 var prop = pl.get("* prop");
346 print("got prop "+ prop + "\n");
349 if (! Regex.match_simple("\\[\\]$", prop)) {
350 // it's a standard prop..
352 // munge property..??
354 this.out_nodeprops.set(prop, pl);
356 this.els.add( prop + " : " + this.mungeChild ( this.pad + indent_str, pl));
366 var sprop = prop.replace("[]", "");
367 print("sprop is : " + sprop + "\n");
369 // it's an array type..
371 if (!this.ar_props.has_key(sprop)) {
373 this.ar_props.set(sprop, "");
374 this.out_props_array.set(sprop, new Gee.ArrayList<Node>());
376 old = this.ar_props.get(sprop);
378 var nstr = old += old.length > 0 ? ",\n" : "";
379 nstr += this.mungeChild( this.pad + indent_str + indent_str + indent_str , pl);
380 this.out_props_array.get(sprop).add( pl);
381 this.ar_props.set(sprop, nstr);
388 * Standardize this crap...
390 * standard properties (use to set)
391 * If they are long values show the dialog..
394 * bool is_xxx :: can show a pulldown.. (true/false)
396 * $ string html = string with value interpolated eg. baseURL + ".."
397 * Clutter.ActorAlign x_align (typed) -- shows pulldowns if type is ENUM?
398 * $ untypedvalue = javascript untyped value...
399 * _ string html ... = translatable..
402 * object properties (not part of the GOjbect being wrapped?
403 * # Gee.ArrayList<Xcls_fileitem> fileitems
408 * methods -- always text editor..
416 * * init -- big string?
418 * event handlers (listeners)
423 * +XXXX -- indicates it's a instance property / not glob...
424 * *XXXX -- skip writing glob property (used as classes that can be created...)
428 public void readProps()
433 if (this.node.props.has_key("$ xns")) {
434 this.out_props.set("'|xns'", this.node.props.get("$ xns") );
436 this.els.add("'|xns' : '" + this.node.props.get("$ xns") + "'");
442 func_regex = new Regex("^\\s+|\\s+$");
444 print("failed to build regex");
447 // sort the key's so they always get rendered in the same order..
449 var keys = new Gee.ArrayList<string>();
450 var piter = this.node.props.map_iterator();
451 while (piter.next() ) {
455 this.node.normalize_key(piter.get_key(), out k, out kflag, out ktype);
460 keys.sort(( a, b) => {
461 return ((string)a).collate((string)b);
462 //if (a == b) return 0;
463 //return a < b ? -1 : 1;
468 for (var i = 0; i< keys.size; i++) {
469 var key = this.node.get_key(keys.get(i));
470 print("ADD KEY %s\n", key);
475 this.node.normalize_key(key, out k, out kflag, out ktype);
478 var v = this.node.get(key);
481 //if (this.skip.contains(k) ) {
484 if ( Regex.match_simple("\\[\\]$", k)) {
485 // array .. not supported... here?
491 // skip builder stuff. prefixed with '.' .. just like unix fs..
492 if (kflag == ".") { // |. or . -- do not output..
496 // ignore '* prop'; ???
501 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
502 left = "'" + leftv + "'";
503 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
504 var val = this.node.quoteString(leftv);
506 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
512 // next.. is it a function.. or a raw string..
520 // ??? any others that are raw output..
522 // does not hapepnd with arrays..
523 if (v.length < 1) { //if (typeof(el) == 'string' && !obj[i].length) { //skip empty.
530 str = func_regex.replace(v,v.length, 0, "");
532 print("regex failed");
538 var lines = str.split("\n");
540 if (lines.length > 0) {
541 nstr = string.joinv("\n" + this.pad, lines);
542 //nstr = string.joinv("\n", lines);
544 this.out_props.set(left, nstr);
545 //print("==> " + str + "\n");
546 this.els.add(left + " : "+ nstr);
557 ktype.down() == "boolean"
559 ktype.down() == "bool"
561 ktype.down() == "number"
563 ktype.down() == "int"
564 ) { // boolean or number...?
565 this.out_props.set(left, v.down());
566 this.els.add(left + " : " + v.down() );
570 // is it a translated string?
576 //if (this.doubleStringProps.size < 1) {
577 // this.els.add(left + this.node.quoteString(v));
581 if (this.doubleStringProps.index_of(k) > -1) {
582 // then use the translated version...
584 this.els.add(left + " : _this._strings['" +
585 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
588 this.out_props.set(left, "_this._strings['" +
589 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
593 if (ktype.down() == "string" && k[0] == '_') {
594 this.els.add(left + " : _this._strings['" +
595 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
598 this.out_props.set(left, " _this._strings['" +
599 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
606 // otherwise it needs to be encapsulated.. as single quotes..
608 var vv = this.node.quoteString(v);
609 // single quote.. v.substring(1, v.length-1).replace("'", "\\'") + "'";
610 this.els.add(left + " : " + "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
611 this.out_props.set(left, "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
618 public void readArrayProps()
621 // this is not needed in the new version
622 // as array props are handled more directly..
624 // handle the childitems that are arrays.. eg. button[] = { }...
626 // note this does not handle a mix of nodes and properties with the same
630 var iter = this.ar_props.map_iterator();
631 while (iter.next()) {
632 var k = iter.get_key();
633 var right = iter.get_value();
635 string leftv = k[0] == '|' ? k.substring(1) : k;
636 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
637 left = "'" + leftv + "'";
638 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
639 var val = this.node.quoteString(leftv);
641 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
647 if (right.length > 0){
648 //if (this.out_props_array_plain.has_key(left)) {
649 // this.out_props_array_plain.set(left, new Gee.ArrayList<string>());
651 //this.out_props_array_plain.get(left).add(right);
653 this.els.add(left + " : [\n" + this.pad + indent_str + indent_str +
654 right + "\n" + this.pad + "]");
661 public void readListeners()
664 if (this.node.listeners.size < 1) {
667 // munge the listeners.
668 //print("ADDING listeners?");
673 var keys = new Gee.ArrayList<string>();
674 var piter = this.node.listeners.map_iterator();
675 while (piter.next() ) {
677 keys.add(piter.get_key());
679 keys.sort(( a, b) => {
680 return ((string)a).collate((string)b);
681 //if (a == b) return 0;
682 //return a < b ? -1 : 1;
685 var itms = "listeners : {\n";
687 for (var i = 0; i< keys.size; i++) {
688 var key = keys.get(i);
689 var val = this.node.listeners.get(key);
692 itms += i >0 ? ",\n" : "";
694 var str = val.strip();
695 var lines = str.split("\n");
696 if (lines.length > 0) {
697 //str = string.joinv("\n" + this.pad + " ", lines);
698 str = string.joinv("\n" + this.pad + indent_str + indent_str , lines);
701 itms += this.pad + indent_str + key.replace("|", "") + " : " + str;
702 this.out_listeners.set(key.replace("|", "") ,str);
706 itms += "\n" + this.pad + "}";
707 //print ( "ADD " + itms);
712 public void iterChildren()
716 // finally munge the children...
717 if (this.node.items.size < 1) {
720 var itms = "items : [\n";
722 for(var i = 0; i < this.node.items.size;i++) {
723 var ele = this.node.items.get(i);
724 if (ele.props.has_key("* prop")) {
731 itms += this.pad + indent_str +
732 this.mungeChild( this.pad + indent_str + indent_str , ele);
733 this.out_children.add(ele);
736 itms += "\n"+ this.pad + "]" + "\n";
740 // finally output listeners...
742 public void xIncludeToString()