Attribute changed old-javascript
authorAlan Knowles <alan@akbkhome.com>
Sun, 1 Feb 2015 13:30:11 +0000 (21:30 +0800)
committerAlan Knowles <alan@akbkhome.com>
Sun, 1 Feb 2015 13:30:11 +0000 (21:30 +0800)
17 files changed:
old-javascript/File.js [new file with mode: 0644]
old-javascript/Globals.js [new file with mode: 0644]
old-javascript/JsParser.js [new file with mode: 0644]
old-javascript/Observable.js [new file with mode: 0644]
old-javascript/Options.js [new file with mode: 0644]
old-javascript/ProjectManager.js [new file with mode: 0755]
old-javascript/Spawn.js [new file with mode: 0644]
old-javascript/String.js [new file with mode: 0644]
old-javascript/XObject.js [new file with mode: 0644]
old-javascript/builder.html.js [new file with mode: 0644]
old-javascript/builder_run.js [new file with mode: 0755]
old-javascript/console.js [new file with mode: 0644]
old-javascript/dbgenerate.js [new file with mode: 0644]
old-javascript/gtkrun.js [new file with mode: 0644]
old-javascript/roojs-bootstrap-debug.js [new file with mode: 0644]
old-javascript/roojs-bootstrap.js [new file with mode: 0644]
old-javascript/test.js [new file with mode: 0644]

diff --git a/old-javascript/File.js b/old-javascript/File.js
new file mode 100644 (file)
index 0000000..f836e9a
--- /dev/null
@@ -0,0 +1,270 @@
+// <script type ="text/Javascript">
+GLib = imports.gi.GLib;
+Gio = imports.gi.Gio;
+
+
+
+/**
+* @namespace File
+* 
+* Library to wrap GLib and Gio basic File related methods
+* 
+* usage:
+* 
+* File = import.File.File;
+* 
+* var contents = File.read("/tmp/test.txt");
+*
+* 
+* 
+*/
+var File = {
+
+    SEPARATOR : '/',
+
+    // fixme - this needs a bitter location.. 
+    // they where in a string class before, but  overriding String methods is not a good normally a good idea..
+       
+    rtrim : function (s,toTrim) {
+        if (s.substr(s.length - toTrim.length) == toTrim) {
+            return s.slice(0, s.length - toTrim.length);
+        }
+   
+        return s;
+    },
+    trim : function (s,toTrim) {
+        var out = s.ltrim(toTrim);
+        out = out.rtrim(toTrim);
+        return out;
+    },
+    
+    ltrim : function (s, toTrim) {
+        if (s.substr(0, toTrim.length) == toTrim) {
+            return s.slice(toTrim.length);
+        }
+        
+        return s;
+    },
+    
+    join : function () {
+        var out = "";
+        for (var i = 0; i < arguments.length; i++) {
+            if (i == 0) {
+              out += this.rtrim(arguments[i], File.SEPARATOR);
+            }
+            else if (i == arguments.length - 1) {
+              out += File.SEPARATOR + this.ltrim(arguments[i], File.SEPARATOR);
+            }
+            else {
+              out += File.SEPARATOR + this.trim(arguments[i], File.SEPARATOR);
+            }
+        }
+        return out;
+    },
+    
+    dirname : function(s)
+    {
+        var ar = s.split(File.SEPARATOR);
+        ar.pop();
+        return ar.join(File.SEPARATOR);
+    },
+    basename : function(s)
+    {
+        var ar = s.split(File.SEPARATOR);
+        return ar.pop();
+    },
+    
+    read : function (path) {
+        var out = {};
+        GLib.file_get_contents(path, out, null, null);
+               
+               //print(JSON.stringify(out));
+               
+        return out['value'];
+    },
+
+    isFile : function (path) {
+      return GLib.file_test(path, GLib.FileTest.IS_REGULAR);
+    },
+    exists : function (path) {
+      return GLib.file_test(path, GLib.FileTest.EXISTS);
+    },
+    isDirectory : function (path) {
+      return GLib.file_test(path, GLib.FileTest.IS_DIR);
+    },
+
+    list : function (path) {
+        var listing = [];
+        print(path);
+        var f = Gio.file_new_for_path(String(path));
+        var file_enum = f.enumerate_children(Gio.FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, Gio.FileQueryInfoFlags.NONE, null);
+
+        var next_file = null;
+
+        while ((next_file = file_enum.next_file(null)) != null) {
+          listing.push(next_file.get_display_name());
+        }
+
+        file_enum.close(null);
+
+        listing.sort();
+
+        return listing;
+    },
+
+    mtime : function (path) {
+        var f = Gio.file_new_for_path(String(path));
+        var mtime = new GLib.TimeVal();
+
+        var info = f.query_info(Gio.FILE_ATTRIBUTE_TIME_MODIFIED, Gio.FileQueryInfoFlags.NONE, null);
+        info.get_modification_time(mtime);
+
+        return new Date(mtime.tv_sec * 1000);
+    },
+
+    /**
+     * resolve the real path
+     * @arg path {String} Path to resolve
+     * @returns {String} the resolved path path.
+     * 
+     */
+    realpath :  function (path) { 
+        return this.canonical(path);
+    },
+    canonical : function (path) { 
+        var f = Gio.file_new_for_path(String(path));
+        var can = f.resolve_relative_path('');
+        return can.get_path();
+    },
+    /**
+     * write a string to a file
+     * @arg path {String} File to write to alwasy overwrites.
+     * @arg string {String} Contents of file.
+     * 
+     */
+    write : function (path, string) {
+        var d = new Date();
+        var f = Gio.file_new_for_path(String(path));
+        var data_out = new Gio.DataOutputStream({base_stream:f.replace(null, false, Gio.FileCreateFlags.NONE, null)});
+        data_out.put_string(string, null);
+        data_out.close(null);
+        print("WRITE : " + path + " in " + ((new Date()) - d) + 'ms');
+        
+    },
+    /**
+     * append
+     * @arg path {String} File to write to
+     * @arg string {String} string to append to file.
+     * 
+     */
+    append : function (path, string) {
+        var f = Gio.file_new_for_path(String(path));
+        var data_out = new Gio.DataOutputStream({
+                base_stream:f.append_to(Gio.FileCreateFlags.NONE, null)
+        });
+        data_out.put_string(string, null);
+        data_out.close(null);
+    },
+    /**
+     * remove 
+     * Delete a file.
+     * @arg path {String} File to remove
+     * 
+     * 
+     */
+    remove : function (path)
+    {
+        var f = Gio.file_new_for_path(String(path));
+        return f['delete']();
+    },
+    // copy files recursively from fromDir, silently ignore them if they already exist in toDir
+    silentRecursiveCopy : function (fromDir, toDir) {
+        var filesToCopy = File.recursiveListing(fromDir);
+        var srcPath, destPath, src, dest;
+
+        for (var index in filesToCopy) {
+          srcPath = File.join(String(fromDir), filesToCopy[index]);
+          destPath = File.join(String(toDir), filesToCopy[index]);
+
+          if (File.isFile(srcPath) && !File.isFile(destPath)) {
+            File.copyFile(srcPath, destPath);
+          }
+          else if (File.isDirectory(srcPath) && !File.isDirectory(destPath)) {
+            File.mkdir(destPath);
+          }
+
+        }
+    },
+    /**
+     * Make a symbolic link
+     * @arg  new_link {String} The new link
+     * @arg  target    {String} Where it links to.
+     */
+    link : function (new_link, target) {
+        var dest = Gio.file_new_for_path(String(new_link));
+        return dest.make_symbolic_link(target, null);
+    },
+    /**
+     * Make a directory
+     * FIXME - needs perms setting..
+     * 
+     * @arg  directory  {String} Directory to make
+     */
+
+    mkdir : function (destPath) {
+        var dest = Gio.file_new_for_path(String(destPath));
+        return dest.make_directory(null);
+    },
+
+    /**
+     * Copy a file or (directory maybe?)
+     * @arg  srcPath {String} source file
+     * @arg  destPath {String} destination file
+     * @arg  flags {Gio.FileCopyFlags} to overwrite etc...  Gio.FileCopyFlags.OVERWRITE
+     */
+    copy : function (srcPath, destPath, flags) {
+        return this.copyFile(srcPath, destPath, flags);
+    },
+    copyFile : function (srcPath, destPath, flags) {
+        
+        flags = typeof(flags) == 'undefined' ? Gio.FileCopyFlags.NONE : flags;
+        var dest = Gio.file_new_for_path(String(destPath));
+        var src = Gio.file_new_for_path(String(srcPath));
+
+        // a bit of a hack for the fact that Gio.File.copy arguments
+        // can be nulled, but not according to the GIR file
+        return src.copy(dest, flags);
+    },
+    
+    
+    
+
+    recursiveListing : function (dir) {
+
+        function recursiveListingInternal(prefix, listing, dir) {
+          var entries = File.list(dir);
+          var next, fullPath;
+
+          for (var index in entries) {
+            next = entries[index];
+            fullPath = File.join(prefix, dir, next);
+
+            if (File.isDirectory(fullPath)) {
+              listing.push(next);
+              listing = listing.concat(recursiveListingInternal(next, [], fullPath));
+            }
+            else {
+              if (prefix) {
+                next = File.join(prefix, next);
+              }
+              listing.push(next);
+            }
+          }
+
+          return listing;
+        }
+
+        return recursiveListingInternal('', [], dir);
+    }
+
+};
diff --git a/old-javascript/Globals.js b/old-javascript/Globals.js
new file mode 100644 (file)
index 0000000..5b4cad1
--- /dev/null
@@ -0,0 +1,20 @@
+Gtk = imports.gi.Gtk;
+Gdk = imports.gi.Gdk;
+
+
+atoms = {
+               "STRING" : Gdk.atom_intern("STRING")
+       };
+targetList = new Gtk.TargetList();
+targetList.add(  atoms["STRING"], 0, 0);
+
+
+
+Gtk.rc_parse_string(
+            "style \"gtkcombobox-style\" {\n" + 
+            "    GtkComboBox::appears-as-list = 1\n" +
+            "}\n"+
+            "class \"GtkComboBox\" style \"gtkcombobox-style\"\n");
+
+
+//imports.Window.Window.el.show_all();
diff --git a/old-javascript/JsParser.js b/old-javascript/JsParser.js
new file mode 100644 (file)
index 0000000..adbc921
--- /dev/null
@@ -0,0 +1,588 @@
+//<script type="text/javscript">
+
+XObject = imports.XObject.XObject;
+console     = imports.console.console;
+Collapse = imports.JSDOC.Collapse.Collapse;
+/**
+ * 
+ * this takes our collased file, and turns it into the config array..
+ * 
+ * @see rconv.js (our tester file)
+ * 
+ * STATUS:
+ *
+ *  - Pman.Tab.* appears to work.
+ * .. next up ..Dialog...
+ *
+ *
+ *
+ * Current issues:
+ *  - xtype is combined on generated files. (not xns + xtype)
+ *  - listeners are prefixed with '|' ... 
+ *  - modkey is not getting picked up..
+ *  - suspect some of the elements are not getting flattened
+ *  - parent on 
+ */
+
+JsParser  =  XObject.define(
+    function (ar)
+    {
+        JsParser.superclass.constructor.call(this, ar);
+       // console.log("STARTING OUTPUT");
+        
+         
+
+    },
+    Collapse, 
+    {
+        
+        cfg : { },
+
+        parse: function()
+        {
+            // standard pman dialog
+            if (this.tokens[0].data == 'Pman.on') {
+                this.parsePmanLayout();
+                return;
+            }
+         
+            
+            // Standard Pman Dialog - 
+            if (this.tokens[2].props && typeof(this.tokens[2].props.create) != 'undefined') {
+                this.parsePmanDialog();
+                return;
+            }
+            
+            
+            // Seed Gtk XObject application. 
+            if (this.tokens.length > 2 && this.tokens[2].data.match(/^imports\./)) {
+                this.parseXObject();
+                return;
+            }
+            
+            Seed.print("Unknown format");
+            Seed.print(JSON.stringify(this.tokens,null,4));
+            Seed.quit();
+            
+            
+            
+            
+            
+            
+            
+            
+            // perfect for dialogs... - is this our 'generic, non-pman code?'
+            
+            
+            var pos = this.lookFor( 'function');
+            
+            // XXXXX = function(
+            var cfg = {};
+            
+            if (pos > -1 && (this.tokens[pos-1].data == '=') && (this.tokens[pos-2].type == 'NAME')) {
+                
+                this.cfg = {
+                    '*class' : this.tokens[pos-2].data,
+                    '*extends' : '',
+                    '//constructor' :  this.tokens[pos-2].prefix,
+                    '|constructor' : 'function ' + this.tokens[pos+1].toRaw() + 
+                            this.tokens[pos+2].toRaw()
+                    
+                };
+                this.cursor = pos+2;
+                
+            }
+            
+            if (pos < 0) {
+                // no function - we have a static one...
+                pos = this.lookFor( '=');
+                if (pos > 1 && 
+                    (this.tokens[pos-1].type == 'NAME') &&
+                    (this.tokens[pos+1].data == '{')
+                ) {
+                    this.cfg = {
+                        '*class' : this.tokens[pos-1].data,
+                        '//*class' :  this.tokens[pos-1].prefix
+                        
+                        
+                    };
+                    XObject.extend(this.cfg, this.parseProps(this.tokens[pos+1].props));
+                    return;
+                    
+                }
+                
+                
+                
+            }
+            
+            
+              // Roo.apply (l
+            var pos = this.lookFor( 'Roo.apply');
+            //console.dump(this.tokens);
+            
+            
+            if (
+                (pos > -1) &&
+                (this.tokens[pos+1].items[0][0].data  == this.cfg['*class'] + '.prototype')
+            ) {
+                // XXXXXx.prototype = {
+                
+                
+                    
+                XObject.extend(this.cfg, this.parseProps(this.tokens[pos+1].items[1][0].props));
+                return;
+                
+            }
+            
+            
+            var pos = this.lookFor('new');
+            
+            if (pos > -1 && 
+                (this.tokens[pos-2].type == 'NAME') &&
+                (this.tokens[pos-1].data == '=') && 
+                (this.tokens[pos+1].type == 'NAME') &&
+                (this.tokens[pos+2].data == '(') 
+            ) {
+                
+                this.cfg = {
+                    '//*class' : this.tokens[pos-2].prefix,
+                    '*class' : this.tokens[pos-2].data,
+                    '*extends' : this.tokens[pos+1].data
+                };
+                    
+                XObject.extend(this.cfg, this.parseProps(this.tokens[pos+2].items[0][0].props));
+                
+                return;
+                
+            }
+            
+            ///Builder.Provider.ProjectManager = new Roo.Observable({
+                
+            
+            
+            var pos = this.lookFor( 'Roo.extend');
+            if (pos > -1) {
+                
+                this.cfg['*extends'] = this.tokens[pos+1].items[1][0].data;
+                XObject.extend(this.cfg, this.parseProps(this.tokens[pos+1].items[2][0].props));
+                
+                // no more..
+                return;
+            }
+            
+             
+                
+            var pos = this.lookFor( 'Roo.extend');
+            if (pos > -1) {
+                
+                this.cfg['*extends'] = this.tokens[pos+1].items[1][0].data;
+                XObject.extend(this.cfg, this.parseProps(this.tokens[pos+1].items[2][0].props));
+                
+                // no more..
+                return;
+            }
+            
+            
+            
+            //console.dump(cfg);
+            //Seed.quit();
+            
+            
+            
+            // other type of layout
+          //  console.dump(this.tokens);
+            
+            // this type of file..
+            // xxxx.xxx = function
+            // -> into |constructor..
+            // -> extend + prototype
+             
+            
+            
+                
+        },
+        
+        
+        parsePmanLayout : function()
+        {
+                // then it's a layout style..
+            
+            //Seed.quit();
+            
+            
+            //console.dump(this.tokens);
+            //              the list of statements inside of function..?
+            
+            
+            var stmts =  this.tokens[1].items[1][2].items;
+            
+            // look for register..
+            var topp = false;
+            stmts.map( function(s, i) {
+                if (s[0].data == 'Pman.register') {
+                    topp = brace = s[1].items[0][0].props;
+                }
+            });
+            if (!topp) {
+                console.dump(this.tokens);
+                throw "could not find top props...";
+                
+            }
+            //print(JSON.stringify(topp,null,4));
+            
+            this.cfg = this.parseProps(topp);
+            for(var k in this.cfg) {
+                this.cfg[k.replace(/^\|/, '')] = this.cfg[k];
+            }
+            if (this.cfg.name) {
+                this.cfg.title = this.cfg.name;
+                delete this.cfg.name;
+            }
+           // this.cfg.fullname = this.cfg.name;
+            this.cfg.type = 'Roo';
+            
+            
+            
+            // looking for parent / name..
+            
+            
+            this.cfg.modOrder = this.cfg.modKey.split('-').shift(); 
+            print(JSON.stringify(this.cfg,null,4));
+            
+            
+            //                  (            {          add    { this.panel (  {
+            var cfg = this.tokens[7].items[0][0].props.add.val[2].items[2][3].items[0][0].props;
+            this.cfg.items = [ this.parseProps(cfg) ];
+            //console.dump(this.cfg); 
+        },
+        
+        
+        parsePmanDialog : function() {
+            
+            //console.dump(this.tokens);
+            this.cfg.name = this.tokens[0].data;
+            
+            
+            
+            var cfg = this.tokens[2].props.create.val[2].items[1][3].items[0][0].props;
+            this.cfg.type = 'Roo';
+            //console.dump(this.tokens);
+            //print(JSON.stringify(cfg,null,4)); Seed.quit();
+            
+           // print("Trying standard dialog");Seed.quit();;
+            
+            this.cfg.items = [ this.parseProps(cfg) ];
+            return;
+            
+        },
+        
+        // Seed xobject file.
+        parseXObject : function() {
+            
+            this.parseImports();
+              
+            var pos = this.lookFor('XObject');
+            if (pos < 0)  {
+                throw "Can not find XObject";
+            }
+            this.cfg.name = this.tokens[pos-3].data;
+            this.cfg.type = 'Gtk';
+            var cfg = this.tokens[pos+1].items[0][0].props;
+            this.cfg.items = [ this.parseProps(cfg) ];
+            
+            //print(JSON.stringify(this.tokens[pos]));
+            
+            //print(JSON.stringify(this.tokens,null,4)); Seed.quit();
+            //Seed.quit();
+            
+        },
+        
+        
+        
+        /**
+         *  parse Imports lines.
+         *
+         */
+        
+        parseImports : function()
+        {
+           // console.dump(this.tokens);
+            this.cfg.giImports = [];
+            this.cfg.imports= [];
+            while (true) {
+                var pos = this.lookFor('=');
+                if (pos < 0)  {
+                    break;
+                }
+                this.cursor = pos;
+                var k = this.look(-1, true);
+                var v = this.look(1, true);
+               // Seed.print(k.data + " => " + v.data);
+               
+                /// finish!!! - not an import ...
+               
+                if (!v.data.match(/^imports/)) {
+                    return; ///
+                    
+                    this.cursor++;
+                    continue;
+                }
+                if (v.data.match(/^imports\.gi/)) {
+                    // gi import..
+                    this.cfg.giImports.push(v.data.replace(/imports\.gi\./, ''));
+                    
+                    this.cursor++;
+                    continue;
+                }
+                  
+                // two types of import left
+                // imports.xnew
+                if (v.data.match(/^imports\./)) {
+                    this.cfg.imports[k.data] = v.data.replace(/imports\./, '') + '.js';
+                    this.cursor++;
+                    continue;
+                }
+                // imports[.....]
+                this.cursor++;
+                if (this.lookFor('[') > this.lookFor('=')) {
+                    continue;
+                }
+                var bpos = this.lookFor('[');
+               // console.dump(this.tokens[bpos]);
+                
+                this.cfg.imports[k.data] = this.tokens[bpos].items[0][0].toJS();
+                
+                this.cursor++;
+                
+            }
+        //    console.dump(this.giImports);
+          //  console.dump(this.imports);
+            //Seed.quit();
+            
+        },
+        
+        ///------------------- GENERIC PARSING ------------------
+        
+        
+        
+        
+        
+        
+        parseProps:  function(o)
+        {
+            //print(JSON.stringify(o,null,4));
+            
+            var ret = { };
+            var fakeItems =  [];
+            for(var k in o) {
+                
+                //print( "parsing prop: " + k);
+                if (o[k].key.data == '}') {
+                    // typo trailing comma in object def.
+                    continue;
+                }
+                
+                var kv = k;
+                if (o[k].key.type == 'STRN') {
+                    kv = o[k].key.toJS();
+                }
+                if (!o[k].val.length) {
+                    console.dump(o[k]);
+                }
+                
+                //console.dump(o[k]);
+                if (o[k].val[0].data == "function") {
+                    // add comments..
+                  //   console.dump(o[k].key.prefix); 
+                    var pr = typeof(o[k].key.prefix) == 'undefined' ? '' : o[k].key.prefix ;
+                    pr = this.clean_prefix( pr) ;
+                    if (pr.length) {
+                        ret['//' +kv ] =  pr;
+                    }
+                    //print("running expand");
+                    ret['|' +kv ] =  this.clean_body( this.expand(o[k].val));
+                    continue;
+                }
+                
+                
+                if (o[k].val[0].data == "[") {
+                    
+                    if (o[k].val[0].items[0][0].data == '{') {
+                        // array of objects..
+                        
+                        // this works for items..
+                        
+                        // used elsewhere for buttons: -> in which case we have a fake xtype
+                        
+                        
+                        
+                        // if K is not ITEMS - we need to add '*prop' -> and add it to the items array..
+                        var add = this.parseArray(o[k].val[0].items);
+                        if (kv == 'items') {
+                            ret[kv] = add;
+                            continue;
+                        }
+                        add.forEach(function(a) {
+                            a['*prop'] = kv + '[]';
+                            fakeItems.push(a);
+                        });
+                        
+                        continue;
+                    } 
+                    // raw array 
+                    
+                    
+                    ret['|' +kv ] =  this.clean_body(this.expand(o[k].val)); // remove ','...
+                    continue;
+                }
+                if (o[k].val[0].data == "(") {
+                    ret['|' +kv ] =  this.expand(o[k].val);
+                    continue;
+                }
+                // value is an object..
+                
+                if (o[k].val[0].data == "{") {
+                    
+                    // things that can be property of object type:
+                    // listeners, set, 
+                    var add = this.parseProps(o[k].val[0].props);
+                    
+                    
+                    
+                    if (kv == 'set' || kv =='listeners') {
+                        ret[kv ] = add;
+                        continue;
+                    }
+                    if ((typeof(add.xtype) != 'undefined') ||  ['sortInfo', 'center', 'east', 'west', 'north', 'south'].indexOf(kv) > -1) {
+                        add['*prop'] =  kv;
+                        fakeItems.push(add);
+                        continue;
+                    }
+                    
+                    
+                    ret[ '|' + kv ] =  this.expand(o[k].val);
+                    
+                    
+                    // this hsould be added to 'items', with a *prop element..
+                    continue;
+                }
+                //console.dump(o[k].val);
+                
+                if (o[k].val[1].data == ',' || o[k].val[1].data == '}') {
+                    // single item piece of data...
+                    var t1= o[k].val[0];
+                    switch(o[k].val[0].type) {
+                        case 'STRN':
+                        case 'NUMB':
+                        case 'KEYW':
+                            ret[  kv ]  = t1.toJS();
+                            continue;
+                        case 'NAME':
+                            ret[ '|' + kv ] =  t1.data;
+                            continue;
+                        
+                    }
+                }
+                // finally give up..
+                ret[ '|' + kv ] =  this.clean_body(this.expand(o[k].val));
+                
+            }
+            if (!ret.items && fakeItems.length) {
+                ret.items = [];
+            }
+            fakeItems.forEach(  function(e) {
+                ret.items.push(e);
+            });
+            // merge fakeItems;
+            //console.dump(ret);
+            
+            return ret;
+        },
+        parseArray: function(ar) {
+          // console.dump(ar);
+           // Seed.quit();
+            var ret = [];
+            ar.map(function (e) {
+                // has no props...
+                if (typeof(e[0].props) == 'undefined') {
+                    return;
+                }
+               
+                
+                ret.push( this.parseProps(e[0].props));
+                     
+            },this);
+             
+            return ret;
+          
+        },
+        
+        /**
+         * convert a function call token array back into a string
+         */
+        expand: function(ar)
+        {
+            var ret = '';
+            //print(JSON.stringify(ar,null,4));
+             
+            for(var i =0 ; i < ar.length -1; i++) {
+                ret += ar[i].toRaw();
+            }
+            
+            return ret;
+            
+            
+        },
+        
+        /***
+         * change the indentation on a function 
+         *
+         */
+        clean_body : function(str)
+        {
+            var lns = str.split("\n");
+            var mindent = -1;
+            lns.map( function(l, i) {
+                if (!i || !l.length || l.match(/^\s+$/)) {
+                    return;
+                }
+                
+                var spc = l.match(/\s+/);
+                if (!spc || !spc[0].length) {
+                    return;
+                }
+                mindent = mindent < 0 ? spc[0].length : Math.min(spc[0].length, mindent);
+                
+            });
+            //console.log(mindent + ":" + lns[0]);
+            var ar = [];
+            if (mindent < 0) {
+                return str;
+            }
+            lns.map( function(l,i) {
+                if (!i) {
+                    ar.push(l.replace(/^\s+/, ''));
+                    return;
+                }
+                ar.push(l.substring(mindent));
+            });
+            //print(str);
+            //print(JSON.stringify(ar,null,4));
+            
+            
+            return ar.join("\n");
+        },
+        clean_prefix: function(str) {
+            
+            
+            
+            if (!str.length) {
+                return '';
+            }
+            var ret = str.replace(/^\s+/gm, "\n").replace(/\n+/gm, "\n");
+            return ret == "\n" ? '' : ret;
+            
+        }    
+             
+    
+});
\ No newline at end of file
diff --git a/old-javascript/Observable.js b/old-javascript/Observable.js
new file mode 100644 (file)
index 0000000..46cb8a2
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+XObject = imports.XObject.XObject;
+/**
+ * @class Observable
+ * Base class that provides a common interface for publishing events. Subclasses are expected to
+ * to have a property "events" with all the events defined.<br>
+ * For example:
+ * <pre><code>
+ Employee = XObject.define(
+      function(name){
+        this.name = name;
+        this.addEvents({
+            "fired" : true,
+            "quit" : true
+        });
+     },
+     Observable, {});
+     
+</code></pre>
+ * @param {Object} config properties to use (incuding events / listeners)
+ */
+Observable = XObject.define(
+    function(cfg){
+        
+        cfg = cfg|| {};
+        this.addEvents(cfg.events || {});
+        if (cfg.events) {
+            delete cfg.events; // make sure
+        }
+         
+        XObject.extend(this, cfg);
+        
+        if(this.listeners){
+            this.on(this.listeners);
+            delete this.listeners;
+        }
+    },
+    Object,  
+    {
+        /** 
+         * @cfg {Object} listeners  list of events and functions to call for this object, 
+         * For example :
+         * <pre><code>
+            listeners :  { 
+               'click' : function(e) {
+                   ..... 
+                } ,
+                .... 
+            } 
+          </code></pre>
+         */
+            
+        
+        /**
+         * Fires the specified event with the passed parameters (minus the event name).
+         * @param {String} eventName
+         * @param {Object...} args Variable number of parameters are passed to handlers
+         * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
+         */
+        fireEvent : function(){
+            var ce = this.events[arguments[0].toLowerCase()];
+            if(typeof ce == "object"){
+                return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
+            }else{
+                return true;
+            }
+        },
+
+        // private - blcoks these types of signals?
+        filterOptRe : /^(?:scope|delay|buffer|single)$/,
+
+        /**
+         * Appends an event handler to this component
+         * @param {String}   eventName The type of event to listen for
+         * @param {Function} handler The method the event invokes
+         * @param {Object}   scope (optional) The scope in which to execute the handler
+         * function. The handler function's "this" context.
+         * @param {Object}   options (optional) An object containing handler configuration
+         * properties. This may contain any of the following properties:<ul>
+         * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
+         * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.NOT AVAIALBLE</li>
+         * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
+         * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link DelayedEvent} delayed NOT AVAIALBLE
+         * by the specified number of milliseconds. If the event fires again within that time, the original
+         * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
+         * </ul><br>
+         * <p>
+         * <b>Combining Options</b><br>
+         * Using the options argument, it is possible to combine different types of listeners:<br>
+         * <br>
+         * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
+            <pre><code>
+            el.on('click', this.onClick, this, {
+                single: true,
+                delay: 100,
+                forumId: 4
+            });
+            </code></pre>
+         * <p>
+         * <b>Attaching multiple handlers in 1 call</b><br>
+         * The method also allows for a single argument to be passed which is a config object containing properties
+         * which specify multiple handlers.
+         * <pre><code>
+            el.on({
+                'click': {
+                    fn: this.onClick,
+                    scope: this,
+                    delay: 100
+                }, 
+                'mouseover': {
+                    fn: this.onMouseOver,
+                    scope: this
+                },
+                'mouseout': {
+                    fn: this.onMouseOut,
+                    scope: this
+                }
+            });
+            </code></pre>
+         * <p>
+         * Or a shorthand syntax which passes the same scope object to all handlers:
+            <pre><code>
+            el.on({
+                'click': this.onClick,
+                'mouseover': this.onMouseOver,
+                'mouseout': this.onMouseOut,
+                scope: this
+            });
+            </code></pre>
+         */
+        on : function(eventName, fn, scope, o){
+            if(typeof eventName == "object"){
+                o = eventName;
+                for(var e in o){
+                    if(this.filterOptRe.test(e)){
+                        continue;
+                    }
+                    if(typeof o[e] == "function"){
+                        // shared options
+                        this.on(e, o[e], o.scope,  o);
+                    }else{
+                        // individual options
+                        this.on(e, o[e].fn, o[e].scope, o[e]);
+                    }
+                }
+                return;
+            }
+            o = (!o || typeof o == "boolean") ? {} : o;
+            eventName = eventName.toLowerCase();
+            var ce = this.events[eventName] || true;
+            if(typeof ce == "boolean"){
+                ce = new Event(this, eventName);
+                this.events[eventName] = ce;
+            }
+            ce.addListener(fn, scope, o);
+        },
+
+        /**
+         * Removes a listener
+         * @param {String}   eventName     The type of event to listen for
+         * @param {Function} handler        The handler to remove
+         * @param {Object}   scope  (optional) The scope (this object) for the handler
+         */
+        un : function(eventName, fn, scope){
+            var ce = this.events[eventName.toLowerCase()];
+            if(typeof ce == "object"){
+                ce.removeListener(fn, scope);
+            }
+        },
+
+        /**
+         * Removes all listeners for this object
+         */
+        purgeListeners : function(){
+            for(var evt in this.events){
+                if(typeof this.events[evt] == "object"){
+                     this.events[evt].clearListeners();
+                }
+            }
+        },
+        _combine : function(){
+            var as = arguments, l = as.length, r = [];
+            for(var i = 0; i < l; i++){
+                var a = as[i];
+                if(a instanceof Array){
+                    r = r.concat(a);
+                }else if(a.length !== undefined && !a.substr){
+                    r = r.concat(Array.prototype.slice.call(a, 0));
+                }else{
+                    r.push(a);
+                }
+            }
+            return r;
+        },
+        
+        relayEvents : function(o, events){
+            var createHandler = function(ename){
+                return function(){
+                    return this.fireEvent.apply(this, Event.prototype.combine(ename, 
+                            Array.prototype.slice.call(arguments, 0)));
+                };
+            };
+            for(var i = 0, len = events.length; i < len; i++){
+                var ename = events[i];
+                if(!this.events[ename]){ this.events[ename] = true; };
+                o.on(ename, createHandler(ename), this);
+            }
+        },
+
+        /**
+         * Used to define events on this Observable
+         * @param {Object} object The object with the events defined
+         */
+        addEvents : function(o){
+            if(!this.events){
+                this.events = {};
+            }
+            XObject.extendIf(this.events, o);
+        },
+
+        /**
+         * Checks to see if this object has any listeners for a specified event
+         * @param {String} eventName The name of the event to check for
+         * @return {Boolean} True if the event is being listened for, else false
+         */
+        hasListener : function(eventName){
+            var e = this.events[eventName];
+            return typeof e == "object" && e.listeners.length > 0;
+        }
+});
+/**
+ * Starts capture on the specified Observable. All events will be passed
+ * to the supplied function with the event name + standard signature of the event
+ * <b>before</b> the event is fired. If the supplied function returns false,
+ * the event will not fire.
+ * @param {Observable} o The Observable to capture
+ * @param {Function} fn The function to call
+ * @param {Object} scope (optional) The scope (this object) for the fn
+ * @static
+ */
+Observable.capture = function(o, fn, scope){
+    o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
+};
+
+/**
+ * Removes <b>all</b> added captures from the Observable.
+ * @param {Observable} o The Observable to release
+ * @static
+ */
+Observable.releaseCapture = function(o){
+    o.fireEvent = Observable.prototype.fireEvent;
+};
+
+
+var createSingle = function(h, e, fn, scope){
+    return function(){
+        e.removeListener(fn, scope);
+        return h.apply(scope, arguments);
+    };
+};
+
+// NOT SUPPORTED YET>
+//var createBuffered = function(h, o, scope){
+//    var task = new DelayedTask();
+//    return function(){
+//        task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
+//    };
+//};
+
+
+//var createDelayed = function(h, o, scope){
+//    return function(){
+//        var args = Array.prototype.slice.call(arguments, 0);
+//        setTimeout(function(){
+//            h.apply(scope, args);
+//        }, o.delay || 10);
+//    };
+//};
+
+
+/**
+ * Event Object - manages a specific event.
+ * 
+ * 
+ * 
+ */
+
+
+
+Event = XObject.define(
+    function(obj, name){
+        this.name = name;
+        this.obj = obj;
+        this.listeners = [];
+    },
+    Object, 
+    {
+        addListener : function(fn, scope, options){
+            var o = options || {};
+            scope = scope || this.obj;
+            if(!this.isListening(fn, scope)){
+                var l = {fn: fn, scope: scope, options: o};
+                var h = fn;
+               // if(o.delay){
+                //       h = createDelayed(h, o, scope);
+               // }
+                if(o.single){
+                    h = createSingle(h, this, fn, scope);
+                }
+                //if(o.buffer){
+               //     h = createBuffered(h, o, scope);
+                //}
+                l.fireFn = h;
+                if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
+                    this.listeners.push(l);
+                }else{
+                    this.listeners = this.listeners.slice(0);
+                    this.listeners.push(l);
+                }
+            }
+        },
+
+        findListener : function(fn, scope){
+            scope = scope || this.obj;
+            var ls = this.listeners;
+            for(var i = 0, len = ls.length; i < len; i++){
+                var l = ls[i];
+                if(l.fn == fn && l.scope == scope){
+                    return i;
+                }
+            }
+            return -1;
+        },
+
+        isListening : function(fn, scope){
+            return this.findListener(fn, scope) != -1;
+        },
+
+        removeListener : function(fn, scope){
+            var index;
+            if((index = this.findListener(fn, scope)) != -1){
+                if(!this.firing){
+                    this.listeners.splice(index, 1);
+                }else{
+                    this.listeners = this.listeners.slice(0);
+                    this.listeners.splice(index, 1);
+                }
+                return true;
+            }
+            return false;
+        },
+
+        clearListeners : function(){
+            this.listeners = [];
+        },
+
+        fire : function(){
+            var ls = this.listeners, scope, len = ls.length;
+            if(len > 0){
+                this.firing = true;
+                var args = Array.prototype.slice.call(arguments, 0);
+                for(var i = 0; i < len; i++){
+                    var l = ls[i];
+                    if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
+                        this.firing = false;
+                        return false;
+                    }
+                }
+                this.firing = false;
+            }
+            return true;
+        }
+    }
+);
diff --git a/old-javascript/Options.js b/old-javascript/Options.js
new file mode 100644 (file)
index 0000000..ff81713
--- /dev/null
@@ -0,0 +1,193 @@
+//<script type="text/javascript">
+
+XObject = imports.XObject.XObject
+/**
+ * Options parsing is needed as GLib's built in GOptionGroup is not feasible to use in an introspected way at present.
+ * 
+ * usage :
+ * 
+ * o = new Options(
+ *    help_desription : 'Help about this',
+ *    options : [
+ *        { arg_short : 'a', arg_long: 'test', description : 'a test', flag_array: true , flag_boolean : false, arg_default: 'fred'}
+ *    ]
+ * );
+ * cfg = o.parse(Seed.argv);
+ * 
+ * Currently only supports simple parsing
+ * eg. --longarg test -b test
+ * 
+ * Does not support --aaaaa=bbbb
+ */
+Options  = XObject.define(
+    function (cfg) {
+        options = []; // default.
+        XObject.extend(this,cfg);
+        if (this.help_description.length) {
+            this.options.push({ arg_short : 'h', arg_long: 'help', description : 'Show Help', flag_boolean : true});
+            
+        }
+    },
+    Object,
+    {
+        /**
+         * @cfg {String} help_description what appears at the start of the help message.
+         */
+        help_description: '',
+        /**
+         * @cfg {Boolean} If extra arguments are allowed.
+         */
+        allow_extra : false,
+        /**
+         * @param {Object} Resulting key/value of data.
+         */
+        result : false,
+        /**
+         * @prop {Array} the arguments
+         */
+        args: false,
+        /**
+         * @prop {Array} extra the arguments that are not accounted for.
+         */
+        extra: false,
+        /**
+         * parse the argv
+         * usage: options.parse(Seed.argv)
+         */
+        parse: function (argv)
+        {
+            var _this = this;
+            this.result = {};
+            this.options.forEach(function(a) {
+                
+                if (typeof(a.arg_default) != 'undefined') {
+                    _this.result[a.arg_long] = a.arg_default;
+                    return;
+                }
+                
+                if (a.flag_boolean) {
+                    _this.result[a.arg_long] = false;
+                    return;
+                }
+                if (a.flag_array) {
+                    _this.result[a.arg_long] = [];
+                    return;
+                }
+                
+            })
+            
+            this.extra = {};
+            var args = Array.prototype.slice.call(Seed.argv);
+            args.shift(); //seed
+            args.shift(); //script..
+        
+            for(var i =0; i < args.length;i++) {
+                
+                var a= this.findArg(args[i]);
+                
+                if (!a) {
+                    if (!this.allow_extra) {
+                        throw {
+                            name: "ArgumentError", 
+                            message: "Unknown argument: " + args[i] 
+                        };
+                    }
+                    this.extra.push(args[i]);
+                }
+                
+                if (a.arg_long == 'help' ) {
+                    print("Help Message Requested");
+                    this.showHelp();
+                    Seed.quit();
+                    return;
+                }
+                
+                if (a.flag_boolean) {
+                    this.result[a.arg_long] = true;
+                    continue;
+                }
+                var next = args[i+1];
+                if (this.findArg(next)) {
+                    throw {
+                        name: "ArgumentError", 
+                        message: "Invalid argument sequence: " + args[i] + ' ' + next
+                    };
+                }
+                // type juggling -- fixme...
+                
+                if (a.flag_array) {
+                    this.result[a.arg_long].push(next);
+                    i++;
+                    continue;
+                }
+            
+                if (typeof(this.result[a.arg_long]) != 'undefined' && this.result[a.arg_long] != a.arg_default) {
+                    throw {
+                        name: "ArgumentError", 
+                        message: "Invalid argument duplicate: " + args[i] + ' ' + next
+                    };
+                }
+                
+                this.result[a.arg_long] = next;
+                i++;
+            }
+            // validate results..
+            this.options.forEach(function(a) {
+                if (typeof(a.arg_default) != 'undefined') {
+                    return;
+                }
+                if (a.flag_boolean) {
+                    return; 
+                }
+                if (typeof(_this.result[a.arg_long]) != 'undefined') {
+                    return;
+                }
+                _this.showHelp();
+                throw {
+                    name: "ArgumentError", 
+                    message: "Missing Argument: --" + a.arg_long
+                };
+            });
+            
+            
+            return this.result;
+        },
+            
+             
+        findArg : function(str)
+        {
+            var ret = false;
+            var type = str.substring(0,1) == '-' ? 'arg_short' : '';
+            type = str.substring(0,2) == '--' ? 'arg_long' : type;
+            if (type == '') {
+                return false; // not an arg..
+            }
+            var match = str.substring(type =='arg_long' ? 2 : 1);
+            
+            this.options.forEach(function(o) {
+                if (ret) {
+                    return; // no more parsing.
+                }
+                if (o[type] == match) {
+                    ret = o;
+                }
+                
+            });
+            return ret;
+            
+        },
+        
+        
+        showHelp: function()
+        {
+            print(this.help_description);
+            this.options.forEach(function(o) {
+                // fixme needs tidying up..
+                print('  --' + o.arg_long + '   (-' + o.arg_short + ')  ' + o.description);
+            });
+            
+                
+        }
+    }
+);
diff --git a/old-javascript/ProjectManager.js b/old-javascript/ProjectManager.js
new file mode 100755 (executable)
index 0000000..32cf44a
--- /dev/null
@@ -0,0 +1,198 @@
+//<Script type="text/javascript">
+Gio         = imports.gi.Gio;
+GLib        = imports.gi.GLib;
+
+
+console     = imports.console;
+XObject     = imports.XObject.XObject;
+Observable  = imports.Observable.Observable;
+File        = imports.File.File;
+/**
+ * 
+ * /home/alan/.BuilderConfig/*
+ * 
+ * 
+ */
+
+ProjectManager =  new Observable({
+    
+    events : {
+        'changed' : true
+    },
+    
+    
+    listeners : {
+        'changed' :  function() {
+            this.saveConfig();
+        }
+        
+    },
+    
+    palete : { }, 
+    projects : [],
+    filename : false,
+    
+    loadConfig : function ()
+    {
+        // we can not do this async.... 
+        this.dirname = GLib.get_home_dir() + '/.Builder'; 
+        
+        var dir = Gio.file_new_for_path(this.dirname);
+        if (!dir.query_exists()) {
+            dir.make_directory();
+            return;
+        }
+      
+        this.projects = [];
+        var files = File.list(this.dirname);
+        
+        
+        //print(files);Seed.quit();
+        for (var i =0 ; i < files.length;i++) {
+            var fn = files[i];
+             print(fn);
+            if (!fn.match(/\.json$/)) {
+                continue;
+            }
+            var str = File.read(this.dirname + '/' + fn);
+            if (!str || !str.length) {
+                print("EMPTY");
+                continue; // empty file.
+            }
+             
+            
+            var ar = JSON.parse(str); 
+            Seed.print(ar.xtype);
+            
+            // construct...
+            var cls = imports.Project[ar.xtype][ar.xtype];
+            this.projects.push( new cls(ar));
+            
+            
+            
+            
+            
+             
+        }
+//        print(JSON.stringify(this.projects.length));Seed.quit();
+   
+        this.projects.sort(function(a,b) {
+            if (a.getName() == b.getName()) {
+                return 0;
+            }
+            return a.getName() > b.getName() ? 1 : -1;
+            
+            
+        });
+   
+        
+       
+        
+        
+        
+        
+        
+        
+    },
+    
+    
+    saveConfig : function()
+    {
+        var _this = this;
+        this.projects.forEach( function(p) {
+            
+            if (!p.fn) {
+                // make the filename..
+                var t = new GLib.TimeVal();
+                GLib.get_current_time(t);
+                var str = '' + t.tv_sec + ':' + t.tv_usec;
+                Seed.print(str);
+                p.fn = GLib.compute_checksum_for_string(GLib.ChecksumType.MD5, str, str.length);
+                Seed.print(p.fn);
+
+            }
+            var  s =  p.toJSON();
+            File.write(_this.dirname + '/' + p.fn + '.json', s);
+           
+           
+        });
+        
+        
+        
+        
+    },
+    update : function(proj) {
+        
+        //Seed.print(JSON.stringify(proj));
+        var found = false;
+        this.projects.forEach( function(p) {
+            if (proj == p) {
+                found = true;
+                return true;
+            }
+        });
+        if (found) {
+            this.fireEvent('changed', this);
+            return proj;
+            return;
+        }
+        var cls = imports.Project[proj.xtype][proj.xtype];
+        var pr = new cls(proj);
+        this.projects.push(pr );
+        this.fireEvent('changed', this);
+        return pr;
+        
+        
+    },
+    
+    deleteProject : function (fn)
+    {
+        var newplist = [];
+        var _this = this;
+        this.projects.forEach(function(p) {
+            if (p.fn != fn) {
+                newplist.push(p);
+                return;
+            }
+            var file = _this.dirname + '/' + p.fn + '.json';
+            if (File.exists(file)) {
+                File.remove(file);
+            }
+            
+        });
+        this.projects = newplist;
+        this.fireEvent('changed', this);
+    },
+    
+    
+    getByFn : function (fn) {
+        var  ret = false;
+        this.projects.forEach(function(p) {
+            if (p.fn == fn) {
+                ret = p;
+                return true;
+            }
+        });
+        return ret;
+        
+    },
+    getPalete: function(type) {
+        if (typeof(ProjectManager.palete[type]) != 'undefined') {
+            //print ("ALREADY GOT " + type);
+            return ProjectManager.palete[type];
+        }
+        var cls = imports.Palete[type][type];
+        
+        ProjectManager.palete[type] =  new cls();
+        print (typeof(ProjectManager.palete[type]));
+        return ProjectManager.palete[type];
+    }
+
+    
+    
+});
+
+
+
diff --git a/old-javascript/Spawn.js b/old-javascript/Spawn.js
new file mode 100644 (file)
index 0000000..7181e0f
--- /dev/null
@@ -0,0 +1,439 @@
+///<script type="text/javascript">
+
+var Gio      = imports.gi.Gio;
+var GLib      = imports.gi.GLib;
+
+
+/**
+* @namespace Spawn
+* 
+* Library to wrap GLib.spawn_async_with_pipes
+* 
+* usage:
+* 
+* Spawn = import.Spawn;
+* 
+* simple version..
+* var output = Spawn.run({
+*   cwd : '/home',
+*   args : [ 'ls', '-l' ],
+*   env : [], // optional
+*   listeners : {
+        output : function (line) { Seed.print(line); },
+*       stderr :  function (line) {Seed.print("ERROR" + line);  },
+*       input : function() { return 'xxx' },
+*   }
+*  });
+*
+*
+*
+
+*
+*
+*  CRITICAL - needs this change to gir in GLib-2.0.gir g_spawn_async_with_pipes
+*  Fixed in Ubuntu 12.10
+    <parameter name="argv" transfer-ownership="none">
+         <array c:type="gchar**">
+            <type name="utf8"/>
+          </array>
+        </parameter>
+        <parameter name="envp" transfer-ownership="none" allow-none="1">
+          <array c:type="gchar**">
+            <type name="utf8"/>
+          </array>
+        </parameter>
+*
+*  ALSO in GLib-2.0.gir
+
+<method name="read_line"
+              c:identifier="g_io_channel_read_line"
+              throws="1">
+        <return-value transfer-ownership="none">
+          <type name="IOStatus" c:type="GIOStatus"/>
+        </return-value>
+        <parameters>
+          <parameter name="str_return" transfer-ownership="full" direction="out">
+            <type name="utf8" c:type="gchar**"/>
+          </parameter>
+          <parameter name="length" transfer-ownership="none" direction="out">
+            <type name="gsize" c:type="gsize*"/>
+          </parameter>
+          <parameter name="terminator_pos" transfer-ownership="none"  direction="out">
+            <type name="gsize" c:type="gsize*"/>
+          </parameter>
+        </parameters>
+      </method>
+*
+* run g-ir-compile -o /usr/lib/girepostitory-1.0/GLib-2.0.typelib GLib-2.0.gir
+*
+* 
+*/
+
+
+/**
+ * @class Spawn
+ * @param cfg {Object} settings - see properties.
+ * 
+ * @arg cwd {String}            working directory. (defaults to home directory)
+ * @arg args {Array}            arguments eg. [ 'ls', '-l' ]
+ * @arg listeners {Object} (optional) handlers for output, stderr, input
+ *     stderr/output both receive output line as argument
+ *     input should return any standard input
+ *     finish recieves result as argument.
+ * @arg env {Array}             enviroment eg. [ 'GITDIR=/home/test' ]
+ * @arg async {Boolean} (optional)return instantly, or wait for exit. (default no)
+ * @arg exceptions {Boolean}    throw exception on failure (default no)
+ * @arg debug {Boolean}    print out what's going on.. (default no)
+ * 
+ */
+function Spawn(cfg) {
+    for(var i in cfg) {
+        this[i] = cfg[i];
+    }
+    // set defaults?
+    this.listeners = this.listeners || {};
+    this.cwd =  this.cwd || GLib.get_home_dir();
+    if (!this.args || !this.args.length) {
+        throw "No arguments";
+    }
+    
+}
+
+
+Spawn.prototype = {
+    
+    ctx : false, // the mainloop ctx.
+    listeners : false,
+    async : false,
+    env : null,
+    cwd: false,
+    args: false,
+    exceptions : false,
+    debug : false,
+    /**
+     * @property output {String} resulting output
+     */
+    output  : '',
+    /**
+     * @property stderr {String} resulting output from stderr
+     */
+    stderr  : '',
+     /**
+     * @property result {Number} execution result.
+     */
+    result: 0,
+    /**
+     * @property pid {Number} pid of child process (of false if it's not running)
+     */
+    pid : false,
+    /**
+     * @property in_ch {GLib.IOChannel} input io channel
+     */
+    in_ch : false,
+    /**
+     * @property out_ch {GLib.IOChannel} output io channel
+     */
+    out_ch : false,
+    /**
+     * @property err_ch {GLib.IOChannel} stderr io channel
+     */
+    err_ch : false,
+    /**
+     * 
+     * @method run
+     * Run the configured command.
+     * result is applied to object properties (eg. 'output' or 'stderr')
+     * @returns {Object} self.
+     */
+    run : function()
+    {
+        
+        var _this = this;
+        
+        var err_src = false;
+        var out_src = false;
+        var ret = {};
+        
+        if (this.debug) {
+            print("cd " + this.cwd +";" + this.args.join(" "));
+        }
+        
+        var gret = GLib.spawn_async_with_pipes(this.cwd, this.args, this.env, 
+            GLib.SpawnFlags.DO_NOT_REAP_CHILD + GLib.SpawnFlags.SEARCH_PATH , 
+            null, null, ret);
+        
+               var isSeed = true;
+               if (typeof(Seed) == 'undefined') {
+                       ret = {
+                               child_pid : gret[1],
+                               standard_input : gret[2],
+                           standard_output: gret[3], 
+                           standard_error: gret[4]
+                       };
+                       isSeed = false; 
+               }
+               
+       //print(JSON.stringify(gret));    
+        this.pid = ret.child_pid;
+        
+        if (this.debug) {
+            print("PID: " + this.pid);
+        }
+         
+        
+       
+        GLib.child_watch_add(GLib.PRIORITY_DEFAULT, this.pid, function(pid, result) {
+            _this.result = result;
+            if (_this.debug) {
+                print("child_watch_add : result: " + result);
+            }
+            _this.read(_this.out_ch);
+            _this.read(_this.err_ch);
+            
+                       
+            GLib.spawn_close_pid(_this.pid);
+            _this.pid = false;
+            if (_this.ctx) {
+                _this.ctx.quit();
+            }
+            tidyup();
+           //print("DONE TIDYUP");
+            if (_this.listeners.finish) {
+                _this.listeners.finish.call(this, _this.result);
+            }
+        });
+        
+        function tidyup()
+        {
+            if (_this.pid) {
+                GLib.spawn_close_pid(_this.pid); // hopefully kills it..
+                _this.pid = false;
+            }
+            if (_this.in_ch)  _this.in_ch.close();
+            if (_this.out_ch)  _this.out_ch.close();
+            if (_this.err_ch)  _this.err_ch.close();
+            // blank out channels
+            _this.in_ch = false;
+            _this.err_ch = false;
+            _this.out_ch = false;
+            // rmeove listeners !! important otherwise we kill the CPU
+            if (err_src !== false) GLib.source_remove(err_src);
+            if (out_src !== false) GLib.source_remove(out_src);
+            err_src = false;
+            out_src = false;
+            
+        }
+        
+        
+        this.in_ch = new GLib.IOChannel.unix_new(ret.standard_input);
+        this.out_ch = new GLib.IOChannel.unix_new(ret.standard_output);
+        this.err_ch = new GLib.IOChannel.unix_new(ret.standard_error);
+        
+        // make everything non-blocking!
+        
+        
+      
+                       // using NONBLOCKING only works if io_add_watch
+          //returns true/false in right conditions
+          this.in_ch.set_flags (GLib.IOFlags.NONBLOCK);
+          this.out_ch.set_flags (GLib.IOFlags.NONBLOCK);
+          this.err_ch.set_flags (GLib.IOFlags.NONBLOCK);
+                       
+
+      
+        // add handlers for output and stderr.
+        out_src= GLib.io_add_watch(this.out_ch, GLib.PRIORITY_DEFAULT, 
+            GLib.IOCondition.OUT + GLib.IOCondition.IN  + GLib.IOCondition.PRI +  GLib.IOCondition.HUP +  GLib.IOCondition.ERR,
+            function() {
+                
+               return  _this.read(_this.out_ch);
+            
+            }
+        );
+        err_src= GLib.io_add_watch(this.err_ch, GLib.PRIORITY_DEFAULT, 
+            GLib.IOCondition.ERR + GLib.IOCondition.IN + GLib.IOCondition.PRI + GLib.IOCondition.OUT +  GLib.IOCondition.HUP, 
+            function()
+        {
+            return _this.read(_this.err_ch);
+             
+        });
+        
+      
+        
+        // call input.. 
+        if (this.pid !== false) {
+            // child can exit before 1we get this far..
+            if (this.listeners.input) {
+                               print("Trying to call listeners");
+                try {
+                    this.write(this.listeners.input.call(this));
+                    // this probably needs to be a bit smarter...
+                   //but... let's close input now..
+                   this.in_ch.close();
+                   _this.in_ch = false;
+                  
+                   
+                   
+                   
+                   
+                } catch (e) {
+                    tidyup();
+                    throw e;
+                    
+                }
+                
+            }
+        }
+        // async - if running - return..
+        if (this.async && this.pid) {
+            return this;
+        }
+         
+        // start mainloop if not async..
+        
+        if (this.pid !== false) {
+            if (this.debug) {
+                print("starting main loop");
+            }
+           
+            this.ctx = isSeed ? new GLib.MainLoop.c_new (null, false) : GLib.MainLoop.new (null, false);;
+            this.ctx.run(false); // wait fore exit?
+            
+            //print("main_loop done!");
+        } else {
+            tidyup(); // tidyup get's called in main loop. 
+        }
+        
+        if (this.exceptions && this.result != 0) {
+            print(this.stderr);
+            print(this.output);
+            this.toString = function() { return this.stderr; };
+            throw this; // we throw self...
+        }
+        
+        // finally throw, or return self..
+        
+        return this;
+    
+    },
+    /**
+     * write to stdin of process
+     * @arg str {String} string to write to stdin of process
+     * @returns GLib.IOStatus (0 == error, 1= NORMAL)
+     */
+    write : function(str) // write a line to 
+    {
+        if (!this.in_ch) {
+            return 0; // input is closed
+        }
+        //print("write: " + str);
+        // NEEDS GIR FIX! for return value.. let's ignore for the time being..
+        //var ret = {};
+            //var res = this.in_ch.write_chars(str, str.length, ret);
+        var res = this.in_ch.write_chars(str, str.length);
+        
+        //print("write_char retunred:" + JSON.stringify(res) +  ' ' +JSON.stringify(ret)  );
+        
+        if (res != GLib.IOStatus.NORMAL) {
+            throw "Write failed";
+        }
+        //return ret.value;
+        return str.length;
+        
+    },
+    
+    /**
+     * read from pipe and call appropriate listerner and add to output or stderr string.
+     * @arg giochannel to read from.
+     * @returns none
+     */
+    read: function(ch) 
+    {
+        var prop = ch == this.out_ch ? 'output' : 'stderr';
+       // print("prop: " + prop);
+        var _this = this;
+        
+       
+        //print(JSON.stringify(ch, null,4));
+        while (true) {
+            var x =   {};
+            var status = ch.read_line( x);
+            // print('status: '  +JSON.stringify(status));
+            // print(JSON.stringify(x));
+             switch(status) {
+                case GLib.IOStatus.NORMAL:
+               
+                    //write(fn, x.str);
+                    if (this.listeners[prop]) {
+                        this.listeners[prop].call(this, x.str_return);
+                    }
+                    _this[prop] += x.str_return;
+                    if (_this.debug) {
+                        print(prop + ':' + x.str_return.replace(/\n/, ''));
+                    }
+                    if (this.async) {
+                        try {
+                            if (imports.gi.Gtk.events_pending()) {
+                                imports.gi.Gtk.main_iteration();
+                            }
+                        } catch(e) {
+                            
+                        }
+                    }
+                    
+                    //this.ctx.iteration(true);
+                   continue;
+                case GLib.IOStatus.AGAIN:
+                   //print("Should be called again.. waiting for more data..");
+                   return true;
+                    break;
+                case GLib.IOStatus.ERROR:    
+                case GLib.IOStatus.EOF:
+                   return false;
+                   break;
+                
+            }
+            break;
+        }
+       
+        //print("RETURNING");
+         return false; // allow it to be called again..
+    }
+    
+};
+/**
+ * @function run 
+ * 
+ * simple run a process - returns result, or throws stderr result...
+ * @param cfg {Object}  see spawn
+ * @return {string} stdout output.
+ */
+function run(cfg) {
+    cfg.exceptions = true;
+    cfg.async = false;
+    var s = new Spawn(cfg);
+    var ret = s.run();
+    return s.output;
+}
+ /*
+// test
+try { 
+    Seed.print(run({
+        args: ['ls', '/tmp'],
+        debug : true
+    }));
+} catch (e) { print(JSON.stringify(e)); }
+var secs = (new Date()).getSeconds() 
+
+try {      
+Seed.print(run({
+    args: ['/bin/touch', '/tmp/spawntest-' + secs ],
+    debug : true
+}));
+} catch (e) { print( 'Error: ' + JSON.stringify(e)); }
+
+ */
diff --git a/old-javascript/String.js b/old-javascript/String.js
new file mode 100644 (file)
index 0000000..37ff1d4
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+// usage:
+//imports['String.js'].load(String);
+if (imports) {
+    load = false; // declare global for gnome langs.
+}
+(function () {
+    
+
+    var string =  {
+    
+        /** @scope String */
+        
+        /**
+         * Escapes the passed string for ' and \
+         * @param {String} string The string to escape
+         * @return {String} The escaped string
+         * @static
+         */
+        escape : function(string) {
+            return string.replace(/('|\\)/g, "\\$1");
+        },
+
+        /**
+         * Pads the left side of a string with a specified character.  This is especially useful
+         * for normalizing number and date strings.  Example usage:
+         * <pre><code>
+    var s = String.leftPad('123', 5, '0');
+    // s now contains the string: '00123'
+    </code></pre>
+         * @param {String} string The original string
+         * @param {Number} size The total length of the output string
+         * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
+         * @return {String} The padded string
+         * @static
+         */
+        leftPad : function (val, size, ch) {
+            var result = new String(val);
+            if(ch === null || ch === undefined || ch === '') {
+                ch = " ";
+            }
+            while (result.length < size) {
+                result = ch + result;
+            }
+            return result;
+        },
+         /**
+         * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
+         * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
+         * <pre><code>
+    var cls = 'my-class', text = 'Some text';
+    var s = String.format('<div class="{0}">{1}</div>', cls, text);
+    // s now contains the string: '<div class="my-class">Some text</div>'
+    </code></pre>
+         * @p aram {String} string The tokenized string to be formatted
+         * @param {String} value1 The value to replace token {0}
+         * @param {String} value2 Etc...
+         * @return {String} The formatted string
+         * @static
+         */
+        format : function(format){
+            var args = Array.prototype.slice.call(arguments, 1);
+            return format.replace(/\{(\d+)\}/g, function(m, i){
+                return args[i];
+            });
+        },
+        
+
+        /**
+         * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
+         * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
+         * <pre><code>
+    var cls = 'my-class', text = 'Some text';
+    var s = String.format('<div class="{0}">{1}</div>', cls, text);
+    // s now contains the string: '<div class="my-class">Some text</div>'
+    </code></pre>
+         * @param {String} string The tokenized string to be formatted
+         * @param {String} value1 The value to replace token {0}
+         * @param {String} value2 Etc...
+         * @return {String} The formatted string, all arguments will be htmlEncoded.
+         * @static
+         */
+        htmlFormat : function(format){
+            var args = Array.prototype.slice.call(arguments, 1);
+            return format.replace(/\{(\d+)\}/g, function(m, i){
+                return this.htmlEncode(args[i]);
+            });
+        },
+        
+        /**
+         * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
+         * @param {String} value The string to encode
+         * @return {String} The encoded text
+         */
+        htmlEncode : function(value){
+            return !value ? value : 
+                String(value).replace(/&/g, "&amp;"
+                    ).replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
+        }
+        
+        
+    };
+
+    /**
+     * Utility function that allows you to easily switch a string between two alternating values.  The passed value
+     * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
+     * they are already different, the first value passed in is returned.  Note that this method returns the new value
+     * but does not change the current string.
+     * <pre><code>
+    // alternate sort directions
+    sort = sort.toggle('ASC', 'DESC');
+
+    // instead of conditional logic:
+    sort = (sort == 'ASC' ? 'DESC' : 'ASC');
+    </code></pre>
+     * @param {String} value The value to compare to the current string
+     * @param {String} other The new value to use if the string already equals the first value passed in
+     * @return {String} The new value
+     */
+     
+    var stringPrototype = {
+        toggle : function(value, other){
+            return this == value ? other : value;
+        },
+        
+        trim : function (toTrim) {
+            var out = this.ltrim(toTrim);
+            out = out.rtrim(toTrim);
+            return out;
+        },
+        
+        ltrim : function (toTrim) {
+            if (this.substr(0, toTrim.length) == toTrim) {
+                return this.slice(toTrim.length);
+            }
+            
+            return this;
+        },
+        
+        rtrim : function (toTrim) {
+            if (this.substr(this.length - toTrim.length) == toTrim) {
+                return this.slice(0, this.length - toTrim.length);
+            }
+       
+            return this;
+        }
+    };
+    
+    
+    
+    if (imports) {
+        load = function(ar) {
+            String = ar;
+            imports.lang.copyPropertiesNoOverwrite(string,ar);
+            imports.lang.copyPropertiesNoOverwrite(stringPrototype,ar.prototype);
+        };
+    } else {
+        // non imports version.
+        for(i in stringPrototype) {
+            if (!String.prototype[i]) {
+                String.prototype[i] = stringPrototype[i];
+            }
+        }
+        for(i in string) {
+            if (!String[i]) {
+                String[i] = string[i];
+            }
+        }
+    }
+})();
\ No newline at end of file
diff --git a/old-javascript/XObject.js b/old-javascript/XObject.js
new file mode 100644 (file)
index 0000000..872ec44
--- /dev/null
@@ -0,0 +1,834 @@
+//<script type="text/javascript">
+GIRepository = imports.gi.GIRepository;
+GObject = imports.gi.GObject;
+/**
+ * XObject
+ * Yet another attempt to create a usable object construction library for seed..
+ * 
+ * Why is this useful?
+ * A) It turns rather messy code into a tree structure, making it easy to find code relating to 
+ *    an interface element
+ * B) In theory it should be gjs/Seed compatible..
+ * C) It provides getElementById style lookups for elements.
+ * D) It provides classic OO constructors for Javascript (extend/define)
+ * E) It does not modify any buildin prototypes.. 
+ *
+ * Extend this.. to use it's wonderful features..
+ * 
+ * normal usage:
+ * XObject = imports.XObject.XObject;
+ * 
+ * Xyz = new XObject({
+ *     xtype: Gtk.Window,
+ *     id : 'window',
+ *     items : [
+ *     
+ *     ]
+ *  });
+ *  Xyz.init(); // create and show.
+ * 
+ * 
+ * use XObject.debug = 1 to turn on debugging
+ * 
+ * If XObjectBase/[xns]/[xtype].js exists, it will use this to override properties..
+ * 
+ * 
+ * He's some questions.
+ * - should we have a special property to use as the constructor / gobject.properties rather
+ *   than sending all basic types to this?
+ * 
+ * @cfg xtype {String|Function} constructor or string.
+ * @cfg id {String}  (optional) id for registry
+ * @cfg xns {String|Object}   (optional) namespace eg. Gtk or 'Gtk' - used with xtype.
+ * @cfg items {Array}   (optional) list of child elements which will be constructed.. using XObject
+ * @cfg listeners {Object}   (optional) map Gobject signals to functions
+ * @cfg pack {Function|String|Array}   (optional) how this object gets added to it's parent
+ * @cfg el {Object}   (optional) premade GObject
+ *  
+ */
+
+function XObject (cfg) {
+    // first apply cfg if set.
+      //print("new XOBJECT!!!");
+      
+    //print ("XObject ctr");
+      
+    this.config = {}; // used to initialize GObject
+    
+    this.cfg = XObject.extend({}, cfg); // used to store original configuration.. for referencing..
+    
+    // used by baseobject to create fake child elements on init..
+    if (cfg.el) {
+        this.el = cfg.el;
+    }
+    
+    // we could use this to determine if 
+    // we are actually inside a inherited class...
+    // as define() should actually set this up..
+    
+    if (!this.constructor) {
+        
+        this.constructor = XObject;
+        var base = XObject.baseXObject(cfg);
+        if (base) {
+            XObject.extend(this,  base.prototype);
+        }
+        
+    }
+    
+    // copy down all elements into self..
+    // make an extra copy in this.config?? - which is the one used in the constructor later
+    
+    for (var i in cfg) {
+        this[i] = cfg[i];
+        if (typeof(cfg[i]) == 'function') { // do we skip objects.
+            continue;
+        }
+        // these properties are not copied to cfg.
+        if (    i == 'pack' ||
+                i == 'items' ||
+                i == 'id' ||
+                i == 'xtype' ||
+                i == 'xdebug' ||
+                i == 'xns') {
+            continue;
+        }
+        
+        
+        this.config[i] = cfg[i];
+    }
+    
+    
+    this.items = this.items || [];
+    
+    
+    // pack can be false!
+    if (typeof(this.pack) == 'undefined') {
+        
+        this.pack = [ 'add' ]
+        /*
+        var Gtk  = imports.gi.Gtk;
+        switch (true) {
+            // any others!!
+            case (this.xtype == Gtk.MenuItem):  this.pack = [ 'append' ]; break;
+            
+        }
+        */
+        
+    }
+    
+    // interesting question should we call constructor on items here...
+    // as the real work is done in init anyway..
+    var _this= this;
+    var items = []
+    for(var i = 0; i < this.items.length;i++) {
+       items.push(this.items[i]);
+    }
+
+
+
+    this.items = [];
+    // create XObject for all the children.
+    for(var i = 0; i < items.length;i++) {
+    
+        var base = XObject.baseXObject(items[i]);
+        base = base || XObject;
+        var item = (items[i].constructor == XObject) ? items[i] : new base(items[i]);
+        item.parent = _this;
+        _this.items.push(item);
+        //_this.addItem(i);
+    };
+     
+    
+}
+
+
+
+XObject.prototype = {
+    /**
+     * @property el {GObject} the Gtk / etc. element.
+     */
+    el : false, 
+    /*
+     * @property items {Array} list of sub elements
+     */
+    /**
+     * @property parent {XObject} parent Element
+     */
+     
+     /**
+     * @property config {Object} the construction configuration.
+     */
+     /**
+      * @method init
+      * Initializes the Element (el) hooks up all the listeners
+      * and packs the children.
+      * you can override this, in child objects, then 
+      * do this to do thi initaliztion.
+      * 
+      * XObject.prototype.init.call(this); 
+      * 
+      */ 
+    init : function(parent)
+    {
+         
+       // var items = [];
+        //this.items.forEach(function(i) {
+        //    items.push(i);
+        //});
+        // remove items.
+        this.listeners = this.listeners || {}; 
+        //this.items = [];
+         
+        // do we need to call 'beforeInit here?'
+         
+        // handle include?
+        //if ((this.xtype == 'Include')) {
+        //    o = this.pre_registry[cls];
+        //}
+        var isSeed = typeof(Seed) != 'undefined';
+         
+        // xtype= Gtk.Menu ?? what about c_new stuff?
+        XObject.log("init: ID:"+ this.id +" typeof(xtype): "  + typeof(this.xtype));
+        if (!this.el && typeof(this.xtype) == 'function') {
+            XObject.log("func?"  + XObject.keys(this.config).join(','));
+            this.el = this.xtype(this.config);
+           
+        }
+        if (!this.el && typeof(this.xtype) == 'object') {
+            XObject.log("obj?"  + XObject.keys(this.config).join(','));
+            this.el = new (this.xtype)(this.config);
+      
+        }
+        //print(this.el);
+        if (!this.el && this.xns) {
+            
+            var NS = imports.gi[this.xns];
+            if (!NS) {
+                XObject.error('Invalid xns: ' + this.xns, true);
+            }
+            constructor = NS[this.xtype];
+            if (!constructor) {
+                XObject.error('Invalid xtype: ' + this.xns + '.' + this.xtype);
+            }
+            this.el  =   isSeed ? new constructor(this.config) : new constructor();
+            
+        }
+        XObject.log("init: ID:"+ this.id +" typeof(el):" + this.el);
+        
+        // always overlay props..
+        // check for 'write' on object..
+        /*
+        if (typeof(XObject.writeablePropsCache[this.xtype.type]) == 'undefined') {
+                
+            var gi = GIRepository.IRepository.get_default();
+            var ty = gi.find_by_gtype(this.xtype.type);
+            var write = [];
+            for (var i =0; i < GIRepository.object_info_get_n_properties(ty);i++) {
+                var p =   GIRepository.object_info_get_property(ty,i);
+                if (GIRepository.property_info_get_flags(p) & 2) {
+                    write.push(GIRepository.base_info_get_name(p));
+                }
+            }
+            XObject.writeablePropsCache[this.xtype.type] = write;
+            print(write.join(", "));
+        }
+        
+        */
+        
+         
+        for (var i in this.config) {
+            if (i == 'type') { // problem with Gtk.Window... - not decided on a better way to handle this.
+                continue;
+            }
+            if (i == 'buttons') { // problem with Gtk.MessageDialog..
+                continue;
+            }
+            if (i[0] == '.') { // parent? - 
+                continue;
+            }
+            this.el[i] = this.config[i];
+        }
+        
+        // register it!
+        //if (o.xnsid  && o.id) {
+         //   XObject.registry = XObject.registry || { };
+         //   XObject.registry[o.xnsid] = XObject.registry[o.xnsid] || {}; 
+         //   XObject.registry[o.xnsid][o.id] = this;
+        //}
+        
+        var type = this.xtype.type ? GObject.type_name(this.xtype.type) : '';
+        XObject.log("add children to " + type);
+        
+        var _this=this;
+        for (var i = 0; i < this.items.length;i++) { 
+            _this.addItem(this.items[i],i);
+        }
+            
+        
+        for (var i in this.listeners) {
+            this.addListener(i, this.listeners[i]);
+        }
+        
+        this.init = XObject.emptyFn;
+           
+        // delete this.listeners ?
+        // do again so child props work!
+       
+        // do we need to call 'init here?'
+    },
+      
+     
+     /**
+      * Adds an item to the object using a new XObject
+      * uses pack property to determine how to add it.
+      * @arg cfg {Object} same as XObject constructor.
+      */
+    addItem : function(item, pos) 
+    {
+        
+        if (typeof(item) == 'undefined') {
+            XObject.error("Invalid Item added to this!");
+            imports.console.dump(this.cfg);
+            Seed.quit();
+        }
+        // what about extended items!?!?!?
+       
+        item.init(this);
+        //print("CTR:PROTO:" + ( item.id ? item.id : '??'));
+       // print("addItem - call init [" + item.pack.join(',') + ']');
+        if (!item.el) {
+            XObject.error("NO EL!");
+            imports.console.dump(item);
+            Seed.quit();
+        }
+        XObject.log(XObject.type(this.xtype) + ":pack=" + item.pack);
+        
+        if (item.pack===false) {  // no packing.. various items have this ..
+            return;
+        }
+        
+        if (typeof(item.pack) == 'function') { // pack is a function..
+            // parent, child
+            item.pack.apply(item, [ this , item  ]);
+            item.parent = this;
+            return;
+        }
+        
+        // pack =  'add,x,y'
+        var args = [];
+        var pack_m  = false;
+        if (typeof(item.pack) == 'string') {
+             
+            item.pack.split(',').forEach(function(e, i) {
+                
+                if (e == 'false') { args.push( false); return; }
+                if (e == 'true') {  args.push( true);  return; }
+                if (!isNaN(parseInt(e))) { args.push( parseInt(e)); return; }
+                args.push(e);
+            });
+            //print(args.join(","));
+            
+            pack_m = args.shift();
+        } else {
+            pack_m = item.pack.shift();
+            args = item.pack;
+        }
+        
+        // handle error.
+        if (pack_m && typeof(this.el[pack_m]) == 'undefined') {
+            
+            throw {
+                name: "ArgumentError", 
+                message : 'pack method not available : ' + this.id + " : " + this.xtype + '.' +  pack_m + " ADDING " + item.el
+                    
+            }
+           
+            return;
+        }
+        
+        
+        // finally call the pack method 
+        //Seed.print('Pack ' + this.el + '.'+ pack_m + '(' + item.el + ')');
+        
+        args.unshift(item.el);
+        
+         
+        
+        
+        
+        XObject.log(pack_m + '[' + args.join(',') +']');
+        //Seed.print('args: ' + args.length);
+        if (pack_m) {
+            this.el[pack_m].apply(this.el, args);
+        }
+        
+       
+        
+    },
+    /**
+    * Connects a method to a signal. (gjs/Seed aware)
+    * 
+    * @param {String} sig  name of signal
+    * @param {Function} fn  handler.
+    */
+    addListener  : function(sig, fn) 
+    {
+        XObject.log("Add signal " + sig);
+        fn.id= sig;
+        var _li = XObject.createDelegate(fn,this);
+        // private listeners that are not copied to GTk.
+        
+        if (typeof(Seed) != 'undefined') {
+          //   Seed.print(typeof(_li));
+            this.el.signal[sig].connect(_li);
+        } else {
+            this.el.connect( sig, _li);
+        }
+             
+        
+    },
+     /**
+      * @method get
+      * Finds an object in the child elements using xid of object.
+      * prefix with '.' to look up the tree.. 
+      * prefix with multiple '..' to look further up..
+      * prefix with '/' to look from the top, eg. '^LeftTree.model'
+      * 
+      * @param {String} name name of signal
+      * @return  {XObject|false} the object if found.
+      */
+    get : function(xid)
+    {
+        XObject.log("SEARCH FOR " + xid + " in " + this.id);
+        return this.getBySearch(xid);
+    },
+    getBySearch : function(xid) {
+        
+        var ret=  false;
+        var oid = '' + xid;
+        if (!xid.length) {
+            throw {
+                name: "ArgumentError", 
+                message : "ID not found : empty id"
+            }
+        }
+        
+        if (xid[0] == '.') {
+            return this.parent.getBySearch(xid.substring(1));
+        }
+        if (xid[0] == '/') {
+            
+            if (typeof(XObject.cache[xid]) != 'undefined') {
+                return XObject.cache[xid]; 
+            }
+            if (xid.indexOf('.') > -1) {
+                
+                var child = xid.split('.');
+                var nxid = child.shift();
+                    
+                child = child.join('.');
+                if (typeof(XObject.cache[nxid]) != 'undefined') {
+                    return XObject.cache[nxid].getBySearch(child);
+                }
+                
+                
+            }
+            var e = this;
+            while (e.parent) {
+                e = e.parent;
+            }
+            
+            try {
+                ret = e.getBySearch(xid.substring(1));
+            } catch (ex) { }
+            
+            if (!ret) {
+                throw {
+                    name: "ArgumentError", 
+                    message : "ID not found : " + oid
+                }
+            }
+            XObject.cache[xid] = ret;
+            return XObject.cache[xid];
+        }
+        var child = false;
+        
+        if (xid.indexOf('.') > -1) {
+            child = xid.split('.');
+            xid = child.shift();
+            
+            child = child.join('.');
+            
+        }
+        if (xid == this.id) {
+            try {
+                return child === false ? this : this.getBySearch(child);
+            } catch (ex) {
+                throw {
+                    name: "ArgumentError", 
+                    message : "ID not found : " + oid
+                }
+            }
+            
+        }
+        
+        
+        this.items.forEach(function(ch) {
+            if (ret) {
+                return;
+            }
+            if (ch.id == xid) {
+                ret = ch;
+            }
+        })
+        if (ret) {
+            try {
+                return child === false ? ret : ret.getBySearch(child);
+            } catch (ex) {
+                throw {
+                    name: "ArgumentError", 
+                    message : "ID not found : " + oid
+                }
+            }
+            
+        }
+        // iterate children.
+        var _this = this;
+        this.items.forEach(function(ch) {
+            if (ret) {
+                return;
+            }
+            if (!ch.get) {
+                XObject.error("invalid item...");
+                imports.console.dump(_this);
+                Seed.quit();
+            }
+            try {
+                ret = ch.getBySearch(xid);
+            } catch (ex) { }
+            
+            
+        });
+        if (!ret) {
+            throw {
+                name: "ArgumentError", 
+                message : "ID not found : " + oid
+            }
+        }
+        try {
+            return child === false ? ret : ret.getBySearch(child);
+        } catch (ex) {
+            throw {
+                name: "ArgumentError", 
+                message : "ID not found : " + oid
+            }
+        }
+    }
+      
+      
+} 
+         
+     
+/**
+ * Copies all the properties of config to obj.
+ *
+ * Pretty much the same as JQuery/Prototype.. or Roo.apply
+ * @param {Object} obj The receiver of the properties
+ * @param {Object} config The source of the properties
+ * @param {Object} defaults A different object that will also be applied for default values
+ * @return {Object} returns obj
+ * @member XObject extend
+ */
+
+
+XObject.extend = function(o, c, defaults){
+    if(defaults){
+        // no "this" reference for friendly out of scope calls
+        XObject.extend(o, defaults);
+    }
+    if(o && c && typeof c == 'object'){
+        for(var p in c){
+            o[p] = c[p];
+        }
+    }
+    return o;
+};
+
+XObject.extend(XObject,
+{
+     
+    /**
+     * @property {Boolean} debug XObject  debugging.  - set to true to debug.
+     * 
+     */
+    debug : true,
+    /**
+     * @property {Object} cache - cache of object ids
+     * 
+     */
+    cache: { },
+    /**
+     * Empty function
+     * 
+     */
+    emptyFn : function () { },
+      
+      
+      
+    /**
+     * Debug Logging
+     * @param {String|Object} output String to print.
+     */
+    log : function(output)
+    {
+        if (!this.debug) {
+            return;
+        }
+        print("LOG:" + output);  
+    },
+     
+    /**
+     * Error Logging
+     * @param {String|Object} output String to print.
+     */
+    error : function(output)
+    {
+        print("ERROR: " + output);  
+    },
+    /**
+     * fatal error
+     * @param {String|Object} output String to print.
+     */
+    fatal : function(output)
+    {
+        
+        throw {
+                name: "ArgumentError", 
+                message : output
+                    
+            }
+    },
+   
+    /**
+     * Copies all the properties of config to obj, if the do not exist.
+     * @param {Object} obj The receiver of the properties
+     * @param {Object} config The source of the properties
+     * @return {Object} returns obj
+     * @member Object extendIf
+     */
+
+
+    extendIf : function(o, c)
+    {
+
+        if(!o || !c || typeof c != 'object'){
+            return o;
+        }
+        for(var p in c){
+            if (typeof(o[p]) != 'undefined') {
+                continue;
+            }
+            o[p] = c[p];
+        }
+        return o;
+    },
+
+    /**
+     * Deep clone..
+     * @param {Object} o the object to clone..
+     * @return {Object} returns clone of object
+     * @member Object xclone
+     */
+    xclone : function(o)
+    {
+        var cp = function(e) {
+             
+            if (typeof(e) != 'object') {
+                return e;
+            }
+            
+            if (typeof(e) == 'object' && Array.isArray(e)) {
+                var ar  = [];
+                for (var i =0; i < e.length;i++) {
+                    ar.push(cp(e[i])); 
+                }
+                return ar;
+            }
+            
+            return XObject.xclone(e);
+            
+        };
+        
+        var r = {};
+        for(var p in o){
+            //print (p + ': ' + typeof(o[p]));
+            r[p] = cp(o[p])
+        }
+        return r;
+    },
+
+
+    /**
+     * Extends one class with another class and optionally overrides members with the passed literal. This class
+     * also adds the function "override()" to the class that can be used to override
+     * members on an instance.
+     *
+     * usage:
+     * MyObject = Object.define(
+     *     function(...) {
+     *          ....
+     *     },
+     *     parentClass, // or Object
+     *     {
+     *        ... methods and properties.
+     *     }
+     * });
+     * @param {Function} constructor The class inheriting the functionality
+     * @param {Object} superclass The class being extended
+     * @param {Object} overrides (optional) A literal with members
+     * @return {Function} constructor (eg. class
+     * @method define
+     */
+    define : function()
+    {
+        // inline overrides
+        var io = function(o){
+            for(var m in o){
+                this[m] = o[m];
+            }
+        };
+        return function(constructor, parentClass, overrides) {
+            if (typeof(parentClass) == 'undefined') {
+                XObject.error("XObject.define: Missing parentClass: when applying: " );
+                XObject.error(new String(constructor));
+                Seed.quit(); 
+            }
+            if (typeof(parentClass.prototype) == 'undefined') {
+                XObject.error("Missing protype: when applying: " );
+                XObject.error(new String(constructor));
+                XObject.error(new String(parentClass));
+                Seed.quit(); 
+            }
+            var F = function(){};
+            var sbp;
+            var spp = parentClass.prototype;
+            
+            F.prototype = spp;
+            sbp = constructor.prototype = new F();
+            sbp.constructor=constructor;
+            constructor.superclass=spp;
+
+            // extends Object.
+            if(spp.constructor == Object.prototype.constructor){
+                spp.constructor=parentClass;
+            }
+            
+            constructor.override = function(o){
+                Object.extend(constructor.prototype, o);
+            };
+            sbp.override = io;
+            XObject.extend(constructor.prototype, overrides);
+            return constructor;
+        };
+    }(),
+
+         
+    /**
+     * returns a list of keys of the object.
+     * @param {Object} obj object to inspect
+     * @return {Array} returns list of kyes
+     * @member XObject keys
+     */
+    keys : function(o)
+    {
+        var ret = [];
+        for(var i in o) {
+            ret.push(i);
+        }
+        return ret;
+    },
+    /**
+     * return the Gobject name of a constructor - does not appear to work on structs..
+     * @param {Object} gobject ctr
+     * @return {String} returns name
+     * @member XObject type
+     */
+    type : function(o)
+    {
+        if (typeof(o) == 'object') {
+            return GObject.type_name(o.type);
+           // print("GNAME:" +gname + " GTYPE:"+cfg.xtype.type);
+        }
+        return 'unknown';
+    },
+    /**
+     * return the XObjectBase class for a cfg (which includes an xtype)
+     * @param {Object} configuration.
+     * @return {function} constructor
+     * @member XObject baseXObject
+     */
+    baseXObject : function(cfg)
+    {
+          try {
+            // loocks for XObject/Gtk/TreeView.js [   TreeView = { .... } ]
+            // xns is not a string!!!?
+            var gname = false;
+            if (typeof(cfg.xtype) == 'object') {
+                gname = XObject.type(cfg.xtype);
+            
+            }
+            if (typeof(cfg.xtype) == 'string') {
+                gname  = cfg.xtype;
+            }
+            
+            XObject.log("TRYING BASE OBJECT : " + gname);
+            // in the situation where we have been called and there is a base object
+            // defining the behavior..
+            // then we should copy the prototypes from the base object into this..
+            
+            // see if file exists???
+            
+            var base = gname  ? imports.XObjectBase[gname][gname] : false;
+            return base;
+            
+        } catch (e) {
+            // if debug?
+            XObject.log("error finding " + gname + " - " + e.toString());
+            return false;
+        }
+        
+        
+    },
+    
+    /**
+     * @member XObject createDelegate
+     * creates a delage metdhod
+     * @param {Function} method to wrap
+     * @param {Object} scope 
+     * @param {Array} args to add
+     * @param {Boolean|Number} append arguments or replace after N arguments.
+     * @return {Function} returns the delegate
+     */
+
+    createDelegate : function(method, obj, args, appendArgs){
+        
+        return function() {
+            XObject.log("CALL: " + obj.id + ':'+ method.id);
+            
+            var callArgs = args || arguments;
+            if(appendArgs === true){
+                callArgs = Array.prototype.slice.call(arguments, 0);
+                callArgs = callArgs.concat(args);
+            }else if(typeof appendArgs == "number"){
+                callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
+                    var applyArgs = [appendArgs, 0].concat(args); // create method call params
+                    Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
+                }
+                return method.apply(obj || window, callArgs);
+            };
+    }
+    
+});
diff --git a/old-javascript/builder.html.js b/old-javascript/builder.html.js
new file mode 100644 (file)
index 0000000..ec722e5
--- /dev/null
@@ -0,0 +1,624 @@
+//<script type="text/javascript">
+
+var MODULE = { isBuilder : true };
+// BC
+var _this = MODULE;
+
+// the apprenderer.
+Builder  = {
+    
+    scriptTag : false,
+    
+    id : 1,
+    
+    render : function(data, clsname)
+    {
+        
+       // console.log(data);
+        console.log(clsname);
+        // for debugging 
+        // console.log(data);        return; 
+        //Roo.log(data);
+        //Roo.log(data);
+        // This would be alot simpler if we just use the XComponent code...
+        // data should now be dialog or xcomponent..
+        // only snag here is that we do not know the name currently..
+        //Roo.log(clsname);
+        var  ix = '_src_' + this.id++;
+        // should replace module name with Builder._src_{id}
+        data =  data.replace(clsname, 'Builder.' + ix);
+        // next.. we need to ensure that parent is set correctly..
+        // done by sender... otherwise building becomes difficult..
+        //data  += "\n" + 'Builder.' + ix + ".parent = '#renderel';\n";
+        console.log(data);
+        //Roo.log(data);return;
+        //Roo.log(data);
+        if (this.scriptTag) { 
+            document.body.removeChild(this.scriptTag);
+            this.scriptTag = false;
+        }
+        
+        this.scriptTag = document.body.appendChild(document.createElement('script'));
+        this.scriptTag.setAttribute('type','text/javascript');
+         
+        this.id++;
+        this.scriptTag.appendChild(
+                    document.createTextNode(
+                            data 
+        ));
+         
+        
+        //Roo.log(this.tree);
+        MODULE = { isBuilder : true }; 
+        _this = MODULE;
+        if (!Builder.click) {
+            Builder.click= Roo.get(document.body).on('click', this.onclick, this);
+        }
+        Roo.log('Builder.'+ ix);
+        Roo.XComponent.build();
+        return;
+        
+        return;
+        var  wait_for_tree = function() {
+            
+            Builder.tree = Builder[ix];
+            if (!Builder.tree) {
+                Roo.log("Wating for tree : " + ix);
+                wait_for_tree.defer(100);
+                return;
+            }
+             Builder.redraw(false);
+        }
+        wait_for_tree.defer(100);
+    },
+    
+    
+    
+    tree : {}, 
+    renderObj :  { isBuilder : true },
+    dialogroot : false,
+    
+    redrawClear : function(isAuto)
+    {
+        this.renderObj = { isBuilder : true };
+        
+        this.scroll = {
+            top:0,
+            left:0
+        };
+        
+         
+        
+        //if (this.panelroot) {
+        //    this.scroll = this.panelroot.el.getScroll();
+        //    this.layout.remove('center', this.panelroot);
+        //    this.panelroot = false;
+        //}
+        if (this.dialogroot) {
+            this.dialogroot.remove();
+            this.dialogroot = false;
+        }
+        if (this.layoutbase) {
+            //console.log(Builder.dump(this.layoutbase.el));
+            
+            
+            try {
+                var pan = this.layoutbase.getRegion('center').getPanel(0);
+                if (pan) {
+                    this.layoutbase.remove('center', pan);
+                }
+                
+                
+            } catch( e) {
+                console.log(e);
+                console.log(JSON.stringify(e));
+                // reload!!?
+            }
+            
+            
+            
+            //this.layoutbase= false;
+        }
+         
+        
+    },
+    
+    
+    redraw: function(isAuto)
+    {
+        
+        // top level is not relivant
+        this.redrawClear(isAuto);
+        
+        
+        var cfg =  this.tree;
+        //console.log(this.dump(cfg));
+        if (!cfg) {
+            return;
+        }
+        
+        
+        this.munge(cfg);
+        this.cfg = cfg;
+        //console.log(this.dump(cfg)); 
+        // we draw either a dialog or a tab..
+        
+        if (cfg.xtype == 'LayoutDialog') {
+            
+            cfg.modal = false;
+            //var xy  = Pman.Tab.BuilderPanel.panel.el.getXY();
+            //cfg.items[0].x = xy[0];
+            //cfg.items[0].y = xy[1];
+            //cfg.items[0].constraintoviewport = false;
+        
+            this.dialogroot = Roo.get( document.body).createChild({
+                id : cfg.id
+            });
+            
+            
+            MODULE.dialog = new Roo[cfg.xtype](this.dialogroot, cfg);
+            //this.dialog.el.on('click', this.panelClick, this);
+            MODULE.dialog.show();
+            return;
+            
+        }
+        
+        // otherwise we are creating a layout area on the document..
+        
+         
+        // handles 
+        // contentpanel, nestedlayoutpanel, contentpanel.. etc. 
+        // force center region..
+        cfg.region = 'center';
+        cfg.background = false;
+        if (!this.layoutbase) {
+                
+            this.layoutbase = new Ext.BorderLayout(document.body, {
+              
+                 center: {
+                    titlebar: false,
+                    autoScroll:false,
+                    closeOnTab: true,
+                    tabPosition: 'top',
+                    //resizeTabs: true,
+                    alwaysShowTabs: true,
+                    minTabWidth: 140
+                }
+            });
+        }
+        try {
+            console.log("ADDING CFG");    
+            console.log(cfg)
+            this.layoutbase.addxtype(  cfg ); 
+        } catch (e) {
+            console.log("GOT ERROR? - saved in Builder.lastError");
+            Builder.lastError = e;
+            console.log(e);
+            console.log(typeof(e));
+            
+            console.log(this.dump(e));
+            console.trace();
+        }
+        
+        
+    },
+  
+    
+    munge :function (cfg, isListener)
+    {
+        var xitems = false;
+        //cfg.cls = cfg.cls || '';
+        //cfg.cls += ' ' + cfg.id;
+        if (!cfg.id) {
+            this.dump(cfg);
+        }
+        
+        //console.log(cfg.xtype + ': ' + cfg.id);
+        
+        if (cfg.items) {
+            xitems = cfg.items;
+            delete cfg.items;
+        }
+        if (typeof(cfg.background) != 'undefined') {
+            cfg.background = false;
+        }
+        
+        var xtype = (cfg['|xns'] || '')  + '.' + (cfg.xtype || '');
+        
+        for(var p in cfg){
+            // key is not string?!?!?!!?
+          
+            if (typeof(p) != 'string') {
+                continue;
+            }
+            
+            if (typeof(cfg[p]) == 'object') { // listeners!!!
+                this.munge(cfg[p], p == 'listeners');
+                continue;
+            }
+            // SPECIAL - PIPE
+            if (p.charAt(0) == '|' || isListener) {
+                
+                if (!cfg[p].length) {
+                    delete cfg[p];
+                    continue;
+                }
+                var pp = p.charAt(0) == '|'  ? p.substring(1) : p;
+                try {
+                    
+                    
+                    var _tmp = false;
+                    
+                    /** eval:var:MOUDULE **/
+                    /** eval:var:_this **/
+                    /** eval:var:_tmp **/
+                    // stupid IE can not return objects evaluated..
+                   // console.log('_tmp =(' + cfg[p] + ')');
+                    eval('_tmp =(' + cfg[p] + ')');
+                    cfg[pp] = _tmp;
+                    
+                    //if (typeof(_tmp) == 'undefined') {
+                    //    alert(cfg[p]);
+                   // }
+                   
+                } catch(e) {  
+                    console.log('Error evaluating: '  + cfg[p] + "\r\n" + JSON.stringify(e)); 
+                };
+                if (pp != p) {
+                    delete cfg[p];
+                }
+                
+                    
+                
+                continue;
+            }
+            // skip '*'
+            if ((p.charAt(0) == '*') || (p.charAt(0) == '+')) {
+                delete cfg[p];
+                continue;
+            }
+            // normal..
+              
+        }
+        
+        if (cfg.xtype && cfg.xtype.match(/^Roo\./) && !cfg.xns) {
+            // xtype contains full path..
+            var bits = cfg.xtype.split('.');
+            bits.shift(); // remove roo..
+            cfg.xtype = bits.pop(); // get the last bit..
+            cfg.xns = Roo;
+            while (bits.length) {
+                cfg.xns = cfg.xns[bits.shift()]; 
+            }
+             
+        }
+        if (cfg.xtype) {
+            if (!cfg.xns || typeof(cfg.xns[cfg.xtype]) == 'undefined') {
+                throw "Invalid Xtype " + cfg.xtype + ' on ' + cfg.xtreepath;
+            }
+        }
+        if (!isListener) {
+            cfg.listeners = cfg.listeners || {};
+        }
+        // we can overlay some event handlers here..
+        
+       
+        //console.log('xtype'  + xtype)
+        switch(xtype) {
+            case 'Roo.LayoutDialog':
+                cfg.listeners.resize = function(dlg, w,h)
+                {
+                    console.log('{ "id" : "' + dlg.id + '", "set" : "width", "value": ' + w + '}');
+                    console.log('{ "id" : "' + dlg.id + '", "set" : "height", "value": ' + h + '}');
+                }
+                break;
+        }
+        
+        
+        
+        
+        
+        // now for all the children.. (items)
+        if (xitems === false) {
+            
+            return;
+        }
+        cfg.items = [];
+        for (var i = 0; i < xitems.length; i++) {
+            // if +builderhide set !!!! drop it!!
+            
+            
+            var xi = xitems[i];
+            if (typeof(xi['*prop']) != 'undefined') {
+                //console.log('adding prop:' + xi['*prop']);
+                
+                var pr = xi['*prop'];
+                this.munge(xi);
+                // if prop is an array - then it's items are really the value..
+                if (pr.match(/\[\]$/)) {
+                    //console.log('adding array?:' + pr);
+                    pr = pr.replace(/\[\]$/, '');
+                    cfg[pr] = cfg[pr]  || [];
+                    cfg[pr].push(xi);
+                    continue;
+                }
+                
+                
+                if (xi.xtype && xi.xtype  == 'Array') {
+                    cfg[pr] = xi.items;
+                } else {
+                    //console.log('setting property:' + pr);
+                    cfg[pr] = xi;
+                }
+                
+                
+                continue;
+            }
+            this.munge(xi);
+            cfg.items.push(xi);
+        }
+        
+        if (cfg.items.length == 0) {
+            delete cfg.items;
+        }
+        console.log(cfg);
+        
+        
+    },
+    
+    
+    
+    cloneConfig : function(config) {
+               if (!config) { return null; }
+               var newConfig = {};
+               for (var i in config) {
+                       if (typeof config[i] == 'object') {
+                               newConfig[i] = this.cloneConfig(config[i]);
+                       } else if (typeof config[i] != 'function') {
+                               newConfig[i] = config[i];
+                       }
+               }
+               return newConfig;
+       },
+    dump : function (arr,level) {
+        var dumped_text = "";
+        if(!level) level = 0;
+        if (level >  3) {
+            return '... TO DEEP ...';
+        }
+        //The padding given at the beginning of the line.
+        var level_padding = "";
+        for(var j=0;j<level+1;j++) level_padding += "    ";
+        
+        if(typeof(arr) == 'object') { //Array/Hashes/Objects 
+            for(var item in arr) {
+                
+                var value = arr[item];
+                if (item == 'xns') {
+                    continue;
+                }
+                if(typeof(value) == 'function') { //If it is an array,
+                    // fake dump...
+                    dumped_text += level_padding + "'" + item + "' : function() { ... },\n";
+                    continue;
+                }
+                if(typeof(value) == 'object') { //If it is an array,
+                    dumped_text += level_padding + "'" + item + "': {\n";
+                    dumped_text += this.dump(value,level+1);
+                    dumped_text += level_padding + "}\n";
+                    continue;
+                }
+                dumped_text += level_padding + "'" + item + "' : \"" + value + "\"\n";
+                
+            }
+        } else { //Stings/Chars/Numbers etc.
+            dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
+        }
+        return dumped_text;
+    },
+    findNode : function(ftg , method) {
+        if (!ftg) {
+            return; false
+        }
+      // console.log(ftg.id);
+        if (ftg.id && typeof(ftg.id) == 'string' && ftg.id.match(/builder-/)) {
+            var nid = ftg.id.replace('builder-', '').replace('x-form-el-', '');
+            this[method]( nid );
+            return true;
+        }
+        // needs fixing..
+        if (ftg.dom.className.match(/[0-9]+/)) {
+            //console.log(ftg.dom.className);
+            var cmat = ftg.dom.className.match(/x-grid-hd-builder-(form-gen-[0-9:]+)/);
+            if (cmat) {
+                this[method]( cmat[1] );
+                return true;
+            }
+        }
+        
+        
+        
+        
+        return false;
+    },
+    
+    overPos: function(x,y) 
+    {
+        
+        var el = document.elementFromPoint(x,y);
+       // //console.log(el.id);
+       // console.log(document.body.innerHTML);
+        this.hover( {
+            getTarget : function () {
+                return el;
+            },
+            stopEvent : function() {
+                
+            }
+        });
+        
+        
+    },
+    onclick: function(e) {
+        var tg = Roo.get(e.getTarget());
+        if (!tg) {
+            //console.log('no target');
+            return;
+           }
+         
+        if (this.findNode(tg,'logClick')) {
+            return;
+        }
+        var dp = Roo.get(tg.up(''));
+        if (dp && this.findNode(dp,'logClick')) {
+            return;
+        }
+        
+        var ns = Roo.get(tg.getNextSibling());
+        if (ns && this.findNode(ns,'logClick')) {
+          
+            return;
+        }
+        if (ns && ns.down('') && this.findNode(Roo.get(ns.down('')) ,'logClick') ) {
+            return;
+        }
+        
+        for(var i =0; i < 5; i++) {
+            tg = Roo.get(tg.up(''));
+            if (!tg) {
+                //console.log('no parent' + i);
+                return;
+            }
+            if (tg && this.findNode(tg,'logClick')) {
+                return;
+            }
+        }
+        //console.log('no target in parents');
+        
+    },
+    logClick : function(id) 
+    {
+         var bid = id.length ? 'builder-' + id : '';
+         console.log('{ "id" :  "' + bid + '"}');
+    },
+    
+    
+    hover : function(e) {
+        
+       
+        var tg = Roo.get(e.getTarget());
+        if (!tg) {
+            //console.log('no target');
+            this.logMove('');
+            return;
+           }
+         
+        if (this.findNode(tg,'logMove')) {
+            e.stopEvent();
+            return;
+        }
+        var dp = Roo.get(tg.up(''));
+        if (dp && this.findNode(dp,'logMove')) {
+            e.stopEvent();
+            return;
+        }
+        
+        var ns = Roo.get(tg.getNextSibling());
+        if (ns && this.findNode(ns,'logMove')) {
+            e.stopEvent();
+            return;
+        }
+        if (ns && ns.down('') && this.findNode(Roo.get(ns.down('')) ,'logMove' )) {
+            e.stopEvent();
+            return;
+        }
+        
+        for(var i =0; i < 5; i++) {
+            tg = Roo.get(tg.up(''));
+            if (!tg) {
+                //console.log('no parent' + i);
+                this.logMove('');
+                return;
+            }
+            if (tg && this.findNode(tg,'logMove')) {
+                e.stopEvent();
+                return;
+            }
+        }
+        //console.log('no target in parents');
+        this.logMove('');
+    },
+    logMove : function (id) {
+        //console.log("LOGMOVE: " + id);
+        
+        if (this.lastID === id) {
+            return;
+       }
+       id = ''+ id;
+       var bid = id.length ? 'builder-' + id : '';
+       console.log('{ "hover-node" :  "' + bid + '"}');
+       this.lastID = id;
+    },
+    clearBootstrap : function()
+    {
+        // if the page is not bootstrap
+        
+        if ( typeof(BuilderUseBootstrap) != 'undefined' ) {
+            Roo.log("it's boostrap - BuilderUseBootstrap is defined ");
+            // it's bootstrap - probably remove roo's css..
+            return;
+        }
+        Roo.log("remove css = BuilderUseBootstrap is not defined");
+        var rem = [];
+        var ar = document.getElementsByTagName('link');
+        for (var i = 0; i < ar.length;i++) {
+            var l = ar[i];
+            Roo.log(l.getAttribute('href'));
+            if (l.getAttribute('href').match(/bootstrap/)) {
+                rem.push(l);
+                
+                
+            }
+            //code
+        }
+        Roo.each(rem, function(l) { l.parentNode.removeChild(l);});
+    },
+    
+    applyFlexy: function(tree)
+    {
+        if (typeof(tree['flexy:foreach']) != 'undefined') {
+            //Roo.log("add flexy:foreach");
+            tree.el.attr('flexy:foreach', tree['flexy:foreach']);
+        }
+        if (typeof(tree['flexy:if']) != 'undefined') {
+            //Roo.log("add flexy:if");
+            tree.el.attr('flexy:if', tree['flexy:if']);
+        }
+        if (typeof(tree['flexy:include']) != 'undefined') {
+            //Roo.log("add flexy:if");
+            tree.el.attr('flexy:include', tree['flexy:include']);
+        }
+        
+        if (typeof(tree['xtype-bootstrap']) != 'undefined') {
+            //Roo.log("add flexy:if");
+            tree.el.attr('xtype', tree['xtype-bootstrap']);
+        }
+        
+        
+        if (!tree.items || !tree.items.length) { return; }
+        
+        for (var i = 0; i < tree.items.length; i++){
+            this.applyFlexy(tree.items[i]);
+        }
+    }
+    
+     
+    
+};
+Roo.onReady(function() { Builder.clearBootstrap(); });
+Roo.XComponent.on('buildcomplete', function() {
+    Roo.log("xcomponent built!");
+    
+    Builder.applyFlexy(Roo.XComponent.modules[0].el);
+});
\ No newline at end of file
diff --git a/old-javascript/builder_run.js b/old-javascript/builder_run.js
new file mode 100755 (executable)
index 0000000..47d8f5c
--- /dev/null
@@ -0,0 +1,3 @@
+//<Script type="text/javascript">
+
+print("Use seed gtkrun.js Builder");
diff --git a/old-javascript/console.js b/old-javascript/console.js
new file mode 100644 (file)
index 0000000..952ef3b
--- /dev/null
@@ -0,0 +1,67 @@
+//<Script type="text/javascript">
+/**
+ * 
+ * simple console wrapper - emulates what you would expect from console
+ * 
+ * in theory could be replaced with a 'in-line console'
+ * 
+ * provides 'dump' in addtion to 'log'
+ * 
+ */
+
+function log (v)  
+{
+        print(v);
+}
+function dump (ar) 
+{
+        print(_dump(ar, 0));
+}
+
+function _dump(arr,level) 
+{
+    level = level || 0;
+    
+    var dumped_text = "";
+    
+    
+    
+    //The padding given at the beginning of the line.
+    var level_padding = "";
+    
+    for(var j=0;j<level+1;j++) {
+        level_padding += "    ";
+    }
+    
+    if(level > 15) {
+        return  level_padding + "[ ... to deep ...]\n";
+    }
+    
+    if (typeof(arr) != 'object') { //Array/Hashes/Objects 
+        return "===>"+arr+"<===("+typeof(arr)+")";
+    }
+
+    for(var item in arr) {
+        var value = arr[item];
+        if (item == 'prototype') {
+            continue;
+           }
+        switch (typeof(value)) {
+            case 'object' : 
+                dumped_text += level_padding + "'" + item + "' ...\n";
+                dumped_text += _dump(value,level+1) + "\n";
+                break;
+            
+            case 'function' : 
+                dumped_text += level_padding + "'" + item + "' => FUNCTION \n";
+                break;
+            
+            default: 
+                dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
+                break;
+        }
+    }
+        
+    return dumped_text;
+}
diff --git a/old-javascript/dbgenerate.js b/old-javascript/dbgenerate.js
new file mode 100644 (file)
index 0000000..0ea16fd
--- /dev/null
@@ -0,0 +1,914 @@
+//<script type="text/javascript">
+
+/**
+ * This is a hacky generator to generate element definitions for the Roo version from the database
+ * 
+ * Let's see if libgda can be used to generate our Readers for roo...
+ * 
+ * Concept - conect to database..
+ * 
+ * list tables
+ * 
+ * extra schemas..
+ * 
+ * write readers..
+ * 
+ * usage: seed generate.js
+ *
+ *
+ *
+ *
+ *Hack needed to latest GLib-2.0.gir 
+ *
+ * <record name="KeyFile" c:type="GKeyFile" disguised="1">
+       <constructor name="new" c:identifier="g_key_file_new">
+        <return-value transfer-ownership="full">
+          <type name="KeyFile" c:type="GKeyFile*"/>
+        </return-value>
+      </constructor>
+ *
+ *
+ * remove introspectable =0 from g_key_file_get_groups
+ *   and add transfer-owneership = none to return value
+ * remove introspectable =0 from g_key_file_get_keys
+ *   and add transfer-owneership = none to return value* 
+ * 
+ */
+Gda  = imports.gi.Gda;
+GObject = imports.gi.GObject;
+
+GLib = imports.gi.GLib;
+
+console = imports.console;
+File = imports.File.File;
+Options = imports.Options.Options;
+
+//Gda.init();
+
+var prov = Gda.Config.list_providers ();
+//print(prov.dump_as_string());
+
+var o = new Options({
+    help_description : 'Element builder for App Builder based on database schema',
+    
+    options:  [
+        { arg_long : 'DBTYPE' , arg_short : 't', description : 'Database Type (eg. MySQL or PostgreSQL ' },
+        { arg_long : 'DBNAME' , arg_short : 'd', description : 'Database Name' },
+        { arg_long : 'USERNAME' , arg_short : 'u', description : 'Username'},
+        { arg_long : 'PASSWORD' , arg_short : 'p', description : 'Password' , arg_default :'' },
+        { arg_long : 'INI' , arg_short : 'I', description :
+                    'Either base directory which has Pman/***/DataObjects/***.links.ini or location of ini file.' },
+    ]
+           
+})
+
+
+
+var cfg = o.parse(Seed.argv);
+print(JSON.stringify(cfg, null,4));
+
+var   cnc = Gda.Connection.open_from_string (cfg.DBTYPE,
+         "DB_NAME=" + cfg.DBNAME, 
+        "USERNAME=" + cfg.USERNAME + ';PASSWORD=' + cfg.PASSWORD,
+        Gda.ConnectionOptions.NONE, null);
+
+
+
+                                              
+
+Gda.DataSelect.prototype.fetchAll = function()
+{
+    var cols = [];
+    
+    for (var i =0;i < this.get_n_columns(); i++) {
+        cols.push(this.get_column_name(i));
+    }
+    //print(JSON.stringify(cols, null,4));
+    var iter = this.create_iter();
+    var res = [];
+    //print(this.get_n_rows());
+    var _this = this;
+    for (var r = 0; r < this.get_n_rows(); r++) {
+        
+        // single clo..
+        //print("GOT ROW");
+        if (cols.length == 1) {
+            res.push(this.get_value_at(0,r).get_string());
+            continue;
+        }
+        var add = { };
+        
+        cols.forEach(function(n,i) {
+            var val = _this.get_value_at(i,r);
+            var type = GObject.type_name(val.g_type) ;
+            var vs = ['GdaBinary', 'GdaBlob' ].indexOf(type) > -1 ? val.value.to_string(1024) : val.value;
+            //print(n + " : TYPE: " + GObject.type_name(val.g_type) + " : " + vs);
+            //print (n + '=' + iter.get_value_at(i).value);
+            add[n] = vs;
+        });
+        
+        res.push(add);
+        
+    }
+    return res;
+
+}
+
+var map = {
+    'date' : 'date',
+    'datetime' : 'date',
+    'timestamp with time zone' : 'date',
+    'timestamp without time zone' : 'date',
+    'time' : 'string', //bogus
+    'int' : 'int',
+    'integer' : 'int',
+    'bigint' : 'int',
+    'double' : 'float',
+    'tinyint' : 'int',
+    'smallint' : 'int',
+    'decimal' : 'float',
+    'float' : 'float',
+    'numeric' : 'float',
+    'char' : 'string',
+    'character' : 'string',
+    'character varying' : 'string',
+    'varchar' : 'string',
+    'text' : 'string',
+    'longtext' : 'string',
+    'tinytext' : 'string',
+    'mediumtext' : 'string',
+    'enum' : 'string',
+    'timestamp' : 'number',
+    'blob' : 'text',
+    'bytea' : 'text',
+    'boolean' : 'int',
+    'text[]' : 'string',
+    
+}
+
+var ini = { }
+
+function readIni(fn)
+{
+    print('Read INI : ' + fn);
+    var key_file = new GLib.KeyFile.c_new();
+    if (!key_file.load_from_file (fn , GLib.KeyFileFlags.NONE )) {
+        return;
+    }
+   
+    var groups = key_file.get_groups();
+    groups.forEach(function(g) {
+        //print("KEY:"+g);
+        ini[g] = {}
+        
+        var keys = key_file.get_keys(g);
+        if (!keys) { return; }
+        
+        keys.forEach(function(k) {
+                print("GET val: " + k);
+                ini[g][k] = key_file.get_value(g,k);
+                print(ini[g][k] );
+        });
+        //print("DONE KEY:"+g);
+    });
+    //print("DONE KEYS");
+}
+if (File.isFile(cfg.INI)) {
+    if (cfg.INI.match(/links\.ini$/)) {
+        readIni(cfg.INI);
+    } else {
+        readIni(cfg.INI.replace(/\.ini$/, ".links.ini"));
+    }
+}
+
+
+if (File.isDirectory(cfg.INI)) {
+        
+
+    //--- load ini files..
+    // this is very specific.
+    
+    var dirs = File.list( cfg.INI + '/Pman').filter( 
+        function(e) { 
+            if (!File.isDirectory(cfg.INI + '/Pman/' + e + '/DataObjects')) {
+                return false;
+            }
+            return true;
+        }
+    );
+    
+     
+    dirs.forEach(function(d) {
+        // this currently misses the web.*/Pman/XXXX/DataObjects..
+        var path = cfg.INI + '/Pman/' + d + '/DataObjects';
+         
+        if (!File.isDirectory(path)) {
+            return; //skip
+        }
+        var inis = File.list(path).filter(
+            function(e) { return e.match(/\.links\.ini$/); }
+        );
+        if (!inis.length) {
+            return;
+        }
+        
+        inis.forEach(function(i) {
+            readIni(path + '/' + i); 
+            
+        })
+    });
+    // look at web.XXXX/Pman/XXX/DataObjects/*.ini
+    var inis = File.list(cfg.INI).filter(
+        function(e) { return e.match(/\.links\.ini$/); }
+    )
+    
+     inis.forEach(function(i) {
+        readIni(path + '/' + i); 
+        
+    })
+    
+    
+}
+//print(JSON.stringify(ini, null,4));
+ //console.dump(ini);
+print("DONE INI");
+
+ //Seed.quit();
+
+//GLib.key_file_load_from_file (key_file, String file, KeyFileFlags flags) : Boolean
+
+
+switch(cfg.DBTYPE) {
+    case "MySQL":
+        query_tables = "SHOW TABLES";
+        query_describe_table = "DESCRIBE `%s`";
+        break;
+    
+    case 'PostgreSQL':
+        query_tables = "select c.relname FROM pg_catalog.pg_class c " + 
+            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace " + 
+            "WHERE c.relkind IN ('r','') AND n.nspname NOT IN ('pg_catalog', 'pg_toast')" +
+            "AND pg_catalog.pg_table_is_visible(c.oid) ";
+         query_describe_table =  
+                "SELECT " +
+                "f.attnum AS number, " +
+                "f.attname AS Field, " +
+                "f.attnum, " +
+                "CASE WHEN f.attnotnull = 't' THEN 'NO' ELSE 'YES' END AS isNull, " + 
+                "pg_catalog.format_type(f.atttypid,f.atttypmod) AS Type, " +
+                "CASE WHEN p.contype = 'p' THEN 't' ELSE 'f' END AS primarykey, " +
+                "CASE WHEN p.contype = 'u' THEN 't' ELSE 'f' END AS uniquekey, " +
+                "CASE WHEN p.contype = 'f' THEN g.relname END AS foreignkey, " +
+                "CASE WHEN p.contype = 'f' THEN p.confkey END AS foreignkey_fieldnum, " +
+                "CASE WHEN p.contype = 'f' THEN g.relname END AS foreignkey, " +
+                "CASE WHEN p.contype = 'f' THEN p.conkey END AS foreignkey_connnum, " +
+                "CASE WHEN f.atthasdef = 't' THEN d.adsrc END AS default " +
+                "FROM pg_attribute f JOIN pg_class c ON c.oid = f.attrelid " +
+                "        JOIN pg_type t ON t.oid = f.atttypid " +
+                "        LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = f.attnum " +
+                "        LEFT JOIN pg_namespace n ON n.oid = c.relnamespace " +
+                "        LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY ( p.conkey ) " +
+                "        LEFT JOIN pg_class AS g ON p.confrelid = g.oid " +
+                "WHERE c.relkind = 'r'::char AND n.nspname = '%n' " +
+                "AND c.relname = '%s' AND f.attnum > 0 ORDER BY number";
+                
+                
+                
+        break;
+    default:
+        throw {
+             name: "ArgumentError", 
+             message: "Invalid data base type " + cfg.DBTYPE + " should be MySQL or PostgreSQL"
+         };
+            
+/*
+           "Field": "province",
+        "Type": "varchar(255)",
+        "Null": "NO", << or is null
+        "Key": null,
+        "Default": null,
+        "Extra": 
+*/  
+}
+
+
+
+var tables = cnc.execute_select_command( query_tables).fetchAll();
+print(JSON.stringify(tables));
+
+var readers = [];
+tables.forEach(function(table) {
+    //print(table);
+    var schema = cnc.execute_select_command(
+            query_describe_table.replace(/%s/, table).replace(/%n/,'public')
+            ).fetchAll();
+    
+    
+    var reader = []; 
+    var colmodel = []; 
+    var combofields= [ { name : 'id', type: 'int' } ]; // technically the primary key..
+         
+    var form = {}
+       
+    var firstTxtCol = '';
+    
+    //print(JSON.stringify(schema, null,4));    Seed.quit();
+    
+    schema.forEach(function(e)  {
+        e.Type = e.Type || e.type;
+        e.Field = e.Field || e.field;
+         
+        var type = e.Type.match(/([^(]+)\(([^\)]+)\)/);
+        var row  = { }; 
+        if (type) {
+            e.Type = type[1];
+            e.Size = type[2];
+        }
+        
+        
+        
+        row.name = e.Field;
+        
+        
+        if (typeof(map[e.Type]) == 'undefined') {
+           console.dump(e);
+           throw {
+                name: "ArgumentError", 
+                message: "Unknown mapping for type : " + e.Type
+            };
+        }
+        row.type = map[e.Type];
+        
+        if (row.type == 'string' && !firstTxtCol.length) {
+            firstTxtCol = row.name;
+        }
+        
+        if (row.type == 'date') {
+            row.dateFormat = 'Y-m-d';
+        }
+        reader.push(row);
+        
+        if (combofields.length == 1 && row.type == 'string') {
+            combofields.push(row);
+        }
+        
+        
+        var title = row.name.replace(/_id/, '').replace(/_/g, ' ');
+        title  = title[0].toUpperCase() + title.substring(1);
+        
+        colmodel.push({
+            "xtype": "ColumnModel",
+            "header": title,
+            "width":  row.type == 'string' ? 200 : 75,
+            "dataIndex": row.name,
+            "|renderer": row.type != 'date' ? 
+                    "function(v) { return String.format('{0}', v); }" :
+                    "function(v) { return String.format('{0}', v ? v.format('d/M/Y') : ''); }" , // special for date
+            "|xns": "Roo.grid",
+            "*prop": "colModel[]"
+        });
+        var xtype = 'TextField';
+        
+        
+        if (row.type == 'number') {
+            xtype = 'NumberField';
+        }
+        if (row.type == 'date') {
+            xtype = 'DateField';
+        }
+        if (e.Type == 'text') {
+            xtype = 'TextArea';
+        }
+        if (row.name == 'id') {
+            xtype = 'Hidden';
+        } 
+        // what about booleans.. -> checkboxes..
+        
+        
+        
+        form[row.name] = {
+            fieldLabel : title,
+            name : row.name,
+            width : row.type == 'string' ? 200 : 75,
+            '|xns' : 'Roo.form',
+            xtype : xtype
+        }
+         if (xtype == 'DateField') {
+            form[row.name].format = 'Y-m-d';
+            form[row.name].width = 100;
+        }
+        
+        if (xtype == 'TextArea') {
+            form[row.name].height = 100;
+        }
+        if (xtype == 'Hidden') {
+            delete form[row.name].fieldLabel;
+            delete form[row.name].width;
+        }
+        
+    });
+    
+    var combo = {
+        '|xns' : 'Roo.form',
+        xtype: 'ComboBox',
+        allowBlank : false,
+        editable : false,
+        emptyText : 'Select ' + table,
+        forceSelection : true,
+        listWidth : 400,
+        loadingText: 'Searching...',
+        minChars : 2,
+        pageSize : 20,
+        qtip: 'Select ' + table,
+        selectOnFocus: true,
+        triggerAction : 'all',
+        typeAhead: true,
+        
+        width: 300,
+        
+        
+        
+        tpl : '<div class="x-grid-cell-text x-btn button"><b>{name}</b> </div>', // SET WHEN USED
+        queryParam : '',// SET WHEN USED
+        fieldLabel : table,  // SET WHEN USED
+        valueField : 'id',
+        displayField : '', // SET WHEN USED eg. project_id_name
+        hiddenName : '', // SET WHEN USED eg. project_id
+        name : '', // SET WHEN USED eg. project_id_name
+        items : [
+            {
+                    
+                '*prop' : 'store',
+                'xtype' : 'Store',
+                '|xns' : 'Roo.data',
+                'remoteSort' : true,
+                '|sortInfo' : '{ direction : \'ASC\', field: \'id\' }',
+                listeners : {
+                    '|beforeload' : 'function (_self, o)' +
+                    "{\n" +
+                    "    o.params = o.params || {};\n" +
+                    "    // set more here\n" +
+                    "}\n"
+                },
+                items : [
+                    {
+                        '*prop' : 'proxy',
+                        'xtype' : 'HttpProxy',
+                        'method' : 'GET',
+                        '|xns' : 'Roo.data',
+                        '|url' : "baseURL + '/Roo/" + table + ".php'",
+                    },
+                    
+                    {
+                        '*prop' : 'reader',
+                        'xtype' : 'JsonReader',
+                        '|xns' : 'Roo.data',
+                        'id' : 'id',
+                        'root' : 'data',
+                        'totalProperty' : 'total',
+                        '|fields' : JSON.stringify(combofields)
+                        
+                    }
+                ]
+            }
+        ]
+    }
+    
+    
+    
+    
+    //print(JSON.stringify(reader,null,4));
+    readers.push({
+        table : table ,
+        combo : combo,
+        combofields : combofields,
+        reader :  reader,
+        oreader : JSON.parse(JSON.stringify(reader)), // dupe it..
+        colmodel : colmodel,
+        firstTxtCol : firstTxtCol,
+        form : form
+    });
+    
+    //console.dump(schema );
+    
+     
+});
+
+
+
+// merge in the linked tables..
+readers.forEach(function(reader) {
+    if (typeof(ini[reader.table]) == 'undefined') {
+     
+        return;
+    }
+    print("OVERLAY - " + reader.table);
+    // we have a map..
+    for (var col in ini[reader.table]) {
+        var kv = ini[reader.table][col].split(':');
+        
+        
+        var add = readers.filter(function(r) { return r.table == kv[0] })[0];
+        if (!add) {
+            continue;
+        }
+        // merge in data (eg. project_id => project_id_*****
+     
+        add.oreader.forEach(function(or) {
+            reader.reader.push({
+                name : col + '_' + or.name,
+                type : or.type
+            });
+        });
+        
+        // col is mapped to something..
+        var combofields = add.combofields;
+        if (add.combofields.length < 2) {
+            continue;
+        }
+        if (typeof(reader.form[col]) == 'undefined') {
+            print (JSON.stringify(reader.form, null,4));
+            print("missing linked column " + col);
+            continue;
+        }
+        
+        var combofields_name = add.combofields[1].name;
+        var old =   reader.form[col];
+        reader.form[col] = JSON.parse(JSON.stringify(add.combo)); // clone
+        reader.form[col].queryParam  = 'query[' + combofields_name + ']';// SET WHEN USED
+        reader.form[col].fieldLabel = old.fieldLabel;  // SET WHEN USED
+        reader.form[col].hiddenName = old.name; // SET WHEN USED eg. project_id
+        reader.form[col].displayField = combofields_name; // SET WHEN USED eg. project_id
+        reader.form[col].name  = old.name + '_' + combofields_name; // SET WHEN USED eg. project_id_name
+        reader.form[col].tpl = '<div class="x-grid-cell-text x-btn button"><b>{' + combofields_name +'}</b> </div>'; // SET WHEN USED
+        
+             
+    };
+    
+    
+});
+
+//readers.forEach(function(reader) {
+//    delete reader.oreader;
+//});
+
+
+
+
+//print(JSON.stringify(readers, null, 4));
+
+readers.forEach(function(reader) {
+    
+
+    var dir = GLib.get_home_dir() + '/.Builder/Roo.data.JsonReader'; 
+    if (!File.isDirectory(dir)) {
+        print("mkdir " + dir);
+        File.mkdir(dir);
+    }
+    
+    // READERS
+    print("WRITE: " +  dir + '/' + cfg.DBNAME + '_' + reader.table + '.json');
+    
+                
+    var jreader = {
+        '|xns' : 'Roo.data',
+        xtype : "JsonReader",
+        totalProperty : "total",
+        root : "data",
+        '*prop' : "reader",
+        id : 'id', // maybe no..
+       
+        '|fields' :  JSON.stringify(reader.reader, null,4).replace(/"/g,"'")
+    };
+    
+    File.write(
+        dir + '/' + cfg.DBNAME + '_' + reader.table + '.json',
+        JSON.stringify(jreader, null, 4)
+    )
+    
+    
+    // GRIDS
+    dir = GLib.get_home_dir() + '/.Builder/Roo.GridPanel'; 
+    if (!File.isDirectory(dir)) {
+        print("mkdir " + dir);
+        File.mkdir(dir);
+    }
+    
+
+    print("WRITE: " +  dir + '/' + cfg.DBNAME + '_' + reader.table + '.json');
+    
+    File.write(
+        dir + '/' + cfg.DBNAME + '_' + reader.table + '.json',
+            
+       
+        JSON.stringify({
+            '|xns' : 'Roo',
+            xtype : "GridPanel",
+            "title": reader.table,
+            "fitToframe": true,
+            "fitContainer": true,
+            "tableName": reader.table,
+            "background": true,
+            "region" : 'center',
+            "listeners": {
+                "|activate": "function() {\n    _this.panel = this;\n    if (_this.grid) {\n        _this.grid.footer.onClick('first');\n    }\n}"
+            },
+            "items": [
+                {
+                    "*prop": "grid",
+                    "xtype": "Grid",
+                    "autoExpandColumn": reader.firstTxtCol,
+                    "loadMask": true,
+                    "listeners": {
+                        "|render": "function() \n" +
+                            "{\n" +
+                            "    _this.grid = this; \n" +
+                            "    //_this.dialog = Pman.Dialog.FILL_IN\n" +
+                            "    if (_this.panel.active) {\n" +
+                            "       this.footer.onClick('first');\n" +
+                            "    }\n" +
+                            "}",
+                        "|rowdblclick": "function (_self, rowIndex, e)\n" + 
+                            "{\n" + 
+                            "    if (!_this.dialog) return;\n" + 
+                            "    _this.dialog.show( this.getDataSource().getAt(rowIndex).data, function() {\n" + 
+                            "        _this.grid.footer.onClick('first');\n" + 
+                            "    }); \n" + 
+                            "}\n"
+                    },
+                    "|xns": "Roo.grid",
+
+                    "items": [
+                        {
+                            "*prop": "dataSource",
+                            "xtype": "Store",
+                             remoteSort : true,
+                            '|sortInfo' : "{ field : '" + reader.firstTxtCol  +  "', direction: 'ASC' }", 
+                            "|xns": "Roo.data",
+                            "items": [
+                                
+                                {
+                                    "*prop": "proxy",
+                                    "xtype": "HttpProxy",
+                                    "method": "GET",
+                                    "|url": "baseURL + '/Roo/" + reader.table + ".php'",
+                                    "|xns": "Roo.data"
+                                },
+                                jreader
+                            ]
+                        },
+                        {
+                            "*prop": "footer",
+                            "xtype": "PagingToolbar",
+                            "pageSize": 25,
+                            "displayInfo": true,
+                            "displayMsg": "Displaying " + reader.table + "{0} - {1} of {2}",
+                            "emptyMsg": "No " + reader.table + " found",
+                            "|xns": "Roo"
+                        },
+                        {
+                            "*prop": "toolbar",
+                            "xtype": "Toolbar",
+                            "|xns": "Roo",
+                            "items": [
+                                {
+                                    "text": "Add",
+                                    "xtype": "Button",
+                                    "cls": "x-btn-text-icon",
+                                    "|icon": "Roo.rootURL + 'images/default/dd/drop-add.gif'",
+                                    "listeners": {
+                                        "|click": "function()\n"+
+                                            "{\n"+
+                                            "    if (!_this.dialog) return;\n" +
+                                            "    _this.dialog.show( { id : 0 } , function() {\n"+
+                                            "        _this.grid.footer.onClick('first');\n"+
+                                            "   }); \n"+
+                                            "}\n"
+                                    },
+                                    "|xns": "Roo.Toolbar"
+                                },
+                                {
+                                    "text": "Edit",
+                                    "xtype": "Button",
+                                    "cls": "x-btn-text-icon",
+                                    "|icon": "Roo.rootURL + 'images/default/tree/leaf.gif'",
+                                    "listeners": {
+                                        "|click": "function()\n"+
+                                            "{\n"+
+                                            "    var s = _this.grid.getSelectionModel().getSelections();\n"+
+                                            "    if (!s.length || (s.length > 1))  {\n"+
+                                            "        Roo.MessageBox.alert(\"Error\", s.length ? \"Select only one Row\" : \"Select a Row\");\n"+
+                                            "        return;\n"+
+                                            "    }\n"+
+                                            "    if (!_this.dialog) return;\n" +
+                                            "    _this.dialog.show(s[0].data, function() {\n"+
+                                            "        _this.grid.footer.onClick('first');\n"+
+                                            "    }); \n"+
+                                            "    \n"+
+                                            "}\n" 
+                                        
+                                    },
+                                    "|xns": "Roo.Toolbar"
+                                },
+                                {
+                                    "text": "Delete",
+                                    "cls": "x-btn-text-icon",
+                                    "|icon": "rootURL + '/Pman/templates/images/trash.gif'",
+                                    "xtype": "Button",
+                                    "listeners": {
+                                        "|click": "function()\n"+
+                                            "{\n"+
+                                            "     Pman.genericDelete(_this, '" + reader.table + "'); \n"+
+                                            "}\n"+
+                                            "        "
+                                    },
+                                    "|xns": "Roo.Toolbar"
+                                }
+                            ]
+                        }, // end toolbar
+                    ].concat( reader.colmodel)
+                }
+            ]
+            
+            
+        }, null, 4)
+    )
+    
+    /// FORMS..
+    
+    dir = GLib.get_home_dir() + '/.Builder/Roo.form.Form'; 
+    if (!File.isDirectory(dir)) {
+        print("mkdir " + dir);
+        File.mkdir(dir);
+    }
+    var formElements = [];
+    var formHeight = 50;
+    for (var k in reader.form) {
+        if (k == 'id') { // should really do primary key testing..
+            continue;
+        }
+        formHeight += reader.form[k].xtype == 'TextArea' ? 100 : 30;
+        
+        formElements.push(reader.form[k]);
+    }
+    if (reader.form['id']) {
+        formElements.push(reader.form['id']);
+    }
+    
+
+    print("WRITE: " +  dir + '/' + cfg.DBNAME + '_' + reader.table + '.json');
+    var frmCfg = 
+    {
+        '|xns' : 'Roo.form',
+        xtype : "Form",
+        listeners : {
+            "|actioncomplete" : "function(_self,action)\n"+
+                "{\n"+
+                "    if (action.type == 'setdata') {\n"+
+                "       //_this.dialog.el.mask(\"Loading\");\n"+
+                "       //this.load({ method: 'GET', params: { '_id' : _this.data.id }});\n"+
+                "       return;\n"+
+                "    }\n"+
+                "    if (action.type == 'load') {\n"+
+                "        _this.dialog.el.unmask();\n"+
+                "        return;\n"+
+                "    }\n"+
+                "    if (action.type =='submit') {\n"+
+                "    \n"+
+                "        _this.dialog.el.unmask();\n"+
+                "        _this.dialog.hide();\n"+
+                "    \n"+
+                "         if (_this.callback) {\n"+
+                "            _this.callback.call(_this, _this.form.getValues());\n"+
+                "         }\n"+
+                "         _this.form.reset();\n"+
+                "         return;\n"+
+                "    }\n"+
+                "}\n",
+            
+            "|rendered" : "function (form)\n"+
+                "{\n"+
+                "    _this.form= form;\n"+
+                "}\n"
+        },
+        method : "POST",
+        style : "margin:10px;",
+        "|url" : "baseURL + '/Roo/" + reader.table + ".php'",
+        items : formElements
+    };
+    
+    
+    File.write(
+        dir + '/' + cfg.DBNAME + '_' + reader.table + '.json',
+            
+       
+        JSON.stringify( frmCfg, null, 4)
+    );
+            
+            
+   
+   
+   
+     /// COMBO..
+    
+    dir = GLib.get_home_dir() + '/.Builder/Roo.form.ComboBox'; 
+    if (!File.isDirectory(dir)) {
+        print("mkdir " + dir);
+        File.mkdir(dir);
+    }
+   
+    print("WRITE: " +  dir + '/' + cfg.DBNAME + '_' + reader.table + '.json');
+    
+    File.write(
+        dir + '/' + cfg.DBNAME + '_' + reader.table + '.json',
+            
+       
+        JSON.stringify(reader.combo, null, 4)
+    );
+            
+   
+   
+   
+   
+   
+    // DIALOG.
+   
+   
+    dir = GLib.get_home_dir() + '/.Builder/Roo.LayoutDialog'; 
+    if (!File.isDirectory(dir)) {
+        print("mkdir " + dir);
+        File.mkdir(dir);
+    }
+    var formElements = [];
+    for (var k in reader.form) {
+        if (k == 'id') { // should really do primary key testing..
+            continue;
+        }
+        formElements.push(reader.form[k]);
+    }
+    formElements.push(reader.form['id']);
+
+    print("WRITE: " +  dir + '/' + cfg.DBNAME + '_' + reader.table + '.json');
+    
+    File.write(
+        dir + '/' + cfg.DBNAME + '_' + reader.table + '.json',
+            
+       
+        JSON.stringify({
+       
+            "closable": false,
+            "collapsible": false,
+            "height": formHeight,
+            "resizable": false,
+            "title": "Edit / Create " + reader.table,
+            "width": 400,
+            "modal" : true,
+            "xtype": "LayoutDialog",
+            "|xns": "Roo",
+            "items": [
+                {
+                    "|xns": "Roo",
+                    "xtype": "LayoutRegion",
+                    "*prop": "center"
+                },
+                {
+                    "region": "center",
+                    "xtype": "ContentPanel",
+                    "|xns": "Roo",
+                    "items": [
+                        frmCfg
+                    ]
+                },
+                
+                {
+                    "listeners": {
+                        "click": "function (_self, e)\n{\n    _this.dialog.hide();\n}"
+                    },
+                    "*prop": "buttons[]",
+                    "text": "Cancel",
+                    "xtype": "Button",
+                    "|xns": "Roo"
+                },
+                {
+                    "listeners": {
+                        "click": "function (_self, e)\n{\n    // do some checks?\n     \n    \n    _this.dialog.el.mask(\"Saving\");\n    _this.form.doAction(\"submit\");\n\n}"
+                    },
+                    "*prop": "buttons[]",
+                    "text": "Save",
+                    "xtype": "Button",
+                    "|xns": "Roo"
+                }
+            ]
+        }, null,4)
+    );
+   
+   
+   
+});
+
+
diff --git a/old-javascript/gtkrun.js b/old-javascript/gtkrun.js
new file mode 100644 (file)
index 0000000..1ec53ad
--- /dev/null
@@ -0,0 +1,112 @@
+#!/usr/bin/seed 
+//<Script type="text/javascript">
+/**
+ * runtime file
+ * takes a gtk project directory, and turns it into an application!
+ * by compling the files into JS files..
+ * 
+ * Initially developed for runtime testing. (the vte runner)
+ * 
+ * Might be the way to go for full runtime 
+ * 
+ * 
+ * Usage: (call with wrapper to set up directories..)
+ *    sh builder.sh
+ * 
+ * Concepts.. 
+ * a) load dependancies.. (eg. gi's..) - derived later?
+ * Gtk.init()
+ * 
+ * loop the files (find .bjs)
+ *   - comple to js (if not exist // or force enabled..)
+ * b) load all the files
+ * 
+ * Gtk.main();
+ * 
+ */
+// autogen?
+
+// sort out import path - this is  a bit of a mess..
+GIRepository = imports.gi.GIRepository;
+GLib        = imports.gi.GLib;
+
+// we add this in, as it appears to get lost sometimes if we set it using the ENV. variable in builder.sh
+GIRepository.Repository.prepend_search_path(GLib.get_home_dir() + '/.Builder/girepository-1.2');
+//print(JSON.stringify(GIRepository.IRepository.get_search_path()));
+
+Gtk         = imports.gi.Gtk;
+Gdk         = imports.gi.Gdk;
+Pango       = imports.gi.Pango;
+
+Gio         = imports.gi.Gio;
+GObject     = imports.gi.GObject;
+GtkSource   = imports.gi.GtkSource;
+WebKit      = imports.gi.WebKit;
+Vte         = imports.gi.Vte;
+//Gdl         = imports.gi.Gdl;
+
+//GtkClutter  = imports.gi.GtkClutter;
+
+
+if (typeof(GtkClutter) != 'undefined') {    
+    GtkClutter.init(Seed.argv);
+}
+
+
+File    = imports.File.File;
+
+XObject = imports.XObject.XObject;
+//XObject.debug = true;
+Gtk.init(Seed.argv);
+
+Globals = imports.Globals;
+
+
+imports.searchPath.push('/'); // allow global paths..
+// error checking todo..
+var files = File.list(Seed.argv[2]);
+var olist = [];
+
+var gtkbuilder = false;
+files.forEach(function(f) {
+    var fp = Seed.argv[2] + '/' + f;
+    
+    
+    
+    if (!fp.match(/\.js$/)) {
+        return;
+    }
+    var js = fp; //.replace(/\.js$/, '.js');
+    if (File.isFile(js)) {
+        // check file time.. = bjs is less than compiled file..
+        //if (File.mtime(fp) < File.mtime(js)) {
+            XObject.log("LOADING" + js);
+            olist.push(imports[js]);
+            return;
+        //}
+        // Compiling BJS is depreciated..
+        //olist.push(imports[js]);
+        //return;
+        
+    }
+    
+    return;
+    /*
+    var gtkbuilder =  new imports.Builder.Provider.File.Gtk.Gtk({ path : fp });
+    gtkbuilder.loadItems(function() { });
+    XObject.log("COMPILING" + js);
+    var fn = gtkbuilder.saveJS();
+    if (fn === false) { // skip files that do not contain anythng!
+        return;
+    }
+    olist.push(imports[fn]);
+    */
+    
+});
+
+
+
+          
+Gtk.main();
diff --git a/old-javascript/roojs-bootstrap-debug.js b/old-javascript/roojs-bootstrap-debug.js
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/old-javascript/roojs-bootstrap.js b/old-javascript/roojs-bootstrap.js
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/old-javascript/test.js b/old-javascript/test.js
new file mode 100644 (file)
index 0000000..1d1a3a0
--- /dev/null
@@ -0,0 +1,12 @@
+Gtk = imports.gi.Gtk;
+Gdk = imports.gi.Gdk;
+Pango = imports.gi.Pango;
+XObject = imports.XObject.XObject;
+Gtk.init(null,null);
+
+
+_top=new XObject({xtype: Gtk.Window, "type":Gtk.WindowType.TOPLEVEL, "title":"Application Builder", "border_width":2, "id":"builder-0", "xtreepath":"0"})
+
+;_top.init();
+_top.el.show_all();
+Gtk.main();