/** * * Code to convert node tree to Javascript... * * usage : x = (new JsRender.NodeToJs(node)).munge(); * */ public class JsRender.NodeToJs : Object { Node node; Gee.ArrayList doubleStringProps; string pad; Gee.ArrayList els; //Gee.ArrayList skip; Gee.HashMap ar_props; public NodeToJs( Node node, Gee.ArrayList doubleStringProps, string pad) { this.node = node; this.doubleStringProps = doubleStringProps; this.pad = pad; this.els = new Gee.ArrayList(); //this.skip = new Gee.ArrayList(); this.ar_props = new Gee.HashMap(); } public string munge ( ) { //return this.mungeToString(this.node); this.checkChildren(); this.readProps(); this.readArrayProps(); this.readListeners(); if (!this.node.props.has_key("* xinclude")) { this.iterChildren(); } if (this.els.size < 1) { return ""; } // oprops... var spad = pad.substring(0, this.pad.length-4); var str_props = gLibStringListJoin(",\n" + this.pad , this.els) ; //print ("STR PROPS: " + str_props); if (!this.node.props.has_key("* xinclude")) { return "{\n" + this.pad + str_props + "\n" + spad + "}"; } // xinclude... return "Roo.apply(" + this.node.props.get("* xinclude") + "._tree(), "+ "{\n" + this.pad + str_props + "\n" + spad + "})"; } string gLibStringListJoin( string sep, Gee.ArrayList ar) { var ret = ""; for (var i = 0; i < ar.size; i++) { ret += i>0 ? sep : ""; ret += ar.get(i); } return ret; } public string mungeChild(string pad , Node cnode) { var x = new NodeToJs(cnode, this.doubleStringProps, pad); return x.munge(); } public void checkChildren () { // look throught he chilren == looking for * prop.. -- fixme might not work.. if (!this.node.hasChildren()) { return; } // look for '*props' for (var ii =0; ii< this.node.items.size; ii++) { var pl = this.node.items.get(ii); if (!pl.props.has_key("* prop")) { //newitems.add(pl); continue; } //print(JSON.stringify(pl,null,4)); // we have a prop... //var prop = pl['*prop'] + ''; //delete pl['*prop']; var prop = pl.get("* prop"); print("got prop "+ prop + "\n"); // name ends in []; if (! Regex.match_simple("\\[\\]$", prop)) { // it's a standard prop.. // munge property..?? this.els.add( prop + " : " + this.mungeChild ( this.pad + " ", pl)); //keys.push(prop); continue; } var sprop = prop.replace("[]", ""); print("sprop is : " + sprop + "\n"); // it's an array type.. var old = ""; if (!this.ar_props.has_key(sprop)) { this.ar_props.set(sprop, ""); } else { old = this.ar_props.get(sprop); } var nstr = old += old.length > 0 ? ",\n" : ""; nstr += this.mungeChild( this.pad + " ", pl); this.ar_props.set(sprop, nstr); } } /* * Standardize this crap... * * standard properties (use to set) * If they are long values show the dialog.. * * someprop : .... * bool is_xxx :: can show a pulldown.. (true/false) * string html * $ string html = string with value interpolated eg. baseURL + ".." * Clutter.ActorAlign x_align (typed) -- shows pulldowns if type is ENUM? * $ untypedvalue = javascript untyped value... * _ string html ... = translatable.. * * object properties (not part of the GOjbect being wrapped? * # Gee.ArrayList fileitems * * signals * @ void open * * methods -- always text editor.. * | void clearFiles * | someJSmethod * * specials * * prop -- string * * args -- string * * ctor -- string * * init -- big string? * * event handlers (listeners) * just shown * * ----------------- * special ID values * +XXXX -- indicates it's a instance property / not glob... * *XXXX -- skip writing glob property (used as classes that can be created...) * * */ public void readProps() { string left; Regex func_regex ; if (this.node.props.has_key("$ xns")) { this.els.add("'|xns' : '" + this.node.props.get("$ xns") + "'"); } try { func_regex = new Regex("^\\s+|\\s+$"); } catch (Error e) { print("failed to build regex"); return; } var piter = this.node.props.map_iterator(); while (piter.next() ) { var kk = piter.get_key().split(" "); var v = piter.get_value(); var k = kk[kk.length-1]; //if (this.skip.contains(k) ) { // continue; //} if ( Regex.match_simple("\\[\\]$", k)) { } string leftv = k; // skip builder stuff. prefixed with '.' .. just like unix fs.. if (kk[0][0] == '.') { // |. or . -- do not output.. continue; } if (kk[0][0] == '*') { // ignore '*prop'; continue; } if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) { left = "'" + leftv + "'"; } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted. var val = this.node.quoteString(leftv); left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'"; } else { left = leftv; } left += " : "; // next.. is it a function.. or a raw string.. if ( kk[0][0] == '|' || kk[0][0] == '$' || kk[0] == "function" // ??? any others that are raw output.. ) { // does not hapepnd with arrays.. if (v.length < 1) { //if (typeof(el) == 'string' && !obj[i].length) { //skip empty. continue; } /* print(v); string str = ""; try { str = func_regex.replace(v,v.length, 0, ""); } catch(Error e) { print("regex failed"); return ""; } */ var str = v.strip(); var lines = str.split("\n"); var nstr = "" + str; if (lines.length > 0) { nstr = string.joinv("\n" + this.pad, lines); } //print("==> " + str + "\n"); this.els.add(left + nstr); continue; } // standard.. if ( Lang.isNumber(v) || Lang.isBoolean(v) || kk[0].down() == "boolean" || kk[0].down() == "bool" || kk[0].down() == "number" || kk[0].down() == "int" ) { // boolean or number...? this.els.add(left + v.down() ); continue; } // strings.. if (this.doubleStringProps.size < 1) { this.els.add(left + this.node.quoteString(v)); continue; } if (this.doubleStringProps.index_of(k) > -1) { els.add(left + this.node.quoteString(v)); continue; } var vv = this.node.quoteString(v); // single quote.. v.substring(1, v.length-1).replace("'", "\\'") + "'"; this.els.add(left + "'" + vv.substring(1, vv.length-2).replace("'", "\\'") + "'"); } } public void readArrayProps() { // handle the childitems that are arrays.. eg. button[] = { }... string left; var iter = this.ar_props.map_iterator(); while (iter.next()) { var k = iter.get_key(); var right = iter.get_value(); string leftv = k[0] == '|' ? k.substring(1) : k; if (Lang.isKeyword(leftv) || Lang.isBuiltin(leftv)) { left = "'" + leftv + "'"; } else if (Regex.match_simple("[^A-Za-z_]+",leftv)) { // not plain a-z... - quoted. var val = this.node.quoteString(leftv); left = "'" + val.substring(1, val.length-2).replace("'", "\\'") + "'"; } else { left = leftv; } left += " : "; if (right.length > 0){ this.els.add(left + "[\n" + this.pad + " " + right + "\n" + this.pad + "]"); } } } public void readListeners() { if (this.node.listeners.size < 1) { return; } // munge the listeners. //print("ADDING listeners?"); var liter = this.node.listeners.map_iterator(); var itms = "listeners : {\n"; var i =0; while (liter.next()) { itms += i >0 ? ",\n" : ""; // var str = liter.get_value().strip(); var lines = str.split("\n"); if (lines.length > 0) { str = string.joinv("\n" + this.pad + " ", lines); } itms += this.pad + " " + liter.get_key().replace("|", "") + " : " + str; i++; } itms += "\n" + this.pad + "}"; //print ( "ADD " + itms); this.els.add(itms); } public void iterChildren() { // finally munge the children... if (this.node.items.size < 1) { return; } var itms = "items : [\n"; var n = 0; for(var i = 0; i < this.node.items.size;i++) { var ele = this.node.items.get(i); if (ele.props.has_key("* prop")) { continue; } if (n > 0) { itms += ",\n"; } n++; itms += this.pad + " " + this.mungeChild( this.pad + " ", ele); } itms += "\n"+ this.pad + "]" + "\n"; this.els.add(itms); } // finally output listeners... public void xIncludeToString() { } }