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
22 Gee.HashMap<string,string> out_props;
23 Gee.HashMap<string,string> out_listeners;
24 Gee.HashMap<string,Node> out_nodeprops;
25 Gee.ArrayList<Node> out_children;
26 Gee.HashMap<string,Gee.ArrayList<Node>> out_props_array;
27 Gee.HashMap<string,Gee.ArrayList<string>> out_props_array_plain;
35 public NodeToJs( Node node, Gee.ArrayList<string> doubleStringProps, string pad, NodeToJs? parent)
38 this.doubleStringProps = doubleStringProps;
41 //this.els = new Gee.ArrayList<string>();
42 //this.ar_props = new Gee.HashMap<string,string>();
45 this.out_props = new Gee.HashMap<string,string>();
46 this.out_listeners = new Gee.HashMap<string,string>();
47 this.out_nodeprops = new Gee.HashMap<string,Node>() ;
48 this.out_children = new Gee.ArrayList<Node> ();
49 this.out_props_array = new Gee.HashMap<string,Gee.ArrayList<Node>>() ;
50 this.out_props_array_plain = new Gee.HashMap<string,Gee.ArrayList<string>>() ;
54 this.cur_line = parent == null ? 0 : parent.cur_line ; //-1 as we usuall concat onto the existin gline?
56 this.top = parent == null ? this : parent.top;
59 node.node_lines = new Gee.ArrayList<int>();
60 node.node_lines_map = new Gee.HashMap<int,Node>();
69 public string munge ( )
71 //return this.mungeToString(this.node);
76 //this.readArrayProps();
79 if (!this.node.props.has_key("* xinclude")) {
85 // no properties to output...
86 //if (this.els.size < 1) {
96 This currently works by creating a key/value array of this.els, which is just an array of properties..
97 this is so that join() works...
101 b) output plan properties.
102 c) output listeners..
104 g) output prop_arrays..
112 public Gee.ArrayList<string> orderedPropKeys() {
114 var ret = new Gee.ArrayList<string> ();
115 var niter = this.out_props.map_iterator();
116 while(niter.next()) {
117 ret.add(niter.get_key());
120 ret.sort(( a, b) => {
121 return ((string)a).collate((string)b);
122 //if (a == b) return 0;
123 //return a < b ? -1 : 1;
127 public Gee.ArrayList<string> orderedListenerKeys() {
129 var ret = new Gee.ArrayList<string> ();
130 var niter = this.out_listeners.map_iterator();
131 while(niter.next()) {
132 ret.add(niter.get_key());
135 ret.sort(( a, b) => {
136 return ((string)a).collate((string)b);
137 //if (a == b) return 0;
138 //return a < b ? -1 : 1;
144 public string mungeOut()
146 this.node.line_start = this.cur_line;
147 this.top.node.setNodeLine(this.cur_line, this.node);
148 var spad = this.pad.substring(0, this.pad.length-indent);
150 if (this.node.props.has_key("* xinclude")) {
151 this.addLine("Roo.apply(" + this.node.props.get("* xinclude") + "._tree(), {");
157 // output the items...
158 // work out remaining items...
159 var total_nodes = this.out_props.size +
160 this.out_props_array_plain.size +
161 (this.out_listeners.size > 0 ? 1 : 0) +
162 this.out_nodeprops.size +
163 this.out_props_array.size +
164 (this.out_children.size > 0 ? 1 : 0);
169 var iter = this.orderedPropKeys().list_iterator();
172 suffix = total_nodes > 0 ? "," : "";
174 var v = this.out_props.get(k);
176 this.addMultiLine(this.pad + k + " : " + v + suffix);
181 if (this.out_listeners.size > 0 ) {
183 this.addLine(this.pad + "listeners : {");
184 iter = this.orderedListenerKeys().list_iterator();
186 var sz = this.out_listeners.size;
189 suffix = sz > 0 ? "," : "";
191 var v = this.out_listeners.get(k);
192 this.addMultiLine(this.pad + indent_str + k + " : " + v + suffix);
194 suffix = total_nodes > 0 ? "," : "";
195 this.addLine(this.pad + "}" + suffix);
199 //------- at this point it is the end of the code relating directly to the object..
201 this.node.line_end = this.cur_line;
207 var niter = this.out_nodeprops.map_iterator();
209 while(niter.next()) {
211 suffix = total_nodes > 0 ? "," : "";
212 var l = this.pad + niter.get_key() + " : " +
213 this.mungeChildNew(this.pad + indent_str, niter.get_value()) + suffix;
214 this.addMultiLine(l);
218 var piter = this.out_props_array.map_iterator();
220 while(piter.next()) {
223 this.addLine(this.pad + piter.get_key() + " : [");
224 var pliter = piter.get_value().list_iterator();
225 while (pliter.next()) {
226 suffix = pliter.has_next() ? "," : "";
227 this.addMultiLine(this.pad + indent_str +
228 this.mungeChildNew(this.pad + indent_str + indent_str, pliter.get()) + suffix);
231 suffix = total_nodes > 0 ? "," : "";
233 this.addLine(this.pad + "]" + suffix);
237 if (this.out_children.size > 0) {
238 this.addLine(this.pad + "items : [" );
239 var cniter = this.out_children.list_iterator();
240 while (cniter.next()) {
241 suffix = cniter.has_next() ? "," : "";
242 this.addMultiLine(this.pad + indent_str +
243 this.mungeChildNew(this.pad + indent_str + indent_str, cniter.get()) + suffix
248 this.addLine(this.pad + "]");
251 if (this.node.props.has_key("* xinclude")) {
252 this.ret += spad + "})";
255 this.ret += spad + "}";
258 this.node.sortLines();
267 public void addLine(string str= "")
270 //this.ret += str+ "\n";
271 this.ret += "/*%d(%d-%d)*/ ".printf(this.cur_line -1, this.node.line_start,this.node.line_end) + str + "\n";
276 public void addMultiLine(string str= "")
279 this.cur_line += str.split("\n").length;
280 this.ret += "/*%d(%d-%d)*/ ".printf(l, this.node.line_start,this.node.line_end)+ str + "\n";
281 //this.ret += str + "\n";
284 public string mungeChildNew(string pad , Node cnode )
286 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);
334 var sprop = prop.replace("[]", "");
335 print("sprop is : " + sprop + "\n");
337 // it's an array type..
339 if (!this.out_props_array.has_key(sprop)) {
340 this.out_props_array.set(sprop, new Gee.ArrayList<Node>());
344 this.out_props_array.get(sprop).add( pl);
345 //this.ar_props.set(sprop, nstr);
352 * Standardize this crap...
354 * standard properties (use to set)
355 * If they are long values show the dialog..
358 * bool is_xxx :: can show a pulldown.. (true/false)
360 * $ string html = string with value interpolated eg. baseURL + ".."
361 * Clutter.ActorAlign x_align (typed) -- shows pulldowns if type is ENUM?
362 * $ untypedvalue = javascript untyped value...
363 * _ string html ... = translatable..
366 * object properties (not part of the GOjbect being wrapped?
367 * # Gee.ArrayList<Xcls_fileitem> fileitems
372 * methods -- always text editor..
380 * * init -- big string?
382 * event handlers (listeners)
387 * +XXXX -- indicates it's a instance property / not glob...
388 * *XXXX -- skip writing glob property (used as classes that can be created...)
392 public void readProps()
397 if (this.node.props.has_key("$ xns")) {
398 this.out_props.set("'|xns'", "'" + this.node.props.get("$ xns") + "'" );
400 //this.els.add("'|xns' : '" + this.node.props.get("$ xns") + "'");
406 func_regex = new Regex("^\\s+|\\s+$");
407 } catch (RegexError e) {
408 print("failed to build regex");
411 // sort the key's so they always get rendered in the same order..
413 var keys = new Gee.ArrayList<string>();
414 var piter = this.node.props.map_iterator();
415 while (piter.next() ) {
419 this.node.normalize_key(piter.get_key(), out k, out kflag, out ktype);
424 keys.sort(( a, b) => {
425 return ((string)a).collate((string)b);
426 //if (a == b) return 0;
427 //return a < b ? -1 : 1;
432 for (var i = 0; i< keys.size; i++) {
433 var key = this.node.get_key(keys.get(i));
434 print("ADD KEY %s\n", key);
439 this.node.normalize_key(key, out k, out kflag, out ktype);
442 var v = this.node.get(key);
445 //if (this.skip.contains(k) ) {
448 if ( Regex.match_simple("\\[\\]$", k)) {
449 // array .. not supported... here?
455 // skip builder stuff. prefixed with '.' .. just like unix fs..
456 if (kflag == ".") { // |. or . -- do not output..
460 // ignore '* prop'; ???
465 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
466 left = "'" + leftv + "'";
467 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
468 var val = this.node.quoteString(leftv);
470 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
476 // next.. is it a function.. or a raw string..
484 // ??? any others that are raw output..
486 // does not hapepnd with arrays..
487 if (v.length < 1) { //if (typeof(el) == 'string' && !obj[i].length) { //skip empty.
494 str = func_regex.replace(v,v.length, 0, "");
496 print("regex failed");
502 var lines = str.split("\n");
504 if (lines.length > 0) {
505 nstr = string.joinv("\n" + this.pad, lines);
506 //nstr = string.joinv("\n", lines);
508 this.out_props.set(left, nstr);
509 //print("==> " + str + "\n");
510 //this.els.add(left + " : "+ nstr);
521 ktype.down() == "boolean"
523 ktype.down() == "bool"
525 ktype.down() == "number"
527 ktype.down() == "int"
528 ) { // boolean or number...?
529 this.out_props.set(left, v.down());
530 //this.els.add(left + " : " + v.down() );
534 // is it a translated string?
540 //if (this.doubleStringProps.size < 1) {
541 // this.els.add(left + this.node.quoteString(v));
545 if ((this.doubleStringProps.index_of(k) > -1) ||
546 (ktype.down() == "string" && k[0] == '_')
549 // then use the translated version...
552 (v.split("\n").length > 1 ?
553 ("\n" + this.pad + string.joinv(this.pad + "\n", v.split("\n")).replace("*/", "* - /") + "\n" + this.pad + "*/ ") :
554 (v.replace("*/", "* - /") + " */")
557 //this.els.add(left + " : _this._strings['" +
558 // GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
561 this.out_props.set(left, "_this._strings['" +
562 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
567 // otherwise it needs to be encapsulated.. as single quotes..
569 var vv = this.node.quoteString(v);
570 // single quote.. v.substring(1, v.length-1).replace("'", "\\'") + "'";
571 //this.els.add(left + " : " + "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
572 this.out_props.set(left, "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
580 public void readListeners()
583 if (this.node.listeners.size < 1) {
586 // munge the listeners.
587 //print("ADDING listeners?");
592 var keys = new Gee.ArrayList<string>();
593 var piter = this.node.listeners.map_iterator();
594 while (piter.next() ) {
596 keys.add(piter.get_key());
598 keys.sort(( a, b) => {
599 return ((string)a).collate((string)b);
600 //if (a == b) return 0;
601 //return a < b ? -1 : 1;
605 for (var i = 0; i< keys.size; i++) {
606 var key = keys.get(i);
607 var val = this.node.listeners.get(key);
611 var str = val.strip();
612 var lines = str.split("\n");
613 if (lines.length > 0) {
614 //str = string.joinv("\n" + this.pad + " ", lines);
615 str = string.joinv("\n" + this.pad + indent_str + indent_str , lines);
618 this.out_listeners.set(key.replace("|", "") ,str);
627 public void iterChildren()
631 // finally munge the children...
632 if (this.node.items.size < 1) {
635 var itms = "items : [\n";
637 for(var i = 0; i < this.node.items.size;i++) {
638 var ele = this.node.items.get(i);
639 if (ele.props.has_key("* prop")) {
643 this.out_children.add(ele);
646 itms += "\n"+ this.pad + "]" + "\n";
647 //this.els.add(itms);
650 // finally output listeners...
652 public void xIncludeToString()