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..
135 public string mungeOut()
138 var spad = this.pad.substring(0, this.pad.length-indent);
140 if (this.node.props.has_key("* xinclude")) {
141 this.addLine("Roo.apply(" + this.node.props.get("* xinclude") + "._tree(), {");
147 // output the items...
148 // work out remaining items...
149 var total_nodes = this.out_props.size +
150 this.out_props_array_plain.size +
151 (this.out_listeners.size > 0 ? 1 : 0) +
152 this.out_nodeprops.size +
153 this.out_props_array.size +
154 (this.out_children.size > 0 ? 1 : 0);
157 var iter = this.out_props.map_iterator();
160 suffix = total_nodes > 0 ? "," : "";
161 this.addLine(this.pad + iter.get_key() + " : " + iter.get_value() + suffix);
164 // out_props_array_plain -- not used?
165 var paiter = this.out_props_array_plain.map_iterator();
167 while(paiter.next()) {
170 this.addLine(this.pad + paiter.get_key() + " : [");
171 var paliter = paiter.get_value().list_iterator();
172 while (paliter.next()) {
173 suffix = paliter.has_next() ? "," : "";
174 this.addMultiLine(this.pad + indent_str + paliter.get() + suffix);
177 suffix = total_nodes > 0 ? "," : "";
178 // this.mungeChild(this.pad + indent_str, niter.get_value())
179 this.addLine(this.pad + "]" + suffix);
185 if (this.out_listeners.size > 0 ) {
187 this.addLine(this.pad + "listeners : {");
188 iter = this.out_listeners.map_iterator();
189 var sz = this.out_listeners.size;
192 suffix = sz > 0 ? "," : "";
193 this.addMultiLine(this.pad + indent_str + iter.get_key() + " : " + iter.get_value() + suffix);
195 suffix = total_nodes > 0 ? "," : "";
196 this.addLine(this.pad + "}" + suffix);
201 var niter = this.out_nodeprops.map_iterator();
203 while(niter.next()) {
205 suffix = total_nodes > 0 ? "," : "";
206 this.addMultiLine(this.pad + niter.get_key() + " : " +
207 this.mungeChild(this.pad + indent_str, niter.get_value())
212 var piter = this.out_props_array.map_iterator();
214 while(piter.next()) {
217 this.addLine(this.pad + niter.get_key() + " : [");
218 var pliter = piter.get_value().list_iterator();
219 while (pliter.next()) {
220 suffix = pliter.has_next() ? "," : "";
221 this.addMultiLine(this.pad + indent_str +
222 this.mungeChild(this.pad + indent_str + indent_str, pliter.get()) + suffix);
225 suffix = total_nodes > 0 ? "," : "";
226 // this.mungeChild(this.pad + indent_str, niter.get_value())
227 this.addLine(this.pad + "]" + suffix);
231 if (this.out_children.size > 0) {
232 this.addLine(this.pad + "items : [");
233 var cniter = this.out_children.list_iterator();
234 while (cniter.next()) {
235 suffix = cniter.has_next() ? "," : "";
236 this.addMultiLine(this.pad +
237 this.mungeChild(this.pad + indent_str + indent_str, cniter.get()) + suffix
242 this.addLine(this.pad + indent_str + "]");
245 if (this.node.props.has_key("* xinclude")) {
246 this.addLine(spad + "})");
249 this.addLine(spad + "}");
261 public void addLine(string str= "")
264 this.ret += str+ "\n";
270 public void addMultiLine(string str= "")
273 this.cur_line += str.split("\n").length;
274 //this.ret += "/*%d*/ ".printf(l) + str + "\n";
275 this.ret += str + "\n";
278 string gLibStringListJoin( string sep, Gee.ArrayList<string> ar)
281 for (var i = 0; i < ar.size; i++) {
282 ret += i>0 ? sep : "";
288 public string mungeChild(string pad , Node cnode)
290 var x = new NodeToJs(cnode, this.doubleStringProps, pad, this);
297 public void checkChildren ()
301 // look throught he chilren == looking for * prop.. -- fixme might not work..
304 if (!this.node.hasChildren()) {
309 for (var ii =0; ii< this.node.items.size; ii++) {
310 var pl = this.node.items.get(ii);
311 if (!pl.props.has_key("* prop")) {
316 //print(JSON.stringify(pl,null,4));
318 //var prop = pl['*prop'] + '';
319 //delete pl['*prop'];
320 var prop = pl.get("* prop");
321 print("got prop "+ prop + "\n");
324 if (! Regex.match_simple("\\[\\]$", prop)) {
325 // it's a standard prop..
327 // munge property..??
329 this.out_nodeprops.set(prop, pl);
331 this.els.add( prop + " : " + this.mungeChild ( this.pad + indent_str, pl));
341 var sprop = prop.replace("[]", "");
342 print("sprop is : " + sprop + "\n");
344 // it's an array type..
346 if (!this.ar_props.has_key(sprop)) {
348 this.ar_props.set(sprop, "");
349 this.out_props_array.set(sprop, new Gee.ArrayList<Node>());
351 old = this.ar_props.get(sprop);
353 var nstr = old += old.length > 0 ? ",\n" : "";
354 nstr += this.mungeChild( this.pad + indent_str + indent_str + indent_str , pl);
355 this.out_props_array.get(sprop).add( pl);
356 this.ar_props.set(sprop, nstr);
363 * Standardize this crap...
365 * standard properties (use to set)
366 * If they are long values show the dialog..
369 * bool is_xxx :: can show a pulldown.. (true/false)
371 * $ string html = string with value interpolated eg. baseURL + ".."
372 * Clutter.ActorAlign x_align (typed) -- shows pulldowns if type is ENUM?
373 * $ untypedvalue = javascript untyped value...
374 * _ string html ... = translatable..
377 * object properties (not part of the GOjbect being wrapped?
378 * # Gee.ArrayList<Xcls_fileitem> fileitems
383 * methods -- always text editor..
391 * * init -- big string?
393 * event handlers (listeners)
398 * +XXXX -- indicates it's a instance property / not glob...
399 * *XXXX -- skip writing glob property (used as classes that can be created...)
403 public void readProps()
408 if (this.node.props.has_key("$ xns")) {
409 this.out_props.set("'|xns'", this.node.props.get("$ xns") );
411 this.els.add("'|xns' : '" + this.node.props.get("$ xns") + "'");
417 func_regex = new Regex("^\\s+|\\s+$");
419 print("failed to build regex");
422 // sort the key's so they always get rendered in the same order..
424 var keys = new Gee.ArrayList<string>();
425 var piter = this.node.props.map_iterator();
426 while (piter.next() ) {
430 this.node.normalize_key(piter.get_key(), out k, out kflag, out ktype);
435 keys.sort(( a, b) => {
436 return ((string)a).collate((string)b);
437 //if (a == b) return 0;
438 //return a < b ? -1 : 1;
443 for (var i = 0; i< keys.size; i++) {
444 var key = this.node.get_key(keys.get(i));
445 print("ADD KEY %s\n", key);
450 this.node.normalize_key(key, out k, out kflag, out ktype);
453 var v = this.node.get(key);
456 //if (this.skip.contains(k) ) {
459 if ( Regex.match_simple("\\[\\]$", k)) {
460 // array .. not supported... here?
466 // skip builder stuff. prefixed with '.' .. just like unix fs..
467 if (kflag == ".") { // |. or . -- do not output..
471 // ignore '* prop'; ???
476 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
477 left = "'" + leftv + "'";
478 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
479 var val = this.node.quoteString(leftv);
481 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
487 // next.. is it a function.. or a raw string..
495 // ??? any others that are raw output..
497 // does not hapepnd with arrays..
498 if (v.length < 1) { //if (typeof(el) == 'string' && !obj[i].length) { //skip empty.
505 str = func_regex.replace(v,v.length, 0, "");
507 print("regex failed");
513 var lines = str.split("\n");
515 if (lines.length > 0) {
516 nstr = string.joinv("\n" + this.pad, lines);
517 //nstr = string.joinv("\n", lines);
519 this.out_props.set(left, nstr);
520 //print("==> " + str + "\n");
521 this.els.add(left + " : "+ nstr);
532 ktype.down() == "boolean"
534 ktype.down() == "bool"
536 ktype.down() == "number"
538 ktype.down() == "int"
539 ) { // boolean or number...?
540 this.out_props.set(left, v.down());
541 this.els.add(left + " : " + v.down() );
545 // is it a translated string?
551 //if (this.doubleStringProps.size < 1) {
552 // this.els.add(left + this.node.quoteString(v));
556 if (this.doubleStringProps.index_of(k) > -1) {
557 // then use the translated version...
559 els.add(left + " : _this._strings['" +
560 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
565 if (ktype.down() == "string" && k[0] == '_') {
566 els.add(left + " : _this._strings['" +
567 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
572 // otherwise it needs to be encapsulated.. as single quotes..
574 var vv = this.node.quoteString(v);
575 // single quote.. v.substring(1, v.length-1).replace("'", "\\'") + "'";
576 this.els.add(left + " : " + "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
577 this.out_props.set(left, "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
584 public void readArrayProps()
587 // this is not needed in the new version
588 // as array props are handled more directly..
590 // handle the childitems that are arrays.. eg. button[] = { }...
592 // note this does not handle a mix of nodes and properties with the same
596 var iter = this.ar_props.map_iterator();
597 while (iter.next()) {
598 var k = iter.get_key();
599 var right = iter.get_value();
601 string leftv = k[0] == '|' ? k.substring(1) : k;
602 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
603 left = "'" + leftv + "'";
604 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
605 var val = this.node.quoteString(leftv);
607 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
613 if (right.length > 0){
614 //if (this.out_props_array_plain.has_key(left)) {
615 // this.out_props_array_plain.set(left, new Gee.ArrayList<string>());
617 //this.out_props_array_plain.get(left).add(right);
619 this.els.add(left + " : [\n" + this.pad + indent_str + indent_str +
620 right + "\n" + this.pad + "]");
627 public void readListeners()
630 if (this.node.listeners.size < 1) {
633 // munge the listeners.
634 //print("ADDING listeners?");
639 var keys = new Gee.ArrayList<string>();
640 var piter = this.node.listeners.map_iterator();
641 while (piter.next() ) {
643 keys.add(piter.get_key());
645 keys.sort(( a, b) => {
646 return ((string)a).collate((string)b);
647 //if (a == b) return 0;
648 //return a < b ? -1 : 1;
651 var itms = "listeners : {\n";
653 for (var i = 0; i< keys.size; i++) {
654 var key = keys.get(i);
655 var val = this.node.listeners.get(key);
658 itms += i >0 ? ",\n" : "";
660 var str = val.strip();
661 var lines = str.split("\n");
662 if (lines.length > 0) {
663 //str = string.joinv("\n" + this.pad + " ", lines);
664 str = string.joinv("\n" + this.pad + indent_str + indent_str , lines);
667 itms += this.pad + indent_str + key.replace("|", "") + " : " + str;
668 this.out_listeners.set(key.replace("|", "") ,str);
672 itms += "\n" + this.pad + "}";
673 //print ( "ADD " + itms);
678 public void iterChildren()
682 // finally munge the children...
683 if (this.node.items.size < 1) {
686 var itms = "items : [\n";
688 for(var i = 0; i < this.node.items.size;i++) {
689 var ele = this.node.items.get(i);
690 if (ele.props.has_key("* prop")) {
697 itms += this.pad + indent_str +
698 this.mungeChild( this.pad + indent_str + indent_str , ele);
699 this.out_children.add(ele);
702 itms += "\n"+ this.pad + "]" + "\n";
706 // finally output listeners...
708 public void xIncludeToString()