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);
73 this.node.line_start = this.cur_line;
77 //this.readArrayProps();
80 if (!this.node.props.has_key("* xinclude")) {
86 // no properties to output...
87 //if (this.els.size < 1) {
97 This currently works by creating a key/value array of this.els, which is just an array of properties..
98 this is so that join() works...
102 b) output plan properties.
103 c) output listeners..
105 g) output prop_arrays..
113 public Gee.ArrayList<string> orderedPropKeys() {
115 var ret = new Gee.ArrayList<string> ();
116 var niter = this.out_props.map_iterator();
117 while(niter.next()) {
118 ret.add(niter.get_key());
121 ret.sort(( a, b) => {
122 return ((string)a).collate((string)b);
123 //if (a == b) return 0;
124 //return a < b ? -1 : 1;
128 public Gee.ArrayList<string> orderedListenerKeys() {
130 var ret = new Gee.ArrayList<string> ();
131 var niter = this.out_listeners.map_iterator();
132 while(niter.next()) {
133 ret.add(niter.get_key());
136 ret.sort(( a, b) => {
137 return ((string)a).collate((string)b);
138 //if (a == b) return 0;
139 //return a < b ? -1 : 1;
145 public string mungeOut()
147 this.node.line_start = this.cur_line;
148 this.top.node.setNodeLine(this.cur_line, this.node);
149 var spad = this.pad.substring(0, this.pad.length-indent);
151 if (this.node.props.has_key("* xinclude")) {
152 this.addLine("Roo.apply(" + this.node.props.get("* xinclude") + "._tree(), {");
158 // output the items...
159 // work out remaining items...
160 var total_nodes = this.out_props.size +
161 this.out_props_array_plain.size +
162 (this.out_listeners.size > 0 ? 1 : 0) +
163 this.out_nodeprops.size +
164 this.out_props_array.size +
165 (this.out_children.size > 0 ? 1 : 0);
170 var iter = this.orderedPropKeys().list_iterator();
173 suffix = total_nodes > 0 ? "," : "";
175 var v = this.out_props.get(k);
177 this.addMultiLine(this.pad + k + " : " + v + suffix);
182 if (this.out_listeners.size > 0 ) {
184 this.addLine(this.pad + "listeners : {");
185 iter = this.orderedListenerKeys().list_iterator();
187 var sz = this.out_listeners.size;
190 suffix = sz > 0 ? "," : "";
192 var v = this.out_listeners.get(k);
193 this.addMultiLine(this.pad + indent_str + k + " : " + v + suffix);
195 suffix = total_nodes > 0 ? "," : "";
196 this.addLine(this.pad + "}" + suffix);
200 //------- at this point it is the end of the code relating directly to the object..
202 this.node.line_end = this.cur_line;
208 var niter = this.out_nodeprops.map_iterator();
210 while(niter.next()) {
212 suffix = total_nodes > 0 ? "," : "";
213 var l = this.pad + niter.get_key() + " : " +
214 this.mungeChildNew(this.pad + indent_str, niter.get_value()) + suffix;
215 this.addMultiLine(l);
219 var piter = this.out_props_array.map_iterator();
221 while(piter.next()) {
224 this.addLine(this.pad + piter.get_key() + " : [");
225 var pliter = piter.get_value().list_iterator();
226 while (pliter.next()) {
227 suffix = pliter.has_next() ? "," : "";
228 this.addMultiLine(this.pad + indent_str +
229 this.mungeChildNew(this.pad + indent_str + indent_str, pliter.get()) + suffix);
232 suffix = total_nodes > 0 ? "," : "";
234 this.addLine(this.pad + "]" + suffix);
238 if (this.out_children.size > 0) {
239 this.addLine(this.pad + "items : [" );
240 var cniter = this.out_children.list_iterator();
241 while (cniter.next()) {
242 suffix = cniter.has_next() ? "," : "";
243 this.addMultiLine(this.pad + indent_str +
244 this.mungeChildNew(this.pad + indent_str + indent_str, cniter.get()) + suffix
249 this.addLine(this.pad + "]");
252 if (this.node.props.has_key("* xinclude")) {
253 this.ret += spad + "})";
256 this.ret += spad + "}";
259 this.node.sortLines();
268 public void addLine(string str= "")
271 //this.ret += str+ "\n";
272 this.ret += "/*%d(%d-%d)*/ ".printf(this.cur_line -1, this.node.line_start,this.node.line_end) + str + "\n";
277 public void addMultiLine(string str= "")
280 this.cur_line += str.split("\n").length;
281 //this.ret += "/*%d(%d-%d)*/ ".printf(l, this.node.line_start,this.node.line_end)+ str + "\n";
282 //this.ret += str + "\n";
285 public string mungeChildNew(string pad , Node cnode )
287 var x = new NodeToJs(cnode, this.doubleStringProps, pad, this);
295 public void checkChildren ()
299 // look throught he chilren == looking for * prop.. -- fixme might not work..
302 if (!this.node.hasChildren()) {
307 for (var ii =0; ii< this.node.items.size; ii++) {
308 var pl = this.node.items.get(ii);
309 if (!pl.props.has_key("* prop")) {
314 //print(JSON.stringify(pl,null,4));
316 //var prop = pl['*prop'] + '';
317 //delete pl['*prop'];
318 var prop = pl.get("* prop");
319 print("got prop "+ prop + "\n");
322 if (! Regex.match_simple("\\[\\]$", prop)) {
323 // it's a standard prop..
325 // munge property..??
327 this.out_nodeprops.set(prop, pl);
335 var sprop = prop.replace("[]", "");
336 print("sprop is : " + sprop + "\n");
338 // it's an array type..
340 if (!this.out_props_array.has_key(sprop)) {
341 this.out_props_array.set(sprop, new Gee.ArrayList<Node>());
345 this.out_props_array.get(sprop).add( pl);
346 //this.ar_props.set(sprop, nstr);
353 * Standardize this crap...
355 * standard properties (use to set)
356 * If they are long values show the dialog..
359 * bool is_xxx :: can show a pulldown.. (true/false)
361 * $ string html = string with value interpolated eg. baseURL + ".."
362 * Clutter.ActorAlign x_align (typed) -- shows pulldowns if type is ENUM?
363 * $ untypedvalue = javascript untyped value...
364 * _ string html ... = translatable..
367 * object properties (not part of the GOjbect being wrapped?
368 * # Gee.ArrayList<Xcls_fileitem> fileitems
373 * methods -- always text editor..
381 * * init -- big string?
383 * event handlers (listeners)
388 * +XXXX -- indicates it's a instance property / not glob...
389 * *XXXX -- skip writing glob property (used as classes that can be created...)
393 public void readProps()
398 if (this.node.props.has_key("$ xns")) {
399 this.out_props.set("'|xns'", "'" + this.node.props.get("$ xns") + "'" );
401 //this.els.add("'|xns' : '" + this.node.props.get("$ xns") + "'");
407 func_regex = new Regex("^\\s+|\\s+$");
408 } catch (RegexError e) {
409 print("failed to build regex");
412 // sort the key's so they always get rendered in the same order..
414 var keys = new Gee.ArrayList<string>();
415 var piter = this.node.props.map_iterator();
416 while (piter.next() ) {
420 this.node.normalize_key(piter.get_key(), out k, out kflag, out ktype);
425 keys.sort(( a, b) => {
426 return ((string)a).collate((string)b);
427 //if (a == b) return 0;
428 //return a < b ? -1 : 1;
433 for (var i = 0; i< keys.size; i++) {
434 var key = this.node.get_key(keys.get(i));
435 print("ADD KEY %s\n", key);
440 this.node.normalize_key(key, out k, out kflag, out ktype);
443 var v = this.node.get(key);
446 //if (this.skip.contains(k) ) {
449 if ( Regex.match_simple("\\[\\]$", k)) {
450 // array .. not supported... here?
456 // skip builder stuff. prefixed with '.' .. just like unix fs..
457 if (kflag == ".") { // |. or . -- do not output..
461 // ignore '* prop'; ???
466 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
467 left = "'" + leftv + "'";
468 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
469 var val = this.node.quoteString(leftv);
471 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
477 // next.. is it a function.. or a raw string..
485 // ??? any others that are raw output..
487 // does not hapepnd with arrays..
488 if (v.length < 1) { //if (typeof(el) == 'string' && !obj[i].length) { //skip empty.
495 str = func_regex.replace(v,v.length, 0, "");
497 print("regex failed");
503 var lines = str.split("\n");
505 if (lines.length > 0) {
506 nstr = string.joinv("\n" + this.pad, lines);
507 //nstr = string.joinv("\n", lines);
509 this.out_props.set(left, nstr);
510 //print("==> " + str + "\n");
511 //this.els.add(left + " : "+ nstr);
522 ktype.down() == "boolean"
524 ktype.down() == "bool"
526 ktype.down() == "number"
528 ktype.down() == "int"
529 ) { // boolean or number...?
530 this.out_props.set(left, v.down());
531 //this.els.add(left + " : " + v.down() );
535 // is it a translated string?
541 //if (this.doubleStringProps.size < 1) {
542 // this.els.add(left + this.node.quoteString(v));
546 if ((this.doubleStringProps.index_of(k) > -1) ||
547 (ktype.down() == "string" && k[0] == '_')
550 // then use the translated version...
553 (v.split("\n").length > 1 ?
554 ("\n" + this.pad + string.joinv(this.pad + "\n", v.split("\n")).replace("*/", "* - /") + "\n" + this.pad + "*/ ") :
555 (v.replace("*/", "* - /") + " */")
558 //this.els.add(left + " : _this._strings['" +
559 // GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
562 this.out_props.set(left, "_this._strings['" +
563 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
568 // otherwise it needs to be encapsulated.. as single quotes..
570 var vv = this.node.quoteString(v);
571 // single quote.. v.substring(1, v.length-1).replace("'", "\\'") + "'";
572 //this.els.add(left + " : " + "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
573 this.out_props.set(left, "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
581 public void readListeners()
584 if (this.node.listeners.size < 1) {
587 // munge the listeners.
588 //print("ADDING listeners?");
593 var keys = new Gee.ArrayList<string>();
594 var piter = this.node.listeners.map_iterator();
595 while (piter.next() ) {
597 keys.add(piter.get_key());
599 keys.sort(( a, b) => {
600 return ((string)a).collate((string)b);
601 //if (a == b) return 0;
602 //return a < b ? -1 : 1;
606 for (var i = 0; i< keys.size; i++) {
607 var key = keys.get(i);
608 var val = this.node.listeners.get(key);
612 var str = val.strip();
613 var lines = str.split("\n");
614 if (lines.length > 0) {
615 //str = string.joinv("\n" + this.pad + " ", lines);
616 str = string.joinv("\n" + this.pad + indent_str + indent_str , lines);
619 this.out_listeners.set(key.replace("|", "") ,str);
628 public void iterChildren()
632 // finally munge the children...
633 if (this.node.items.size < 1) {
636 var itms = "items : [\n";
638 for(var i = 0; i < this.node.items.size;i++) {
639 var ele = this.node.items.get(i);
640 if (ele.props.has_key("* prop")) {
644 this.out_children.add(ele);
647 itms += "\n"+ this.pad + "]" + "\n";
648 //this.els.add(itms);
651 // finally output listeners...
653 public void xIncludeToString()