/* * Renderer for Javascript output (roo library based) * * - translation support * - doubleStringProps contains elements that are 'translable' * ** in the old method this our compression tool could extract them * - the new idea is to make a list at the top of the javascript file * and output a map... * * * * * */ namespace JsRender { static int rid = 0; class Roo : JsRender { string region; bool disabled; public Roo(Project.Project project, string path) { base( project, path); this.xtype = "Roo"; this.language = "js"; this.content_type = ""; //this.items = false; //if (cfg.json) { // var jstr = JSON.parse(cfg.json); // this.items = [ jstr ]; // //console.log(cfg.items.length); // delete cfg.json; // not needed! // } this.modOrder = "001"; /// sequence id that this uses. this.region = "center"; this.disabled = false; // super?!?! this.id = "file-roo-%d".printf(rid++); //console.dump(this); // various loader methods.. string[] dsp = { "title", "legend", "loadingText", "emptyText", "qtip", "value", "text", "emptyMsg", "displayMsg", "html", "headline", "header", "placeholder", "fieldLabel", }; for (var i=0;i 0 ) { this.tree = new Node(); var ar = obj.get_array_member("items"); var tree_base = ar.get_object_element(0); this.tree.loadFromJson(tree_base, int.parse(bjs_version_str)); } this.loaded = true; this.toSource(); // force it to number the lines... } public override void save() { GLib.debug("--- JsRender.Roo.save"); GLib.debug("save() - reset transStrings\n"); this.transStrings = new Gee.HashMap(); this.findTransStrings(this.tree); this.saveBJS(); // no tree.. if (this.tree == null) { return; } // now write the js file.. string js; try { Regex regex = new Regex("\\.(bjs|js)$"); js = regex.replace(this.path,this.path.length , 0 , ".js"); } catch (RegexError e) { this.name = "???"; print("count not make filename from path"); return; } //var d = new Date(); var js_src = this.toSource(); //print("TO SOURCE in " + ((new Date()) - d) + "ms"); try { this.writeFile(js, js_src); } catch (FileError e ) { print("Save failed\n"); } // for bootstrap - we can write the HTML to the templates directory.. //var top = this.guessName(this.items[0]); //print ("TOP = " + top) } public override void saveHTML ( string html ) { var top = this.tree.fqn(); GLib.debug ("TOP = " + top + "\n" ); if (top.index_of("Roo.bootstrap.") < 0 && top.index_of("Roo.mailer.") < 0 ) { return; } //now write the js file.. string fn; try { Regex regex = new Regex("\\.(bjs|js)$"); fn = regex.replace(this.path,this.path.length , 0 , ".html"); } catch (RegexError e) { this.name = "???"; print("count not make filename from path"); return; } var bn = GLib.Path.get_basename(fn); var dn = GLib.Path.get_dirname(fn); var targetdir = dn + ( top.index_of("Roo.mailer.") < 0 ? "/templates" : "" ); if (!FileUtils.test(targetdir, FileTest.IS_DIR)) { print("Skip save - templates folder does not exist : %s\n", targetdir); return; } //print("SAVE HTML -- %s\n%s\n",targetdir + "/" + bn, html); try { this.writeFile(targetdir + "/" + bn , html); } catch (FileError e ) { print("SaveHtml failed\n"); } } public Gee.ArrayList findxincludes(Node node, Gee.ArrayList ret) { if (node.props.has_key("* xinclude")) { ret.add(node.props.get("* xinclude")); } for (var i =0; i < node.items.size; i++) { this.findxincludes(node.items.get(i), ret); } return ret; } public override void findTransStrings(Node? node ) { // iterate properties... // use doubleStringProps // flagging a translatable string.. // the code would use string _astring to indicate a translatable string // the to use it it would do String.format(this._message, somedata); // loop through and find string starting with '_' if (node == null) { return; } var iter = node.props.map_iterator(); while (iter.next()) { // key formats : XXXX // XXX - plain // string XXX - with type // $ XXX - with flag (no type) // $ string XXX - with flag string kname; string ktype; string kflag; node.normalize_key(iter.get_key(), out kname, out kflag, out ktype); if (kflag == "$") { continue; } // skip cms-id nodes... if (kname == "html" && node.has("cms-id")) { continue; } var str = iter.get_value(); if (this.doubleStringProps.index_of(kname) > -1) { GLib.debug("flag=%s type=%s name=%s : %s\n", kflag,ktype,kname,str); this.transStrings.set(str, GLib.Checksum.compute_for_string (ChecksumType.MD5, str.strip()) ); continue; } if (ktype.down() == "string" && kname[0] == '_') { GLib.debug("flag=%s type=%s name=%s : %s\n", kflag,ktype,kname,str); this.transStrings.set(str, GLib.Checksum.compute_for_string (ChecksumType.MD5, str.strip()) ); continue; } } // iterate children.. for (var i =0; i < node.items.size; i++) { this.findTransStrings(node.items.get(i) ); } } public string transStringsToJs() { GLib.debug("Roo.transStringsToJs()\n"); if (this.transStrings.size < 1) { GLib.debug("Roo.transStringsToJs() size < 1?\n"); return ""; } string[] kvs = {}; var iter = this.transStrings.map_iterator(); while (iter.next()) { kvs += (" '" + iter.get_value() + "' :" + this.tree.quoteString(iter.get_key()) ); } return " _strings : {\n" + string.joinv(",\n", kvs) + "\n" + " },"; } /** * javascript used in Webkit preview */ public override string toSourcePreview() { print("toSourcePreview() - reset transStrings\n"); this.transStrings = new Gee.HashMap(); print("to source preview\n"); if (this.tree == null) { return ""; } this.findTransStrings(this.tree); var top = this.tree.fqn(); var xinc = new Gee.ArrayList(); this.findxincludes(this.tree, xinc); print("got %d xincludes\n", xinc.size); var prefix_data = ""; if (xinc.size > 0 ) { for(var i = 0; i < xinc.size; i++) { print("check xinclude: %s\n", xinc.get(i)); var sf = this.project.getByName(xinc.get(i)); if (sf == null) { print("Failed to find file by name?\n"); continue; } sf.loadItems(); sf.findTransStrings(sf.tree); var xinc_str = sf.toSource(); //string xinc_str; //FileUtils.get_contents(js, out xinc_str); prefix_data += "\n" + xinc_str + "\n"; } } //print(JSON.stringify(this.items, null,4)); if (top == null) { print ("guessname returned false"); return ""; } if (top.contains("Dialog")) { return prefix_data + this.toSourceDialog(true); } if (top.contains("Modal")) { return prefix_data + this.toSourceModal(true); } return prefix_data + this.toSourceLayout(true); } public override void setSource(string str) {} /** * This needs to use some options on the project * to determine how the file is output.. * * At present we are hard coding it.. * * */ public override string toSourceCode() { this.transStrings = new Gee.HashMap(); this.findTransStrings(this.tree); return this.toSource(); } public override string toSource() { // dump the file tree back out to a string. // we have 2 types = dialogs and components // if (this.tree == null) { return ""; } var top = this.tree.fqn(); if (top == null) { return ""; } // get the translatable strings.. = we reload them again so calling methods get the right data... this.transStrings = new Gee.HashMap(); this.findTransStrings(this.tree); if (top.contains("Dialog")) { return this.toSourceDialog(false); } if (top.contains("Modal")) { return this.toSourceModal(false); } return this.toSourceLayout(false); /* eventually support 'classes??' return this.toSourceStdClass(); */ } /** * * munge JSON tree into Javascript code. * * NOTE - needs a deep copy of original tree, before starting.. * - so that it does not modify current.. * * FIXME: + or / prefixes to properties hide it from renderer. * FIXME: '*props' - not supported by this.. ?? - upto rendering code.. * FIXME: needs to understand what properties might be translatable (eg. double quotes) * * @arg {object} obj the object or array to munge.. * @arg {boolean} isListener - is the array being sent a listener.. * @arg {string} pad - the padding to indent with. */ public string mungeToStringWrap(string pad, string prefix, string suffix) { if (this.tree == null) { return ""; } var x = new NodeToJs(this.tree, this.doubleStringProps, pad, null); x.renderer = this; x.cur_line = prefix.split("\n").length; var ret = x.munge(); //var nret = x.ret; // output both files.. so we can diff them... //this.writeFile("/tmp/old.js", ret); //this.writeFile("/tmp/new.js", nret); return prefix + ret + suffix; } public string outputHeader() { string[] s = { "//