fix typos
[roojs1] / roojs-debug.js
index 219f737..2109150 100644 (file)
@@ -57,6 +57,7 @@ Roo.apply = function(o, c, defaults){
         isIE = ua.indexOf("msie") > -1,
         isIE7 = ua.indexOf("msie 7") > -1,
         isIE11 = /trident.*rv\:11\./.test(ua),
+        isEdge = ua.indexOf("edge") > -1,
         isGecko = !isSafari && ua.indexOf("gecko") > -1,
         isBorderBox = isIE && !isStrict,
         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
@@ -64,6 +65,7 @@ Roo.apply = function(o, c, defaults){
         isLinux = (ua.indexOf("linux") != -1),
         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
         isIOS = /iphone|ipad/.test(ua),
+        isAndroid = /android/.test(ua),
         isTouch =  (function() {
             try {
                 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
@@ -340,8 +342,8 @@ Roo.factory(conf, Roo.data);
             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
                 return; // alerT?
             }
-            console.log(s);
             
+            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.
@@ -628,6 +630,8 @@ Roo.factory(conf, Roo.data);
         /** @type Boolean */
         isIE11 : isIE11,
         /** @type Boolean */
+        isEdge : isEdge,
+        /** @type Boolean */
         isGecko : isGecko,
         /** @type Boolean */
         isBorderBox : isBorderBox,
@@ -640,6 +644,8 @@ Roo.factory(conf, Roo.data);
         /** @type Boolean */
         isIOS : isIOS,
         /** @type Boolean */
+        isAndroid : isAndroid,
+        /** @type Boolean */
         isTouch : isTouch,
 
         /**
@@ -879,6 +885,8 @@ var s = String.format('<div class="{0}">{1}</div>', cls, text);
             return Roo.util.Format.htmlEncode(args[i]);
         });
     }
+  
+    
 });
 
 /**
@@ -900,7 +908,31 @@ sort = (sort == 'ASC' ? 'DESC' : 'ASC');
  
 String.prototype.toggle = function(value, other){
     return this == value ? other : value;
-};/*
+};
+
+
+/**
+  * Remove invalid unicode characters from a string 
+  *
+  * @return {String} The clean string
+  */
+String.prototype.unicodeClean = function () {
+    return this.replace(/[\s\S]/g,
+        function(character) {
+            if (character.charCodeAt()< 256) {
+              return character;
+           }
+           try {
+                encodeURIComponent(character);
+           } catch(e) { 
+              return '';
+           }
+           return character;
+        }
+    );
+};
+  
+/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -4635,6 +4667,7 @@ Roo.Template.prototype = {
      * @return {String} The HTML fragment
      */
     applyTemplate : function(values){
+        //Roo.log(["applyTemplate", values]);
         try {
            
             if(this.compiled){
@@ -6041,10 +6074,10 @@ Roo.util.Observable.releaseCapture = function(o){
             var ls = this.listeners, scope, len = ls.length;
             if(len > 0){
                 this.firing = true;
-                var args = Array.prototype.slice.call(arguments, 0);
+               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){
+                   var l = ls[i];
+                    if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
                         this.firing = false;
                         return false;
                     }
@@ -6055,6 +6088,51 @@ Roo.util.Observable.releaseCapture = function(o){
         }
     };
 })();/*
+ * RooJS Library 
+ * Copyright(c) 2007-2017, Roo J Solutions Ltd
+ *
+ * Licence LGPL 
+ *
+ */
+/**
+ * @class Roo.Document
+ * @extends Roo.util.Observable
+ * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
+ * 
+ * @param {Object} config the methods and properties of the 'base' class for the application.
+ * 
+ *  Generic Page handler - implement this to start your app..
+ * 
+ * eg.
+ *  MyProject = new Roo.Document({
+        events : {
+            'load' : true // your events..
+        },
+        listeners : {
+            'ready' : function() {
+                // fired on Roo.onReady()
+            }
+        }
+ * 
+ */
+Roo.Document = function(cfg) {
+     
+    this.addEvents({ 
+        'ready' : true
+    });
+    Roo.util.Observable.call(this,cfg);
+    
+    var _this = this;
+    
+    Roo.onReady(function() {
+        _this.fireEvent('ready');
+    },null,false);
+    
+    
+}
+
+Roo.extend(Roo.Document, Roo.util.Observable, {});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -6228,6 +6306,7 @@ Roo.EventManager = function(){
         if(o.buffer){
             h = createBuffered(h, o);
         }
+        
         fn._handlers = fn._handlers || [];
         
         
@@ -6580,6 +6659,8 @@ Roo.onReady(function(){
 
     var cls = [
             Roo.isIE ? "roo-ie"
+            : Roo.isIE11 ? "roo-ie11"
+            : Roo.isEdge ? "roo-edge"
             : Roo.isGecko ? "roo-gecko"
             : Roo.isOpera ? "roo-opera"
             : Roo.isSafari ? "roo-safari" : ""];
@@ -7117,6 +7198,37 @@ if(opt.anim.isAnimated()){
             var p = Roo.fly(this.dom.parentNode, '_internal');
             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
         },
+        
+        /**
+         * Looks at  the scrollable parent element
+         */
+        findScrollableParent : function()
+        {
+            var overflowRegex = /(auto|scroll)/;
+            
+            if(this.getStyle('position') === 'fixed'){
+                return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
+            }
+            
+            var excludeStaticParent = this.getStyle('position') === "absolute";
+            
+            for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
+                
+                if (excludeStaticParent && parent.getStyle('position') === "static") {
+                    continue;
+                }
+                
+                if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
+                    return parent;
+                }
+                
+                if(parent.dom.nodeName.toLowerCase() == 'body'){
+                    return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
+                }
+            }
+            
+            return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
+        },
 
         /**
          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
@@ -9014,6 +9126,7 @@ if(opt.anim.isAnimated()){
             if(!this._mask){
                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
             }
+            
             this.addClass("x-masked");
             this._mask.setDisplayed(true);
             
@@ -9035,12 +9148,23 @@ if(opt.anim.isAnimated()){
            
             if(typeof msg == 'string'){
                 if(!this._maskMsg){
-                    this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
+                    this._maskMsg = Roo.DomHelper.append(this.dom, {
+                        cls: "roo-el-mask-msg", 
+                        cn: [
+                            {
+                                tag: 'i',
+                                cls: 'fa fa-spinner fa-spin'
+                            },
+                            {
+                                tag: 'div'
+                            }   
+                        ]
+                    }, true);
                 }
                 var mm = this._maskMsg;
                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
-                if (mm.dom.firstChild) { // weird IE issue?
-                    mm.dom.firstChild.innerHTML = msg;
+                if (mm.dom.lastChild) { // weird IE issue?
+                    mm.dom.lastChild.innerHTML = msg;
                 }
                 mm.setDisplayed(true);
                 mm.center(this);
@@ -11348,16 +11472,17 @@ Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addLi
  * @class Roo.data.Connection
  * @extends Roo.util.Observable
  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
- * either to a configured URL, or to a URL specified at request time.<br><br>
- * <p>
+ * either to a configured URL, or to a URL specified at request time. 
+ * 
  * Requests made by this class are asynchronous, and will return immediately. No data from
  * the server will be available to the statement immediately following the {@link #request} call.
- * To process returned data, use a callback in the request options object, or an event listener.</p><br>
- * <p>
+ * To process returned data, use a callback in the request options object, or an event listener.
+ * 
  * Note: If you are doing a file upload, you will not get a normal response object sent back to
  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
  * The response object is created using the innerHTML of the IFRAME's document as the responseText
- * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
+ * property and, if present, the IFRAME's XML document as the responseXML property.
+ * 
  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
@@ -11489,6 +11614,11 @@ Roo.extend(Roo.data.Connection, Roo.util.Observable, {
                 url = url || form.action;
 
                 var enctype = form.getAttribute("enctype");
+                
+                if (o.formData) {
+                    return this.doFormDataUpload(o,p,url);
+                }
+                
                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
                     return this.doFormUpload(o, p, url);
                 }
@@ -11530,7 +11660,9 @@ Roo.extend(Roo.data.Connection, Roo.util.Observable, {
                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
                 p = '';
             }
+            Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
+            Roo.lib.Ajax.useDefaultHeader == true;
             return this.transId;
         }else{
             Roo.callback(o.callback, o.scope, [o, null, null]);
@@ -11666,7 +11798,40 @@ Roo.extend(Roo.data.Connection, Roo.util.Observable, {
                 form.removeChild(hiddens[i]);
             }
         }
+    },
+    // this is a 'formdata version???'
+    
+    
+    doFormDataUpload : function(o, ps, url)
+    {
+        var form = Roo.getDom(o.form);
+        form.enctype = form.encoding = 'multipart/form-data';
+        var formData = o.formData === true ? new FormData(form) : o.formData;
+      
+        var cb = {
+            success: this.handleResponse,
+            failure: this.handleFailure,
+            scope: this,
+            argument: {options: o},
+            timeout : o.timeout || this.timeout
+        };
+        if(typeof o.autoAbort == 'boolean'){ // options gets top priority
+            if(o.autoAbort){
+                this.abort();
+            }
+        }else if(this.autoAbort !== false){
+            this.abort();
+        }
+
+        //Roo.lib.Ajax.defaultPostHeader = null;
+        Roo.lib.Ajax.useDefaultHeader = false;
+        this.transId = Roo.lib.Ajax.request( "POST", url, cb, o.formData, o);
+        Roo.lib.Ajax.useDefaultHeader = true;
+         
     }
+    
 });
 /*
  * Based on:
@@ -13137,6 +13302,9 @@ mc.add(otherEl);
  * @return {Object} The item associated with the passed key.
  */
     item : function(key){
+        if (key === 'length') {
+            return null;
+        }
         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
     },
@@ -13657,12 +13825,15 @@ Roo.util.Format = function(){
          * eventually this should probably emulate php's number_format
          * @param {Number/String} value The numeric value to format
          * @param {Number} decimals number of decimal places
+         * @param {String} delimiter for thousands (default comma)
          * @return {String} The formatted currency string
          */
-        number : function(v,decimals)
+        number : function(v, decimals, thousandsDelimiter)
         {
             // multiply and round.
             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
+            thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
+            
             var mul = Math.pow(10, decimals);
             var zero = String(mul).substring(1);
             v = (Math.round((v-0)*mul))/mul;
@@ -13674,13 +13845,12 @@ Roo.util.Format = function(){
             var ps = v.split('.');
             var whole = ps[0];
             
-            
             var r = /(\d+)(\d{3})/;
             // add comma's
-            while (r.test(whole)) {
-                whole = whole.replace(r, '$1' + ',' + '$2');
-            }
             
+            if(thousandsDelimiter.length != 0) {
+                whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
+            } 
             
             var sub = ps[1] ?
                     // has decimals..
@@ -15269,7 +15439,7 @@ Roo.extend(Roo.Component, Roo.util.Observable, {
     /**
      * @cfg {String} actionMode 
      * which property holds the element that used for  hide() / show() / disable() / enable()
-     * default is 'el' 
+     * default is 'el' for forms you probably want to set this to fieldEl 
      */
     actionMode : "el",
 
@@ -15284,40 +15454,49 @@ Roo.extend(Roo.Component, Roo.util.Observable, {
      * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
      */
     render : function(container, position){
-        if(!this.rendered && this.fireEvent("beforerender", this) !== false){
-            if(!container && this.el){
-                this.el = Roo.get(this.el);
-                container = this.el.dom.parentNode;
-                this.allowDomMove = false;
-            }
-            this.container = Roo.get(container);
-            this.rendered = true;
-            if(position !== undefined){
-                if(typeof position == 'number'){
-                    position = this.container.dom.childNodes[position];
-                }else{
-                    position = Roo.getDom(position);
-                }
-            }
-            this.onRender(this.container, position || null);
-            if(this.cls){
-                this.el.addClass(this.cls);
-                delete this.cls;
-            }
-            if(this.style){
-                this.el.applyStyles(this.style);
-                delete this.style;
-            }
-            this.fireEvent("render", this);
-            this.afterRender(this.container);
-            if(this.hidden){
-                this.hide();
-            }
-            if(this.disabled){
-                this.disable();
+        
+        if(this.rendered){
+            return this;
+        }
+        
+        if(this.fireEvent("beforerender", this) === false){
+            return false;
+        }
+        
+        if(!container && this.el){
+            this.el = Roo.get(this.el);
+            container = this.el.dom.parentNode;
+            this.allowDomMove = false;
+        }
+        this.container = Roo.get(container);
+        this.rendered = true;
+        if(position !== undefined){
+            if(typeof position == 'number'){
+                position = this.container.dom.childNodes[position];
+            }else{
+                position = Roo.getDom(position);
             }
         }
+        this.onRender(this.container, position || null);
+        if(this.cls){
+            this.el.addClass(this.cls);
+            delete this.cls;
+        }
+        if(this.style){
+            this.el.applyStyles(this.style);
+            delete this.style;
+        }
+        this.fireEvent("render", this);
+        this.afterRender(this.container);
+        if(this.hidden){
+            this.hide();
+        }
+        if(this.disabled){
+            this.disable();
+        }
+
         return this;
+        
     },
 
     /** @private */
@@ -15825,260 +16004,785 @@ Roo.extend(Roo.BoxComponent, Roo.Component, {
         return {x : x, y: y};
     }
 });/*
- * Original code for Roojs - LGPL
+ * 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">
  */
+ (function(){ 
 /**
- * @class Roo.XComponent
- * A delayed Element creator...
- * Or a way to group chunks of interface together.
- * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
- *  used in conjunction with XComponent.build() it will create an instance of each element,
- *  then call addxtype() to build the User interface.
- * 
- * 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
-        }
-     ]
- *})
- *
- *
- * It can be used to build a big heiracy, with parent etc.
- * or you can just use this to render a single compoent to a dom element
- * MYPART.render(Roo.Element | String(id) | dom_element )
- *
- *
- * Usage patterns.
- *
- * Classic Roo
- *
- * Roo is designed primarily as a single page application, so the UI build for a standard interface will
- * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
- *
- * Each sub module is expected to have a parent pointing to the class name of it's parent module.
- *
- * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
- * - if mulitple topModules exist, the last one is defined as the top module.
- *
- * Embeded Roo
- * 
- * When the top level or multiple modules are to embedded into a existing HTML page,
- * the parent element can container '#id' of the element where the module will be drawn.
- *
- * Bootstrap Roo
- *
- * Unlike classic Roo, the bootstrap tends not to be used as a single page.
- * it relies more on a include mechanism, where sub modules are included into an outer page.
- * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
- * 
- * Bootstrap Roo Included elements
- *
- * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
- * hence confusing the component builder as it thinks there are multiple top level elements. 
- *
- * 
- * 
- * @extends Roo.util.Observable
+ * @class Roo.Layer
+ * @extends Roo.Element
+ * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
+ * automatic maintaining of shadow/shim positions.
+ * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
+ * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
+ * you can pass a string with a CSS class name. False turns off the shadow.
+ * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
+ * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
+ * @cfg {String} cls CSS class to add to the element
+ * @cfg {Number} zindex Starting z-index (defaults to 11000)
+ * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
  * @constructor
- * @param cfg {Object} configuration of component
- * 
+ * @param {Object} config An object with config options.
+ * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
  */
-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
-        
-    });
-    this.region = this.region || 'center'; // default..
-    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 {String} region
-     * Region to render component to (defaults to center)
-     */
-    region : 'center',
-    
-    /**
-     * @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,
-    
-    /**
-     * @property _tree
-     * The method that retuns the tree of parts that make up this compoennt 
-     * @type {function}
-     */
-    _tree  : false,
-    
-     /**
-     * render
-     * render element to dom or tree
-     * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
-     */
-    
-    render : function(el)
-    {
-        
-        el = el || false;
-        var hp = this.parent ? 1 : 0;
-        Roo.debug &&  Roo.log(this);
-        
-        if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
-            // if parent is a '#.....' string, then let's use that..
-            var ename = this.parent.substr(1);
-            this.parent = false;
-            Roo.debug && Roo.log(ename);
-            switch (ename) {
-                case 'bootstrap-body' :
-                    if (typeof(Roo.bootstrap.Body) != 'undefined') {
-                        this.parent = { el :  new  Roo.bootstrap.Body() };
-                        Roo.debug && Roo.log("setting el to doc body");
-                         
-                    } else {
-                        throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
-                    }
-                    break;
-                case 'bootstrap':
-                    this.parent = { el : true};
-                    // fall through
-                default:
-                    el = Roo.get(ename);
-                    break;
-            }
-                
-            
-            if (!el && !this.parent) {
-                Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
-                return;
-            }
+
+Roo.Layer = function(config, existingEl){
+    config = config || {};
+    var dh = Roo.DomHelper;
+    var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
+    if(existingEl){
+        this.dom = Roo.getDom(existingEl);
+    }
+    if(!this.dom){
+        var o = config.dh || {tag: "div", cls: "x-layer"};
+        this.dom = dh.append(pel, o);
+    }
+    if(config.cls){
+        this.addClass(config.cls);
+    }
+    this.constrain = config.constrain !== false;
+    this.visibilityMode = Roo.Element.VISIBILITY;
+    if(config.id){
+        this.id = this.dom.id = config.id;
+    }else{
+        this.id = Roo.id(this.dom);
+    }
+    this.zindex = config.zindex || this.getZIndex();
+    this.position("absolute", this.zindex);
+    if(config.shadow){
+        this.shadowOffset = config.shadowOffset || 4;
+        this.shadow = new Roo.Shadow({
+            offset : this.shadowOffset,
+            mode : config.shadow
+        });
+    }else{
+        this.shadowOffset = 0;
+    }
+    this.useShim = config.shim !== false && Roo.useShims;
+    this.useDisplay = config.useDisplay;
+    this.hide();
+};
+
+var supr = Roo.Element.prototype;
+
+// shims are shared among layer to keep from having 100 iframes
+var shims = [];
+
+Roo.extend(Roo.Layer, Roo.Element, {
+
+    getZIndex : function(){
+        return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
+    },
+
+    getShim : function(){
+        if(!this.useShim){
+            return null;
         }
-        Roo.debug && Roo.log("EL:");
-        Roo.debug && Roo.log(el);
-        Roo.debug && Roo.log("this.parent.el:");
-        Roo.debug && Roo.log(this.parent.el);
-        
-        var tree = this._tree ? this._tree() : this.tree();
+        if(this.shim){
+            return this.shim;
+        }
+        var shim = shims.shift();
+        if(!shim){
+            shim = this.createShim();
+            shim.enableDisplayMode('block');
+            shim.dom.style.display = 'none';
+            shim.dom.style.visibility = 'visible';
+        }
+        var pn = this.dom.parentNode;
+        if(shim.dom.parentNode != pn){
+            pn.insertBefore(shim.dom, this.dom);
+        }
+        shim.setStyle('z-index', this.getZIndex()-2);
+        this.shim = shim;
+        return shim;
+    },
 
-        // altertive root elements ??? - we need a better way to indicate these.
-        var is_alt = Roo.XComponent.is_alt || (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
-                        (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
-        
-        if (!this.parent && is_alt) {
-            //el = Roo.get(document.body);
-            this.parent = { el : true };
+    hideShim : function(){
+        if(this.shim){
+            this.shim.setDisplayed(false);
+            shims.push(this.shim);
+            delete this.shim;
         }
-            
-            
-        
-        if (!this.parent) {
-            
-            Roo.debug && Roo.log("no parent - creating one");
-            
-            el = el ? Roo.get(el) : false;     
-            
-            // it's a top level one..
-            this.parent =  {
-                el : new Roo.BorderLayout(el || document.body, {
-                
-                     center: {
-                         titlebar: false,
-                         autoScroll:false,
-                         closeOnTab: true,
-                         tabPosition: 'top',
-                          //resizeTabs: true,
-                         alwaysShowTabs: el && hp? false :  true,
-                         hideTabs: el || !hp ? true :  false,
-                         minTabWidth: 140
-                     }
-                 })
-            };
+    },
+
+    disableShadow : function(){
+        if(this.shadow){
+            this.shadowDisabled = true;
+            this.shadow.hide();
+            this.lastShadowOffset = this.shadowOffset;
+            this.shadowOffset = 0;
         }
-        
-        if (!this.parent.el) {
-                // probably an old style ctor, which has been disabled.
-                return;
+    },
 
+    enableShadow : function(show){
+        if(this.shadow){
+            this.shadowDisabled = false;
+            this.shadowOffset = this.lastShadowOffset;
+            delete this.lastShadowOffset;
+            if(show){
+                this.sync(true);
+            }
         }
-               // The 'tree' method is  '_tree now' 
+    },
+
+    // private
+    // this code can execute repeatedly in milliseconds (i.e. during a drag) so
+    // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
+    sync : function(doShow){
+        var sw = this.shadow;
+        if(!this.updating && this.isVisible() && (sw || this.useShim)){
+            var sh = this.getShim();
+
+            var w = this.getWidth(),
+                h = this.getHeight();
+
+            var l = this.getLeft(true),
+                t = this.getTop(true);
+
+            if(sw && !this.shadowDisabled){
+                if(doShow && !sw.isVisible()){
+                    sw.show(this);
+                }else{
+                    sw.realign(l, t, w, h);
+                }
+                if(sh){
+                    if(doShow){
+                       sh.show();
+                    }
+                    // fit the shim behind the shadow, so it is shimmed too
+                    var a = sw.adjusts, s = sh.dom.style;
+                    s.left = (Math.min(l, l+a.l))+"px";
+                    s.top = (Math.min(t, t+a.t))+"px";
+                    s.width = (w+a.w)+"px";
+                    s.height = (h+a.h)+"px";
+                }
+            }else if(sh){
+                if(doShow){
+                   sh.show();
+                }
+                sh.setSize(w, h);
+                sh.setLeftTop(l, t);
+            }
             
-        tree.region = tree.region || this.region;
-        var is_body = false;
-        if (this.parent.el === true) {
-            // bootstrap... - body..
-            this.parent.el = Roo.factory(tree);
-            is_body = true;
         }
-        
-        this.el = this.parent.el.addxtype(tree, undefined, is_body);
+    },
+
+    // private
+    destroy : function(){
+        this.hideShim();
+        if(this.shadow){
+            this.shadow.hide();
+        }
+        this.removeAllListeners();
+        var pn = this.dom.parentNode;
+        if(pn){
+            pn.removeChild(this.dom);
+        }
+        Roo.Element.uncache(this.id);
+    },
+
+    remove : function(){
+        this.destroy();
+    },
+
+    // private
+    beginUpdate : function(){
+        this.updating = true;
+    },
+
+    // private
+    endUpdate : function(){
+        this.updating = false;
+        this.sync(true);
+    },
+
+    // private
+    hideUnders : function(negOffset){
+        if(this.shadow){
+            this.shadow.hide();
+        }
+        this.hideShim();
+    },
+
+    // private
+    constrainXY : function(){
+        if(this.constrain){
+            var vw = Roo.lib.Dom.getViewWidth(),
+                vh = Roo.lib.Dom.getViewHeight();
+            var s = Roo.get(document).getScroll();
+
+            var xy = this.getXY();
+            var x = xy[0], y = xy[1];   
+            var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
+            // only move it if it needs it
+            var moved = false;
+            // first validate right/bottom
+            if((x + w) > vw+s.left){
+                x = vw - w - this.shadowOffset;
+                moved = true;
+            }
+            if((y + h) > vh+s.top){
+                y = vh - h - this.shadowOffset;
+                moved = true;
+            }
+            // then make sure top/left isn't negative
+            if(x < s.left){
+                x = s.left;
+                moved = true;
+            }
+            if(y < s.top){
+                y = s.top;
+                moved = true;
+            }
+            if(moved){
+                if(this.avoidY){
+                    var ay = this.avoidY;
+                    if(y <= ay && (y+h) >= ay){
+                        y = ay-h-5;   
+                    }
+                }
+                xy = [x, y];
+                this.storeXY(xy);
+                supr.setXY.call(this, xy);
+                this.sync();
+            }
+        }
+    },
+
+    isVisible : function(){
+        return this.visible;    
+    },
+
+    // private
+    showAction : function(){
+        this.visible = true; // track visibility to prevent getStyle calls
+        if(this.useDisplay === true){
+            this.setDisplayed("");
+        }else if(this.lastXY){
+            supr.setXY.call(this, this.lastXY);
+        }else if(this.lastLT){
+            supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
+        }
+    },
+
+    // private
+    hideAction : function(){
+        this.visible = false;
+        if(this.useDisplay === true){
+            this.setDisplayed(false);
+        }else{
+            this.setLeftTop(-10000,-10000);
+        }
+    },
+
+    // overridden Element method
+    setVisible : function(v, a, d, c, e){
+        if(v){
+            this.showAction();
+        }
+        if(a && v){
+            var cb = function(){
+                this.sync(true);
+                if(c){
+                    c();
+                }
+            }.createDelegate(this);
+            supr.setVisible.call(this, true, true, d, cb, e);
+        }else{
+            if(!v){
+                this.hideUnders(true);
+            }
+            var cb = c;
+            if(a){
+                cb = function(){
+                    this.hideAction();
+                    if(c){
+                        c();
+                    }
+                }.createDelegate(this);
+            }
+            supr.setVisible.call(this, v, a, d, cb, e);
+            if(v){
+                this.sync(true);
+            }else if(!a){
+                this.hideAction();
+            }
+        }
+    },
+
+    storeXY : function(xy){
+        delete this.lastLT;
+        this.lastXY = xy;
+    },
+
+    storeLeftTop : function(left, top){
+        delete this.lastXY;
+        this.lastLT = [left, top];
+    },
+
+    // private
+    beforeFx : function(){
+        this.beforeAction();
+        return Roo.Layer.superclass.beforeFx.apply(this, arguments);
+    },
+
+    // private
+    afterFx : function(){
+        Roo.Layer.superclass.afterFx.apply(this, arguments);
+        this.sync(this.isVisible());
+    },
+
+    // private
+    beforeAction : function(){
+        if(!this.updating && this.shadow){
+            this.shadow.hide();
+        }
+    },
+
+    // overridden Element method
+    setLeft : function(left){
+        this.storeLeftTop(left, this.getTop(true));
+        supr.setLeft.apply(this, arguments);
+        this.sync();
+    },
+
+    setTop : function(top){
+        this.storeLeftTop(this.getLeft(true), top);
+        supr.setTop.apply(this, arguments);
+        this.sync();
+    },
+
+    setLeftTop : function(left, top){
+        this.storeLeftTop(left, top);
+        supr.setLeftTop.apply(this, arguments);
+        this.sync();
+    },
+
+    setXY : function(xy, a, d, c, e){
+        this.fixDisplay();
+        this.beforeAction();
+        this.storeXY(xy);
+        var cb = this.createCB(c);
+        supr.setXY.call(this, xy, a, d, cb, e);
+        if(!a){
+            cb();
+        }
+    },
+
+    // private
+    createCB : function(c){
+        var el = this;
+        return function(){
+            el.constrainXY();
+            el.sync(true);
+            if(c){
+                c();
+            }
+        };
+    },
+
+    // overridden Element method
+    setX : function(x, a, d, c, e){
+        this.setXY([x, this.getY()], a, d, c, e);
+    },
+
+    // overridden Element method
+    setY : function(y, a, d, c, e){
+        this.setXY([this.getX(), y], a, d, c, e);
+    },
+
+    // overridden Element method
+    setSize : function(w, h, a, d, c, e){
+        this.beforeAction();
+        var cb = this.createCB(c);
+        supr.setSize.call(this, w, h, a, d, cb, e);
+        if(!a){
+            cb();
+        }
+    },
+
+    // overridden Element method
+    setWidth : function(w, a, d, c, e){
+        this.beforeAction();
+        var cb = this.createCB(c);
+        supr.setWidth.call(this, w, a, d, cb, e);
+        if(!a){
+            cb();
+        }
+    },
+
+    // overridden Element method
+    setHeight : function(h, a, d, c, e){
+        this.beforeAction();
+        var cb = this.createCB(c);
+        supr.setHeight.call(this, h, a, d, cb, e);
+        if(!a){
+            cb();
+        }
+    },
+
+    // overridden Element method
+    setBounds : function(x, y, w, h, a, d, c, e){
+        this.beforeAction();
+        var cb = this.createCB(c);
+        if(!a){
+            this.storeXY([x, y]);
+            supr.setXY.call(this, [x, y]);
+            supr.setSize.call(this, w, h, a, d, cb, e);
+            cb();
+        }else{
+            supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
+        }
+        return this;
+    },
+    
+    /**
+     * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
+     * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
+     * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
+     * @param {Number} zindex The new z-index to set
+     * @return {this} The Layer
+     */
+    setZIndex : function(zindex){
+        this.zindex = zindex;
+        this.setStyle("z-index", zindex + 2);
+        if(this.shadow){
+            this.shadow.setZIndex(zindex + 1);
+        }
+        if(this.shim){
+            this.shim.setStyle("z-index", zindex);
+        }
+    }
+});
+})();/*
+ * Original code for Roojs - LGPL
+ * <script type="text/javascript">
+ */
+/**
+ * @class Roo.XComponent
+ * A delayed Element creator...
+ * Or a way to group chunks of interface together.
+ * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
+ *  used in conjunction with XComponent.build() it will create an instance of each element,
+ *  then call addxtype() to build the User interface.
+ * 
+ * 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
+        }
+     ]
+ *})
+ *
+ *
+ * It can be used to build a big heiracy, with parent etc.
+ * or you can just use this to render a single compoent to a dom element
+ * MYPART.render(Roo.Element | String(id) | dom_element )
+ *
+ *
+ * Usage patterns.
+ *
+ * Classic Roo
+ *
+ * Roo is designed primarily as a single page application, so the UI build for a standard interface will
+ * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
+ *
+ * Each sub module is expected to have a parent pointing to the class name of it's parent module.
+ *
+ * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
+ * - if mulitple topModules exist, the last one is defined as the top module.
+ *
+ * Embeded Roo
+ * 
+ * When the top level or multiple modules are to embedded into a existing HTML page,
+ * the parent element can container '#id' of the element where the module will be drawn.
+ *
+ * Bootstrap Roo
+ *
+ * Unlike classic Roo, the bootstrap tends not to be used as a single page.
+ * it relies more on a include mechanism, where sub modules are included into an outer page.
+ * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
+ * 
+ * Bootstrap Roo Included elements
+ *
+ * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
+ * hence confusing the component builder as it thinks there are multiple top level elements. 
+ *
+ * String Over-ride & Translations
+ *
+ * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
+ * and also the 'overlaying of string values - needed when different versions of the same application with different text content
+ * are needed. @see Roo.XComponent.overlayString  
+ * 
+ * 
+ * 
+ * @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
+        
+    });
+    this.region = this.region || 'center'; // default..
+    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 {String} region
+     * Region to render component to (defaults to center)
+     */
+    region : 'center',
+    
+    /**
+     * @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,
+    
+    /**
+     * @property _tree
+     * The method that retuns the tree of parts that make up this compoennt 
+     * @type {function}
+     */
+    _tree  : false,
+    
+     /**
+     * render
+     * render element to dom or tree
+     * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
+     */
+    
+    render : function(el)
+    {
+        
+        el = el || false;
+        var hp = this.parent ? 1 : 0;
+        Roo.debug &&  Roo.log(this);
+        
+        var tree = this._tree ? this._tree() : this.tree();
+
+        
+        if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
+            // if parent is a '#.....' string, then let's use that..
+            var ename = this.parent.substr(1);
+            this.parent = false;
+            Roo.debug && Roo.log(ename);
+            switch (ename) {
+                case 'bootstrap-body':
+                    if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
+                        // this is the BorderLayout standard?
+                       this.parent = { el : true };
+                       break;
+                    }
+                    if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
+                        // need to insert stuff...
+                        this.parent =  {
+                             el : new Roo.bootstrap.layout.Border({
+                                 el : document.body, 
+                     
+                                 center: {
+                                    titlebar: false,
+                                    autoScroll:false,
+                                    closeOnTab: true,
+                                    tabPosition: 'top',
+                                      //resizeTabs: true,
+                                    alwaysShowTabs: true,
+                                    hideTabs: false
+                                     //minTabWidth: 140
+                                 }
+                             })
+                        
+                         };
+                         break;
+                    }
+                         
+                    if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
+                        this.parent = { el :  new  Roo.bootstrap.Body() };
+                        Roo.debug && Roo.log("setting el to doc body");
+                         
+                    } else {
+                        throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
+                    }
+                    break;
+                case 'bootstrap':
+                    this.parent = { el : true};
+                    // fall through
+                default:
+                    el = Roo.get(ename);
+                    if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
+                        this.parent = { el : true};
+                    }
+                    
+                    break;
+            }
+                
+            
+            if (!el && !this.parent) {
+                Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
+                return;
+            }
+        }
+        
+        Roo.debug && Roo.log("EL:");
+        Roo.debug && Roo.log(el);
+        Roo.debug && Roo.log("this.parent.el:");
+        Roo.debug && Roo.log(this.parent.el);
+        
+
+        // altertive root elements ??? - we need a better way to indicate these.
+        var is_alt = Roo.XComponent.is_alt ||
+                    (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
+                    (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
+                    (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
+        
+        
+        
+        if (!this.parent && is_alt) {
+            //el = Roo.get(document.body);
+            this.parent = { el : true };
+        }
+            
+            
+        
+        if (!this.parent) {
+            
+            Roo.debug && Roo.log("no parent - creating one");
+            
+            el = el ? Roo.get(el) : false;     
+            
+            if (typeof(Roo.BorderLayout) == 'undefined' ) {
+                
+                this.parent =  {
+                    el : new Roo.bootstrap.layout.Border({
+                        el: el || document.body,
+                    
+                        center: {
+                            titlebar: false,
+                            autoScroll:false,
+                            closeOnTab: true,
+                            tabPosition: 'top',
+                             //resizeTabs: true,
+                            alwaysShowTabs: false,
+                            hideTabs: true,
+                            minTabWidth: 140,
+                            overflow: 'visible'
+                         }
+                     })
+                };
+            } else {
+            
+                // it's a top level one..
+                this.parent =  {
+                    el : new Roo.BorderLayout(el || document.body, {
+                        center: {
+                            titlebar: false,
+                            autoScroll:false,
+                            closeOnTab: true,
+                            tabPosition: 'top',
+                             //resizeTabs: true,
+                            alwaysShowTabs: el && hp? false :  true,
+                            hideTabs: el || !hp ? true :  false,
+                            minTabWidth: 140
+                         }
+                    })
+                };
+            }
+        }
+        
+        if (!this.parent.el) {
+                // probably an old style ctor, which has been disabled.
+                return;
+
+        }
+               // The 'tree' method is  '_tree now' 
+            
+        tree.region = tree.region || this.region;
+        var is_body = false;
+        if (this.parent.el === true) {
+            // bootstrap... - body..
+            if (el) {
+                tree.el = el;
+            }
+            this.parent.el = Roo.factory(tree);
+            is_body = true;
+        }
+        
+        this.el = this.parent.el.addxtype(tree, undefined, is_body);
         this.fireEvent('built', this);
         
         this.panel = this.el;
@@ -16178,7 +16882,7 @@ Roo.apply(Roo.XComponent, {
                 break;
             
             default:
-                if (obj.disabled) {
+                if (obj.disabled || obj.region == '#disabled') {
                         return;
                 }
                 break;
@@ -16371,6 +17075,7 @@ Roo.apply(Roo.XComponent, {
                msg: msg,
                width:450,
                progress:true,
+              buttons : false,
                closable:false,
                modal: false
               
@@ -16408,7 +17113,7 @@ Roo.apply(Roo.XComponent, {
                     " of " + total + 
                     (m.name ? (' - ' + m.name) : '');
                        Roo.debug && Roo.log(msg);
-            if (!this.hideProgress &&  Roo.MessageBox) { 
+            if (!_this.hideProgress &&  Roo.MessageBox) { 
                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
             }
             
@@ -16436,7 +17141,32 @@ Roo.apply(Roo.XComponent, {
         
         
     },
-       
+    /**
+     * Overlay a set of modified strings onto a component
+     * This is dependant on our builder exporting the strings and 'named strings' elements.
+     * 
+     * @param {Object} element to overlay on - eg. Pman.Dialog.Login
+     * @param {Object} associative array of 'named' string and it's new value.
+     * 
+     */
+       overlayStrings : function( component, strings )
+    {
+        if (typeof(component['_named_strings']) == 'undefined') {
+            throw "ERROR: component does not have _named_strings";
+        }
+        for ( var k in strings ) {
+            var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
+            if (md !== false) {
+                component['_strings'][md] = strings[k];
+            } else {
+                Roo.log('could not find named string: ' + k + ' in');
+                Roo.log(component);
+            }
+            
+        }
+        
+    },
+    
        
        /**
         * Event Object.
@@ -16533,10 +17263,86 @@ Roo.Markdown.toHtml = function(text) {
 //
 (function() {
     
+     /**
+         * eval:var:escape
+         * eval:var:unescape
+         * eval:var:replace
+         */
+      
+    /**
+     * Helpers
+     */
+    
+    var escape = function (html, encode) {
+      return html
+        .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
+        .replace(/</g, '&lt;')
+        .replace(/>/g, '&gt;')
+        .replace(/"/g, '&quot;')
+        .replace(/'/g, '&#39;');
+    }
+    
+    var unescape = function (html) {
+        // explicitly match decimal, hex, and named HTML entities 
+      return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
+        n = n.toLowerCase();
+        if (n === 'colon') { return ':'; }
+        if (n.charAt(0) === '#') {
+          return n.charAt(1) === 'x'
+            ? String.fromCharCode(parseInt(n.substring(2), 16))
+            : String.fromCharCode(+n.substring(1));
+        }
+        return '';
+      });
+    }
+    
+    var replace = function (regex, opt) {
+      regex = regex.source;
+      opt = opt || '';
+      return function self(name, val) {
+        if (!name) { return new RegExp(regex, opt); }
+        val = val.source || val;
+        val = val.replace(/(^|[^\[])\^/g, '$1');
+        regex = regex.replace(name, val);
+        return self;
+      };
+    }
+
+
+         /**
+         * eval:var:noop
+    */
+    var noop = function () {}
+    noop.exec = noop;
+    
+         /**
+         * eval:var:merge
+    */
+    var merge = function (obj) {
+      var i = 1
+        , target
+        , key;
+    
+      for (; i < arguments.length; i++) {
+        target = arguments[i];
+        for (key in target) {
+          if (Object.prototype.hasOwnProperty.call(target, key)) {
+            obj[key] = target[key];
+          }
+        }
+      }
+    
+      return obj;
+    }
+    
+    
     /**
      * Block-Level Grammar
      */
     
+    
+    
+    
     var block = {
       newline: /^\n+/,
       code: /^( {4}[^\n]+\n*)+/,
@@ -16626,7 +17432,7 @@ Roo.Markdown.toHtml = function(text) {
      * Block Lexer
      */
     
-    function Lexer(options) {
+    var Lexer = function (options) {
       this.tokens = [];
       this.tokens.links = {};
       this.options = options || marked.defaults;
@@ -17044,7 +17850,7 @@ Roo.Markdown.toHtml = function(text) {
      * Inline Lexer & Compiler
      */
     
-    function InlineLexer(links, options) {
+    var InlineLexer  = function (links, options) {
       this.options = options || marked.defaults;
       this.links = links;
       this.rules = inline.normal;
@@ -17284,7 +18090,11 @@ Roo.Markdown.toHtml = function(text) {
      * Renderer
      */
     
-    function Renderer(options) {
+     /**
+         * eval:var:Renderer
+    */
+    
+    var Renderer   = function (options) {
       this.options = options || {};
     }
     
@@ -17433,8 +18243,11 @@ Roo.Markdown.toHtml = function(text) {
     /**
      * Parsing & Compiling
      */
+         /**
+         * eval:var:Parser
+    */
     
-    function Parser(options) {
+    var Parser= function (options) {
       this.tokens = [];
       this.token = null;
       this.options = options || marked.defaults;
@@ -17609,72 +18422,15 @@ Roo.Markdown.toHtml = function(text) {
         }
       }
     };
-    
-    /**
-     * Helpers
-     */
-    
-    function escape(html, encode) {
-      return html
-        .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
-        .replace(/</g, '&lt;')
-        .replace(/>/g, '&gt;')
-        .replace(/"/g, '&quot;')
-        .replace(/'/g, '&#39;');
-    }
-    
-    function unescape(html) {
-        // explicitly match decimal, hex, and named HTML entities 
-      return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
-        n = n.toLowerCase();
-        if (n === 'colon') { return ':'; }
-        if (n.charAt(0) === '#') {
-          return n.charAt(1) === 'x'
-            ? String.fromCharCode(parseInt(n.substring(2), 16))
-            : String.fromCharCode(+n.substring(1));
-        }
-        return '';
-      });
-    }
-    
-    function replace(regex, opt) {
-      regex = regex.source;
-      opt = opt || '';
-      return function self(name, val) {
-        if (!name) { return new RegExp(regex, opt); }
-        val = val.source || val;
-        val = val.replace(/(^|[^\[])\^/g, '$1');
-        regex = regex.replace(name, val);
-        return self;
-      };
-    }
-    
-    function noop() {}
-    noop.exec = noop;
-    
-    function merge(obj) {
-      var i = 1
-        , target
-        , key;
-    
-      for (; i < arguments.length; i++) {
-        target = arguments[i];
-        for (key in target) {
-          if (Object.prototype.hasOwnProperty.call(target, key)) {
-            obj[key] = target[key];
-          }
-        }
-      }
-    
-      return obj;
-    }
-    
+  
     
     /**
      * Marked
      */
-    
-    function marked(src, opt, callback) {
+         /**
+         * eval:var:marked
+    */
+    var marked = function (src, opt, callback) {
       if (callback || typeof opt === 'function') {
         if (!callback) {
           callback = opt;
@@ -17695,7 +18451,9 @@ Roo.Markdown.toHtml = function(text) {
         }
     
         pending = tokens.length;
-    
+         /**
+         * eval:var:done
+    */
         var done = function(err) {
           if (err) {
             opt.highlight = highlight;
@@ -20828,8 +21586,8 @@ Roo.dd.DDTarget = function(id, sGroup, config) {
     if (id) {
         this.initTarget(id, sGroup, config);
     }
-    if (config.listeners || config.events) { 
-       Roo.dd.DragDrop.superclass.constructor.call(this,  { 
+    if (config && (config.listeners || config.events)) { 
+        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
             listeners : config.listeners || {}, 
             events : config.events || {} 
         });    
@@ -22751,6 +23509,7 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
     remove : function(record){
         var index = this.data.indexOf(record);
         this.data.removeAt(index);
         if(this.pruneModifiedRecords){
             this.modified.remove(record);
         }
@@ -22938,6 +23697,17 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
             this.totalLength = Math.max(t, this.data.length+r.length);
             this.add(r);
         }
+        
+        if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
+                
+            var e = new Roo.data.Record({});
+
+            e.set(this.parent.displayField, this.parent.emptyTitle);
+            e.set(this.parent.valueField, '');
+
+            this.insert(0, e);
+        }
+            
         this.fireEvent("load", this, r, options, o);
         if(options.callback){
             options.callback.call(options.scope || this, r, options, true);
@@ -22956,6 +23726,16 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
         var r = this.reader.readRecords(o);
         this.loadRecords(r, {add: append}, true);
     },
+    
+     /**
+     * using 'cn' the nested child reader read the child array into it's child stores.
+     * @param {Object} rec The record with a 'children array
+     */
+    loadDataFromChildren : function(rec)
+    {
+        this.loadData(this.reader.toLoadData(rec));
+    },
+    
 
     /**
      * Gets the number of cached records.
@@ -23260,14 +24040,16 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
  * Small helper class to make creating Stores from Array data easier.
  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
  * @cfg {Array} fields An array of field definition objects, or field name strings.
+ * @cfg {Object} an existing reader (eg. copied from another store)
  * @cfg {Array} data The multi-dimensional array of data
  * @constructor
  * @param {Object} config
  */
-Roo.data.SimpleStore = function(config){
+Roo.data.SimpleStore = function(config)
+{
     Roo.data.SimpleStore.superclass.constructor.call(this, {
         isLocal : true,
-        reader: new Roo.data.ArrayReader({
+        reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
                 id: config.id
             },
             Roo.data.Record.create(config.fields)
@@ -23444,6 +24226,9 @@ Roo.data.DataReader = function(meta, recordType){
 };
 
 Roo.data.DataReader.prototype = {
+    
+    
+    readerType : 'Data',
      /**
      * Create an empty record
      * @param {Object} data (optional) - overlay some values
@@ -23464,6 +24249,7 @@ Roo.data.DataReader.prototype = {
         return new this.recordType(Roo.apply(da, d));
     }
     
+    
 };/*
  * Based on:
  * Ext JS Library 1.1.1
@@ -23549,6 +24335,7 @@ Roo.data.MemoryProxy = function(data){
 };
 
 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
+    
     /**
      * Load data from the requested source (in this case an in-memory
      * data object passed to the constructor), read the data object into
@@ -23570,7 +24357,7 @@ Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
         params = params || {};
         var result;
         try {
-            result = reader.readRecords(this.data);
+            result = reader.readRecords(params.data ? params.data :this.data);
         }catch(e){
             this.fireEvent("loadexception", this, arg, null, e);
             callback.call(scope, null, arg, false);
@@ -24001,6 +24788,8 @@ Roo.data.JsonReader = function(meta, recordType){
 };
 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
     
+    readerType : 'Json',
+    
     /**
      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
      * Used by Store query builder to append _requestMeta to params.
@@ -24142,6 +24931,14 @@ Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
             records : records,
             totalRecords : totalRecords
         };
+    },
+    // used when loading children.. @see loadDataFromChildren
+    toLoadData: function(rec)
+    {
+       // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
+       var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
+       return { data : data, total : data.length };
+       
     }
 });/*
  * Based on:
@@ -24212,6 +25009,9 @@ Roo.data.XmlReader = function(meta, recordType){
     Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
 };
 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
+    
+    readerType : 'Xml',
+    
     /**
      * This method is only used by a DataProxy which has retrieved data from a remote server.
         * @param {Object} response The XHR object which contains the parsed XML document.  The response is expected
@@ -24309,51 +25109,68 @@ var myReader = new Roo.data.ArrayReader({
  * <pre><code>
 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
   </code></pre>
- * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
  * @constructor
  * Create a new JsonReader
  * @param {Object} meta Metadata configuration options.
- * @param {Object} recordType Either an Array of field definition objects
+ * @param {Object|Array} recordType Either an Array of field definition objects
+ * 
+ * @cfg {Array} fields Array of field definition objects
+ * @cfg {String} id Name of the property within a row object that contains a record identifier value.
  * as specified to {@link Roo.data.Record#create},
  * or an {@link Roo.data.Record} object
+ *
+ * 
  * created using {@link Roo.data.Record#create}.
  */
-Roo.data.ArrayReader = function(meta, recordType){
-    Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
+Roo.data.ArrayReader = function(meta, recordType)
+{    
+    Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
 };
 
 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
-    /**
+    
+      /**
      * Create a data block containing Roo.data.Records from an XML document.
      * @param {Object} o An Array of row objects which represents the dataset.
-     * @return {Object} data A data block which is used by an Roo.data.Store object as
+     * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
      * a cache of Roo.data.Records.
      */
-    readRecords : function(o){
+    readRecords : function(o)
+    {
         var sid = this.meta ? this.meta.id : null;
        var recordType = this.recordType, fields = recordType.prototype.fields;
        var records = [];
        var root = o;
-           for(var i = 0; i < root.length; i++){
-                   var n = root[i];
-               var values = {};
-               var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
-               for(var j = 0, jlen = fields.length; j < jlen; j++){
-                var f = fields.items[j];
-                var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
-                var v = n[k] !== undefined ? n[k] : f.defaultValue;
-                v = f.convert(v);
-                values[f.name] = v;
-            }
-               var record = new recordType(values, id);
-               record.json = n;
-               records[records.length] = record;
+       for(var i = 0; i < root.length; i++){
+               var n = root[i];
+           var values = {};
+           var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
+           for(var j = 0, jlen = fields.length; j < jlen; j++){
+               var f = fields.items[j];
+               var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
+               var v = n[k] !== undefined ? n[k] : f.defaultValue;
+               v = f.convert(v);
+               values[f.name] = v;
            }
-           return {
-               records : records,
-               totalRecords : records.length
-           };
+           var record = new recordType(values, id);
+           record.json = n;
+           records[records.length] = record;
+       }
+       return {
+           records : records,
+           totalRecords : records.length
+       };
+    },
+    // used when loading children.. @see loadDataFromChildren
+    toLoadData: function(rec)
+    {
+       // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
+       return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
+       
     }
+    
+    
 });/*
  * Based on:
  * Ext JS Library 1.1.1
@@ -24651,907 +25468,455 @@ Roo.data.Node = function(attributes){
 Roo.extend(Roo.data.Node, Roo.util.Observable, {
     fireEvent : function(evtName){
         // first do standard event for this node
-        if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
-            return false;
-        }
-        // then bubble it up to the tree if the event wasn't cancelled
-        var ot = this.getOwnerTree();
-        if(ot){
-            if(ot.proxyNodeEvent.apply(ot, arguments) === false){
-                return false;
-            }
-        }
-        return true;
-    },
-
-    /**
-     * Returns true if this node is a leaf
-     * @return {Boolean}
-     */
-    isLeaf : function(){
-        return this.leaf === true;
-    },
-
-    // private
-    setFirstChild : function(node){
-        this.firstChild = node;
-    },
-
-    //private
-    setLastChild : function(node){
-        this.lastChild = node;
-    },
-
-
-    /**
-     * Returns true if this node is the last child of its parent
-     * @return {Boolean}
-     */
-    isLast : function(){
-       return (!this.parentNode ? true : this.parentNode.lastChild == this);
-    },
-
-    /**
-     * Returns true if this node is the first child of its parent
-     * @return {Boolean}
-     */
-    isFirst : function(){
-       return (!this.parentNode ? true : this.parentNode.firstChild == this);
-    },
-
-    hasChildNodes : function(){
-        return !this.isLeaf() && this.childNodes.length > 0;
-    },
-
-    /**
-     * Insert node(s) as the last child node of this node.
-     * @param {Node/Array} node The node or Array of nodes to append
-     * @return {Node} The appended node if single append, or null if an array was passed
-     */
-    appendChild : function(node){
-        var multi = false;
-        if(node instanceof Array){
-            multi = node;
-        }else if(arguments.length > 1){
-            multi = arguments;
-        }
-        // if passed an array or multiple args do them one by one
-        if(multi){
-            for(var i = 0, len = multi.length; i < len; i++) {
-               this.appendChild(multi[i]);
-            }
-        }else{
-            if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
-                return false;
-            }
-            var index = this.childNodes.length;
-            var oldParent = node.parentNode;
-            // it's a move, make sure we move it cleanly
-            if(oldParent){
-                if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
-                    return false;
-                }
-                oldParent.removeChild(node);
-            }
-            index = this.childNodes.length;
-            if(index == 0){
-                this.setFirstChild(node);
-            }
-            this.childNodes.push(node);
-            node.parentNode = this;
-            var ps = this.childNodes[index-1];
-            if(ps){
-                node.previousSibling = ps;
-                ps.nextSibling = node;
-            }else{
-                node.previousSibling = null;
-            }
-            node.nextSibling = null;
-            this.setLastChild(node);
-            node.setOwnerTree(this.getOwnerTree());
-            this.fireEvent("append", this.ownerTree, this, node, index);
-            if(oldParent){
-                node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
-            }
-            return node;
-        }
-    },
-
-    /**
-     * Removes a child node from this node.
-     * @param {Node} node The node to remove
-     * @return {Node} The removed node
-     */
-    removeChild : function(node){
-        var index = this.childNodes.indexOf(node);
-        if(index == -1){
-            return false;
-        }
-        if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
-            return false;
-        }
-
-        // remove it from childNodes collection
-        this.childNodes.splice(index, 1);
-
-        // update siblings
-        if(node.previousSibling){
-            node.previousSibling.nextSibling = node.nextSibling;
-        }
-        if(node.nextSibling){
-            node.nextSibling.previousSibling = node.previousSibling;
-        }
-
-        // update child refs
-        if(this.firstChild == node){
-            this.setFirstChild(node.nextSibling);
-        }
-        if(this.lastChild == node){
-            this.setLastChild(node.previousSibling);
-        }
-
-        node.setOwnerTree(null);
-        // clear any references from the node
-        node.parentNode = null;
-        node.previousSibling = null;
-        node.nextSibling = null;
-        this.fireEvent("remove", this.ownerTree, this, node);
-        return node;
-    },
-
-    /**
-     * Inserts the first node before the second node in this nodes childNodes collection.
-     * @param {Node} node The node to insert
-     * @param {Node} refNode The node to insert before (if null the node is appended)
-     * @return {Node} The inserted node
-     */
-    insertBefore : function(node, refNode){
-        if(!refNode){ // like standard Dom, refNode can be null for append
-            return this.appendChild(node);
-        }
-        // nothing to do
-        if(node == refNode){
-            return false;
-        }
-
-        if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
-            return false;
-        }
-        var index = this.childNodes.indexOf(refNode);
-        var oldParent = node.parentNode;
-        var refIndex = index;
-
-        // when moving internally, indexes will change after remove
-        if(oldParent == this && this.childNodes.indexOf(node) < index){
-            refIndex--;
-        }
-
-        // it's a move, make sure we move it cleanly
-        if(oldParent){
-            if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
-                return false;
-            }
-            oldParent.removeChild(node);
-        }
-        if(refIndex == 0){
-            this.setFirstChild(node);
-        }
-        this.childNodes.splice(refIndex, 0, node);
-        node.parentNode = this;
-        var ps = this.childNodes[refIndex-1];
-        if(ps){
-            node.previousSibling = ps;
-            ps.nextSibling = node;
-        }else{
-            node.previousSibling = null;
-        }
-        node.nextSibling = refNode;
-        refNode.previousSibling = node;
-        node.setOwnerTree(this.getOwnerTree());
-        this.fireEvent("insert", this.ownerTree, this, node, refNode);
-        if(oldParent){
-            node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
-        }
-        return node;
-    },
-
-    /**
-     * Returns the child node at the specified index.
-     * @param {Number} index
-     * @return {Node}
-     */
-    item : function(index){
-        return this.childNodes[index];
-    },
-
-    /**
-     * Replaces one child node in this node with another.
-     * @param {Node} newChild The replacement node
-     * @param {Node} oldChild The node to replace
-     * @return {Node} The replaced node
-     */
-    replaceChild : function(newChild, oldChild){
-        this.insertBefore(newChild, oldChild);
-        this.removeChild(oldChild);
-        return oldChild;
-    },
-
-    /**
-     * Returns the index of a child node
-     * @param {Node} node
-     * @return {Number} The index of the node or -1 if it was not found
-     */
-    indexOf : function(child){
-        return this.childNodes.indexOf(child);
-    },
-
-    /**
-     * Returns the tree this node is in.
-     * @return {Tree}
-     */
-    getOwnerTree : function(){
-        // if it doesn't have one, look for one
-        if(!this.ownerTree){
-            var p = this;
-            while(p){
-                if(p.ownerTree){
-                    this.ownerTree = p.ownerTree;
-                    break;
-                }
-                p = p.parentNode;
+        if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
+            return false;
+        }
+        // then bubble it up to the tree if the event wasn't cancelled
+        var ot = this.getOwnerTree();
+        if(ot){
+            if(ot.proxyNodeEvent.apply(ot, arguments) === false){
+                return false;
             }
         }
-        return this.ownerTree;
+        return true;
     },
 
     /**
-     * Returns depth of this node (the root node has a depth of 0)
-     * @return {Number}
+     * Returns true if this node is a leaf
+     * @return {Boolean}
      */
-    getDepth : function(){
-        var depth = 0;
-        var p = this;
-        while(p.parentNode){
-            ++depth;
-            p = p.parentNode;
-        }
-        return depth;
+    isLeaf : function(){
+        return this.leaf === true;
     },
 
     // private
-    setOwnerTree : function(tree){
-        // if it's move, we need to update everyone
-        if(tree != this.ownerTree){
-            if(this.ownerTree){
-                this.ownerTree.unregisterNode(this);
-            }
-            this.ownerTree = tree;
-            var cs = this.childNodes;
-            for(var i = 0, len = cs.length; i < len; i++) {
-               cs[i].setOwnerTree(tree);
-            }
-            if(tree){
-                tree.registerNode(this);
-            }
-        }
+    setFirstChild : function(node){
+        this.firstChild = node;
     },
 
-    /**
-     * Returns the path for this node. The path can be used to expand or select this node programmatically.
-     * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
-     * @return {String} The path
-     */
-    getPath : function(attr){
-        attr = attr || "id";
-        var p = this.parentNode;
-        var b = [this.attributes[attr]];
-        while(p){
-            b.unshift(p.attributes[attr]);
-            p = p.parentNode;
-        }
-        var sep = this.getOwnerTree().pathSeparator;
-        return sep + b.join(sep);
+    //private
+    setLastChild : function(node){
+        this.lastChild = node;
     },
 
-    /**
-     * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
-     * function call will be the scope provided or the current node. The arguments to the function
-     * will be the args provided or the current node. If the function returns false at any point,
-     * the bubble is stopped.
-     * @param {Function} fn The function to call
-     * @param {Object} scope (optional) The scope of the function (defaults to current node)
-     * @param {Array} args (optional) The args to call the function with (default to passing the current node)
-     */
-    bubble : function(fn, scope, args){
-        var p = this;
-        while(p){
-            if(fn.call(scope || p, args || p) === false){
-                break;
-            }
-            p = p.parentNode;
-        }
-    },
 
     /**
-     * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
-     * function call will be the scope provided or the current node. The arguments to the function
-     * will be the args provided or the current node. If the function returns false at any point,
-     * the cascade is stopped on that branch.
-     * @param {Function} fn The function to call
-     * @param {Object} scope (optional) The scope of the function (defaults to current node)
-     * @param {Array} args (optional) The args to call the function with (default to passing the current node)
+     * Returns true if this node is the last child of its parent
+     * @return {Boolean}
      */
-    cascade : function(fn, scope, args){
-        if(fn.call(scope || this, args || this) !== false){
-            var cs = this.childNodes;
-            for(var i = 0, len = cs.length; i < len; i++) {
-               cs[i].cascade(fn, scope, args);
-            }
-        }
+    isLast : function(){
+       return (!this.parentNode ? true : this.parentNode.lastChild == this);
     },
 
     /**
-     * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
-     * function call will be the scope provided or the current node. The arguments to the function
-     * will be the args provided or the current node. If the function returns false at any point,
-     * the iteration stops.
-     * @param {Function} fn The function to call
-     * @param {Object} scope (optional) The scope of the function (defaults to current node)
-     * @param {Array} args (optional) The args to call the function with (default to passing the current node)
+     * Returns true if this node is the first child of its parent
+     * @return {Boolean}
      */
-    eachChild : function(fn, scope, args){
-        var cs = this.childNodes;
-        for(var i = 0, len = cs.length; i < len; i++) {
-               if(fn.call(scope || this, args || cs[i]) === false){
-                   break;
-               }
-        }
+    isFirst : function(){
+       return (!this.parentNode ? true : this.parentNode.firstChild == this);
     },
 
-    /**
-     * Finds the first child that has the attribute with the specified value.
-     * @param {String} attribute The attribute name
-     * @param {Mixed} value The value to search for
-     * @return {Node} The found child or null if none was found
-     */
-    findChild : function(attribute, value){
-        var cs = this.childNodes;
-        for(var i = 0, len = cs.length; i < len; i++) {
-               if(cs[i].attributes[attribute] == value){
-                   return cs[i];
-               }
-        }
-        return null;
+    hasChildNodes : function(){
+        return !this.isLeaf() && this.childNodes.length > 0;
     },
 
     /**
-     * Finds the first child by a custom function. The child matches if the function passed
-     * returns true.
-     * @param {Function} fn
-     * @param {Object} scope (optional)
-     * @return {Node} The found child or null if none was found
+     * Insert node(s) as the last child node of this node.
+     * @param {Node/Array} node The node or Array of nodes to append
+     * @return {Node} The appended node if single append, or null if an array was passed
      */
-    findChildBy : function(fn, scope){
-        var cs = this.childNodes;
-        for(var i = 0, len = cs.length; i < len; i++) {
-               if(fn.call(scope||cs[i], cs[i]) === true){
-                   return cs[i];
-               }
+    appendChild : function(node){
+        var multi = false;
+        if(node instanceof Array){
+            multi = node;
+        }else if(arguments.length > 1){
+            multi = arguments;
         }
-        return null;
-    },
-
-    /**
-     * Sorts this nodes children using the supplied sort function
-     * @param {Function} fn
-     * @param {Object} scope (optional)
-     */
-    sort : function(fn, scope){
-        var cs = this.childNodes;
-        var len = cs.length;
-        if(len > 0){
-            var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
-            cs.sort(sortFn);
-            for(var i = 0; i < len; i++){
-                var n = cs[i];
-                n.previousSibling = cs[i-1];
-                n.nextSibling = cs[i+1];
-                if(i == 0){
-                    this.setFirstChild(n);
-                }
-                if(i == len-1){
-                    this.setLastChild(n);
+        
+        // if passed an array or multiple args do them one by one
+        if(multi){
+            for(var i = 0, len = multi.length; i < len; i++) {
+               this.appendChild(multi[i]);
+            }
+        }else{
+            if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
+                return false;
+            }
+            var index = this.childNodes.length;
+            var oldParent = node.parentNode;
+            // it's a move, make sure we move it cleanly
+            if(oldParent){
+                if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
+                    return false;
                 }
+                oldParent.removeChild(node);
+            }
+            
+            index = this.childNodes.length;
+            if(index == 0){
+                this.setFirstChild(node);
+            }
+            this.childNodes.push(node);
+            node.parentNode = this;
+            var ps = this.childNodes[index-1];
+            if(ps){
+                node.previousSibling = ps;
+                ps.nextSibling = node;
+            }else{
+                node.previousSibling = null;
+            }
+            node.nextSibling = null;
+            this.setLastChild(node);
+            node.setOwnerTree(this.getOwnerTree());
+            this.fireEvent("append", this.ownerTree, this, node, index);
+            if(this.ownerTree) {
+                this.ownerTree.fireEvent("appendnode", this, node, index);
             }
+            if(oldParent){
+                node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
+            }
+            return node;
         }
     },
 
     /**
-     * Returns true if this node is an ancestor (at any point) of the passed node.
-     * @param {Node} node
-     * @return {Boolean}
-     */
-    contains : function(node){
-        return node.isAncestor(this);
-    },
-
-    /**
-     * Returns true if the passed node is an ancestor (at any point) of this node.
-     * @param {Node} node
-     * @return {Boolean}
+     * Removes a child node from this node.
+     * @param {Node} node The node to remove
+     * @return {Node} The removed node
      */
-    isAncestor : function(node){
-        var p = this.parentNode;
-        while(p){
-            if(p == node){
-                return true;
-            }
-            p = p.parentNode;
-        }
-        return false;
-    },
-
-    toString : function(){
-        return "[Node"+(this.id?" "+this.id:"")+"]";
-    }
-});/*
- * 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">
- */
- (function(){ 
-/**
- * @class Roo.Layer
- * @extends Roo.Element
- * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
- * automatic maintaining of shadow/shim positions.
- * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
- * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
- * you can pass a string with a CSS class name. False turns off the shadow.
- * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
- * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
- * @cfg {String} cls CSS class to add to the element
- * @cfg {Number} zindex Starting z-index (defaults to 11000)
- * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
- * @constructor
- * @param {Object} config An object with config options.
- * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
- */
-
-Roo.Layer = function(config, existingEl){
-    config = config || {};
-    var dh = Roo.DomHelper;
-    var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
-    if(existingEl){
-        this.dom = Roo.getDom(existingEl);
-    }
-    if(!this.dom){
-        var o = config.dh || {tag: "div", cls: "x-layer"};
-        this.dom = dh.append(pel, o);
-    }
-    if(config.cls){
-        this.addClass(config.cls);
-    }
-    this.constrain = config.constrain !== false;
-    this.visibilityMode = Roo.Element.VISIBILITY;
-    if(config.id){
-        this.id = this.dom.id = config.id;
-    }else{
-        this.id = Roo.id(this.dom);
-    }
-    this.zindex = config.zindex || this.getZIndex();
-    this.position("absolute", this.zindex);
-    if(config.shadow){
-        this.shadowOffset = config.shadowOffset || 4;
-        this.shadow = new Roo.Shadow({
-            offset : this.shadowOffset,
-            mode : config.shadow
-        });
-    }else{
-        this.shadowOffset = 0;
-    }
-    this.useShim = config.shim !== false && Roo.useShims;
-    this.useDisplay = config.useDisplay;
-    this.hide();
-};
-
-var supr = Roo.Element.prototype;
-
-// shims are shared among layer to keep from having 100 iframes
-var shims = [];
-
-Roo.extend(Roo.Layer, Roo.Element, {
-
-    getZIndex : function(){
-        return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
-    },
-
-    getShim : function(){
-        if(!this.useShim){
-            return null;
-        }
-        if(this.shim){
-            return this.shim;
-        }
-        var shim = shims.shift();
-        if(!shim){
-            shim = this.createShim();
-            shim.enableDisplayMode('block');
-            shim.dom.style.display = 'none';
-            shim.dom.style.visibility = 'visible';
-        }
-        var pn = this.dom.parentNode;
-        if(shim.dom.parentNode != pn){
-            pn.insertBefore(shim.dom, this.dom);
+    removeChild : function(node){
+        var index = this.childNodes.indexOf(node);
+        if(index == -1){
+            return false;
         }
-        shim.setStyle('z-index', this.getZIndex()-2);
-        this.shim = shim;
-        return shim;
-    },
-
-    hideShim : function(){
-        if(this.shim){
-            this.shim.setDisplayed(false);
-            shims.push(this.shim);
-            delete this.shim;
+        if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
+            return false;
         }
-    },
 
-    disableShadow : function(){
-        if(this.shadow){
-            this.shadowDisabled = true;
-            this.shadow.hide();
-            this.lastShadowOffset = this.shadowOffset;
-            this.shadowOffset = 0;
-        }
-    },
+        // remove it from childNodes collection
+        this.childNodes.splice(index, 1);
 
-    enableShadow : function(show){
-        if(this.shadow){
-            this.shadowDisabled = false;
-            this.shadowOffset = this.lastShadowOffset;
-            delete this.lastShadowOffset;
-            if(show){
-                this.sync(true);
-            }
+        // update siblings
+        if(node.previousSibling){
+            node.previousSibling.nextSibling = node.nextSibling;
         }
-    },
-
-    // private
-    // this code can execute repeatedly in milliseconds (i.e. during a drag) so
-    // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
-    sync : function(doShow){
-        var sw = this.shadow;
-        if(!this.updating && this.isVisible() && (sw || this.useShim)){
-            var sh = this.getShim();
-
-            var w = this.getWidth(),
-                h = this.getHeight();
-
-            var l = this.getLeft(true),
-                t = this.getTop(true);
-
-            if(sw && !this.shadowDisabled){
-                if(doShow && !sw.isVisible()){
-                    sw.show(this);
-                }else{
-                    sw.realign(l, t, w, h);
-                }
-                if(sh){
-                    if(doShow){
-                       sh.show();
-                    }
-                    // fit the shim behind the shadow, so it is shimmed too
-                    var a = sw.adjusts, s = sh.dom.style;
-                    s.left = (Math.min(l, l+a.l))+"px";
-                    s.top = (Math.min(t, t+a.t))+"px";
-                    s.width = (w+a.w)+"px";
-                    s.height = (h+a.h)+"px";
-                }
-            }else if(sh){
-                if(doShow){
-                   sh.show();
-                }
-                sh.setSize(w, h);
-                sh.setLeftTop(l, t);
-            }
-            
+        if(node.nextSibling){
+            node.nextSibling.previousSibling = node.previousSibling;
         }
-    },
 
-    // private
-    destroy : function(){
-        this.hideShim();
-        if(this.shadow){
-            this.shadow.hide();
+        // update child refs
+        if(this.firstChild == node){
+            this.setFirstChild(node.nextSibling);
         }
-        this.removeAllListeners();
-        var pn = this.dom.parentNode;
-        if(pn){
-            pn.removeChild(this.dom);
+        if(this.lastChild == node){
+            this.setLastChild(node.previousSibling);
         }
-        Roo.Element.uncache(this.id);
-    },
-
-    remove : function(){
-        this.destroy();
-    },
-
-    // private
-    beginUpdate : function(){
-        this.updating = true;
-    },
-
-    // private
-    endUpdate : function(){
-        this.updating = false;
-        this.sync(true);
-    },
 
-    // private
-    hideUnders : function(negOffset){
-        if(this.shadow){
-            this.shadow.hide();
-        }
-        this.hideShim();
+        node.setOwnerTree(null);
+        // clear any references from the node
+        node.parentNode = null;
+        node.previousSibling = null;
+        node.nextSibling = null;
+        this.fireEvent("remove", this.ownerTree, this, node);
+        return node;
     },
 
-    // private
-    constrainXY : function(){
-        if(this.constrain){
-            var vw = Roo.lib.Dom.getViewWidth(),
-                vh = Roo.lib.Dom.getViewHeight();
-            var s = Roo.get(document).getScroll();
-
-            var xy = this.getXY();
-            var x = xy[0], y = xy[1];   
-            var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
-            // only move it if it needs it
-            var moved = false;
-            // first validate right/bottom
-            if((x + w) > vw+s.left){
-                x = vw - w - this.shadowOffset;
-                moved = true;
-            }
-            if((y + h) > vh+s.top){
-                y = vh - h - this.shadowOffset;
-                moved = true;
-            }
-            // then make sure top/left isn't negative
-            if(x < s.left){
-                x = s.left;
-                moved = true;
-            }
-            if(y < s.top){
-                y = s.top;
-                moved = true;
-            }
-            if(moved){
-                if(this.avoidY){
-                    var ay = this.avoidY;
-                    if(y <= ay && (y+h) >= ay){
-                        y = ay-h-5;   
-                    }
-                }
-                xy = [x, y];
-                this.storeXY(xy);
-                supr.setXY.call(this, xy);
-                this.sync();
-            }
+    /**
+     * Inserts the first node before the second node in this nodes childNodes collection.
+     * @param {Node} node The node to insert
+     * @param {Node} refNode The node to insert before (if null the node is appended)
+     * @return {Node} The inserted node
+     */
+    insertBefore : function(node, refNode){
+        if(!refNode){ // like standard Dom, refNode can be null for append
+            return this.appendChild(node);
+        }
+        // nothing to do
+        if(node == refNode){
+            return false;
         }
-    },
-
-    isVisible : function(){
-        return this.visible;    
-    },
 
-    // private
-    showAction : function(){
-        this.visible = true; // track visibility to prevent getStyle calls
-        if(this.useDisplay === true){
-            this.setDisplayed("");
-        }else if(this.lastXY){
-            supr.setXY.call(this, this.lastXY);
-        }else if(this.lastLT){
-            supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
+        if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
+            return false;
         }
-    },
+        var index = this.childNodes.indexOf(refNode);
+        var oldParent = node.parentNode;
+        var refIndex = index;
 
-    // private
-    hideAction : function(){
-        this.visible = false;
-        if(this.useDisplay === true){
-            this.setDisplayed(false);
-        }else{
-            this.setLeftTop(-10000,-10000);
+        // when moving internally, indexes will change after remove
+        if(oldParent == this && this.childNodes.indexOf(node) < index){
+            refIndex--;
         }
-    },
 
-    // overridden Element method
-    setVisible : function(v, a, d, c, e){
-        if(v){
-            this.showAction();
+        // it's a move, make sure we move it cleanly
+        if(oldParent){
+            if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
+                return false;
+            }
+            oldParent.removeChild(node);
         }
-        if(a && v){
-            var cb = function(){
-                this.sync(true);
-                if(c){
-                    c();
-                }
-            }.createDelegate(this);
-            supr.setVisible.call(this, true, true, d, cb, e);
+        if(refIndex == 0){
+            this.setFirstChild(node);
+        }
+        this.childNodes.splice(refIndex, 0, node);
+        node.parentNode = this;
+        var ps = this.childNodes[refIndex-1];
+        if(ps){
+            node.previousSibling = ps;
+            ps.nextSibling = node;
         }else{
-            if(!v){
-                this.hideUnders(true);
-            }
-            var cb = c;
-            if(a){
-                cb = function(){
-                    this.hideAction();
-                    if(c){
-                        c();
-                    }
-                }.createDelegate(this);
-            }
-            supr.setVisible.call(this, v, a, d, cb, e);
-            if(v){
-                this.sync(true);
-            }else if(!a){
-                this.hideAction();
-            }
+            node.previousSibling = null;
         }
+        node.nextSibling = refNode;
+        refNode.previousSibling = node;
+        node.setOwnerTree(this.getOwnerTree());
+        this.fireEvent("insert", this.ownerTree, this, node, refNode);
+        if(oldParent){
+            node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
+        }
+        return node;
     },
 
-    storeXY : function(xy){
-        delete this.lastLT;
-        this.lastXY = xy;
-    },
-
-    storeLeftTop : function(left, top){
-        delete this.lastXY;
-        this.lastLT = [left, top];
+    /**
+     * Returns the child node at the specified index.
+     * @param {Number} index
+     * @return {Node}
+     */
+    item : function(index){
+        return this.childNodes[index];
     },
 
-    // private
-    beforeFx : function(){
-        this.beforeAction();
-        return Roo.Layer.superclass.beforeFx.apply(this, arguments);
+    /**
+     * Replaces one child node in this node with another.
+     * @param {Node} newChild The replacement node
+     * @param {Node} oldChild The node to replace
+     * @return {Node} The replaced node
+     */
+    replaceChild : function(newChild, oldChild){
+        this.insertBefore(newChild, oldChild);
+        this.removeChild(oldChild);
+        return oldChild;
     },
 
-    // private
-    afterFx : function(){
-        Roo.Layer.superclass.afterFx.apply(this, arguments);
-        this.sync(this.isVisible());
+    /**
+     * Returns the index of a child node
+     * @param {Node} node
+     * @return {Number} The index of the node or -1 if it was not found
+     */
+    indexOf : function(child){
+        return this.childNodes.indexOf(child);
     },
 
-    // private
-    beforeAction : function(){
-        if(!this.updating && this.shadow){
-            this.shadow.hide();
+    /**
+     * Returns the tree this node is in.
+     * @return {Tree}
+     */
+    getOwnerTree : function(){
+        // if it doesn't have one, look for one
+        if(!this.ownerTree){
+            var p = this;
+            while(p){
+                if(p.ownerTree){
+                    this.ownerTree = p.ownerTree;
+                    break;
+                }
+                p = p.parentNode;
+            }
         }
+        return this.ownerTree;
     },
 
-    // overridden Element method
-    setLeft : function(left){
-        this.storeLeftTop(left, this.getTop(true));
-        supr.setLeft.apply(this, arguments);
-        this.sync();
-    },
-
-    setTop : function(top){
-        this.storeLeftTop(this.getLeft(true), top);
-        supr.setTop.apply(this, arguments);
-        this.sync();
+    /**
+     * Returns depth of this node (the root node has a depth of 0)
+     * @return {Number}
+     */
+    getDepth : function(){
+        var depth = 0;
+        var p = this;
+        while(p.parentNode){
+            ++depth;
+            p = p.parentNode;
+        }
+        return depth;
     },
 
-    setLeftTop : function(left, top){
-        this.storeLeftTop(left, top);
-        supr.setLeftTop.apply(this, arguments);
-        this.sync();
+    // private
+    setOwnerTree : function(tree){
+        // if it's move, we need to update everyone
+        if(tree != this.ownerTree){
+            if(this.ownerTree){
+                this.ownerTree.unregisterNode(this);
+            }
+            this.ownerTree = tree;
+            var cs = this.childNodes;
+            for(var i = 0, len = cs.length; i < len; i++) {
+               cs[i].setOwnerTree(tree);
+            }
+            if(tree){
+                tree.registerNode(this);
+            }
+        }
     },
 
-    setXY : function(xy, a, d, c, e){
-        this.fixDisplay();
-        this.beforeAction();
-        this.storeXY(xy);
-        var cb = this.createCB(c);
-        supr.setXY.call(this, xy, a, d, cb, e);
-        if(!a){
-            cb();
+    /**
+     * Returns the path for this node. The path can be used to expand or select this node programmatically.
+     * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
+     * @return {String} The path
+     */
+    getPath : function(attr){
+        attr = attr || "id";
+        var p = this.parentNode;
+        var b = [this.attributes[attr]];
+        while(p){
+            b.unshift(p.attributes[attr]);
+            p = p.parentNode;
         }
+        var sep = this.getOwnerTree().pathSeparator;
+        return sep + b.join(sep);
     },
 
-    // private
-    createCB : function(c){
-        var el = this;
-        return function(){
-            el.constrainXY();
-            el.sync(true);
-            if(c){
-                c();
+    /**
+     * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
+     * function call will be the scope provided or the current node. The arguments to the function
+     * will be the args provided or the current node. If the function returns false at any point,
+     * the bubble is stopped.
+     * @param {Function} fn The function to call
+     * @param {Object} scope (optional) The scope of the function (defaults to current node)
+     * @param {Array} args (optional) The args to call the function with (default to passing the current node)
+     */
+    bubble : function(fn, scope, args){
+        var p = this;
+        while(p){
+            if(fn.call(scope || p, args || p) === false){
+                break;
             }
-        };
+            p = p.parentNode;
+        }
     },
 
-    // overridden Element method
-    setX : function(x, a, d, c, e){
-        this.setXY([x, this.getY()], a, d, c, e);
+    /**
+     * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
+     * function call will be the scope provided or the current node. The arguments to the function
+     * will be the args provided or the current node. If the function returns false at any point,
+     * the cascade is stopped on that branch.
+     * @param {Function} fn The function to call
+     * @param {Object} scope (optional) The scope of the function (defaults to current node)
+     * @param {Array} args (optional) The args to call the function with (default to passing the current node)
+     */
+    cascade : function(fn, scope, args){
+        if(fn.call(scope || this, args || this) !== false){
+            var cs = this.childNodes;
+            for(var i = 0, len = cs.length; i < len; i++) {
+               cs[i].cascade(fn, scope, args);
+            }
+        }
     },
 
-    // overridden Element method
-    setY : function(y, a, d, c, e){
-        this.setXY([this.getX(), y], a, d, c, e);
+    /**
+     * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
+     * function call will be the scope provided or the current node. The arguments to the function
+     * will be the args provided or the current node. If the function returns false at any point,
+     * the iteration stops.
+     * @param {Function} fn The function to call
+     * @param {Object} scope (optional) The scope of the function (defaults to current node)
+     * @param {Array} args (optional) The args to call the function with (default to passing the current node)
+     */
+    eachChild : function(fn, scope, args){
+        var cs = this.childNodes;
+        for(var i = 0, len = cs.length; i < len; i++) {
+               if(fn.call(scope || this, args || cs[i]) === false){
+                   break;
+               }
+        }
     },
 
-    // overridden Element method
-    setSize : function(w, h, a, d, c, e){
-        this.beforeAction();
-        var cb = this.createCB(c);
-        supr.setSize.call(this, w, h, a, d, cb, e);
-        if(!a){
-            cb();
+    /**
+     * Finds the first child that has the attribute with the specified value.
+     * @param {String} attribute The attribute name
+     * @param {Mixed} value The value to search for
+     * @return {Node} The found child or null if none was found
+     */
+    findChild : function(attribute, value){
+        var cs = this.childNodes;
+        for(var i = 0, len = cs.length; i < len; i++) {
+               if(cs[i].attributes[attribute] == value){
+                   return cs[i];
+               }
         }
+        return null;
     },
 
-    // overridden Element method
-    setWidth : function(w, a, d, c, e){
-        this.beforeAction();
-        var cb = this.createCB(c);
-        supr.setWidth.call(this, w, a, d, cb, e);
-        if(!a){
-            cb();
+    /**
+     * Finds the first child by a custom function. The child matches if the function passed
+     * returns true.
+     * @param {Function} fn
+     * @param {Object} scope (optional)
+     * @return {Node} The found child or null if none was found
+     */
+    findChildBy : function(fn, scope){
+        var cs = this.childNodes;
+        for(var i = 0, len = cs.length; i < len; i++) {
+               if(fn.call(scope||cs[i], cs[i]) === true){
+                   return cs[i];
+               }
         }
+        return null;
     },
 
-    // overridden Element method
-    setHeight : function(h, a, d, c, e){
-        this.beforeAction();
-        var cb = this.createCB(c);
-        supr.setHeight.call(this, h, a, d, cb, e);
-        if(!a){
-            cb();
+    /**
+     * Sorts this nodes children using the supplied sort function
+     * @param {Function} fn
+     * @param {Object} scope (optional)
+     */
+    sort : function(fn, scope){
+        var cs = this.childNodes;
+        var len = cs.length;
+        if(len > 0){
+            var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
+            cs.sort(sortFn);
+            for(var i = 0; i < len; i++){
+                var n = cs[i];
+                n.previousSibling = cs[i-1];
+                n.nextSibling = cs[i+1];
+                if(i == 0){
+                    this.setFirstChild(n);
+                }
+                if(i == len-1){
+                    this.setLastChild(n);
+                }
+            }
         }
     },
 
-    // overridden Element method
-    setBounds : function(x, y, w, h, a, d, c, e){
-        this.beforeAction();
-        var cb = this.createCB(c);
-        if(!a){
-            this.storeXY([x, y]);
-            supr.setXY.call(this, [x, y]);
-            supr.setSize.call(this, w, h, a, d, cb, e);
-            cb();
-        }else{
-            supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
-        }
-        return this;
+    /**
+     * Returns true if this node is an ancestor (at any point) of the passed node.
+     * @param {Node} node
+     * @return {Boolean}
+     */
+    contains : function(node){
+        return node.isAncestor(this);
     },
-    
+
     /**
-     * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
-     * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
-     * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
-     * @param {Number} zindex The new z-index to set
-     * @return {this} The Layer
+     * Returns true if the passed node is an ancestor (at any point) of this node.
+     * @param {Node} node
+     * @return {Boolean}
      */
-    setZIndex : function(zindex){
-        this.zindex = zindex;
-        this.setStyle("z-index", zindex + 2);
-        if(this.shadow){
-            this.shadow.setZIndex(zindex + 1);
-        }
-        if(this.shim){
-            this.shim.setStyle("z-index", zindex);
+    isAncestor : function(node){
+        var p = this.parentNode;
+        while(p){
+            if(p == node){
+                return true;
+            }
+            p = p.parentNode;
         }
+        return false;
+    },
+
+    toString : function(){
+        return "[Node"+(this.id?" "+this.id:"")+"]";
     }
-});
-})();/*
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -27035,15 +27400,20 @@ Roo.extend(Roo.JsonView, Roo.View, {
         um.update.apply(um, arguments);
     },
 
+    // note - render is a standard framework call...
+    // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
     render : function(el, response){
+        
         this.clearSelections();
         this.el.update("");
         var o;
         try{
-            o = Roo.util.JSON.decode(response.responseText);
-            if(this.jsonRoot){
-                
-                o = o[this.jsonRoot];
+            if (response != '') {
+                o = Roo.util.JSON.decode(response.responseText);
+                if(this.jsonRoot){
+                    
+                    o = o[this.jsonRoot];
+                }
             }
         } catch(e){
         }
@@ -30074,7 +30444,7 @@ Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
  * A simple class that renders text directly into a toolbar.
  * @constructor
  * Creates a new TextItem
- * @param {String} text
+ * @cfg {string} text 
  */
 Roo.Toolbar.TextItem = function(cfg){
     var  text = cfg || "";
@@ -33392,7 +33762,7 @@ Roo.QuickTips = function(){
         if(ttp){
             showProc = show.defer(tm.showDelay, tm, [{
                 el: t, 
-                text: ttp
+                text: ttp.replace(/\\n/g,'<br/>'),
                 width: et.getAttributeNS(ns, cfg.width),
                 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
                 title: et.getAttributeNS(ns, cfg.title),
@@ -33982,7 +34352,15 @@ Roo.tree.TreePanel = function(el, config){
         * </ul>
         * @param {Object} dragOverEvent
         */
-       "nodedragover" : true
+       "nodedragover" : true,
+       /**
+        * @event appendnode
+        * Fires when append node to the tree
+        * @param {Roo.tree.TreePanel} this
+        * @param {Roo.tree.TreeNode} node
+        * @param {Number} index The index of the newly appended node
+        */
+       "appendnode" : true
         
     });
     if(this.singleExpand){
@@ -34560,7 +34938,7 @@ Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
  * @cfg {Boolean} allowDrop false if this node cannot be drop on
  * @cfg {Boolean} disabled true to start the node disabled
  * @cfg {String} icon The path to an icon for the node. The preferred way to do this
- * is to use the cls or iconCls attributes and add the icon via a CSS background image.
+ *    is to use the cls or iconCls attributes and add the icon via a CSS background image.
  * @cfg {String} cls A css class to be added to the node
  * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
  * @cfg {String} href URL of the link used for the node (defaults to #)
@@ -34843,7 +35221,8 @@ Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
                 this.renderChildren();
             }
             this.expanded = true;
-            if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
+            
+            if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
                 this.ui.animExpand(function(){
                     this.fireEvent("expand", this);
                     if(typeof callback == "function"){
@@ -35294,7 +35673,7 @@ Roo.tree.TreeNodeUI.prototype = {
             this.addClass("x-tree-node-disabled");
         }
         var ot = this.node.getOwnerTree();
-        var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
+        var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
         if(dd && (!this.node.isRoot || ot.rootVisible)){
             Roo.dd.Registry.register(this.elNode, {
                 node: this.node,
@@ -35537,11 +35916,11 @@ Roo.tree.TreeNodeUI.prototype = {
         // add some indent caching, this helps performance when rendering a large tree
         this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
         var t = n.getOwnerTree();
-        var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
+        var txt = t && t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
         if (typeof(n.attributes.html) != 'undefined') {
             txt = n.attributes.html;
         }
-        var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
+        var tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
         var cb = typeof a.checked == 'boolean';
         var href = a.href ? a.href : Roo.isGecko ? "" : "#";
         var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
@@ -35727,7 +36106,9 @@ Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
     myTreeLoader.on("beforeload", function(treeLoader, node) {
         this.baseParams.category = node.attributes.category;
     }, this);
-</code></pre><
+    
+</code></pre>
+ *
  * This would pass an HTTP parameter called "category" to the server containing
  * the value of the Node's "category" attribute.
  * @constructor
@@ -36932,7 +37313,9 @@ Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
  * @param {Object} config Configuration options
  */
 Roo.menu.Menu = function(config){
-    Roo.apply(this, config);
+    
+    Roo.menu.Menu.superclass.constructor.call(this, config);
+    
     this.id = this.id || Roo.id();
     this.addEvents({
         /**
@@ -38413,6 +38796,77 @@ Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
  * <script type="text/javascript">
  */
  
+/**
+ * @class Roo.form.TextItem
+ * @extends Roo.BoxComponent
+ * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
+ * @constructor
+ * Creates a new TextItem
+ * @param {Object} config Configuration options
+ */
+Roo.form.TextItem = function(config){
+    Roo.form.TextItem.superclass.constructor.call(this, config);
+};
+
+Roo.extend(Roo.form.TextItem, Roo.BoxComponent,  {
+    
+    /**
+     * @cfg {String} tag the tag for this item (default div)
+     */
+    tag : 'div',
+    /**
+     * @cfg {String} html the content for this item
+     */
+    html : '',
+    
+    getAutoCreate : function()
+    {
+        var cfg = {
+            id: this.id,
+            tag: this.tag,
+            html: this.html,
+            cls: 'x-form-item'
+        };
+        
+        return cfg;
+        
+    },
+    
+    onRender : function(ct, position)
+    {
+        Roo.form.TextItem.superclass.onRender.call(this, ct, position);
+        
+        if(!this.el){
+            var cfg = this.getAutoCreate();
+            if(!cfg.name){
+                cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
+            }
+            if (!cfg.name.length) {
+                delete cfg.name;
+            }
+            this.el = ct.createChild(cfg, position);
+        }
+    },
+    /*
+     * setHTML
+     * @param {String} html update the Contents of the element.
+     */
+    setHTML : function(html)
+    {
+        this.fieldEl.dom.innerHTML = html;
+    }
+    
+});/*
+ * 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">
+ */
 /**
  * @class Roo.form.Field
  * @extends Roo.BoxComponent
@@ -38698,6 +39152,7 @@ side          Add an error icon to the right of the field with a popup on hover
      */
     reset : function(){
         this.setValue(this.resetValue);
+        this.originalValue = this.getValue();
         this.clearInvalid();
     },
 
@@ -39067,6 +39522,10 @@ Roo.extend(Roo.form.TextField, Roo.form.Field,  {
      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
      */
     selectOnFocus : false,
+    /**
+     * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space 
+     */    
+    allowLeadingSpace : false,
     /**
      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
      */
@@ -39111,8 +39570,11 @@ Roo.extend(Roo.form.TextField, Roo.form.Field,  {
         
         if(this.selectOnFocus){
             this.on("focus", this.preFocus, this);
-            
         }
+       if (!this.allowLeadingSpace) {
+           this.on('blur', this.cleanLeadingSpace, this);
+       }
+       
         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
             this.el.on("keypress", this.filterKeys, this);
         }
@@ -39148,7 +39610,15 @@ Roo.extend(Roo.form.TextField, Roo.form.Field,  {
             this.autoSize();
         }
     },
-
+    // private - clean the leading white space
+    cleanLeadingSpace : function(e)
+    {
+        if ( this.inputType == 'file') {
+            return;
+        }
+        
+        this.setValue((this.getValue() + '').replace(/^\s+/,''));
+    },
     /**
      * Resets the current field value to the originally-loaded value and clears any validation messages.
      *  
@@ -39156,9 +39626,7 @@ Roo.extend(Roo.form.TextField, Roo.form.Field,  {
     reset : function(){
         Roo.form.TextField.superclass.reset.call(this);
        
-    },
-
-    
+    }, 
     // private
     preFocus : function(){
         
@@ -39910,7 +40378,8 @@ Roo.extend(Roo.form.NumberField, Roo.form.TextField,  {
 * Create a new DateField
 * @param {Object} config
  */
-Roo.form.DateField = function(config){
+Roo.form.DateField = function(config)
+{
     Roo.form.DateField.superclass.constructor.call(this, config);
     
       this.addEvents({
@@ -40258,7 +40727,13 @@ dateField.setValue('2006-5-4');
         
         return String(this.getValue()) !== String(this.startValue);
         
+    },
+    // @overide
+    cleanLeadingSpace : function(e)
+    {
+       return;
     }
+    
 });/*
  * Based on:
  * Ext JS Library 1.1.1
@@ -40971,9 +41446,11 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
     // element that contains real text value.. (when hidden is used..)
      
     // private
-    onRender : function(ct, position){
+    onRender : function(ct, position)
+    {
         Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
-        if(this.hiddenName){
+        
+       if(this.hiddenName){
             this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id:  (this.hiddenId||this.hiddenName)},
                     'before', true);
             this.hiddenField.value =
@@ -40985,6 +41462,7 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
              
              
         }
+       
         if(Roo.isGecko){
             this.el.dom.setAttribute('autocomplete', 'off');
         }
@@ -41045,7 +41523,9 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
         }
 
         this.view = new Roo.View(this.innerList, this.tpl, {
-            singleSelect:true, store: this.store, selectedClass: this.selectedClass
+            singleSelect:true,
+           store: this.store,
+           selectedClass: this.selectedClass
         });
 
         this.view.on('click', this.onViewClick, this);
@@ -41394,6 +41874,7 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
     reset : function(){
         // overridden so that last data is reset..
         this.setValue(this.resetValue);
+        this.originalValue = this.getValue();
         this.clearInvalid();
         this.lastData = false;
         if (this.view) {
@@ -41731,7 +42212,7 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
         this.view.select(match);
         var sn = Roo.get(this.view.getSelectedNodes()[0]);
         sn.scrollIntoView(sn.dom.parentNode, false);
-    }
+    } 
 
     /** 
     * @cfg {Boolean} grow 
@@ -41845,7 +42326,10 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
      * @cfg {String} hiddenName    The hidden name of the field, often contains an comma seperated list of names
      */
     hiddenName : false,
-    
+      /**
+     * @cfg {String} seperator    The value seperator normally ',' 
+     */
+    seperator : ',',
     
     // private the array of items that are displayed..
     items  : false,
@@ -41866,7 +42350,7 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
         
         // give fake names to child combo;
         this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
-        this.combo.name = this.name? (this.name+'-subcombo') : this.name;
+        this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
         
         this.combo = Roo.factory(this.combo, Roo.form);
         this.combo.onRender(ct, position);
@@ -41987,6 +42471,7 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
     {
         var valueField = this.combo.valueField;
         var displayField = this.combo.displayField;
+       
         if (this.items.indexOfKey(rec[valueField]) > -1) {
             //console.log("GOT " + rec.data.id);
             return;
@@ -42018,9 +42503,8 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
         
         this.items.each(function(f) {
             ar.push(f.data[idField]);
-           
         });
-        this.hiddenEl.dom.value = ar.join(',');
+        this.hiddenEl.dom.value = ar.join(this.seperator);
         this.validate();
     },
     
@@ -42044,17 +42528,15 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
     },
     setValue: function(v) // not a valid action - must use addItems..
     {
-         
-        this.reset();
-        
-        
         
+        this.reset();
+         
         if (this.store.isLocal && (typeof(v) == 'string')) {
             // then we can use the store to find the values..
             // comma seperated at present.. this needs to allow JSON based encoding..
             this.hiddenEl.value  = v;
             var v_ar = [];
-            Roo.each(v.split(','), function(k) {
+            Roo.each(v.split(this.seperator), function(k) {
                 Roo.log("CHECK " + this.valueField + ',' + k);
                 var li = this.store.query(this.valueField, k);
                 if (!li.length) {
@@ -42071,7 +42553,13 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
         if (typeof(v) == 'object' ) {
             // then let's assume it's an array of objects..
             Roo.each(v, function(l) {
-                this.addItem(l);
+                var add = l;
+                if (typeof(l) == 'string') {
+                    add = {};
+                    add[this.valueField] = l;
+                    add[this.displayField] = l
+                }
+                this.addItem(add);
             }, this);
              
         }
@@ -42093,10 +42581,9 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
         dv = typeof(dv) != 'string' ? '' : dv;
         
         
-        var keys = kv.split(',');
-        var display = dv.split(',');
+        var keys = kv.split(this.seperator);
+        var display = dv.split(this.seperator);
         for (var i = 0 ; i < keys.length; i++) {
-            
             add = {};
             add[this.valueField] = keys[i];
             add[this.displayField] = display[i];
@@ -42144,7 +42631,7 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
             originalValue.push(d[i][this.valueField]);
         }
         
-        return String(this.getValue()) !== String(originalValue.join(','));
+        return String(this.getValue()) !== String(originalValue.join(this.seperator));
         
     }
     
@@ -42232,6 +42719,434 @@ Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
         }
         
     }
+});/*
+ * RooJS Library 1.1.1
+ * Copyright(c) 2008-2011  Alan Knowles
+ *
+ * License - LGPL
+ */
+
+/**
+ * @class Roo.form.ComboNested
+ * @extends Roo.form.ComboBox
+ * A combobox for that allows selection of nested items in a list,
+ * eg.
+ *
+ *  Book
+ *    -> red
+ *    -> green
+ *  Table
+ *    -> square
+ *      ->red
+ *      ->green
+ *    -> rectangle
+ *      ->green
+ *      
+ * 
+ * @constructor
+ * Create a new ComboNested
+ * @param {Object} config Configuration options
+ */
+Roo.form.ComboNested = function(config){
+    Roo.form.ComboCheck.superclass.constructor.call(this, config);
+    // should verify some data...
+    // like
+    // hiddenName = required..
+    // displayField = required
+    // valudField == required
+    var req= [ 'hiddenName', 'displayField', 'valueField' ];
+    var _t = this;
+    Roo.each(req, function(e) {
+        if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
+            throw "Roo.form.ComboNested : missing value for: " + e;
+        }
+    });
+     
+    
+};
+
+Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
+   
+    /*
+     * @config {Number} max Number of columns to show
+     */
+    
+    maxColumns : 3,
+   
+    list : null, // the outermost div..
+    innerLists : null, // the
+    views : null,
+    stores : null,
+    // private
+    loadingChildren : false,
+    
+    onRender : function(ct, position)
+    {
+        Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
+        
+        if(this.hiddenName){
+            this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id:  (this.hiddenId||this.hiddenName)},
+                    'before', true);
+            this.hiddenField.value =
+                this.hiddenValue !== undefined ? this.hiddenValue :
+                this.value !== undefined ? this.value : '';
+
+            // prevent input submission
+            this.el.dom.removeAttribute('name');
+             
+             
+        }
+       
+        if(Roo.isGecko){
+            this.el.dom.setAttribute('autocomplete', 'off');
+        }
+
+        var cls = 'x-combo-list';
+
+        this.list = new Roo.Layer({
+            shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
+        });
+
+        var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
+        this.list.setWidth(lw);
+        this.list.swallowEvent('mousewheel');
+        this.assetHeight = 0;
+
+        if(this.title){
+            this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
+            this.assetHeight += this.header.getHeight();
+        }
+        this.innerLists = [];
+        this.views = [];
+        this.stores = [];
+        for (var i =0 ; i < this.maxColumns; i++) {
+            this.onRenderList( cls, i);
+        }
+        
+        // always needs footer, as we are going to have an 'OK' button.
+        this.footer = this.list.createChild({cls:cls+'-ft'});
+        this.pageTb = new Roo.Toolbar(this.footer);  
+        var _this = this;
+        this.pageTb.add(  {
+            
+            text: 'Done',
+            handler: function()
+            {
+                _this.collapse();
+            }
+        });
+        
+        if ( this.allowBlank && !this.disableClear) {
+            
+            this.pageTb.add(new Roo.Toolbar.Fill(), {
+                cls: 'x-btn-icon x-btn-clear',
+                text: '&#160;',
+                handler: function()
+                {
+                    _this.collapse();
+                    _this.clearValue();
+                    _this.onSelect(false, -1);
+                }
+            });
+        }
+        if (this.footer) {
+            this.assetHeight += this.footer.getHeight();
+        }
+        
+    },
+    onRenderList : function (  cls, i)
+    {
+        
+        var lw = Math.floor(
+                ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
+        );
+        
+        this.list.setWidth(lw); // default to '1'
+
+        var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
+        //il.on('mouseover', this.onViewOver, this, { list:  i });
+        //il.on('mousemove', this.onViewMove, this, { list:  i });
+        il.setWidth(lw);
+        il.setStyle({ 'overflow-x' : 'hidden'});
+
+        if(!this.tpl){
+            this.tpl = new Roo.Template({
+                html :  '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
+                isEmpty: function (value, allValues) {
+                    //Roo.log(value);
+                    var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
+                    return dl ? 'has-children' : 'no-children'
+                }
+            });
+        }
+        
+        var store  = this.store;
+        if (i > 0) {
+            store  = new Roo.data.SimpleStore({
+                //fields : this.store.reader.meta.fields,
+                reader : this.store.reader,
+                data : [ ]
+            });
+        }
+        this.stores[i]  = store;
+                  
+        var view = this.views[i] = new Roo.View(
+            il,
+            this.tpl,
+            {
+                singleSelect:true,
+                store: store,
+                selectedClass: this.selectedClass
+            }
+        );
+        view.getEl().setWidth(lw);
+        view.getEl().setStyle({
+            position: i < 1 ? 'relative' : 'absolute',
+            top: 0,
+            left: (i * lw ) + 'px',
+            display : i > 0 ? 'none' : 'block'
+        });
+        view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
+        view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
+        //view.on('click', this.onViewClick, this, { list : i });
+
+        store.on('beforeload', this.onBeforeLoad, this);
+        store.on('load',  this.onLoad, this, { list  : i});
+        store.on('loadexception', this.onLoadException, this);
+
+        // hide the other vies..
+        
+        
+        
+    },
+      
+    restrictHeight : function()
+    {
+        var mh = 0;
+        Roo.each(this.innerLists, function(il,i) {
+            var el = this.views[i].getEl();
+            el.dom.style.height = '';
+            var inner = el.dom;
+            var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
+            // only adjust heights on other ones..
+            mh = Math.max(h, mh);
+            if (i < 1) {
+                
+                el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
+                il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
+               
+            }
+            
+            
+        }, this);
+        
+        this.list.beginUpdate();
+        this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
+        this.list.alignTo(this.el, this.listAlign);
+        this.list.endUpdate();
+        
+    },
+     
+    
+    // -- store handlers..
+    // private
+    onBeforeLoad : function()
+    {
+        if(!this.hasFocus){
+            return;
+        }
+        this.innerLists[0].update(this.loadingText ?
+               '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
+        this.restrictHeight();
+        this.selectedIndex = -1;
+    },
+    // private
+    onLoad : function(a,b,c,d)
+    {
+        if (!this.loadingChildren) {
+            // then we are loading the top level. - hide the children
+            for (var i = 1;i < this.views.length; i++) {
+                this.views[i].getEl().setStyle({ display : 'none' });
+            }
+            var lw = Math.floor(
+                ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
+            );
+        
+             this.list.setWidth(lw); // default to '1'
+
+            
+        }
+        if(!this.hasFocus){
+            return;
+        }
+        
+        if(this.store.getCount() > 0) {
+            this.expand();
+            this.restrictHeight();   
+        } else {
+            this.onEmptyResults();
+        }
+        
+        if (!this.loadingChildren) {
+            this.selectActive();
+        }
+        /*
+        this.stores[1].loadData([]);
+        this.stores[2].loadData([]);
+        this.views
+        */    
+    
+        //this.el.focus();
+    },
+    
+    
+    // private
+    onLoadException : function()
+    {
+        this.collapse();
+        Roo.log(this.store.reader.jsonData);
+        if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
+            Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
+        }
+        
+        
+    },
+    // no cleaning of leading spaces on blur here.
+    cleanLeadingSpace : function(e) { },
+    
+
+    onSelectChange : function (view, sels, opts )
+    {
+        var ix = view.getSelectedIndexes();
+         
+        if (opts.list > this.maxColumns - 2) {
+            if (view.store.getCount()<  1) {
+                this.views[opts.list ].getEl().setStyle({ display :   'none' });
+
+            } else  {
+                if (ix.length) {
+                    // used to clear ?? but if we are loading unselected 
+                    this.setFromData(view.store.getAt(ix[0]).data);
+                }
+                
+            }
+            
+            return;
+        }
+        
+        if (!ix.length) {
+            // this get's fired when trigger opens..
+           // this.setFromData({});
+            var str = this.stores[opts.list+1];
+            str.data.clear(); // removeall wihtout the fire events..
+            return;
+        }
+        
+        var rec = view.store.getAt(ix[0]);
+         
+        this.setFromData(rec.data);
+        this.fireEvent('select', this, rec, ix[0]);
+        
+        var lw = Math.floor(
+             (
+                (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
+             ) / this.maxColumns
+        );
+        this.loadingChildren = true;
+        this.stores[opts.list+1].loadDataFromChildren( rec );
+        this.loadingChildren = false;
+        var dl = this.stores[opts.list+1]. getTotalCount();
+        
+        this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
+        
+        this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
+        for (var i = opts.list+2; i < this.views.length;i++) {
+            this.views[i].getEl().setStyle({ display : 'none' });
+        }
+        
+        this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
+        this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
+        
+        if (this.isLoading) {
+           // this.selectActive(opts.list);
+        }
+         
+    },
+    
+    
+    
+    
+    onDoubleClick : function()
+    {
+        this.collapse(); //??
+    },
+    
+     
+    
+    
+    
+    // private
+    recordToStack : function(store, prop, value, stack)
+    {
+        var cstore = new Roo.data.SimpleStore({
+            //fields : this.store.reader.meta.fields, // we need array reader.. for
+            reader : this.store.reader,
+            data : [ ]
+        });
+        var _this = this;
+        var record  = false;
+        var srec = false;
+        if(store.getCount() < 1){
+            return false;
+        }
+        store.each(function(r){
+            if(r.data[prop] == value){
+                record = r;
+            srec = r;
+                return false;
+            }
+            if (r.data.cn && r.data.cn.length) {
+                cstore.loadDataFromChildren( r);
+                var cret = _this.recordToStack(cstore, prop, value, stack);
+                if (cret !== false) {
+                    record = cret;
+                    srec = r;
+                    return false;
+                }
+            }
+             
+            return true;
+        });
+        if (record == false) {
+            return false
+        }
+        stack.unshift(srec);
+        return record;
+    },
+    
+    /*
+     * find the stack of stores that match our value.
+     *
+     * 
+     */
+    
+    selectActive : function ()
+    {
+       // if store is not loaded, then we will need to wait for that to happen first.
+        var stack = [];
+        this.recordToStack(this.store, this.valueField, this.getValue(), stack);
+        for (var i = 0; i < stack.length; i++ ) {
+            this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
+        }
+       
+    }
+       
+        
+    
+    
+    
+    
 });/*
  * Based on:
  * Ext JS Library 1.1.1
@@ -42653,7 +43568,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
     black: false,
     white: false,
      
-    
+    bodyCls : '',
 
     /**
      * Protected method that will not generally be called directly. It
@@ -42681,19 +43596,26 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
                    '</style>';
         } else { 
-            
+            st = '<style type="text/css">' +
+                    this.stylesheets +
+                '</style>';
         }
         
         st +=  '<style type="text/css">' +
             'IMG { cursor: pointer } ' +
         '</style>';
 
+        var cls = 'roo-htmleditor-body';
+        
+        if(this.bodyCls.length){
+            cls += ' ' + this.bodyCls;
+        }
         
         return '<html><head>' + st  +
             //<style type="text/css">' +
             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
             //'</style>' +
-            ' </head><body class="roo-htmleditor-body"></body></html>';
+            ' </head><body contenteditable="true" data-enable-grammerly="true" class="' +  cls + '"></body></html>';
     },
 
     // private
@@ -42848,17 +43770,32 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             html = this.cleanHtml(html);
             // fix up the special chars.. normaly like back quotes in word...
             // however we do not want to do this with chinese..
-            html = html.replace(/([\x80-\uffff])/g, function (a, b) {
-                var cc = b.charCodeAt();
-                if (
+            html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
+                
+                var cc = match.charCodeAt();
+
+                // Get the character value, handling surrogate pairs
+                if (match.length == 2) {
+                    // It's a surrogate pair, calculate the Unicode code point
+                    var high = match.charCodeAt(0) - 0xD800;
+                    var low  = match.charCodeAt(1) - 0xDC00;
+                    cc = (high * 0x400) + low + 0x10000;
+                }  else if (
                     (cc >= 0x4E00 && cc < 0xA000 ) ||
                     (cc >= 0x3400 && cc < 0x4E00 ) ||
                     (cc >= 0xf900 && cc < 0xfb00 )
                 ) {
-                        return b;
-                }
-                return "&#"+cc+";" 
+                        return match;
+                }  
+         
+                // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
+                return "&#" + cc + ";";
+                
+                
             });
+            
+            
+             
             if(this.owner.fireEvent('beforesync', this, html) !== false){
                 this.el.dom.value = html;
                 this.owner.fireEvent('sync', this, html);
@@ -43042,7 +43979,11 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
     insertTag : function(tg)
     {
         // could be a bit smarter... -> wrap the current selected tRoo..
-        if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
+        if (tg.toLowerCase() == 'span' ||
+            tg.toLowerCase() == 'code' ||
+            tg.toLowerCase() == 'sup' ||
+            tg.toLowerCase() == 'sub' 
+            ) {
             
             range = this.createRange(this.getSelection());
             var wrappingNode = this.doc.createElement(tg.toLowerCase());
@@ -43107,8 +44048,6 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
     insertAtCursor : function(text)
     {
         
-        
-        
         if(!this.activated){
             return;
         }
@@ -43540,6 +44479,11 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         
         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
         
+        // spans with no attributes - just remove them..
+        if ((!node.attributes || !node.attributes.length) && lcname == 'span') { 
+            remove_keep_children = true;
+        }
+        
         // remove <a name=....> as rendering on yahoo mailer is borked with this.
         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
         
@@ -43560,6 +44504,10 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         }
         
         if (!node.attributes || !node.attributes.length) {
+            
+          
+            
+            
             this.cleanUpChildren(node);
             return;
         }
@@ -43570,7 +44518,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             if (v.match(/^\./) || v.match(/^\//)) {
                 return;
             }
-            if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
+            if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
                 return;
             }
             if (v.match(/^#/)) {
@@ -43656,11 +44604,11 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             
             if (a.name == 'class') {
                 if (a.value.match(/^Mso/)) {
-                    node.className = '';
+                    node.removeAttribute('class');
                 }
                 
-                if (a.value.match(/body/)) {
-                    node.className = '';
+                if (a.value.match(/^body$/)) {
+                    node.removeAttribute('class');
                 }
                 continue;
             }
@@ -43681,12 +44629,29 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
      */
     cleanWord : function(node)
     {
-        
-        
         if (!node) {
             this.cleanWord(this.doc.body);
             return;
         }
+        
+        if(
+                node.nodeName == 'SPAN' &&
+                !node.hasAttributes() &&
+                node.childNodes.length == 1 &&
+                node.firstChild.nodeName == "#text"  
+        ) {
+            var textNode = node.firstChild;
+            node.removeChild(textNode);
+            if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
+                node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
+            }
+            node.parentNode.insertBefore(textNode, node);
+            if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
+                node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
+            }
+            node.parentNode.removeChild(node);
+        }
+        
         if (node.nodeName == "#text") {
             // clean up silly Windows -- stuff?
             return; 
@@ -43701,16 +44666,20 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             node.parentNode.removeChild(node);
             return;
         }
-        
+        //Roo.log(node.tagName);
         // remove - but keep children..
-        if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
+        if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
+            //Roo.log('-- removed');
             while (node.childNodes.length) {
                 var cn = node.childNodes[0];
                 node.removeChild(cn);
                 node.parentNode.insertBefore(cn, node);
+                // move node to parent - and clean it..
+                this.cleanWord(cn);
             }
             node.parentNode.removeChild(node);
-            this.iterateChildren(node, this.cleanWord);
+            /// no need to iterate chidlren = it's got none..
+            //this.iterateChildren(node, this.cleanWord);
             return;
         }
         // clean styles
@@ -44070,6 +45039,17 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
             s.remove();
         });
+    },
+    
+    setStyle : function(style)
+    {
+        Roo.get(this.iframe.contentDocument.head).createChild({
+            tag : 'style',
+            type : 'text/css',
+            html : style
+        });
+
+        return;
     }
     
     // hide stuff that is not compatible
@@ -44939,7 +45919,8 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
         ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"], 
         ["pre"],[ "code"], 
         ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
-        ['div'],['span']
+        ['div'],['span'],
+        ['sup'],['sub']
     ],
     
     cleanStyles : [
@@ -45241,8 +46222,9 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
                     
                     var c = Roo.get(editorcore.doc.body);
                     c.select('[class]').each(function(s) {
-                        s.dom.className = '';
+                        s.dom.removeAttribute('class');
                     });
+                    editorcore.cleanWord();
                     editorcore.syncValue();
                 },
                 tabIndex:-1
@@ -46434,6 +47416,8 @@ Roo.form.BasicForm = function(el, config){
         this.initEl(el);
     }
     Roo.form.BasicForm.superclass.constructor.call(this);
+    
+    Roo.form.BasicForm.popover.apply();
 };
 
 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
@@ -46499,6 +47483,21 @@ Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
      * @type Mixed
      */
     waitMsgTarget : false,
+    
+    /**
+     * @type Boolean
+     */
+    disableMask : false,
+    
+    /**
+     * @cfg {Boolean} errorMask (true|false) default false
+     */
+    errorMask : false,
+    
+    /**
+     * @cfg {Number} maskOffset Default 100
+     */
+    maskOffset : 100,
 
     // private
     initEl : function(el){
@@ -46519,11 +47518,23 @@ Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
      */
     isValid : function(){
         var valid = true;
+        var target = false;
         this.items.each(function(f){
-           if(!f.validate()){
-               valid = false;
-           }
+            if(f.validate()){
+                return;
+            }
+            
+            valid = false;
+                
+            if(!target && f.el.isVisible(true)){
+                target = f;
+            }
         });
+        
+        if(this.errorMask && !valid){
+            Roo.form.BasicForm.popover.mask(this, target);
+        }
+        
         return valid;
     },
 
@@ -46654,15 +47665,17 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
     beforeAction : function(action){
         var o = action.options;
         
-       
-        if(this.waitMsgTarget === true){
-            this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
-        }else if(this.waitMsgTarget){
-            this.waitMsgTarget = Roo.get(this.waitMsgTarget);
-            this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
-        }else {
-            Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
+        if(!this.disableMask) {
+            if(this.waitMsgTarget === true){
+                this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
+            }else if(this.waitMsgTarget){
+                this.waitMsgTarget = Roo.get(this.waitMsgTarget);
+                this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
+            }else {
+                Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
+            }
         }
+        
          
     },
 
@@ -46671,15 +47684,17 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
         this.activeAction = null;
         var o = action.options;
         
-        if(this.waitMsgTarget === true){
-            this.el.unmask();
-        }else if(this.waitMsgTarget){
-            this.waitMsgTarget.unmask();
-        }else{
-            Roo.MessageBox.updateProgress(1);
-            Roo.MessageBox.hide();
+        if(!this.disableMask) {
+            if(this.waitMsgTarget === true){
+                this.el.unmask();
+            }else if(this.waitMsgTarget){
+                this.waitMsgTarget.unmask();
+            }else{
+                Roo.MessageBox.updateProgress(1);
+                Roo.MessageBox.hide();
+            }
         }
-         
+        
         if(success){
             if(o.reset){
                 this.reset();
@@ -46867,7 +47882,7 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
                 
         return this;
     },
-
     /**
      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
      * they are returned as an array.
@@ -46882,6 +47897,23 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
             }, this);
         }
         
+        // use formdata
+        if (typeof(FormData) != 'undefined' && asString !== true) {
+            // this relies on a 'recent' version of chrome apparently...
+            try {
+                var fd = (new FormData(this.el.dom)).entries();
+                var ret = {};
+                var ent = fd.next();
+                while (!ent.done) {
+                    ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
+                    ent = fd.next();
+                };
+                return ret;
+            } catch(e) {
+                
+            }
+            
+        }
         
         
         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
@@ -47037,7 +48069,153 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
 });
 
 // back compat
-Roo.BasicForm = Roo.form.BasicForm;/*
+Roo.BasicForm = Roo.form.BasicForm;
+
+Roo.apply(Roo.form.BasicForm, {
+    
+    popover : {
+        
+        padding : 5,
+        
+        isApplied : false,
+        
+        isMasked : false,
+        
+        form : false,
+        
+        target : false,
+        
+        intervalID : false,
+        
+        maskEl : false,
+        
+        apply : function()
+        {
+            if(this.isApplied){
+                return;
+            }
+            
+            this.maskEl = {
+                top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
+                left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
+                bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
+                right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
+            };
+            
+            this.maskEl.top.enableDisplayMode("block");
+            this.maskEl.left.enableDisplayMode("block");
+            this.maskEl.bottom.enableDisplayMode("block");
+            this.maskEl.right.enableDisplayMode("block");
+            
+            Roo.get(document.body).on('click', function(){
+                this.unmask();
+            }, this);
+            
+            Roo.get(document.body).on('touchstart', function(){
+                this.unmask();
+            }, this);
+            
+            this.isApplied = true
+        },
+        
+        mask : function(form, target)
+        {
+            this.form = form;
+            
+            this.target = target;
+            
+            if(!this.form.errorMask || !target.el){
+                return;
+            }
+            
+            var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
+            
+            var ot = this.target.el.calcOffsetsTo(scrollable);
+            
+            var scrollTo = ot[1] - this.form.maskOffset;
+            
+            scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
+            
+            scrollable.scrollTo('top', scrollTo);
+            
+            var el = this.target.wrap || this.target.el;
+            
+            var box = el.getBox();
+            
+            this.maskEl.top.setStyle('position', 'absolute');
+            this.maskEl.top.setStyle('z-index', 10000);
+            this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
+            this.maskEl.top.setLeft(0);
+            this.maskEl.top.setTop(0);
+            this.maskEl.top.show();
+            
+            this.maskEl.left.setStyle('position', 'absolute');
+            this.maskEl.left.setStyle('z-index', 10000);
+            this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
+            this.maskEl.left.setLeft(0);
+            this.maskEl.left.setTop(box.y - this.padding);
+            this.maskEl.left.show();
+
+            this.maskEl.bottom.setStyle('position', 'absolute');
+            this.maskEl.bottom.setStyle('z-index', 10000);
+            this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
+            this.maskEl.bottom.setLeft(0);
+            this.maskEl.bottom.setTop(box.bottom + this.padding);
+            this.maskEl.bottom.show();
+
+            this.maskEl.right.setStyle('position', 'absolute');
+            this.maskEl.right.setStyle('z-index', 10000);
+            this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
+            this.maskEl.right.setLeft(box.right + this.padding);
+            this.maskEl.right.setTop(box.y - this.padding);
+            this.maskEl.right.show();
+
+            this.intervalID = window.setInterval(function() {
+                Roo.form.BasicForm.popover.unmask();
+            }, 10000);
+
+            window.onwheel = function(){ return false;};
+            
+            (function(){ this.isMasked = true; }).defer(500, this);
+            
+        },
+        
+        unmask : function()
+        {
+            if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
+                return;
+            }
+            
+            this.maskEl.top.setStyle('position', 'absolute');
+            this.maskEl.top.setSize(0, 0).setXY([0, 0]);
+            this.maskEl.top.hide();
+
+            this.maskEl.left.setStyle('position', 'absolute');
+            this.maskEl.left.setSize(0, 0).setXY([0, 0]);
+            this.maskEl.left.hide();
+
+            this.maskEl.bottom.setStyle('position', 'absolute');
+            this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
+            this.maskEl.bottom.hide();
+
+            this.maskEl.right.setStyle('position', 'absolute');
+            this.maskEl.right.setSize(0, 0).setXY([0, 0]);
+            this.maskEl.right.hide();
+            
+            window.onwheel = function(){ return true;};
+            
+            if(this.intervalID){
+                window.clearInterval(this.intervalID);
+                this.intervalID = false;
+            }
+            
+            this.isMasked = false;
+            
+        }
+        
+    }
+    
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -47105,8 +48283,6 @@ Roo.form.Form = function(config){
     
     Roo.each(xitems, this.addxtype, this);
     
-    
-    
 };
 
 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
@@ -47149,7 +48325,13 @@ Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
      */
     
     progressUrl : false,
-  
+    /**
+     * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
+     * sending a formdata with extra parameters - eg uploaded elements.
+     */
+    
+    formData : false,
+    
     /**
      * 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
@@ -47705,7 +48887,8 @@ Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
                 url:this.getUrl(!isPost),
                 method: method,
                 params:isPost ? this.getParams() : null,
-                isUpload: this.form.fileUpload
+                isUpload: this.form.fileUpload,
+                formData : this.form.formData
             }));
             
             this.uploadProgress();
@@ -51422,6 +52605,12 @@ Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
          * @param {Roo.ContentPanel} panel The panel
          */
         "panelremoved" : true,
+        /**
+         * @event beforecollapse
+         * Fires when this region before collapse.
+         * @param {Roo.LayoutRegion} this
+         */
+        "beforecollapse" : true,
         /**
          * @event collapsed
          * Fires when this region is collapsed.
@@ -51973,24 +53162,29 @@ Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
      * Collapses this region.
      * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
      */
-    collapse : function(skipAnim){
+    collapse : function(skipAnim, skipCheck){
         if(this.collapsed) {
             return;
         }
-        this.collapsed = true;
-        if(this.split){
-            this.split.el.hide();
-        }
-        if(this.config.animate && skipAnim !== true){
-            this.fireEvent("invalidated", this);
-            this.animateCollapse();
-        }else{
-            this.el.setLocation(-20000,-20000);
-            this.el.hide();
-            this.collapsedEl.show();
-            this.fireEvent("collapsed", this);
-            this.fireEvent("invalidated", this);
+        
+        if(skipCheck || this.fireEvent("beforecollapse", this) != false){
+            
+            this.collapsed = true;
+            if(this.split){
+                this.split.el.hide();
+            }
+            if(this.config.animate && skipAnim !== true){
+                this.fireEvent("invalidated", this);
+                this.animateCollapse();
+            }else{
+                this.el.setLocation(-20000,-20000);
+                this.el.hide();
+                this.collapsedEl.show();
+                this.fireEvent("collapsed", this);
+                this.fireEvent("invalidated", this);
+            }
         }
+        
     },
 
     animateCollapse : function(){
@@ -53040,8 +54234,7 @@ Roo.ContentPanel = function(el, config, content){
          * @param {Roo.ContentPanel} this
          */
         "render" : true
-        
-        
+         
         
     });
     
@@ -53217,7 +54410,7 @@ panel.load({
         }
         if(this.footer){
             var te = this.footer.getEl();
-            Roo.log("footer:" + te.getHeight());
+            //Roo.log("footer:" + te.getHeight());
             
             height -= te.getHeight();
             te.setWidth(width);
@@ -54290,12 +55483,12 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
         return this;
     },
 
-       /**
-        * Reconfigures the grid to use a different Store and Column Model.
-        * The View will be bound to the new objects and refreshed.
-        * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
-        * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
-        */
+    /**
+     * Reconfigures the grid to use a different Store and Column Model.
+     * The View will be bound to the new objects and refreshed.
+     * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
+     * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
+     */
     reconfigure : function(dataSource, colModel){
         if(this.loadMask){
             this.loadMask.destroy();
@@ -54307,7 +55500,41 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
         this.colModel = colModel;
         this.view.refresh(true);
     },
-
+    /**
+     * addColumns
+     * Add's a column, default at the end..
+     
+     * @param {int} position to add (default end)
+     * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel} 
+     */
+    addColumns : function(pos, ar)
+    {
+        
+        for (var i =0;i< ar.length;i++) {
+            var cfg = ar[i];
+            cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
+            this.cm.lookup[cfg.id] = cfg;
+        }
+        
+        
+        if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
+            pos = this.cm.config.length; //this.cm.config.push(cfg);
+        } 
+        pos = Math.max(0,pos);
+        ar.unshift(0);
+        ar.unshift(pos);
+        this.cm.config.splice.apply(this.cm.config, ar);
+        
+        
+        
+        this.view.generateRules(this.cm);
+        this.view.refresh(true);
+        
+    },
+    
+    
+    
+    
     // private
     onKeyDown : function(e){
         this.fireEvent("keydown", e);
@@ -56909,7 +58136,7 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     /**
      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
      * given the cell's data value. See {@link #setRenderer}. If not specified, the
-     * default renderer uses the raw data value. If an object is returned (bootstrap only)
+     * default renderer returns the escaped data value. If an object is returned (bootstrap only)
      * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
      */
        /**
@@ -56918,6 +58145,9 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     /**
      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
      */
+    /**
+     * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc).  Defaults to undefined.
+     */
     /**
      * @cfg {String} cursor (Optional)
      */
@@ -57285,11 +58515,16 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     }
 });
 
-Roo.grid.ColumnModel.defaultRenderer = function(value){
+Roo.grid.ColumnModel.defaultRenderer = function(value)
+{
+    if(typeof value == "object") {
+        return value;
+    }
        if(typeof value == "string" && value.length < 1){
            return "&#160;";
        }
-       return value;
+    
+       return String.format("{0}", value);
 };
 
 // Alias for backwards compatibility
@@ -60022,20 +61257,18 @@ Roo.LoadMask.prototype = {
         }
         */
     
-        
-        
-        this.el.unmask(this.removeMask);
+        (function() { this.el.unmask(this.removeMask); }).defer(50, this);
     },
     // private
     onLoad : function()
     {
-        this.el.unmask(this.removeMask);
+        (function() { this.el.unmask(this.removeMask); }).defer(50, this);
     },
 
     // private
     onBeforeLoad : function(){
         if(!this.disabled){
-            this.el.mask(this.msg, this.msgCls);
+            (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
         }
     },