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
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>();
47 this.out_props = new Gee.HashMap<string,string>();
48 this.out_listeners = new Gee.HashMap<string,string>();
49 this.out_nodeprops = new Gee.HashMap<string,Node>() ;
50 this.out_children = new Gee.ArrayList<Node> ();
51 this.out_props_array = new Gee.HashMap<string,Gee.ArrayList<Node>>() ;
52 this.out_props_array_plain = new Gee.HashMap<string,Gee.ArrayList<string>>() ;
56 this.cur_line = parent == null ? 0 : parent.cur_line ; //-1 as we usuall concat onto the existin gline?
58 this.jsrender = parent.jsrender;
61 this.top = parent == null ? this : parent.top;
64 node.node_lines = new Gee.ArrayList<int>();
65 node.node_lines_map = new Gee.HashMap<int,Node>();
74 public string munge ( )
76 //return this.mungeToString(this.node);
81 //this.readArrayProps();
84 if (!this.node.props.has_key("* xinclude")) {
90 // no properties to output...
91 //if (this.els.size < 1) {
101 This currently works by creating a key/value array of this.els, which is just an array of properties..
102 this is so that join() works...
106 b) output plan properties.
107 c) output listeners..
109 g) output prop_arrays..
117 public Gee.ArrayList<string> orderedPropKeys() {
119 var ret = new Gee.ArrayList<string> ();
120 var niter = this.out_props.map_iterator();
121 while(niter.next()) {
122 ret.add(niter.get_key());
125 ret.sort(( a, b) => {
126 return ((string)a).collate((string)b);
127 //if (a == b) return 0;
128 //return a < b ? -1 : 1;
132 public Gee.ArrayList<string> orderedListenerKeys() {
134 var ret = new Gee.ArrayList<string> ();
135 var niter = this.out_listeners.map_iterator();
136 while(niter.next()) {
137 ret.add(niter.get_key());
140 ret.sort(( a, b) => {
141 return ((string)a).collate((string)b);
142 //if (a == b) return 0;
143 //return a < b ? -1 : 1;
149 public string mungeOut()
151 this.node.line_start = this.cur_line;
152 this.top.node.setNodeLine(this.cur_line, this.node);
153 var spad = this.pad.substring(0, this.pad.length-indent);
155 if (this.node.props.has_key("* xinclude")) {
156 this.addLine("Roo.apply(" + this.node.props.get("* xinclude") + "._tree(), {");
162 // output the items...
163 // work out remaining items...
164 var total_nodes = this.out_props.size +
165 this.out_props_array_plain.size +
166 (this.out_listeners.size > 0 ? 1 : 0) +
167 this.out_nodeprops.size +
168 this.out_props_array.size +
169 (this.out_children.size > 0 ? 1 : 0);
174 var iter = this.orderedPropKeys().list_iterator();
177 suffix = total_nodes > 0 ? "," : "";
179 var v = this.out_props.get(k);
181 this.addMultiLine(this.pad + k + " : " + v + suffix);
186 if (this.out_listeners.size > 0 ) {
188 this.addLine(this.pad + "listeners : {");
189 iter = this.orderedListenerKeys().list_iterator();
191 var sz = this.out_listeners.size;
194 suffix = sz > 0 ? "," : "";
196 var v = this.out_listeners.get(k);
197 this.addMultiLine(this.pad + indent_str + k + " : " + v + suffix);
199 suffix = total_nodes > 0 ? "," : "";
200 this.addLine(this.pad + "}" + suffix);
204 //------- at this point it is the end of the code relating directly to the object..
206 this.node.line_end = this.cur_line;
212 var niter = this.out_nodeprops.map_iterator();
214 while(niter.next()) {
216 suffix = total_nodes > 0 ? "," : "";
217 var l = this.pad + niter.get_key() + " : " +
218 this.mungeChildNew(this.pad + indent_str, niter.get_value()) + suffix;
219 this.addMultiLine(l);
223 var piter = this.out_props_array.map_iterator();
225 while(piter.next()) {
228 this.addLine(this.pad + piter.get_key() + " : [");
229 var pliter = piter.get_value().list_iterator();
230 while (pliter.next()) {
231 suffix = pliter.has_next() ? "," : "";
232 this.addMultiLine(this.pad + indent_str +
233 this.mungeChildNew(this.pad + indent_str + indent_str, pliter.get()) + suffix);
236 suffix = total_nodes > 0 ? "," : "";
238 this.addLine(this.pad + "]" + suffix);
242 if (this.out_children.size > 0) {
243 this.addLine(this.pad + "items : [" );
244 var cniter = this.out_children.list_iterator();
245 while (cniter.next()) {
246 suffix = cniter.has_next() ? "," : "";
247 this.addMultiLine(this.pad + indent_str +
248 this.mungeChildNew(this.pad + indent_str + indent_str, cniter.get()) + suffix
253 this.addLine(this.pad + "]");
256 if (this.node.props.has_key("* xinclude")) {
257 this.ret += spad + "})";
260 this.ret += spad + "}";
263 this.node.sortLines();
272 public void addLine(string str= "")
275 this.ret += str+ "\n";
276 //this.ret += "/*%d(%d-%d)*/ ".printf(this.cur_line -1, this.node.line_start,this.node.line_end) + str + "\n";
281 public void addMultiLine(string str= "")
284 //this.ret += "/*%d(%d-%d)*/ ".printf(this.cur_line, this.node.line_start,this.node.line_end)+ str + "\n";
285 this.ret += str + "\n";
286 this.cur_line += str.split("\n").length;
289 public string mungeChildNew(string pad , Node cnode )
291 var x = new NodeToJs(cnode, this.doubleStringProps, pad, this);
299 public void checkChildren ()
303 // look throught he chilren == looking for * prop.. -- fixme might not work..
306 if (!this.node.hasChildren()) {
311 for (var ii =0; ii< this.node.items.size; ii++) {
312 var pl = this.node.items.get(ii);
313 if (!pl.props.has_key("* prop")) {
318 //print(JSON.stringify(pl,null,4));
320 //var prop = pl['*prop'] + '';
321 //delete pl['*prop'];
322 var prop = pl.get("* prop");
323 print("got prop "+ prop + "\n");
326 if (! Regex.match_simple("\\[\\]$", prop)) {
327 // it's a standard prop..
329 // munge property..??
331 this.out_nodeprops.set(prop, pl);
339 var sprop = prop.replace("[]", "");
340 print("sprop is : " + sprop + "\n");
342 // it's an array type..
344 if (!this.out_props_array.has_key(sprop)) {
345 this.out_props_array.set(sprop, new Gee.ArrayList<Node>());
349 this.out_props_array.get(sprop).add( pl);
350 //this.ar_props.set(sprop, nstr);
357 * Standardize this crap...
359 * standard properties (use to set)
360 * If they are long values show the dialog..
363 * bool is_xxx :: can show a pulldown.. (true/false)
365 * $ string html = string with value interpolated eg. baseURL + ".."
366 * Clutter.ActorAlign x_align (typed) -- shows pulldowns if type is ENUM?
367 * $ untypedvalue = javascript untyped value...
368 * _ string html ... = translatable..
371 * object properties (not part of the GOjbect being wrapped?
372 * # Gee.ArrayList<Xcls_fileitem> fileitems
377 * methods -- always text editor..
385 * * init -- big string?
387 * event handlers (listeners)
392 * +XXXX -- indicates it's a instance property / not glob...
393 * *XXXX -- skip writing glob property (used as classes that can be created...)
397 public void readProps()
402 if (this.node.props.has_key("$ xns")) {
403 this.out_props.set("'|xns'", "'" + this.node.props.get("$ xns") + "'" );
405 //this.els.add("'|xns' : '" + this.node.props.get("$ xns") + "'");
411 func_regex = new Regex("^\\s+|\\s+$");
412 } catch (RegexError e) {
413 print("failed to build regex");
416 // sort the key's so they always get rendered in the same order..
418 var keys = new Gee.ArrayList<string>();
419 var piter = this.node.props.map_iterator();
420 while (piter.next() ) {
424 this.node.normalize_key(piter.get_key(), out k, out kflag, out ktype);
429 keys.sort(( a, b) => {
430 return ((string)a).collate((string)b);
431 //if (a == b) return 0;
432 //return a < b ? -1 : 1;
435 var has_cms = this.node.has("cms-id");
437 for (var i = 0; i< keys.size; i++) {
438 var key = this.node.get_key(keys.get(i));
439 print("ADD KEY %s\n", key);
444 this.node.normalize_key(key, out k, out kflag, out ktype);
447 var v = this.node.get(key);
450 //if (this.skip.contains(k) ) {
453 if ( Regex.match_simple("\\[\\]$", k)) {
454 // array .. not supported... here?
460 // skip builder stuff. prefixed with '.' .. just like unix fs..
461 if (kflag == ".") { // |. or . -- do not output..
465 // ignore '* prop'; ???
469 // handle cms-id // html
470 if (has_cms && k == "cms-id") {
471 continue; // ignore it...
473 // html must not be a dynamic property...
474 // note - we do not translate this either...
475 if (has_cms && k == "html" && kflag != "$") {
478 this.out_props.set("html", "Pman.Cms.content(" +
479 this.node.quoteString(this.node.get("cms-id")) +
481 this.node.quoteString(v) +
490 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
491 left = "'" + leftv + "'";
492 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
493 var val = this.node.quoteString(leftv);
495 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
501 // next.. is it a function.. or a raw string..
509 // ??? any others that are raw output..
511 // does not hapepnd with arrays..
512 if (v.length < 1) { //if (typeof(el) == 'string' && !obj[i].length) { //skip empty.
519 str = func_regex.replace(v,v.length, 0, "");
521 print("regex failed");
527 var lines = str.split("\n");
529 if (lines.length > 0) {
530 nstr = string.joinv("\n" + this.pad, lines);
531 //nstr = string.joinv("\n", lines);
533 this.out_props.set(left, nstr);
534 //print("==> " + str + "\n");
535 //this.els.add(left + " : "+ nstr);
546 ktype.down() == "boolean"
548 ktype.down() == "bool"
550 ktype.down() == "number"
552 ktype.down() == "int"
553 ) { // boolean or number...?
554 this.out_props.set(left, v.down());
555 //this.els.add(left + " : " + v.down() );
559 // is it a translated string?
565 //if (this.doubleStringProps.size < 1) {
566 // this.els.add(left + this.node.quoteString(v));
570 if ((this.doubleStringProps.index_of(k) > -1) ||
571 (ktype.down() == "string" && k[0] == '_')
574 // then use the translated version...
577 (v.split("\n").length > 1 ?
578 ("\n" + this.pad + string.joinv(this.pad + "\n", v.split("\n")).replace("*/", "* - /") + "\n" + this.pad + "*/ ") :
579 (v.replace("*/", "* - /") + " */")
582 //this.els.add(left + " : _this._strings['" +
583 // GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
586 this.out_props.set(left, "_this._strings['" +
587 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
592 // otherwise it needs to be encapsulated.. as single quotes..
594 var vv = this.node.quoteString(v);
595 // single quote.. v.substring(1, v.length-1).replace("'", "\\'") + "'";
596 //this.els.add(left + " : " + "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
597 this.out_props.set(left, "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
605 public void readListeners()
608 if (this.node.listeners.size < 1) {
611 // munge the listeners.
612 //print("ADDING listeners?");
617 var keys = new Gee.ArrayList<string>();
618 var piter = this.node.listeners.map_iterator();
619 while (piter.next() ) {
621 keys.add(piter.get_key());
623 keys.sort(( a, b) => {
624 return ((string)a).collate((string)b);
625 //if (a == b) return 0;
626 //return a < b ? -1 : 1;
630 for (var i = 0; i< keys.size; i++) {
631 var key = keys.get(i);
632 var val = this.node.listeners.get(key);
636 var str = val.strip();
637 var lines = str.split("\n");
638 if (lines.length > 0) {
639 //str = string.joinv("\n" + this.pad + " ", lines);
640 str = string.joinv("\n" + this.pad + indent_str + indent_str , lines);
643 this.out_listeners.set(key.replace("|", "") ,str);
652 public void iterChildren()
656 // finally munge the children...
657 if (this.node.items.size < 1) {
660 var itms = "items : [\n";
662 for(var i = 0; i < this.node.items.size;i++) {
663 var ele = this.node.items.get(i);
664 if (ele.props.has_key("* prop")) {
668 this.out_children.add(ele);
671 itms += "\n"+ this.pad + "]" + "\n";
672 //this.els.add(itms);
675 // finally output listeners...
677 public void xIncludeToString()