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 = " ";
20 Gee.ArrayList<string> doubleStringProps; // need to think if this is a good idea like this
22 public JsRender renderer;
24 Gee.HashMap<string,string> out_props;
25 Gee.HashMap<string,string> out_listeners;
26 Gee.HashMap<string,Node> out_nodeprops;
27 Gee.ArrayList<Node> out_children;
28 Gee.HashMap<string,Gee.ArrayList<Node>> out_props_array;
29 Gee.HashMap<string,Gee.ArrayList<string>> out_props_array_plain;
37 public NodeToJs( Node node, Gee.ArrayList<string> doubleStringProps, string pad, NodeToJs? parent)
40 this.doubleStringProps = doubleStringProps;
43 //this.els = new Gee.ArrayList<string>();
44 //this.ar_props = new Gee.HashMap<string,string>();
48 // this is the bit that causes issues - we have to output as we go, otherwise we
49 // can not work out which line is which...
51 this.out_props = new Gee.HashMap<string,string>();
52 this.out_listeners = new Gee.HashMap<string,string>();
53 this.out_nodeprops = new Gee.HashMap<string,Node>() ;
54 this.out_children = new Gee.ArrayList<Node> ();
55 this.out_props_array = new Gee.HashMap<string,Gee.ArrayList<Node>>() ;
56 this.out_props_array_plain = new Gee.HashMap<string,Gee.ArrayList<string>>() ;
60 this.cur_line = parent == null ? 0 : parent.cur_line ; //-1 as we usuall concat onto the existin gline?
62 this.renderer = parent.renderer;
65 this.top = parent == null ? this : parent.top;
68 node.node_lines = new Gee.ArrayList<int>();
69 node.node_lines_map = new Gee.HashMap<int,Node>();
78 public string munge ( )
80 //return this.mungeToString(this.node);
85 //this.readArrayProps();
88 if (!this.node.props.has_key("* xinclude")) {
94 // no properties to output...
95 //if (this.els.size < 1) {
105 This currently works by creating a key/value array of this.els, which is just an array of properties..
106 this is so that join() works...
110 b) output plan properties.
111 c) output listeners..
113 g) output prop_arrays..
121 public Gee.ArrayList<string> orderedPropKeys() {
123 var ret = new Gee.ArrayList<string> ();
124 var niter = this.out_props.map_iterator();
125 while(niter.next()) {
126 ret.add(niter.get_key());
129 ret.sort(( a, b) => {
130 return ((string)a).collate((string)b);
131 //if (a == b) return 0;
132 //return a < b ? -1 : 1;
136 public Gee.ArrayList<string> orderedListenerKeys() {
138 var ret = new Gee.ArrayList<string> ();
139 var niter = this.out_listeners.map_iterator();
140 while(niter.next()) {
141 ret.add(niter.get_key());
144 ret.sort(( a, b) => {
145 return ((string)a).collate((string)b);
146 //if (a == b) return 0;
147 //return a < b ? -1 : 1;
153 public string mungeOut()
155 this.node.line_start = this.cur_line;
156 this.top.node.setNodeLine(this.cur_line, this.node);
157 var spad = this.pad.substring(0, this.pad.length-indent);
159 if (this.node.props.has_key("* xinclude")) {
160 this.addLine("Roo.apply(" + this.node.props.get("* xinclude") + "._tree(), {");
166 // output the items...
167 // work out remaining items...
168 var total_nodes = this.out_props.size +
169 this.out_props_array_plain.size +
170 (this.out_listeners.size > 0 ? 1 : 0) +
171 this.out_nodeprops.size +
172 this.out_props_array.size +
173 (this.out_children.size > 0 ? 1 : 0);
178 var iter = this.orderedPropKeys().list_iterator();
181 suffix = total_nodes > 0 ? "," : "";
183 var v = this.out_props.get(k);
185 this.addMultiLine(this.pad + k + " : " + v + suffix);
190 if (this.out_listeners.size > 0 ) {
192 this.addLine(this.pad + "listeners : {");
193 iter = this.orderedListenerKeys().list_iterator();
195 var sz = this.out_listeners.size;
198 suffix = sz > 0 ? "," : "";
200 var v = this.out_listeners.get(k);
201 this.addMultiLine(this.pad + indent_str + k + " : " + v + suffix);
203 suffix = total_nodes > 0 ? "," : "";
204 this.addLine(this.pad + "}" + suffix);
208 //------- at this point it is the end of the code relating directly to the object..
210 this.node.line_end = this.cur_line;
216 var niter = this.out_nodeprops.map_iterator();
218 while(niter.next()) {
220 suffix = total_nodes > 0 ? "," : "";
221 var l = this.pad + niter.get_key() + " : " +
222 this.mungeChildNew(this.pad + indent_str, niter.get_value()) + suffix;
223 this.addMultiLine(l);
227 var piter = this.out_props_array.map_iterator();
229 while(piter.next()) {
232 this.addLine(this.pad + piter.get_key() + " : [");
233 var pliter = piter.get_value().list_iterator();
234 while (pliter.next()) {
235 suffix = pliter.has_next() ? "," : "";
236 this.addMultiLine(this.pad + indent_str +
237 this.mungeChildNew(this.pad + indent_str + indent_str, pliter.get()) + suffix);
240 suffix = total_nodes > 0 ? "," : "";
242 this.addLine(this.pad + "]" + suffix);
246 if (this.out_children.size > 0) {
247 this.addLine(this.pad + "items : [" );
248 var cniter = this.out_children.list_iterator();
249 while (cniter.next()) {
250 suffix = cniter.has_next() ? "," : "";
251 this.addMultiLine(this.pad + indent_str +
252 this.mungeChildNew(this.pad + indent_str + indent_str, cniter.get()) + suffix
257 this.addLine(this.pad + "]");
260 if (this.node.props.has_key("* xinclude")) {
261 this.ret += spad + "})";
264 this.ret += spad + "}";
267 this.node.sortLines();
276 public void addLine(string str= "")
279 this.ret += str+ "\n";
280 //this.ret += "/*%d(%d-%d)*/ ".printf(this.cur_line -1, this.node.line_start,this.node.line_end) + str + "\n";
285 public void addMultiLine(string str= "")
288 //this.ret += "/*%d(%d-%d)*/ ".printf(this.cur_line, this.node.line_start,this.node.line_end)+ str + "\n";
289 this.ret += str + "\n";
290 this.cur_line += str.split("\n").length;
293 public string mungeChildNew(string pad , Node cnode )
295 var x = new NodeToJs(cnode, this.doubleStringProps, pad, this);
303 public void checkChildren ()
307 // look throught he chilren == looking for * prop.. -- fixme might not work..
310 if (!this.node.hasChildren()) {
315 for (var ii =0; ii< this.node.items.size; ii++) {
316 var pl = this.node.items.get(ii);
317 if (!pl.props.has_key("* prop")) {
322 //print(JSON.stringify(pl,null,4));
324 //var prop = pl['*prop'] + '';
325 //delete pl['*prop'];
326 var prop = pl.get("* prop");
327 //print("got prop "+ prop + "\n");
330 if (! Regex.match_simple("\\[\\]$", prop)) {
331 // it's a standard prop..
333 // munge property..??
335 this.out_nodeprops.set(prop, pl);
343 var sprop = prop.replace("[]", "");
344 //print("sprop is : " + sprop + "\n");
346 // it's an array type..
348 if (!this.out_props_array.has_key(sprop)) {
349 this.out_props_array.set(sprop, new Gee.ArrayList<Node>());
353 this.out_props_array.get(sprop).add( pl);
354 //this.ar_props.set(sprop, nstr);
361 * Standardize this crap...
363 * standard properties (use to set)
364 * If they are long values show the dialog..
367 * bool is_xxx :: can show a pulldown.. (true/false)
369 * $ string html = string with value interpolated eg. baseURL + ".."
370 * Clutter.ActorAlign x_align (typed) -- shows pulldowns if type is ENUM?
371 * $ untypedvalue = javascript untyped value...
372 * _ string html ... = translatable..
375 * object properties (not part of the GOjbect being wrapped?
376 * # Gee.ArrayList<Xcls_fileitem> fileitems
381 * methods -- always text editor..
389 * * init -- big string?
391 * event handlers (listeners)
396 * +XXXX -- indicates it's a instance property / not glob...
397 * *XXXX -- skip writing glob property (used as classes that can be created...)
401 public void readProps()
406 if (this.node.props.has_key("$ xns")) {
407 this.out_props.set("'|xns'", "'" + this.node.props.get("$ xns") + "'" );
409 //this.els.add("'|xns' : '" + this.node.props.get("$ xns") + "'");
415 func_regex = new Regex("^\\s+|\\s+$");
416 } catch (RegexError e) {
417 print("failed to build regex");
420 // sort the key's so they always get rendered in the same order..
422 var keys = new Gee.ArrayList<string>();
423 var piter = this.node.props.map_iterator();
424 while (piter.next() ) {
428 this.node.normalize_key(piter.get_key(), out k, out kflag, out ktype);
433 keys.sort(( a, b) => {
434 return ((string)a).collate((string)b);
435 //if (a == b) return 0;
436 //return a < b ? -1 : 1;
439 var has_cms = this.node.has("cms-id");
441 for (var i = 0; i< keys.size; i++) {
442 var key = this.node.get_key(keys.get(i));
443 //("ADD KEY %s\n", key);
448 this.node.normalize_key(key, out k, out kflag, out ktype);
451 var v = this.node.get(key);
454 //if (this.skip.contains(k) ) {
457 if ( Regex.match_simple("\\[\\]$", k)) {
458 // array .. not supported... here?
464 // skip builder stuff. prefixed with '.' .. just like unix fs..
465 if (kflag == ".") { // |. or . -- do not output..
469 // ignore '* prop'; ???
473 // handle cms-id // html
474 if (has_cms && k == "cms-id") {
475 continue; // ignore it...
477 // html must not be a dynamic property...
478 // note - we do not translate this either...
479 if (has_cms && k == "html" && kflag != "$") {
482 this.out_props.set("html", "Pman.Cms.content(" +
483 this.node.quoteString(this.renderer.name + "::" + this.node.get("cms-id")) +
485 this.node.quoteString(v) +
494 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
495 left = "'" + leftv + "'";
496 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
497 var val = this.node.quoteString(leftv);
499 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
505 // next.. is it a function.. or a raw string..
513 // ??? any others that are raw output..
515 // does not hapepnd with arrays..
516 if (v.length < 1) { //if (typeof(el) == 'string' && !obj[i].length) { //skip empty.
523 str = func_regex.replace(v,v.length, 0, "");
525 print("regex failed");
531 var lines = str.split("\n");
533 if (lines.length > 0) {
534 nstr = string.joinv("\n" + this.pad, lines);
535 //nstr = string.joinv("\n", lines);
537 this.out_props.set(left, nstr);
538 //print("==> " + str + "\n");
539 //this.els.add(left + " : "+ nstr);
550 ktype.down() == "boolean"
552 ktype.down() == "bool"
554 ktype.down() == "number"
556 ktype.down() == "int"
557 ) { // boolean or number...?
558 this.out_props.set(left, v.down());
559 //this.els.add(left + " : " + v.down() );
563 // is it a translated string?
569 //if (this.doubleStringProps.size < 1) {
570 // this.els.add(left + this.node.quoteString(v));
574 if ((this.doubleStringProps.index_of(k) > -1) ||
575 (ktype.down() == "string" && k[0] == '_')
578 // then use the translated version...
581 (v.split("\n").length > 1 ?
582 ("\n" + this.pad + string.joinv(this.pad + "\n", v.split("\n")).replace("*/", "* - /") + "\n" + this.pad + "*/ ") :
583 (v.replace("*/", "* - /") + " */")
586 //this.els.add(left + " : _this._strings['" +
587 // GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
590 this.out_props.set(left, "_this._strings['" +
591 GLib.Checksum.compute_for_string (ChecksumType.MD5, v.strip()) +
596 // otherwise it needs to be encapsulated.. as single quotes..
598 var vv = this.node.quoteString(v);
599 // single quote.. v.substring(1, v.length-1).replace("'", "\\'") + "'";
600 //this.els.add(left + " : " + "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
601 this.out_props.set(left, "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
609 public void readListeners()
612 if (this.node.listeners.size < 1) {
615 // munge the listeners.
616 //print("ADDING listeners?");
621 var keys = new Gee.ArrayList<string>();
622 var piter = this.node.listeners.map_iterator();
623 while (piter.next() ) {
625 keys.add(piter.get_key());
627 keys.sort(( a, b) => {
628 return ((string)a).collate((string)b);
629 //if (a == b) return 0;
630 //return a < b ? -1 : 1;
634 for (var i = 0; i< keys.size; i++) {
635 var key = keys.get(i);
636 var val = this.node.listeners.get(key);
640 var str = val.strip();
641 var lines = str.split("\n");
642 if (lines.length > 0) {
643 //str = string.joinv("\n" + this.pad + " ", lines);
644 str = string.joinv("\n" + this.pad + indent_str + indent_str , lines);
647 this.out_listeners.set(key.replace("|", "") ,str);
656 public void iterChildren()
660 // finally munge the children...
661 if (this.node.items.size < 1) {
664 var itms = "items : [\n";
666 for(var i = 0; i < this.node.items.size;i++) {
667 var ele = this.node.items.get(i);
668 if (ele.props.has_key("* prop")) {
672 this.out_children.add(ele);
675 itms += "\n"+ this.pad + "]" + "\n";
676 //this.els.add(itms);
679 // finally output listeners...
681 public void xIncludeToString()