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;
149 public Gee.ArrayList<string> orderedListenerKeys() {
151 var ret = new Gee.ArrayList<string> ();
152 var niter = this.out_listeners.map_iterator();
153 while(niter.next()) {
154 ret.add(niter.get_key());
157 ret.sort(( a, b) => {
158 return ((string)a).collate((string)b);
159 //if (a == b) return 0;
160 //return a < b ? -1 : 1;
166 public string mungeOut()
169 var spad = this.pad.substring(0, this.pad.length-indent);
171 if (this.node.props.has_key("* xinclude")) {
172 this.addLine("Roo.apply(" + this.node.props.get("* xinclude") + "._tree(), {");
178 // output the items...
179 // work out remaining items...
180 var total_nodes = this.out_props.size +
181 this.out_props_array_plain.size +
182 (this.out_listeners.size > 0 ? 1 : 0) +
183 this.out_nodeprops.size +
184 this.out_props_array.size +
185 (this.out_children.size > 0 ? 1 : 0);
190 var niter = this.out_nodeprops.map_iterator();
192 while(niter.next()) {
194 suffix = total_nodes > 0 ? "," : "";
195 this.addMultiLine(this.pad + niter.get_key() + " : " +
196 this.mungeChildNew(this.pad + indent_str, niter.get_value()) + suffix
201 var iter = this.orderedPropKeys().list_iterator();
204 suffix = total_nodes > 0 ? "," : "";
206 var v = this.out_props.get(k);
208 this.addLine(this.pad + k + " : " + v + suffix);
211 // out_props_array_plain -- not used?
212 var paiter = this.out_props_array_plain.map_iterator();
214 while(paiter.next()) {
217 this.addLine(this.pad + paiter.get_key() + " : [");
218 var paliter = paiter.get_value().list_iterator();
219 while (paliter.next()) {
220 suffix = paliter.has_next() ? "," : "";
221 this.addMultiLine(this.pad + indent_str + paliter.get() + suffix);
224 suffix = total_nodes > 0 ? "," : "";
225 // this.mungeChild(this.pad + indent_str, niter.get_value())
226 this.addLine(this.pad + "]" + suffix);
234 var piter = this.out_props_array.map_iterator();
236 while(piter.next()) {
239 this.addLine(this.pad + piter.get_key() + " : [");
240 var pliter = piter.get_value().list_iterator();
241 while (pliter.next()) {
242 suffix = pliter.has_next() ? "," : "";
243 this.addMultiLine(this.pad + indent_str +
244 this.mungeChildNew(this.pad + indent_str + indent_str, pliter.get()) + suffix);
247 suffix = total_nodes > 0 ? "," : "";
249 this.addLine(this.pad + "]" + suffix);
253 if (this.out_listeners.size > 0 ) {
255 this.addLine(this.pad + "listeners : {");
256 iter = this.orderedListenerKeys().list_iterator();
258 var sz = this.out_listeners.size;
261 suffix = sz > 0 ? "," : "";
263 var v = this.out_listeners.get(k);
264 this.addMultiLine(this.pad + indent_str + k + " : " + v + suffix);
266 suffix = total_nodes > 0 ? "," : "";
267 this.addLine(this.pad + "}" + suffix);
271 if (this.out_children.size > 0) {
272 this.addLine(this.pad + "items : [" );
273 var cniter = this.out_children.list_iterator();
274 while (cniter.next()) {
275 suffix = cniter.has_next() ? "," : "";
276 this.addMultiLine(this.pad + indent_str +
277 this.mungeChildNew(this.pad + indent_str + indent_str, cniter.get()) + suffix
282 this.addLine(this.pad + "]");
285 if (this.node.props.has_key("* xinclude")) {
286 this.ret += spad + "})";
289 this.ret += spad + "}";
301 public void addLine(string str= "")
304 this.ret += str+ "\n";
310 public void addMultiLine(string str= "")
313 this.cur_line += str.split("\n").length;
314 //this.ret += "/*%d*/ ".printf(l) + str + "\n";
315 this.ret += str + "\n";
318 string gLibStringListJoin( string sep, Gee.ArrayList<string> ar)
321 for (var i = 0; i < ar.size; i++) {
322 ret += i>0 ? sep : "";
328 public string mungeChild(string pad , Node cnode)
330 var x = new NodeToJs(cnode, this.doubleStringProps, pad, this);
334 public string mungeChildNew(string pad , Node cnode)
336 var x = new NodeToJs(cnode, this.doubleStringProps, pad, this);
343 public void checkChildren ()
347 // look throught he chilren == looking for * prop.. -- fixme might not work..
350 if (!this.node.hasChildren()) {
355 for (var ii =0; ii< this.node.items.size; ii++) {
356 var pl = this.node.items.get(ii);
357 if (!pl.props.has_key("* prop")) {
362 //print(JSON.stringify(pl,null,4));
364 //var prop = pl['*prop'] + '';
365 //delete pl['*prop'];
366 var prop = pl.get("* prop");
367 print("got prop "+ prop + "\n");
370 if (! Regex.match_simple("\\[\\]$", prop)) {
371 // it's a standard prop..
373 // munge property..??
375 this.out_nodeprops.set(prop, pl);
377 this.els.add( prop + " : " + this.mungeChild ( this.pad + indent_str, pl));
387 var sprop = prop.replace("[]", "");
388 print("sprop is : " + sprop + "\n");
390 // it's an array type..
392 if (!this.ar_props.has_key(sprop)) {
394 this.ar_props.set(sprop, "");
395 this.out_props_array.set(sprop, new Gee.ArrayList<Node>());
397 old = this.ar_props.get(sprop);
399 var nstr = old += old.length > 0 ? ",\n" : "";
400 nstr += this.mungeChild( this.pad + indent_str + indent_str + indent_str , pl);
401 this.out_props_array.get(sprop).add( pl);
402 this.ar_props.set(sprop, nstr);
409 * Standardize this crap...
411 * standard properties (use to set)
412 * If they are long values show the dialog..
415 * bool is_xxx :: can show a pulldown.. (true/false)
417 * $ string html = string with value interpolated eg. baseURL + ".."
418 * Clutter.ActorAlign x_align (typed) -- shows pulldowns if type is ENUM?
419 * $ untypedvalue = javascript untyped value...
420 * _ string html ... = translatable..
423 * object properties (not part of the GOjbect being wrapped?
424 * # Gee.ArrayList<Xcls_fileitem> fileitems
429 * methods -- always text editor..
437 * * init -- big string?
439 * event handlers (listeners)
444 * +XXXX -- indicates it's a instance property / not glob...
445 * *XXXX -- skip writing glob property (used as classes that can be created...)
449 public void readProps()
454 if (this.node.props.has_key("$ xns")) {
455 this.out_props.set("'|xns'", "'" + this.node.props.get("$ xns") + "'" );
457 this.els.add("'|xns' : '" + this.node.props.get("$ xns") + "'");
463 func_regex = new Regex("^\\s+|\\s+$");
465 print("failed to build regex");
468 // sort the key's so they always get rendered in the same order..
470 var keys = new Gee.ArrayList<string>();
471 var piter = this.node.props.map_iterator();
472 while (piter.next() ) {
476 this.node.normalize_key(piter.get_key(), out k, out kflag, out ktype);
481 keys.sort(( a, b) => {
482 return ((string)a).collate((string)b);
483 //if (a == b) return 0;
484 //return a < b ? -1 : 1;
489 for (var i = 0; i< keys.size; i++) {
490 var key = this.node.get_key(keys.get(i));
491 print("ADD KEY %s\n", key);
496 this.node.normalize_key(key, out k, out kflag, out ktype);
499 var v = this.node.get(key);
502 //if (this.skip.contains(k) ) {
505 if ( Regex.match_simple("\\[\\]$", k)) {
506 // array .. not supported... here?
512 // skip builder stuff. prefixed with '.' .. just like unix fs..
513 if (kflag == ".") { // |. or . -- do not output..
517 // ignore '* prop'; ???
522 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
523 left = "'" + leftv + "'";
524 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
525 var val = this.node.quoteString(leftv);
527 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
533 // next.. is it a function.. or a raw string..
541 // ??? any others that are raw output..
543 // does not hapepnd with arrays..
544 if (v.length < 1) { //if (typeof(el) == 'string' && !obj[i].length) { //skip empty.
551 str = func_regex.replace(v,v.length, 0, "");
553 print("regex failed");
559 var lines = str.split("\n");
561 if (lines.length > 0) {
562 nstr = string.joinv("\n" + this.pad, lines);
563 //nstr = string.joinv("\n", lines);
565 this.out_props.set(left, nstr);
566 //print("==> " + str + "\n");
567 this.els.add(left + " : "+ nstr);
578 ktype.down() == "boolean"
580 ktype.down() == "bool"
582 ktype.down() == "number"
584 ktype.down() == "int"
585 ) { // boolean or number...?
586 this.out_props.set(left, v.down());
587 this.els.add(left + " : " + v.down() );
591 // is it a translated string?
597 //if (this.doubleStringProps.size < 1) {
598 // this.els.add(left + this.node.quoteString(v));
602 if (this.doubleStringProps.index_of(k) > -1) {
603 // then use the translated version...
605 this.els.add(left + " : _this._strings['" +
606 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
609 this.out_props.set(left, "_this._strings['" +
610 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
614 if (ktype.down() == "string" && k[0] == '_') {
615 this.els.add(left + " : _this._strings['" +
616 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
619 this.out_props.set(left, " _this._strings['" +
620 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
627 // otherwise it needs to be encapsulated.. as single quotes..
629 var vv = this.node.quoteString(v);
630 // single quote.. v.substring(1, v.length-1).replace("'", "\\'") + "'";
631 this.els.add(left + " : " + "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
632 this.out_props.set(left, "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
639 public void readArrayProps()
642 // this is not needed in the new version
643 // as array props are handled more directly..
645 // handle the childitems that are arrays.. eg. button[] = { }...
647 // note this does not handle a mix of nodes and properties with the same
651 var iter = this.ar_props.map_iterator();
652 while (iter.next()) {
653 var k = iter.get_key();
654 var right = iter.get_value();
656 string leftv = k[0] == '|' ? k.substring(1) : k;
657 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
658 left = "'" + leftv + "'";
659 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
660 var val = this.node.quoteString(leftv);
662 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
668 if (right.length > 0){
669 //if (this.out_props_array_plain.has_key(left)) {
670 // this.out_props_array_plain.set(left, new Gee.ArrayList<string>());
672 //this.out_props_array_plain.get(left).add(right);
674 this.els.add(left + " : [\n" + this.pad + indent_str + indent_str +
675 right + "\n" + this.pad + "]");
682 public void readListeners()
685 if (this.node.listeners.size < 1) {
688 // munge the listeners.
689 //print("ADDING listeners?");
694 var keys = new Gee.ArrayList<string>();
695 var piter = this.node.listeners.map_iterator();
696 while (piter.next() ) {
698 keys.add(piter.get_key());
700 keys.sort(( a, b) => {
701 return ((string)a).collate((string)b);
702 //if (a == b) return 0;
703 //return a < b ? -1 : 1;
706 var itms = "listeners : {\n";
708 for (var i = 0; i< keys.size; i++) {
709 var key = keys.get(i);
710 var val = this.node.listeners.get(key);
713 itms += i >0 ? ",\n" : "";
715 var str = val.strip();
716 var lines = str.split("\n");
717 if (lines.length > 0) {
718 //str = string.joinv("\n" + this.pad + " ", lines);
719 str = string.joinv("\n" + this.pad + indent_str + indent_str , lines);
722 itms += this.pad + indent_str + key.replace("|", "") + " : " + str;
723 this.out_listeners.set(key.replace("|", "") ,str);
727 itms += "\n" + this.pad + "}";
728 //print ( "ADD " + itms);
733 public void iterChildren()
737 // finally munge the children...
738 if (this.node.items.size < 1) {
741 var itms = "items : [\n";
743 for(var i = 0; i < this.node.items.size;i++) {
744 var ele = this.node.items.get(i);
745 if (ele.props.has_key("* prop")) {
752 itms += this.pad + indent_str +
753 this.mungeChild( this.pad + indent_str + indent_str , ele);
754 this.out_children.add(ele);
757 itms += "\n"+ this.pad + "]" + "\n";
761 // finally output listeners...
763 public void xIncludeToString()