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.ret += "/*%d(%d-%d)*/ ".printf(this.cur_line, this.node.line_start,this.node.line_end)+ str + "\n";
280 this.ret += str + "\n";
281 this.cur_line += str.split("\n").length;
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;
430 var has_cms = this.node.has("cms-id");
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'; ???
464 // handle cms-id // html
465 if (has_cms && k == "cms-id") {
466 continue; // ignore it...
468 // html must not be a dynamic property...
469 // note - we do not translate this either...
470 if (has_cms && k == "html" && kflag != "$") {
473 this.out_props.set("html", "Pman.Cms.content(" +
474 this.node.quoteString(this.node.get("cms-id")) +
476 this.node.quoteString(v) +
485 if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) {
486 left = "'" + leftv + "'";
487 } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted.
488 var val = this.node.quoteString(leftv);
490 left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'";
496 // next.. is it a function.. or a raw string..
504 // ??? any others that are raw output..
506 // does not hapepnd with arrays..
507 if (v.length < 1) { //if (typeof(el) == 'string' && !obj[i].length) { //skip empty.
514 str = func_regex.replace(v,v.length, 0, "");
516 print("regex failed");
522 var lines = str.split("\n");
524 if (lines.length > 0) {
525 nstr = string.joinv("\n" + this.pad, lines);
526 //nstr = string.joinv("\n", lines);
528 this.out_props.set(left, nstr);
529 //print("==> " + str + "\n");
530 //this.els.add(left + " : "+ nstr);
541 ktype.down() == "boolean"
543 ktype.down() == "bool"
545 ktype.down() == "number"
547 ktype.down() == "int"
548 ) { // boolean or number...?
549 this.out_props.set(left, v.down());
550 //this.els.add(left + " : " + v.down() );
554 // is it a translated string?
560 //if (this.doubleStringProps.size < 1) {
561 // this.els.add(left + this.node.quoteString(v));
565 if ((this.doubleStringProps.index_of(k) > -1) ||
566 (ktype.down() == "string" && k[0] == '_')
569 // then use the translated version...
572 (v.split("\n").length > 1 ?
573 ("\n" + this.pad + string.joinv(this.pad + "\n", v.split("\n")).replace("*/", "* - /") + "\n" + this.pad + "*/ ") :
574 (v.replace("*/", "* - /") + " */")
577 //this.els.add(left + " : _this._strings['" +
578 // GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
581 this.out_props.set(left, "_this._strings['" +
582 GLib.Checksum.compute_for_string (ChecksumType.MD5, v) +
587 // otherwise it needs to be encapsulated.. as single quotes..
589 var vv = this.node.quoteString(v);
590 // single quote.. v.substring(1, v.length-1).replace("'", "\\'") + "'";
591 //this.els.add(left + " : " + "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
592 this.out_props.set(left, "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'");
600 public void readListeners()
603 if (this.node.listeners.size < 1) {
606 // munge the listeners.
607 //print("ADDING listeners?");
612 var keys = new Gee.ArrayList<string>();
613 var piter = this.node.listeners.map_iterator();
614 while (piter.next() ) {
616 keys.add(piter.get_key());
618 keys.sort(( a, b) => {
619 return ((string)a).collate((string)b);
620 //if (a == b) return 0;
621 //return a < b ? -1 : 1;
625 for (var i = 0; i< keys.size; i++) {
626 var key = keys.get(i);
627 var val = this.node.listeners.get(key);
631 var str = val.strip();
632 var lines = str.split("\n");
633 if (lines.length > 0) {
634 //str = string.joinv("\n" + this.pad + " ", lines);
635 str = string.joinv("\n" + this.pad + indent_str + indent_str , lines);
638 this.out_listeners.set(key.replace("|", "") ,str);
647 public void iterChildren()
651 // finally munge the children...
652 if (this.node.items.size < 1) {
655 var itms = "items : [\n";
657 for(var i = 0; i < this.node.items.size;i++) {
658 var ele = this.node.items.get(i);
659 if (ele.props.has_key("* prop")) {
663 this.out_children.add(ele);
666 itms += "\n"+ this.pad + "]" + "\n";
667 //this.els.add(itms);
670 // finally output listeners...
672 public void xIncludeToString()