sync
[roojs1] / roojs-debug.js
index d0fc96f..f578a8a 100644 (file)
@@ -85,6 +85,12 @@ Roo.apply = function(o, c, defaults){
          * @type Boolean
          */
         isReady : false,
+        /**
+         * Turn on debugging output (currently only the factory uses this)
+         * @type Boolean
+         */
+        
+        debug: false,
 
         /**
          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
@@ -297,7 +303,7 @@ Roo.factory(conf, Roo.data);
                 return c;
             }
             if (ns[c.xtype]) {
-                console.log("Roo.Factory(" + c.xtype + ")");
+                if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
                 var ret = new ns[c.xtype](c);
                 ret.xns = false;
                 return ret;
@@ -305,7 +311,20 @@ Roo.factory(conf, Roo.data);
             c.xns = false; // prevent recursion..
             return c;
         },
-         
+         /**
+         * Logs to console if it can.
+         *
+         * @param {String|Object} string
+         * @method log
+         */
+        log : function(s)
+        {
+            if ((typeof(console) == 'undefined') || typeof(console.log) == 'undefined')) {
+                return; // alerT?
+            }
+            console.log(s);
+            
+        },
         /**
          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
          * @param {Object} o
@@ -843,8 +862,32 @@ Roo.applyIf(Array.prototype, {
        if(index != -1){
            this.splice(index, 1);
        }
+    },
+    /**
+     * Map (JS 1.6 compatibility)
+     * @param {Function} function  to call
+     */
+    map : function(fun )
+    {
+        var len = this.length >>> 0;
+        if (typeof fun != "function")
+            throw new TypeError();
+
+        var res = new Array(len);
+        var thisp = arguments[1];
+        for (var i = 0; i < len; i++)
+        {
+            if (i in this)
+                res[i] = fun.call(thisp, this[i], i, this);
+        }
+
+        return res;
     }
-});/*
+    
+});
+
+
+ /*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -4385,36 +4428,43 @@ Roo.Template.prototype = {
      * @return {String} The HTML fragment
      */
     applyTemplate : function(values){
-        if(this.compiled){
-            return this.compiled(values);
-        }
-        var useF = this.disableFormats !== true;
-        var fm = Roo.util.Format, tpl = this;
-        var fn = function(m, name, format, args){
-            if(format && useF){
-                if(format.substr(0, 5) == "this."){
-                    return tpl.call(format.substr(5), values[name], values);
-                }else{
-                    if(args){
-                        // quoted values are required for strings in compiled templates, 
-                        // but for non compiled we need to strip them
-                        // quoted reversed for jsmin
-                        var re = /^\s*['"](.*)["']\s*$/;
-                        args = args.split(',');
-                        for(var i = 0, len = args.length; i < len; i++){
-                            args[i] = args[i].replace(re, "$1");
-                        }
-                        args = [values[name]].concat(args);
+        try {
+            
+            if(this.compiled){
+                return this.compiled(values);
+            }
+            var useF = this.disableFormats !== true;
+            var fm = Roo.util.Format, tpl = this;
+            var fn = function(m, name, format, args){
+                if(format && useF){
+                    if(format.substr(0, 5) == "this."){
+                        return tpl.call(format.substr(5), values[name], values);
                     }else{
-                        args = [values[name]];
+                        if(args){
+                            // quoted values are required for strings in compiled templates, 
+                            // but for non compiled we need to strip them
+                            // quoted reversed for jsmin
+                            var re = /^\s*['"](.*)["']\s*$/;
+                            args = args.split(',');
+                            for(var i = 0, len = args.length; i < len; i++){
+                                args[i] = args[i].replace(re, "$1");
+                            }
+                            args = [values[name]].concat(args);
+                        }else{
+                            args = [values[name]];
+                        }
+                        return fm[format].apply(fm, args);
                     }
-                    return fm[format].apply(fm, args);
+                }else{
+                    return values[name] !== undefined ? values[name] : "";
                 }
-            }else{
-                return values[name] !== undefined ? values[name] : "";
-            }
-        };
-        return this.html.replace(this.re, fn);
+            };
+            return this.html.replace(this.re, fn);
+        } catch (e) {
+            Roo.log(e);
+            throw e;
+        }
+         
     },
     
     /**
@@ -7349,10 +7399,17 @@ if(opt.anim.isAnimated()){
          */
         setStyle : function(prop, value){
             if(typeof prop == "string"){
+                
+                if (prop == 'float') {
+                    this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
+                    return this;
+                }
+                
                 var camel;
                 if(!(camel = propCache[prop])){
                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
                 }
+                
                 if(camel == 'opacity') {
                     this.setOpacity(value);
                 }else{
@@ -13855,6 +13912,8 @@ Roo.util.TextMetrics = function(){
     };
 }();
 
+
 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
     var ml = new Roo.Element(document.createElement('div'));
     document.body.appendChild(ml.dom);
@@ -13865,10 +13924,11 @@ Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
     if(fixedWidth){
         ml.setWidth(fixedWidth);
     }
-
+     
     var instance = {
         /**
          * Returns the size of the specified text based on the internal element's style and width properties
+         * @memberOf Roo.util.TextMetrics.Instance#
          * @param {String} text The text to measure
          * @return {Object} An object containing the text's size {width: (width), height: (height)}
          */
@@ -13882,6 +13942,7 @@ Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
         /**
          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
          * that can affect the size of the rendered text
+         * @memberOf Roo.util.TextMetrics.Instance#
          * @param {String/HTMLElement} el The element, dom node or id
          */
         bind : function(el){
@@ -13893,6 +13954,7 @@ Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
         /**
          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
          * to set a fixed width in order to accurately measure the text height.
+         * @memberOf Roo.util.TextMetrics.Instance#
          * @param {Number} width The width to set on the element
          */
         setFixedWidth : function(width){
@@ -13901,6 +13963,7 @@ Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
 
         /**
          * Returns the measured width of the specified text
+         * @memberOf Roo.util.TextMetrics.Instance#
          * @param {String} text The text to measure
          * @return {Number} width The width in pixels
          */
@@ -13912,6 +13975,7 @@ Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
         /**
          * Returns the measured height of the specified text.  For multiline text, be sure to call
          * {@link #setFixedWidth} if necessary.
+         * @memberOf Roo.util.TextMetrics.Instance#
          * @param {String} text The text to measure
          * @return {Number} height The height in pixels
          */
@@ -23208,12 +23272,13 @@ Roo.SplitBar.BOTTOM = 4;
  <pre><code>
  var store = new Roo.data.Store(...);
 
- var view = new Roo.View("my-element",
- '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
- {
- singleSelect: true,
- selectedClass: "ydataview-selected",
- store: store
+ var view = new Roo.View({
+    el : "my-element",
+    template : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
+    singleSelect: true,
+    selectedClass: "ydataview-selected",
+    store: store
  });
 
  // listen for node click?
@@ -23228,26 +23293,37 @@ Roo.SplitBar.BOTTOM = 4;
  * <br><br>
  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
+ * 
+ * Note: old style constructor is still suported (container, template, config)
+ * 
  * @constructor
  * Create a new View
- * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
- * @param {String/DomHelper.Template} tpl The rendering template or a string to create a template with
  * @param {Object} config The config object
+ * 
  */
-Roo.View = function(container, tpl, config){
-    this.el = Roo.get(container);
-    if(typeof tpl == "string"){
-        tpl = new Roo.Template(tpl);
+Roo.View = function(config, depreciated_tpl, depreciated_config){
+    
+    if (typeof(depreciated_tpl) == 'undefined') {
+        // new way.. - universal constructor.
+        Roo.apply(this, config);
+        this.el  = Roo.get(this.el);
+    } else {
+        // old format..
+        this.el  = Roo.get(config);
+        this.tpl = depreciated_tpl;
+        Roo.apply(this, depreciated_config);
     }
-    tpl.compile();
-    /**
-     * The template used by this View
-     * @type {Roo.DomHelper.Template}
-     */
-    this.tpl = tpl;
-
-    Roo.apply(this, config);
+     
+    
+    if(typeof(this.tpl) == "string"){
+        this.tpl = new Roo.Template(this.tpl);
+    } 
+    
+    
+    this.tpl.compile();
+   
 
+     
     /** @private */
     this.addEvents({
     /**
@@ -23322,12 +23398,29 @@ Roo.View = function(container, tpl, config){
 };
 
 Roo.extend(Roo.View, Roo.util.Observable, {
+    
+     /**
+     * @cfg {Roo.data.Store} store Data store to load data from.
+     */
+    store : false,
+    
     /**
-     * The css class to add to selected nodes
-     * @type {Roo.DomHelper.Template}
+     * @cfg {String|Roo.Element} el The container element.
      */
-    selectedClass : "x-view-selected",
+    el : '',
+    
+    /**
+     * @cfg {String|Roo.Template} tpl The template used by this View 
+     */
+    tpl : false,
     
+    /**
+     * @cfg {String} selectedClass The css class to add to selected nodes
+     */
+    selectedClass : "x-view-selected",
+     /**
+     * @cfg {String} emptyText The empty text to show when nothing is loaded.
+     */
     emptyText : "",
     /**
      * Returns the element this view is bound to.
@@ -23670,10 +23763,12 @@ Roo.extend(Roo.View, Roo.util.Observable, {
  * @extends Roo.View
  * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
 <pre><code>
-var view = new Roo.JsonView("my-element",
-    '&lt;div id="{id}"&gt;{foo} - {bar}&lt;/div&gt;', // auto create template
-    { multiSelect: true, jsonRoot: "data" }
-);
+var view = new Roo.JsonView({
+    container: "my-element",
+    template: '&lt;div id="{id}"&gt;{foo} - {bar}&lt;/div&gt;', // auto create template
+    multiSelect: true, 
+    jsonRoot: "data" 
+});
 
 // listen for node click?
 view.on("click", function(vw, index, node, e){
@@ -23691,7 +23786,9 @@ var tpl = new Roo.Template(
     "&lt;/div&gt;&lt;hr /&gt;"
 );
 
-var moreView = new Roo.JsonView("entry-list", tpl, {
+var moreView = new Roo.JsonView({
+    container :  "entry-list", 
+    template : tpl,
     jsonRoot: "posts"
 });
 moreView.on("beforerender", this.sortEntries, this);
@@ -23701,14 +23798,20 @@ moreView.load({
     text: "Loading Blog Entries..."
 });
 </code></pre>
+* 
+* Note: old code is supported with arguments : (container, template, config)
+* 
+* 
  * @constructor
  * Create a new JsonView
- * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
- * @param {Template} tpl The rendering template
+ * 
  * @param {Object} config The config object
+ * 
  */
-Roo.JsonView = function(container, tpl, config){
-    Roo.JsonView.superclass.constructor.call(this, container, tpl, config);
+Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
+    
+    
+    Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
 
     var um = this.el.getUpdateManager();
     um.setRenderer(this);
@@ -23742,8 +23845,7 @@ Roo.JsonView = function(container, tpl, config){
 };
 Roo.extend(Roo.JsonView, Roo.View, {
     /**
-     * The root property in the loaded JSON object that contains the data
-     * @type {String}
+     * @type {String} The root property in the loaded JSON object that contains the data
      */
     jsonRoot : "",
 
@@ -39565,11 +39667,15 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
  * @param {Object} config Configuration options
  */
 Roo.form.BasicForm = function(el, config){
+    this.allItems = [];
+    this.childForms = [];
     Roo.apply(this, config);
     /*
      * The Roo.form.Field items in this form.
      * @type MixedCollection
      */
+     
+     
     this.items = new Roo.util.MixedCollection(false, function(o){
         return o.id || (o.id = Roo.id());
     });
@@ -39642,7 +39748,20 @@ Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
      * or setValues() data instead of when the form was first created.
      */
     trackResetOnLoad : false,
-
+    
+    
+    /**
+     * childForms - used for multi-tab forms
+     * @type {Array}
+     */
+    childForms : false,
+    
+    /**
+     * allItems - full list of fields.
+     * @type {Array}
+     */
+    allItems : false,
+    
     /**
      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
      * element by passing it or its id or mask the form itself by passing in true.
@@ -39827,7 +39946,28 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
         return field || null;
     },
 
-
+    /**
+     * Add a secondary form to this one, 
+     * Used to provide tabbed forms. One form is primary, with hidden values 
+     * which mirror the elements from the other forms.
+     * 
+     * @param {Roo.form.Form} form to add.
+     * 
+     */
+    addForm : function(form){
+       
+        this.childForms.push(form);
+        Roo.each(form.allItems, function (fe) {
+            
+            if (this.findField(fe.name)) { // already added..
+                return;
+            }
+            this.add( new Roo.form.Hidden({
+                name : fe.name
+            }));
+        }, this);
+        
+    },
     /**
      * Mark fields in this form invalid in bulk.
      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
@@ -39850,6 +39990,10 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
                 }
             }
         }
+        Roo.each(this.childForms || [], function (f) {
+            f.markInvalid(errors);
+        });
+        
         return this;
     },
 
@@ -39900,6 +40044,11 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
                 }
             }
         }
+         
+        Roo.each(this.childForms || [], function (f) {
+            f.setValues(values);
+        });
+                
         return this;
     },
 
@@ -39910,6 +40059,21 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
      * @return {Object}
      */
     getValues : function(asString){
+        if (this.childForms) {
+            // copy values from the child forms
+            Roo.each(this.childForms, function (f) {
+                if (f.allFields) {
+                    Roo.each(f.allFields, function (e) {
+                        if (e.name && e.getValue && this.findField(e.name)) {
+                            this.findField(e.name).setValue(e.getValue());
+                        }
+                    });
+                }
+            }, this);
+        }
+        
+        
+        
         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
         if(asString === true){
             return fs;
@@ -39925,6 +40089,12 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
         this.items.each(function(f){
            f.clearInvalid();
         });
+        
+        Roo.each(this.childForms || [], function (f) {
+            f.clearInvalid();
+        });
+        
+        
         return this;
     },
 
@@ -39936,6 +40106,12 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
         this.items.each(function(f){
             f.reset();
         });
+        
+        Roo.each(this.childForms || [], function (f) {
+            f.reset();
+        });
+       
+        
         return this;
     },
 
@@ -40026,7 +40202,7 @@ Roo.form.Form = function(config){
         xitems = config.items;
         delete config.items;
     }
-    
+   
     
     Roo.form.Form.superclass.constructor.call(this, null, config);
     this.url = this.url || this.action;
@@ -40099,6 +40275,7 @@ Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
      */
     monitorPoll : 200,
 
+  
     /**
      * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
      * fields are added and the column is closed. If no fields are passed the column remains open
@@ -40208,6 +40385,11 @@ Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
         }
         return this;
     },
+    
+
+    
+    
+    
      /**
      * Find any element that has been added to a form, using it's ID or name
      * This can include framesets, columns etc. along with regular fields..
@@ -44528,7 +44710,7 @@ panel.load({
     },
     
       /**
-     * Adds a xtype elements to the panel - currently only supports Forms.
+     * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
      * <pre><code>
 
 layout.addxtype({
@@ -44543,16 +44725,25 @@ layout.addxtype({
     
     addxtype : function(cfg) {
         // add form..
-        if (!cfg.xtype.match(/^Form$/)) {
-            return false;
-        }
-        var el = this.el.createChild();
+        if (cfg.xtype.match(/^Form$/)) {
+            var el = this.el.createChild();
 
-        this.form = new  Roo.form.Form(cfg);
-        
-        
-        if ( this.form.allItems.length) this.form.render(el.dom);
-        return this.form;
+            this.form = new  Roo.form.Form(cfg);
+            
+            
+            if ( this.form.allItems.length) this.form.render(el.dom);
+            return this.form;
+        }
+        if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
+            // views..
+            cfg.el = this.el;
+            // factory?
+            var ret = new Roo[cfg.xtype](cfg);
+            ret.render(false, ''); // render blank..
+            return ret;
+            
+        }
+        return false;
         
     }
 });
@@ -49050,12 +49241,14 @@ Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
             if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
                 this.editing = true;
                 var ed = this.colModel.getCellEditor(col, row);
+                
                 if (!ed) {
                     return;
                 }
                 if(!ed.rendered){
                     ed.render(ed.parentEl || document.body);
                 }
+                ed.field.reset();
                 (function(){ // complex but required for focus issues in safari, ie and opera
                     ed.row = row;
                     ed.col = col;
@@ -49649,4 +49842,980 @@ Roo.extend(Roo.XTemplate, Roo.Template, {
 Roo.XTemplate.from = function(el){
     el = Roo.getDom(el);
     return new Roo.XTemplate(el.value || el.innerHTML);
-};
\ No newline at end of file
+};/*
+ * Original code for Roojs - LGPL
+ * <script type="text/javascript">
+ */
+/**
+ * @class Roo.XComponent
+ * A delayed Element creator...
+ * 
+ * Mypart.xyx = new Roo.XComponent({
+
+    parent : 'Mypart.xyz', // empty == document.element.!!
+    order : '001',
+    name : 'xxxx'
+    region : 'xxxx'
+    disabled : function() {} 
+     
+    tree : function() { // return an tree of xtype declared components
+        var MODULE = this;
+        return 
+        {
+            xtype : 'NestedLayoutPanel',
+            // technicall
+        }
+     ]
+ *})
+ * @extends Roo.util.Observable
+ * @constructor
+ * @param cfg {Object} configuration of component
+ * 
+ */
+Roo.XComponent = function(cfg) {
+    Roo.apply(this, cfg);
+    this.addEvents({ 
+        /**
+            * @event built
+            * Fires when this the componnt is built
+            * @param {Roo.XComponent} c the component
+            */
+        'built' : true,
+        /**
+            * @event buildcomplete
+            * Fires on the top level element when all elements have been built
+            * @param {Roo.XComponent} c the top level component.
+         */
+        'buildcomplete' : true,
+        
+    });
+    
+    Roo.XComponent.register(this);
+    this.modules = false;
+    this.el = false; // where the layout goes..
+    
+    
+}
+Roo.extend(Roo.XComponent, Roo.util.Observable, {
+    /**
+     * @property el
+     * The created element (with Roo.factory())
+     * @type {Roo.Layout}
+     */
+    el  : false,
+    
+    /**
+     * @property el
+     * for BC  - use el in new code
+     * @type {Roo.Layout}
+     */
+    panel : false,
+    
+    /**
+     * @property layout
+     * for BC  - use el in new code
+     * @type {Roo.Layout}
+     */
+    layout : false,
+    
+     /**
+     * @cfg {Function|boolean} disabled
+     * If this module is disabled by some rule, return true from the funtion
+     */
+    disabled : false,
+    
+    /**
+     * @cfg {String} parent 
+     * Name of parent element which it get xtype added to..
+     */
+    parent: false,
+    
+    /**
+     * @cfg {String} order
+     * Used to set the order in which elements are created (usefull for multiple tabs)
+     */
+    
+    order : false,
+    /**
+     * @cfg {String} name
+     * String to display while loading.
+     */
+    name : false,
+    /**
+     * @cfg {Array} items
+     * A single item array - the first element is the root of the tree..
+     * It's done this way to stay compatible with the Xtype system...
+     */
+    items : false,
+     
+     
+    
+});
+
+Roo.apply(Roo.XComponent, {
+    
+    /**
+     * @property  buildCompleted
+     * True when the builder has completed building the interface.
+     * @type Boolean
+     */
+    buildCompleted : false,
+     
+    /**
+     * @property  topModule
+     * the upper most module - uses document.element as it's constructor.
+     * @type Object
+     */
+     
+    topModule  : false,
+      
+    /**
+     * @property  modules
+     * array of modules to be created by registration system.
+     * @type Roo.XComponent
+     */
+    
+    modules : [],
+      
+    
+    /**
+     * Register components to be built later.
+     *
+     * This solves the following issues
+     * - Building is not done on page load, but after an authentication process has occured.
+     * - Interface elements are registered on page load
+     * - Parent Interface elements may not be loaded before child, so this handles that..
+     * 
+     *
+     * example:
+     * 
+     * MyApp.register({
+          order : '000001',
+          module : 'Pman.Tab.projectMgr',
+          region : 'center',
+          parent : 'Pman.layout',
+          disabled : false,  // or use a function..
+        })
+     
+     * * @param {Object} details about module
+     */
+    register : function(obj) {
+        this.modules.push(obj);
+         
+    },
+    /**
+     * convert a string to an object..
+     * 
+     */
+    
+    toObject : function(str)
+    {
+        if (!str || typeof(str) == 'object') {
+            return str;
+        }
+        var ar = str.split('.');
+        var rt, o;
+        rt = ar.shift();
+            /** eval:var:o */
+        eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
+        if (o === false) {
+            throw "Module not found : " + str;
+        }
+        Roo.each(ar, function(e) {
+            if (typeof(o[e]) == 'undefined') {
+                throw "Module not found : " + str;
+            }
+            o = o[e];
+        });
+        return o;
+        
+    },
+    
+    
+    /**
+     * move modules into their correct place in the tree..
+     * 
+     */
+    preBuild : function ()
+    {
+        
+        Roo.each(this.modules , function (obj)
+        {
+            obj.parent = this.toObject(obj.parent);
+            
+            if (!obj.parent) {
+                this.topModule = obj;
+                return;
+            }
+            
+            if (!obj.parent.modules) {
+                obj.parent.modules = new Roo.util.MixedCollection(false, 
+                    function(o) { return o.order + '' }
+                );
+            }
+            
+            obj.parent.modules.add(obj);
+        }, this);
+    },
+    
+     /**
+     * make a list of modules to build.
+     * @return {Array} list of modules. 
+     */ 
+    
+    buildOrder : function()
+    {
+        var _this = this;
+        var cmp = function(a,b) {   
+            return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
+        };
+        
+        if (!this.topModule || !this.topModule.modules) {
+            throw "No top level modules to build";
+        }
+       
+        // make a flat list in order of modules to build.
+        var mods = [ this.topModule ];
+        
+        
+        // add modules to their parents..
+        var addMod = function(m) {
+           // console.log(m.modKey);
+            
+            mods.push(m);
+            if (m.modules) {
+                m.modules.keySort('ASC',  cmp );
+                m.modules.each(addMod);
+            }
+            // not sure if this is used any more..
+            if (m.finalize) {
+                m.finalize.name = m.name + " (clean up) ";
+                mods.push(m.finalize);
+            }
+            
+        }
+        this.topModule.modules.keySort('ASC',  cmp );
+        this.topModule.modules.each(addMod);
+        return mods;
+    },
+    
+     /**
+     * Build the registered modules.
+     * @param {Object} parent element.
+     * @param {Function} optional method to call after module has been added.
+     * 
+     */ 
+   
+    build : function() 
+    {
+        
+        this.preBuild();
+        var mods = this.buildOrder();
+      
+        //this.allmods = mods;
+        //console.log(mods);
+        //return;
+        if (!mods.length) { // should not happen
+            throw "NO modules!!!";
+        }
+        
+        
+        
+        // flash it up as modal - so we store the mask!?
+        Roo.MessageBox.show({ title: 'loading' });
+        Roo.MessageBox.show({
+           title: "Please wait...",
+           msg: "Building Interface...",
+           width:450,
+           progress:true,
+           closable:false,
+           modal: false
+          
+        });
+        var total = mods.length;
+        
+        var _this = this;
+        var progressRun = function() {
+            if (!mods.length) {
+                console.log('hide?');
+                Roo.MessageBox.hide();
+                _this.topModule.fireEvent('buildcomplete', _this.topModule);
+                return;    
+            }
+            
+            var m = mods.shift();
+            console.log(m);
+            if (typeof(m) == 'function') { // not sure if this is supported any more..
+                m.call(this);
+                return progressRun.defer(10, _this);
+            } 
+            
+            Roo.MessageBox.updateProgress(
+                (total  - mods.length)/total,  "Building Interface " + (total  - mods.length) + 
+                    " of " + total + 
+                    (m.name ? (' - ' + m.name) : '')
+                    );
+            
+         
+            
+            var disabled = (typeof(m.disabled) == 'function') ?
+                m.disabled.call(m.module.disabled) : m.disabled;    
+            
+            
+            if (disabled) {
+                return progressRun(); // we do not update the display!
+            }
+            
+            if (!m.parent) {
+                // it's a top level one..
+                var layoutbase = new Ext.BorderLayout(document.body, {
+               
+                    center: {
+                         titlebar: false,
+                         autoScroll:false,
+                         closeOnTab: true,
+                         tabPosition: 'top',
+                         //resizeTabs: true,
+                         alwaysShowTabs: true,
+                         minTabWidth: 140
+                    }
+                });
+                var tree = m.tree();
+                tree.region = 'center';
+                m.el = layoutbase.addxtype(tree);
+                m.panel = m.el;
+                m.layout = m.panel.layout;    
+                return progressRun.defer(10, _this);
+            }
+            
+            var tree = m.tree();
+            tree.region = tree.region || m.region;
+            m.el = m.parent.el.addxtype(tree);
+            m.fireEvent('built', m);
+            m.panel = m.el;
+            m.layout = m.panel.layout;    
+            progressRun.defer(10, _this); 
+            
+        }
+        progressRun.defer(1, _this);
+     
+        
+        
+    }
+     
+   
+    
+    
+});
+ //<script type="text/javascript">
+
+
+/**
+ * @class Roo.Login
+ * @extends Roo.LayoutDialog
+ * A generic Login Dialog..... - only one needed in theory!?!?
+ *
+ * Fires XComponent builder on success...
+ * 
+ * Sends 
+ *    username,password, lang = for login actions.
+ *    check = 1 for periodic checking that sesion is valid.
+ *    passwordRequest = email request password
+ *    logout = 1 = to logout
+ * 
+ * Affects: (this id="????" elements)
+ *   loading  (removed) (used to indicate application is loading)
+ *   loading-mask (hides) (used to hide application when it's building loading)
+ *   
+ * 
+ * Usage: 
+ *    
+ * 
+ * Myapp.login = Roo.Login({
+     url: xxxx,
+   
+     realm : 'Myapp', 
+     
+     
+     method : 'POST',
+     
+     
+     * 
+ })
+ * 
+ * 
+ * 
+ **/
+Roo.Login = function(cfg)
+{
+    this.addEvents({
+        'refreshed' : true,
+    });
+    
+    Roo.apply(this,cfg);
+    
+    Roo.onReady(function() {
+        this.onLoad();
+    }, this);
+    // call parent..
+    
+   
+    Roo.Login.superclass.constructor.call(this, this);
+    //this.addxtype(this.items[0]);
+    
+    
+}
+
+
+Roo.extend(Roo.Login, Roo.LayoutDialog, {
+    
+    /**
+     * @cfg {String} method
+     * Method used to query for login details.
+     */
+    
+    method : 'POST',
+    /**
+     * @cfg {String} url
+     * URL to query login data. - eg. baseURL + '/Login.php'
+     */
+    url : '',
+    
+    /**
+     * @property user
+     * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
+     * @type {Object} 
+     */
+    user : false,
+    /**
+     * @property checkFails
+     * Number of times we have attempted to get authentication check, and failed.
+     * @type {Number} 
+     */
+    checkFails : 0,
+      /**
+     * @property intervalID
+     * The window interval that does the constant login checking.
+     * @type {Number} 
+     */
+    intervalID : 0,
+    
+    
+    onLoad : function() // called on page load...
+    {
+        // load 
+         
+        if (Roo.get('loading')) { // clear any loading indicator..
+            Roo.get('loading').remove();
+        }
+        
+        //this.switchLang('en'); // set the language to english..
+       
+        this.check({
+            success:  function(response, opts)  {  // check successfull...
+            
+                var res = this.processResponse(response);
+                this.checkFails =0;
+                if (!res.success) { // error!
+                    this.checkFails = 5;
+                    //console.log('call failure');
+                    return this.failure(response,opts);
+                }
+                
+                if (!res.data.id) { // id=0 == login failure.
+                    return this.show();
+                }
+                
+                              
+                        //console.log(success);
+                this.fillAuth(res.data);   
+                this.checkFails =0;
+                Roo.XComponent.build();
+            },
+            failure : this.show
+        });
+        
+    }, 
+    
+    
+    check: function(cfg) // called every so often to refresh cookie etc..
+    {
+        if (cfg.again) { // could be undefined..
+            this.checkFails++;
+        } else {
+            this.checkFails = 0;
+        }
+        var _this = this;
+        if (this.sending) {
+            if ( this.checkFails > 4) {
+                Roo.MessageBox.alert("Error",  
+                    "Error getting authentication status. - try reloading, or wait a while", function() {
+                        _this.sending = false;
+                    }); 
+                return;
+            }
+            cfg.again = true;
+            _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
+            return;
+        }
+        this.sending = true;
+        
+        Roo.Ajax.request({  
+            url: this.url,
+            params: {
+                getAuthUser: true
+            },  
+            method: this.method,
+            success:  cfg.success || this.success,
+            failure : cfg.failure || this.failure,
+            scope : this,
+            callCfg : cfg
+              
+        });  
+    }, 
+    
+    
+    logout: function()
+    {
+        window.onbeforeunload = function() { }; // false does not work for IE..
+        this.user = false;
+        var _this = this;
+        
+        Roo.Ajax.request({  
+            url: this.url,
+            params: {
+                logout: 1
+            },  
+            method: 'GET',
+            failure : function() {
+                Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
+                    document.location = document.location.toString() + '?ts=' + Math.random();
+                });
+                
+            },
+            success : function() {
+                _this.user = false;
+                this.checkFails =0;
+                // fixme..
+                document.location = document.location.toString() + '?ts=' + Math.random();
+            }
+              
+              
+        }); 
+    },
+    
+    processResponse : function (response)
+    {
+        var res = '';
+        try {
+            res = Roo.decode(response.responseText);
+            // oops...
+            if (typeof(res) != 'object') {
+                res = { success : false, errorMsg : res, errors : true };
+            }
+            if (typeof(res.success) == 'undefined') {
+                res.success = false;
+            }
+            
+        } catch(e) {
+            res = { success : false,  errorMsg : response.responseText, errors : true };
+        }
+        return res;
+    },
+    
+    success : function(response, opts)  // check successfull...
+    {  
+        this.sending = false;
+        var res = this.processResponse(response);
+        if (!res.success) {
+            return this.failure(response, opts);
+        }
+        if (!res.data || !res.data.id) {
+            return this.failure(response,opts);
+        }
+        //console.log(res);
+        this.fillAuth(res.data);
+        
+        this.checkFails =0;
+        
+    },
+    
+    
+    failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
+    {
+        this.authUser = -1;
+        this.sending = false;
+        var res = this.processResponse(response);
+        //console.log(res);
+        if ( this.checkFails > 2) {
+        
+            Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg : 
+                "Error getting authentication status. - try reloading"); 
+            return;
+        }
+        opts.callCfg.again = true;
+        this.check.defer(1000, this, [ opts.callCfg ]);
+        return;  
+    },
+    
+    
+    
+    fillAuth: function(au) {
+        this.startAuthCheck();
+        this.authUserId = au.id;
+        this.authUser = au;
+        this.lastChecked = new Date();
+        this.fireEvent('refreshed', au);
+        //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
+        //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
+        au.lang = au.lang || 'en';
+        //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
+        Roo.state.Manager.set( this.realm + 'lang' , au.lang);
+        this.switchLang(au.lang );
+        
+     
+        // open system... - -on setyp..
+        if (this.authUserId  < 0) {
+            Roo.MessageBox.alert("Warning", 
+                "This is an open system - please set up a admin user with a password.");  
+        }
+         
+        //Pman.onload(); // which should do nothing if it's a re-auth result...
+        
+             
+    },
+    
+    startAuthCheck : function() // starter for timeout checking..
+    {
+        if (this.intervalID) { // timer already in place...
+            return false;
+        }
+        var _this = this;
+        this.intervalID =  window.setInterval(function() {
+              _this.check(false);
+            }, 120000); // every 120 secs = 2mins..
+        
+        
+    },
+         
+    
+    switchLang : function (lang) 
+    {
+        _T = typeof(_T) == 'undefined' ? false : _T;
+          if (!_T || !lang.length) {
+            return;
+        }
+        
+        if (!_T && lang != 'en') {
+            Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
+            return;
+        }
+        
+        if (typeof(_T.en) == 'undefined') {
+            _T.en = {};
+            Roo.apply(_T.en, _T);
+        }
+        
+        if (typeof(_T[lang]) == 'undefined') {
+            Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
+            return;
+        }
+        
+        
+        Roo.apply(_T, _T[lang]);
+        // just need to set the text values for everything...
+        var _this = this;
+        /* this will not work ...
+        if (this.form) { 
+            
+               
+            function formLabel(name, val) {
+                _this.form.findField(name).fieldEl.child('label').dom.innerHTML  = val;
+            }
+            
+            formLabel('password', "Password"+':');
+            formLabel('username', "Email Address"+':');
+            formLabel('lang', "Language"+':');
+            this.dialog.setTitle("Login");
+            this.dialog.buttons[0].setText("Forgot Password");
+            this.dialog.buttons[1].setText("Login");
+        }
+        */
+        
+        
+    },
+    
+    
+    title: "Login",
+    modal: true,
+    width:  350,
+    //height: 230,
+    height: 180,
+    shadow: true,
+    minWidth:200,
+    minHeight:180,
+    //proxyDrag: true,
+    closable: false,
+    draggable: false,
+    collapsible: false,
+    resizable: false,
+    center: {  // needed??
+        autoScroll:false,
+        titlebar: false,
+       // tabPosition: 'top',
+        hideTabs: true,
+        closeOnTab: true,
+        alwaysShowTabs: false
+    } ,
+    listeners : {
+        
+        show  : function(dlg)
+        {
+            //console.log(this);
+            this.form = this.layout.getRegion('center').activePanel.form;
+            this.form.dialog = dlg;
+            this.buttons[0].form = this.form;
+            this.buttons[0].dialog = dlg
+            this.buttons[1].form = this.form;
+            this.buttons[1].dialog = dlg;
+           
+           //this.resizeToLogo.defer(1000,this);
+            // this is all related to resizing for logos..
+            //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
+           //// if (!sz) {
+             //   this.resizeToLogo.defer(1000,this);
+             //   return;
+           // }
+            //var w = Ext.lib.Dom.getViewWidth() - 100;
+            //var h = Ext.lib.Dom.getViewHeight() - 100;
+            //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
+            //this.center();
+            if (this.disabled) {
+                this.hide();
+                return;
+            }
+            
+            if (this.user.id < 0) { // used for inital setup situations.
+                return;
+            }
+            
+            if (this.intervalID) {
+                // remove the timer
+                window.clearInterval(this.intervalID);
+                this.intervalID = false;
+            }
+            
+            
+            if (Roo.get('loading')) {
+                Roo.get('loading').remove();
+            }
+            if (Roo.get('loading-mask')) {
+                Roo.get('loading-mask').hide();
+            }
+            
+            //incomming._node = tnode;
+            this.form.reset();
+            //this.dialog.modal = !modal;
+            //this.dialog.show();
+            this.el.unmask(); 
+            
+            
+            this.form.setValues({
+                'username' : Roo.state.Manager.get(this.realm + '.username', ''),
+                'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
+            });
+            
+            this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
+            if (this.form.findField('username').getValue().length > 0 ){
+                this.form.findField('password').focus();
+            } else {
+               this.form.findField('username').focus();
+            }
+    
+        }
+    },
+    items : [
+         {
+       
+            xtype : 'ContentPanel',
+            xns : Roo,
+            region: 'center',
+            fitToFrame : true,
+            
+            items : [
+    
+                {
+               
+                    xtype : 'Form',
+                    xns : Roo.form,
+                    labelWidth: 100,
+                    style : 'margin: 10px;',
+                    
+                    listeners : {
+                        actionfailed : function(f, act) {
+                            // form can return { errors: .... }
+                                
+                            //act.result.errors // invalid form element list...
+                            //act.result.errorMsg// invalid form element list...
+                            
+                            this.dialog.el.unmask();
+                            Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg : 
+                                        "Login failed - communication error - try again.");
+                                      
+                        },
+                        actioncomplete: function(re, act) {
+                             
+                            Roo.state.Manager.set(
+                                this.dialog.realm + '.username',  
+                                    this.findField('username').getValue()
+                            );
+                            Roo.state.Manager.set(
+                                this.dialog.realm + '.lang',  
+                                this.findField('lang').getValue() 
+                            );
+                            
+                            this.dialog.fillAuth(act.result.data);
+                              
+                            this.dialog.hide();
+                            
+                            if (Roo.get('loading-mask')) {
+                                Roo.get('loading-mask').show();
+                            }
+                            Roo.XComponent.build();
+                            
+                             
+                            
+                        }
+                    },
+                    items : [
+                        {
+                            xtype : 'TextField',
+                            xns : Roo.form,
+                            fieldLabel: "Email Address",
+                            name: 'username',
+                            width:200,
+                            autoCreate : {tag: "input", type: "text", size: "20"}
+                        },
+                        {
+                            xtype : 'TextField',
+                            xns : Roo.form,
+                            fieldLabel: "Password",
+                            inputType: 'password',
+                            name: 'password',
+                            width:200,
+                            autoCreate : {tag: "input", type: "text", size: "20"},
+                            listeners : {
+                                specialkey : function(e,ev) {
+                                    if (ev.keyCode == 13) {
+                                        this.form.dialog.el.mask("Logging in");
+                                        this.form.doAction('submit', {
+                                            url: this.form.dialog.url,
+                                            method: this.form.dialog.method,
+                                        });
+                                    }
+                                }
+                            }  
+                        },
+                        {
+                            xtype : 'ComboBox',
+                            xns : Roo.form,
+                            fieldLabel: "Language",
+                            name : 'langdisp',
+                            store: {
+                                xtype : 'SimpleStore',
+                                fields: ['lang', 'ldisp'],
+                                data : [
+                                    [ 'en', 'English' ],
+                                    [ 'zh_HK' , '\u7E41\u4E2D' ],
+                                    [ 'zh_CN', '\u7C21\u4E2D' ]
+                                ]
+                            },
+                            
+                            valueField : 'lang',
+                            hiddenName:  'lang',
+                            width: 200,
+                            displayField:'ldisp',
+                            typeAhead: false,
+                            editable: false,
+                            mode: 'local',
+                            triggerAction: 'all',
+                            emptyText:'Select a Language...',
+                            selectOnFocus:true,
+                            listeners : {
+                                select :  function(cb, rec, ix) {
+                                    this.form.switchLang(rec.data.lang);
+                                }
+                            }
+                        
+                        }
+                    ]
+                }
+                  
+                
+            ]
+        }
+    ],
+    buttons : [
+        {
+            xtype : 'Button',
+            xns : 'Roo',
+            text : "Forgot Password",
+            listeners : {
+                click : function() {
+                    //console.log(this);
+                    var n = this.form.findField('username').getValue();
+                    if (!n.length) {
+                        Roo.MessageBox.alert("Error", "Fill in your email address");
+                        return;
+                    }
+                    Roo.Ajax.request({
+                        url: this.dialog.url,
+                        params: {
+                            passwordRequest: n
+                        },
+                        method: this.dialog.method,
+                        success:  function(response, opts)  {  // check successfull...
+                        
+                            var res = this.dialog.processResponse(response);
+                            if (!res.success) { // error!
+                               Roo.MessageBox.alert("Error" ,
+                                    res.errorMsg ? res.errorMsg  : "Problem Requesting Password Reset");
+                               return;
+                            }
+                            Roo.MessageBox.alert("Notice" ,
+                                "Please check you email for the Password Reset message");
+                        },
+                        failure : function() {
+                            Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
+                        }
+                        
+                    });
+                }
+            }
+        },
+        {
+            xtype : 'Button',
+            xns : 'Roo',
+            text : "Login",
+            listeners : {
+                
+                click : function () {
+                        
+                    this.dialog.el.mask("Logging in");
+                    this.form.doAction('submit', {
+                            url: this.dialog.url,
+                            method: this.dialog.method
+                    });
+                }
+            }
+        }
+    ]
+  
+  
+})
+
+
+   
\ No newline at end of file