src/JsRender/JsRender.vala
[app.Builder.js] / src / JsRender / JsRender.vala
1 //<Script type="text/javascript">
2
3 namespace JsRender {
4
5
6         public errordomain Error {
7                 INVALID_FORMAT,
8                 RENAME_FILE_EXISTS
9         }
10                 
11         public abstract class JsRender  : Object {
12                 /**
13                  * @cfg {Array} doubleStringProps list of properties that can be double quoted.
14                  */
15                 public Gee.ArrayList<string> doubleStringProps;
16                 
17                 public string id;
18                 public string name;   // is the JS name of the file.
19                 public string fullname;
20                 public string path;  // is the full path to the file.
21                 public string parent;  // JS parent.
22                 public string region;  // RooJS - insert region.
23         
24                 public string title;  // a title.. ?? nickname.. ??? -
25                 public string build_module; // module to build if we compile (or are running tests...)
26                 
27
28                 public string permname;
29                 public string language;
30                 public string content_type;
31                 public string modOrder;
32                 public string xtype;
33                 public uint64 webkit_page_id; // set by webkit view - used to extract extension/etc..
34                     
35                 public Project.Project project;
36                 //Project : false, // link to container project!
37                 
38                 public Node tree; // the tree of nodes.
39                 
40                 public GLib.List<JsRender> cn; // child files.. (used by project ... should move code here..)
41
42                 public bool hasParent; 
43                 
44                 public Gee.HashMap<string,string> transStrings; // map of md5 -> string.
45                 
46
47                 public signal void changed (Node? node, string source); 
48                 
49                  
50                 public signal void compile_notice(string type, string file, int line, string message);
51                 /**
52                  * UI componenets
53                  * 
54                  */
55                 //public Xcls_Editor editor;
56                 
57                 
58                 
59                 public JsRender(Project.Project project, string path) {
60                     
61                         this.cn = new GLib.List<JsRender>();
62                         this.path = path;
63                         this.project = project;
64                         this.hasParent = false;
65                         this.parent = "";
66                         this.tree = null;
67                         this.title = "";
68                         this.region = "";
69                         this.permname = "";
70                         this.modOrder = "";
71                         this.language = "";
72                         this.content_type = "";
73                         this.build_module = "";
74                         print("JsRender.cto() - reset transStrings\n");
75                         this.transStrings = new Gee.HashMap<string,string> ();
76                         
77                         // should use basename reallly...
78                         
79                         var ar = this.path.split("/");
80                         // name is in theory filename without .bjs (or .js eventually...)
81                         try {
82                                 Regex regex = new Regex ("\\.(bjs|js)$");
83
84                                 this.name = ar.length > 0 ? regex.replace(ar[ar.length-1],ar[ar.length-1].length, 0 , "") : "";
85                         } catch (Error e) {
86                                 this.name = "???";
87                         }
88                         this.fullname = (this.parent.length > 0 ? (this.parent + ".") : "" ) + this.name;
89
90                         this.doubleStringProps = new Gee.ArrayList<string>();
91
92                 }
93                 
94                 public void renameTo(string name) 
95                 {
96                         if (this.xtype == "PlainFile") {
97                                 return;
98                         }
99                         var bjs = GLib.Path.get_dirname(this.path) +"/" +  name + ".bjs";
100                         if (FileUtils.test(bjs, FileTest.EXISTS)) {
101                                 throw new Error.RENAME_FILE_EXISTS("File exists %s\n",name);
102                         }
103                         GLib.FileUtils.remove(this.path);
104                         this.removeFiles();
105                         // remove other files?
106                         
107                         this.name = name;
108                         this.path = bjs;
109                         
110                 }
111                 
112
113                 
114                 // not sure why xt is needed... -> project contains xtype..
115                 
116                 public static JsRender factory(string xt, Project.Project project, string path)
117                 {
118          
119                         switch (xt) {
120                                 case "Gtk":
121                                         return new Gtk(project, path);
122                                 case "Roo":
123                                         return new Roo(project, path);
124                                 case "PlainFile":
125                                         return new PlainFile(project, path);
126                         }
127                         throw new Error.INVALID_FORMAT("JsRender Factory called with xtype=%s", xt);
128                         return null;    
129                 }
130
131                 public string toJsonString()
132                 {
133                         if (this.xtype == "PlainFile") {
134                                 return "";
135                         }
136                         var generator = new Json.Generator ();
137                         generator.indent = 4;
138                         generator.pretty = true;
139                         var node = new Json.Node(Json.NodeType.OBJECT);
140                         node.set_object(this.toJsonObject());
141                         generator.set_root(node);
142                         return generator.to_data(null);
143                 }
144         
145                 public string nickType()
146                 {
147                         var ar = this.name.split(".");
148                         string[] ret = {};
149                         for (var i =0; i < ar.length -1; i++) {
150                                 ret += ar[i];
151                         }
152                         return string.joinv(".", ret);
153                         
154                 }
155                 public string nickName()
156                 {
157                         var ar = this.name.split(".");
158                         return ar[ar.length-1];
159                         
160                 }
161
162                 
163                 public string getIconFileName(bool return_default)
164                 {
165                          
166                         var m5 = GLib.Checksum.compute_for_string(GLib.ChecksumType.MD5,this.path); 
167
168                         var dir = GLib.Environment.get_home_dir() + "/.Builder/icons";
169                         if (!FileUtils.test(dir, FileTest.IS_DIR)) {
170                                  File.new_for_path(dir).make_directory();
171                         }
172                         var fname = dir + "/" + m5 + ".png";
173                         
174                         if (!return_default) {
175                                 print("getIconFileName return %s\n", fname);
176                                 return fname;
177                         }
178                         
179                         if (FileUtils.test(fname, FileTest.EXISTS)) {
180                                 print("getIconFileName return %s\n", fname);
181                                 return fname;
182                         }
183                         // we need to create this somehow...
184                         print("getIconFileName return %s\n", GLib.Environment.get_home_dir() + "/.Builder/test.jpg");
185                         return  GLib.Environment.get_home_dir() + "/.Builder/test.jpg";
186
187                 }
188                 
189
190                 public void saveBJS()
191                 {
192                         if (this.xtype == "PlainFile") {
193                                 return;
194                         }
195                     var generator = new Json.Generator ();
196                     generator.indent = 1;
197                     generator.pretty = true;
198                     var node = new Json.Node(Json.NodeType.OBJECT);
199                     node.set_object(this.toJsonObject());
200                     generator.set_root(node);
201                     
202                     print("WRITE :%s\n " , this.path);// + "\n" + JSON.stringify(write));
203                     try {
204                                 this.writeFile(this.path, generator.to_data(null));
205                         //generator.to_file(this.path);
206                     } catch(Error e) {
207                         print("Save failed");
208                     }
209                 }
210                  
211                  
212
213                 public abstract void loadItems() throws GLib.Error;
214                  
215                  
216                  
217                   
218                 public string jsonHasOrEmpty(Json.Object obj, string key) {
219                         return obj.has_member(key) ? 
220                                                 obj.get_string_member(key) : "";
221                 }
222
223                 
224                 public Json.Object toJsonObject ()
225                 {
226                     
227                     
228                         var ret = new Json.Object();
229                         if (this.xtype == "PlainFile") {
230                                 return ret;
231                         }
232                         
233                         //ret.set_string_member("id", this.id); // not relivant..
234                         ret.set_string_member("name", this.name);
235                         ret.set_string_member("parent", this.parent == null ? "" : this.parent);
236                         ret.set_string_member("title", this.title == null ? "" : this.title);
237                         ret.set_string_member("path", this.path);
238                         //ret.set_string_member("items", this.items);
239                         ret.set_string_member("permname", this.permname  == null ? "" : this.permname);
240                         ret.set_string_member("modOrder", this.modOrder  == null ? "" : this.modOrder);
241                         if (this.project.xtype == "Gtk") {
242                                 ret.set_string_member("build_module", this.build_module  == null ? "" : this.build_module);
243                         }
244                         
245                         if (this.transStrings.size > 0) {
246                                 var tr =  new Json.Object();
247                                 var iter = this.transStrings.map_iterator();
248                                 while (iter.next()) {
249                                         tr.set_string_member(iter.get_value(), iter.get_key());
250                                 }
251                                 ret.set_object_member("strings", tr);
252             }
253                         
254                         
255                         
256                         var ar = new Json.Array();
257                         // empty files do not have a tree.
258                         if (this.tree != null) {
259                                 ar.add_object_element(this.tree.toJsonObject());
260                         }
261                         ret.set_array_member("items", ar);
262                 
263                     return ret;
264                 }
265                 
266                 
267
268                 public string getTitle ()
269                 {
270                     if (this.title.length > 0) {
271                         return this.title;
272                     }
273                     var a = this.path.split("/");
274                     return a[a.length-1];
275                 }
276                 public string getTitleTip()
277                 {
278                     if (this.title.length > 0) {
279                         return "<b>" + this.title + "</b> " + this.path;
280                     }
281                     return this.path;
282                 }
283                 /*
284                     sortCn: function()
285                     {
286                         this.cn.sort(function(a,b) {
287                             return a.path > b.path;// ? 1 : -1;
288                         });
289                     },
290                 */
291                     // should be in palete provider really..
292
293
294                 public Palete.Palete palete()
295                 {
296                         // error on plainfile?
297                         return Palete.factory(this.xtype);
298
299                 }
300                 
301                 public string guessName(Node ar) // turns the object into full name.
302                 {
303                      // eg. xns: Roo, xtype: XXX -> Roo.xxx
304                     if (!ar.hasXnsType()) {
305                        return "";
306                     }
307                     
308                     return ar.get("* xns") + "." + ar.get("* xtype");
309                                       
310                                         
311                 }
312                 /**
313                  *  non-atomic write (replacement for put contents, as it creates temporary files.
314                  */
315                 public void writeFile(string path, string contents) throws GLib.IOError, GLib.Error
316                 {
317
318                                  
319                         var f = GLib.File.new_for_path(path);
320                         var data_out = new GLib.DataOutputStream(
321                                           f.replace(null, false, GLib.FileCreateFlags.NONE, null)
322                        );
323                         data_out.put_string(contents, null);
324                         data_out.close(null);
325                 }
326                  
327                 
328                 /**
329                  * 
330                  * munge JSON tree into Javascript code.
331                  *
332                  * NOTE - needs a deep copy of original tree, before starting..
333                  *     - so that it does not modify current..
334                  * 
335                  * FIXME: + or / prefixes to properties hide it from renderer.
336                  * FIXME: '*props' - not supported by this.. ?? - upto rendering code..
337                  * FIXME: needs to understand what properties might be translatable (eg. double quotes)
338                  * 
339                  * @arg {object} obj the object or array to munge..
340                  * @arg {boolean} isListener - is the array being sent a listener..
341                  * @arg {string} pad - the padding to indent with. 
342                  */
343                 
344                 public string mungeToString(string pad)
345                 {
346                         if (this.tree == null) {
347                                 return "";
348                         }
349                         var x = new NodeToJs(this.tree, this.doubleStringProps, pad);
350                         return x.munge();
351                         
352                     
353                 }
354                 public  Node? lineToNode(int line)
355                 {
356                         if (this.tree == null) {
357                                 return null;
358                         }
359                         return this.tree.lineToNode(line);
360                         
361                         
362                 }
363                 
364                 
365                 public abstract void save();
366                 public abstract void saveHTML(string html);
367                 public abstract string toSource() ;
368                 public abstract void setSource(string str);
369                 public abstract string toSourcePreview() ;
370                 public abstract void removeFiles() ;
371                  public abstract void  findTransStrings(Node? node );
372         } 
373
374 }
375