Roo/Template.js
[roojs1] / roojs-debug.js
index dc8df07..961dc5c 100644 (file)
@@ -68,7 +68,7 @@ Roo.apply = function(o, c, defaults){
             document.execCommand("BackgroundImageCache", false, true);
         }catch(e){}
     }
-
+    
     Roo.apply(Roo, {
         /**
          * True if the browser is in strict mode
@@ -1006,7 +1006,7 @@ Format  Output      Description
   H      15         24-hour format of an hour with leading zeros
   i      05         Minutes with leading zeros
   s      01         Seconds, with leading zeros
-  O      -0600      Difference to Greenwich time (GMT) in hours
+  O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
   T      CST        Timezone setting of the machine running the code
   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
@@ -1387,7 +1387,9 @@ Date.formatCodeToRegex = function(character, currentGroup) {
                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
             ].join(""),
-            s:"([+\-]\\d{4})"};
+            s:"([+\-]\\d{2,4})"};
+    
+    
     case "P":
        return {g:1,
                c:[
@@ -8860,7 +8862,8 @@ if(opt.anim.isAnimated()){
          * @param {String} msgCls (optional) A css class to apply to the msg element
          * @return {Element} The mask  element
          */
-        mask : function(msg, msgCls){
+        mask : function(msg, msgCls)
+        {
             if(this.getStyle("position") == "static"){
                 this.setStyle("position", "relative");
             }
@@ -8869,6 +8872,23 @@ if(opt.anim.isAnimated()){
             }
             this.addClass("x-masked");
             this._mask.setDisplayed(true);
+            
+            // we wander
+            var z = 0;
+            var dom = this.dom
+            while (dom && dom.style) {
+                if (!isNaN(parseInt(dom.style.zIndex))) {
+                    z = Math.max(z, parseInt(dom.style.zIndex));
+                }
+                dom = dom.parentNode;
+            }
+            // if we are masking the body - then it hides everything..
+            if (this.dom == document.body) {
+                z = 1000000;
+                this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
+                this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
+            }
+           
             if(typeof msg == 'string'){
                 if(!this._maskMsg){
                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
@@ -8878,10 +8898,13 @@ if(opt.anim.isAnimated()){
                 mm.dom.firstChild.innerHTML = msg;
                 mm.setDisplayed(true);
                 mm.center(this);
+                mm.setStyle('z-index', z + 102);
             }
             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
                 this._mask.setHeight(this.getHeight());
             }
+            this._mask.setStyle('z-index', z + 100);
+            
             return this._mask;
         },
 
@@ -11554,84 +11577,31 @@ Roo.Ajax = new Roo.data.Connection({
  */
  
 /**
+ * Global Ajax request class.
+ * 
  * @class Roo.Ajax
  * @extends Roo.data.Connection
- * Global Ajax request class.
- *
- * @instanceOf  Roo.data.Connection
+ * @static
+ * 
+ * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
+ * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
+ * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
+ * @cfg {String} method (Optional)  The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
+ * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
+ * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
+ * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
  */
 Roo.Ajax = new Roo.data.Connection({
     // fix up the docs
-    
     /**
-     * fix up scoping
      * @scope Roo.Ajax
-     */
-    
-   /**
-     * @cfg {String} url @hide
-     */
-    /**
-     * @cfg {Object} extraParams @hide
-     */
-    /**
-     * @cfg {Object} defaultHeaders @hide
-     */
-    /**
-     * @cfg {String} method (Optional) @hide
-     */
-    /**
-     * @cfg {Number} timeout (Optional) @hide
-     */
-    /**
-     * @cfg {Boolean} autoAbort (Optional) @hide
-     */
-
-    /**
-     * @cfg {Boolean} disableCaching (Optional) @hide
-     */
-
-    /**
-     * @property  disableCaching
-     * True to add a unique cache-buster param to GET requests. (defaults to true)
-     * @type Boolean
-     */
-    /**
-     * @property  url
-     * The default URL to be used for requests to the server. (defaults to undefined)
-     * @type String
-     */
-    /**
-     * @property  extraParams
-     * An object containing properties which are used as
-     * extra parameters to each request made by this object. (defaults to undefined)
-     * @type Object
-     */
-    /**
-     * @property  defaultHeaders
-     * An object containing request headers which are added to each request made by this object. (defaults to undefined)
-     * @type Object
-     */
-    /**
-     * @property  method
-     * The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
-     * @type String
-     */
-    /**
-     * @property  timeout
-     * The timeout in milliseconds to be used for requests. (defaults to 30000)
-     * @type Number
-     */
-
-    /**
-     * @property  autoAbort
-     * Whether a new request should abort any pending requests. (defaults to false)
-     * @type Boolean
+     * @type {Boolear} 
      */
     autoAbort : false,
 
     /**
      * Serialize the passed form into a url encoded string
+     * @scope Roo.Ajax
      * @param {String/HTMLElement} form
      * @return {String}
      */
@@ -19553,6 +19523,11 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
         }
         // if data returned failure - throw an exception.
         if (o.success === false) {
+            // show a message if no listener is registered.
+            if (!this.hasListener('loadexception') && typeof(this.reader.jsonData.errorMsg) != 'undefined') {
+                    Roo.MessageBox.alert("Error loading",this.reader.jsonData.errorMsg);
+            }
+            // loadmask wil be hooked into this..
             this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
             return;
         }
@@ -19583,6 +19558,7 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
         }
     },
 
+
     /**
      * Loads data from a passed data block. A Reader which understands the format of the data
      * must have been configured in the constructor.
@@ -19825,7 +19801,7 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
         }
         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
     },
-
+    
     // private
     afterReject : function(record){
         this.modified.remove(record);
@@ -30132,14 +30108,35 @@ Roo.MessageBox = function(){
                 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
             }
             msgEl.innerHTML = text || '&#160;';
-            var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth), 
-                        Math.max(opt.minWidth || this.minWidth, bwidth));
+      
+            var cw =  Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
+            //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
+            var w = Math.max(
+                    Math.min(opt.width || cw , this.maxWidth), 
+                    Math.max(opt.minWidth || this.minWidth, bwidth)
+            );
             if(opt.prompt){
                 activeTextEl.setWidth(w);
             }
             if(dlg.isVisible()){
                 dlg.fixedcenter = false;
             }
+            // to big, make it scroll. = But as usual stupid IE does not support
+            // !important..
+            
+            if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
+                bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
+                bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
+            } else {
+                bodyEl.dom.style.height = '';
+                bodyEl.dom.style.overflowY = '';
+            }
+            if (cw > w) {
+                bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
+            } else {
+                bodyEl.dom.style.overflowX = '';
+            }
+            
             dlg.setContentSize(w, bodyEl.getHeight());
             if(dlg.isVisible()){
                 dlg.fixedcenter = true;
@@ -30247,7 +30244,9 @@ Roo.Msg.show({
             if(this.isVisible()){
                 
                 this.hide();
-                Roo.log("Old Dialog Message:" +  msgEl.innerHTML )
+                Roo.log("[Roo.Messagebox] Show called while message displayed:" );
+                Roo.log("Old Dialog Message:" +  msgEl.innerHTML );
+                Roo.log("New Dialog Message:" +  options.msg )
                 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
                 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
                 
@@ -31838,6 +31837,20 @@ Roo.tree.TreeNode = function(attributes){
      * @type TreeNodeUI
      */
     this.ui = new uiClass(this);
+    
+    // finally support items[]
+    if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
+        return;
+    }
+    
+    
+    Roo.each(this.attributes.items, function(c) {
+        this.appendChild(Roo.factory(c,Roo.Tree));
+    }, this);
+    delete this.attributes.items;
+    
+    
+    
 };
 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
     preventHScroll: true,
@@ -31883,7 +31896,8 @@ Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
 
     // these methods are overridden to provide lazy rendering support
     // private override
-    appendChild : function(){
+    appendChild : function()
+    {
         var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
         if(node && this.childrenRendered){
             node.render();
@@ -32834,10 +32848,20 @@ Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
  * nodes from a specified URL. The response must be a javascript Array definition
  * who's elements are node definition objects. eg:
  * <pre><code>
-   [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
-    { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
+{  success : true,
+   data :      [
+   
+    { 'id': 1, 'text': 'A folder Node', 'leaf': false },
+    { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
+    ]
+}
+
+
 </code></pre>
  * <br><br>
+ * The old style respose with just an array is still supported, but not recommended.
+ * <br><br>
+ *
  * A server request is sent, and child nodes are loaded only when a node is expanded.
  * The loading node's id is passed to the server under the parameter name "node" to
  * enable the server to produce the correct child nodes.
@@ -33050,7 +33074,11 @@ Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
             
             var o = Roo.decode(json);
             
-            if (!o.success) {
+            if (this.root === false && typeof(o.success) != undefined) {
+                this.root = 'data'; // the default behaviour for list like data..
+                }
+                
+            if (this.root !== false &&  !o.success) {
                 // it's a failure condition.
                 var a = response.argument;
                 this.fireEvent("loadexception", this, a.node, response);
@@ -33058,8 +33086,10 @@ Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
                 return;
             }
             
+            
+            
             if (this.root !== false) {
-                o = o[this.root];
+                 o = o[this.root];
             }
             
             for(var i = 0, len = o.length; i < len; i++){
@@ -36900,6 +36930,7 @@ Roo.extend(Roo.form.NumberField, Roo.form.TextField,  {
     },
 
     setValue : function(v){
+        v = this.fixPrecision(v);
         Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
     },
 
@@ -36911,7 +36942,7 @@ Roo.extend(Roo.form.NumberField, Roo.form.TextField,  {
     beforeBlur : function(){
         var v = this.parseValue(this.getRawValue());
         if(v){
-            this.setValue(this.fixPrecision(v));
+            this.setValue(v);
         }
     }
 });/*
@@ -37632,7 +37663,7 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
 
         this.store.on('beforeload', this.onBeforeLoad, this);
         this.store.on('load', this.onLoad, this);
-        this.store.on('loadexception', this.collapse, this);
+        this.store.on('loadexception', this.onLoadException, this);
 
         if(this.resizable){
             this.resizer = new Roo.Resizable(this.list,  {
@@ -37752,7 +37783,7 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
         if(this.store){
             this.store.un('beforeload', this.onBeforeLoad, this);
             this.store.un('load', this.onLoad, this);
-            this.store.un('loadexception', this.collapse, this);
+            this.store.un('loadexception', this.onLoadException, this);
         }
         Roo.form.ComboBox.superclass.onDestroy.call(this);
     },
@@ -37849,7 +37880,17 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
         }
         //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);
+        }
+        
+        
+    },
     // private
     onTypeAhead : function(){
         if(this.store.getCount() > 0){
@@ -38588,7 +38629,8 @@ Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
  * @class Ext.form.HtmlEditor
  * @extends Ext.form.Field
  * Provides a lightweight HTML Editor component.
- * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
+ *
+ * This has been tested on Fireforx / Chrome.. IE may not be so great..
  * 
  * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
  * supported by this editor.</b><br/><br/>
@@ -38764,6 +38806,11 @@ Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
             
         }
         
+        st +=  '<style type="text/css">' +
+            'IMG { cursor: pointer } ' +
+        '</style>';
+
+        
         return '<html><head>' + st  +
             //<style type="text/css">' +
             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
@@ -38992,7 +39039,7 @@ Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
     syncValue : function(){
         if(this.initialized){
             var bd = (this.doc.body || this.doc.documentElement);
-            this.cleanUpPaste();
+            //this.cleanUpPaste(); -- this is done else where and causes havoc..
             var html = bd.innerHTML;
             if(Roo.isSafari){
                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
@@ -39002,6 +39049,10 @@ Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
                 }
             }
             html = this.cleanHtml(html);
+            // fix up the special chars..
+            html = html.replace(/([\x80-\uffff])/g, function (a, b) {
+                return "&#"+b.charCodeAt()+";" 
+            });
             if(this.fireEvent('beforesync', this, html) !== false){
                 this.el.dom.value = html;
                 this.fireEvent('sync', this, html);
@@ -39170,7 +39221,7 @@ Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
     onEditorEvent : function(e){
         this.fireEvent('editorevent', this, e);
       //  this.updateToolbar();
-        this.syncValue();
+        this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
     },
 
     insertTag : function(tg)
@@ -39222,17 +39273,23 @@ Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
         this.doc.execCommand(cmd, false, value === undefined ? null : value);
         this.syncValue();
     },
-
    
     /**
      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
      * to insert tRoo.
-     * @param {String} text
+     * @param {String} text | dom node.. 
      */
-    insertAtCursor : function(text){
+    insertAtCursor : function(text)
+    {
+        
+        
+        
         if(!this.activated){
             return;
         }
+        /*
         if(Roo.isIE){
             this.win.focus();
             var r = this.doc.selection.createRange();
@@ -39241,10 +39298,35 @@ Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
                 r.pasteHTML(text);
                 this.syncValue();
                 this.deferFocus();
+            
             }
-        }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
+            return;
+        }
+        */
+        if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
             this.win.focus();
-            this.execCmd('InsertHTML', text);
+            
+            
+            // from jquery ui (MIT licenced)
+            var range, node;
+            var win = this.win;
+            
+            if (win.getSelection && win.getSelection().getRangeAt) {
+                range = win.getSelection().getRangeAt(0);
+                node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
+                range.insertNode(node);
+            } else if (win.document.selection && win.document.selection.createRange) {
+                // no firefox support
+                var txt = typeof(text) == 'string' ? text : text.outerHTML;
+                win.document.selection.createRange().pasteHTML(txt);
+            } else {
+                // no firefox support
+                var txt = typeof(text) == 'string' ? text : text.outerHTML;
+                this.execCmd('InsertHTML', txt);
+            } 
+            
+            this.syncValue();
+            
             this.deferFocus();
         }
     },
@@ -39258,16 +39340,19 @@ Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
                 switch(c){
                     case 'b':
                         cmd = 'bold';
-                    break;
+                        break;
                     case 'i':
                         cmd = 'italic';
-                    break;
+                        break;
+                    
                     case 'u':
                         cmd = 'underline';
+                        break;
+                    
                     case 'v':
                         this.cleanUpPaste.defer(100, this);
                         return;
-                    break;
+                        
                 }
                 if(cmd){
                     this.win.focus();
@@ -39566,11 +39651,28 @@ Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
     cleanUpPaste :  function()
     {
         // cleans up the whole document..
-      //  console.log('cleanuppaste');
+         Roo.log('cleanuppaste');
         this.cleanUpChildren(this.doc.body);
+        var clean = this.cleanWordChars(this.doc.body.innerHTML);
+        if (clean != this.doc.body.innerHTML) {
+            this.doc.body.innerHTML = clean;
+        }
         
+    },
+    
+    cleanWordChars : function(input) {
+        var he = Roo.form.HtmlEditor;
+    
+        var output = input;
+        Roo.each(he.swapCodes, function(sw) { 
         
+            var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
+            output = output.replace(swapper, sw[1]);
+        });
+        return output;
     },
+    
+    
     cleanUpChildren : function (n)
     {
         if (!n.childNodes.length) {
@@ -39603,7 +39705,16 @@ Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
             return;
             
         }
-        if (Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1) {
+        
+        var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
+        
+        // remove <a name=....> as rendering on yahoo mailer is bored with this.
+        
+        if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
+            remove_keep_children = true;
+        }
+        
+        if (remove_keep_children) {
             this.cleanUpChildren(node);
             // inserts everything just before this node...
             while (node.childNodes.length) {
@@ -39678,10 +39789,17 @@ Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
                 cleanStyle(a.name,a.value);
             }
             /// clean up MS crap..
+            // tecnically this should be a list of valid class'es..
+            
+            
             if (a.name == 'class') {
                 if (a.value.match(/^Mso/)) {
                     node.className = '';
                 }
+                
+                if (a.value.match(/body/)) {
+                    node.className = '';
+                }
             }
             
             // style cleanup!?
@@ -39792,7 +39910,19 @@ Roo.form.HtmlEditor.cwhite= [
         'font-size'
 ];
 
-// <script type="text/javascript">
+
+Roo.form.HtmlEditor.swapCodes   =[ 
+    [    8211, "--" ], 
+    [    8212, "--" ], 
+    [    8216,  "'" ],  
+    [    8217, "'" ],  
+    [    8220, '"' ],  
+    [    8221, '"' ],  
+    [    8226, "*" ],  
+    [    8230, "..." ]
+]; 
+
+    // <script type="text/javascript">
 /*
  * Based on
  * Ext JS Library 1.1.1
@@ -40124,6 +40254,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
                     html: this.specialChars[i],
                     handler: function(a,b) {
                         editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
+                        //editor.insertAtCursor(a.html);
                         
                     },
                     tabIndex:-1
@@ -40689,13 +40820,38 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
      * Protected method that will not generally be called directly. It triggers
      * a toolbar update by reading the markup state of the current selection in the editor.
      */
-    updateToolbar: function(ignore_a,ignore_b,sel){
+    updateToolbar: function(editor,ev,sel){
 
-        
+        //Roo.log(ev);
+        // capture mouse up - this is handy for selecting images..
+        // perhaps should go somewhere else...
         if(!this.editor.activated){
              this.editor.onFirstFocus();
             return;
         }
+        
+        // http://developer.yahoo.com/yui/docs/simple-editor.js.html
+        // selectNode - might want to handle IE?
+        if (ev &&
+            (ev.type == 'mouseup' || ev.type == 'click' ) &&
+            ev.target && ev.target.tagName == 'IMG') {
+            // they have click on an image...
+            // let's see if we can change the selection...
+            sel = ev.target;
+         
+              var nodeRange = sel.ownerDocument.createRange();
+            try {
+                nodeRange.selectNode(sel);
+            } catch (e) {
+                nodeRange.selectNodeContents(sel);
+            }
+            //nodeRange.collapse(true);
+            var s = editor.win.getSelection();
+            s.removeAllRanges();
+            s.addRange(nodeRange);
+        }  
+        
+      
         var updateFooter = sel ? false : true;
         
         
@@ -40833,8 +40989,13 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
         
         tb.add(nm+ ":&nbsp;");
         
+        var styles = [];
+        for(var i in this.styles) {
+            styles.push(i);
+        }
+        
         // styles...
-        if (this.styles) {
+        if (styles && styles.length) {
             
             // this needs a multi-select checkbox...
             tb.addField( new Roo.form.ComboBox({
@@ -40856,6 +41017,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
                     'select': function(c, r, i) {
                         // initial support only for on class per el..
                         tb.selectedNode.className =  r ? r.get('val') : '';
+                        editor.syncValue();
                     }
                 }
     
@@ -41291,11 +41453,35 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
             this.fireEvent('actioncomplete', this, action);
             
         }else{
+            
+            // failure condition..
+            // we have a scenario where updates need confirming.
+            // eg. if a locking scenario exists..
+            // we look for { errors : { needs_confirm : true }} in the response.
+            if (typeof(action.result.errors.needs_confirm) != 'undefined') {
+                var _t = this;
+                Roo.MessageBox.confirm(
+                    "Change requires confirmation",
+                    action.result.errorMsg,
+                    function(r) {
+                        if (r != 'yes') {
+                            return;
+                        }
+                        _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
+                    }
+                    
+                );
+                
+                
+                
+                return;
+            }
+            
             Roo.callback(o.failure, o.scope, [this, action]);
             // show an error message if no failed handler is set..
             if (!this.hasListener('actionfailed')) {
                 Roo.MessageBox.alert("Error",
-                    typeof(action.result.errorMsg) != 'undefined' ?
+                    (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
                         action.result.errorMsg :
                         "Saving Failed, please check your entries"
                 );
@@ -42297,7 +42483,6 @@ Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
             Roo.MessageBox.hide();
         }
         
-        
         this.response = response;
         this.failureType = Roo.form.Action.CONNECT_FAILURE;
         this.form.afterAction(this, false);
@@ -43683,7 +43868,10 @@ Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
         var ar = [] ;
         
         try {
-            Roo.log(this.value);
+            //Roo.log(this.value);
+            if (typeof(this.value) == 'undefined') {
+                return [];
+            }
             var ar = Roo.decode(this.value);
             return  ar instanceof Array ? ar : []; //?? valid?
             
@@ -44698,7 +44886,7 @@ layout.addxtype({
             xitems = cfg.items;
             delete cfg.items;
         }
-        
+        var nb = false;
         
         switch(cfg.xtype) 
         {
@@ -44739,7 +44927,7 @@ layout.addxtype({
                 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
                 //console.log('adding nested layout panel '  + cfg.toSource());
                 this.add(region, ret);
-                
+                nb = {}; /// find first...
                 break;
                 
             case 'GridPanel': 
@@ -44780,10 +44968,37 @@ layout.addxtype({
         }
         this.beginUpdate();
         // add children..
+        var region = '';
+        var abn = {};
         Roo.each(xitems, function(i)  {
-            ret.addxtype(i);
+            region = nb && i.region ? i.region : false;
+            
+            var add = ret.addxtype(i);
+           
+            if (region) {
+                nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
+                if (!i.background) {
+                    abn[region] = nb[region] ;
+                }
+            }
+            
         });
         this.endUpdate();
+
+        // make the last non-background panel active..
+        //if (nb) { Roo.log(abn); }
+        if (nb) {
+            
+            for(var r in abn) {
+                region = this.getRegion(r);
+                if (region) {
+                    // tried using nb[r], but it does not work..
+                     
+                    region.showPanel(abn[r]);
+                   
+                }
+            }
+        }
         return ret;
         
     }
@@ -48300,12 +48515,7 @@ Roo.grid.GridView = function(config){
 
 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
 
-    /**
-     * Override this function to apply custom css classes to rows during rendering
-     * @param {Record} record The record
-     * @param {Number} index
-     * @method getRowClass
-     */
+    
     rowClass : "x-grid-row",
 
     cellClass : "x-grid-col",
@@ -49206,6 +49416,7 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
                 // buffers
                 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
                 var hasListener = this.grid.hasListener('rowclass');
                 var rowcfg = {};
                 for(var j = 0, len = rs.length; j < len; j++){
                     r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
@@ -49219,6 +49430,7 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
                         if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
                             p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
                         }
+                        
                         var markup = ct.apply(p);
                         if(!c.locked){
                             cb[cb.length] = markup;
@@ -51130,6 +51342,7 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
  * This class provides the basic implementation for cell selection in a grid.
  * @constructor
  * @param {Object} config The object containing the configuration of this model.
+ * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
  */
 Roo.grid.CellSelectionModel = function(config){
     Roo.apply(this, config);
@@ -51163,12 +51376,29 @@ Roo.grid.CellSelectionModel = function(config){
                <li>o.cell: An array of [rowIndex, columnIndex]</li>
                </ul>
             */
-           "selectionchange" : true
+           "selectionchange" : true,
+        /**
+            * @event tabend
+            * Fires when the tab (or enter) was pressed on the last editable cell
+            * You can use this to trigger add new row.
+            * @param {SelectionModel} this
+            */
+           "tabend" : true,
+         /**
+            * @event beforeeditnext
+            * Fires before the next editable sell is made active
+            * You can use this to skip to another cell or fire the tabend
+            *    if you set cell to false
+            * @param {Object} eventdata object : { cell : [ row, col ] } 
+            */
+           "beforeeditnext" : true
     });
     Roo.grid.CellSelectionModel.superclass.constructor.call(this);
 };
 
 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel,  {
+    
+    enter_is_tab: false,
 
     /** @ignore */
     initEvents : function(){
@@ -51297,41 +51527,52 @@ Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel,  {
         var k = e.getKey(), r = s.cell[0], c = s.cell[1];
         var newCell;
 
+      
+
         switch(k){
             case e.TAB:
                 // handled by onEditorKey
                 if (g.isEditor && g.editing) {
                     return;
                 }
-                if(e.shiftKey){
-                     newCell = walk(r, c-1, -1);
-                }else{
-                     newCell = walk(r, c+1, 1);
+                if(e.shiftKey) {
+                    newCell = walk(r, c-1, -1);
+                } else {
+                    newCell = walk(r, c+1, 1);
                 }
-             break;
-             case e.DOWN:
-                 newCell = walk(r+1, c, 1);
-             break;
-             case e.UP:
-                 newCell = walk(r-1, c, -1);
-             break;
-             case e.RIGHT:
-                 newCell = walk(r, c+1, 1);
-             break;
-             case e.LEFT:
-                 newCell = walk(r, c-1, -1);
-             break;
-             case e.ENTER:
-                 if(g.isEditor && !g.editing){
-                    g.startEditing(r, c);
-                    e.stopEvent();
-                    return;
+                break;
+            
+            case e.DOWN:
+               newCell = walk(r+1, c, 1);
+                break;
+            
+            case e.UP:
+                newCell = walk(r-1, c, -1);
+                break;
+            
+            case e.RIGHT:
+                newCell = walk(r, c+1, 1);
+                break;
+            
+            case e.LEFT:
+                newCell = walk(r, c-1, -1);
+                break;
+            
+            case e.ENTER:
+                
+                if(g.isEditor && !g.editing){
+                   g.startEditing(r, c);
+                   e.stopEvent();
+                   return;
                 }
+                
+                
              break;
         };
         if(newCell){
             this.select(newCell[0], newCell[1]);
             e.stopEvent();
+            
         }
     },
 
@@ -51350,34 +51591,50 @@ Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel,  {
      */
     onEditorKey : function(field, e){
         
-        var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
+        var k = e.getKey(),
+            newCell,
+            g = this.grid,
+            ed = g.activeEditor,
+            forward = false;
         ///Roo.log('onEditorKey' + k);
-        if (!ed) {
-            
-            
-            
+        
+        
+        if (this.enter_is_tab && k == e.ENTER) {
+            k = e.TAB;
         }
+        
         if(k == e.TAB){
             if(e.shiftKey){
                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
             }else{
                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
+                forward = true;
             }
             
             e.stopEvent();
             
-        }else if(k == e.ENTER &&  !e.ctrlKey){
+        } else if(k == e.ENTER &&  !e.ctrlKey){
             ed.completeEdit();
             e.stopEvent();
             newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
-        }else if(k == e.ESC){
+        
+               } else if(k == e.ESC){
             ed.cancelEdit();
         }
-        
-        
+               
+        if (newCell) {
+            var ecall = { cell : newCell, forward : forward };
+            this.fireEvent('beforeeditnext', ecall );
+            newCell = ecall.cell;
+                       forward = ecall.forward;
+        }
+               
         if(newCell){
             //Roo.log('next cell after edit');
             g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
+        } else if (forward) {
+            // tabbed past last
+            this.fireEvent.defer(100, this, ['tabend',this]);
         }
     }
 });/*
@@ -51934,7 +52191,7 @@ Roo.LoadMask = function(el, config){
     if(this.store){
         this.store.on('beforeload', this.onBeforeLoad, this);
         this.store.on('load', this.onLoad, this);
-        this.store.on('loadexception', this.onLoad, this);
+        this.store.on('loadexception', this.onLoadException, this);
         this.removeMask = false;
     }else{
         var um = this.el.getUpdateManager();
@@ -51982,9 +52239,17 @@ Roo.LoadMask.prototype = {
     enable : function(){
         this.disabled = false;
     },
-
+    
+    onLoadException : function()
+    {
+        if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
+            Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
+        }
+        this.el.unmask(this.removeMask);
+    },
     // private
-    onLoad : function(){
+    onLoad : function()
+    {
         this.el.unmask(this.removeMask);
     },
 
@@ -52000,7 +52265,7 @@ Roo.LoadMask.prototype = {
         if(this.store){
             this.store.un('beforeload', this.onBeforeLoad, this);
             this.store.un('load', this.onLoad, this);
-            this.store.un('loadexception', this.onLoad, this);
+            this.store.un('loadexception', this.onLoadException, this);
         }else{
             var um = this.el.getUpdateManager();
             um.un('beforeupdate', this.onBeforeLoad, this);
@@ -52202,13 +52467,7 @@ Roo.XComponent = function(cfg) {
             * Fires when this the componnt is built
             * @param {Roo.XComponent} c the component
             */
-        'built' : true,
-        /**
-            * @event buildcomplete
-            * Fires on the top level element when all elements have been built
-            * @param {Roo.XComponent} c the top level component.
-         */
-        'buildcomplete' : true
+        'built' : true
         
     });
     this.region = this.region || 'center'; // default..
@@ -52276,6 +52535,12 @@ Roo.extend(Roo.XComponent, Roo.util.Observable, {
      */
     items : false,
     
+    /**
+     * @property _tree
+     * The method that retuns the tree of parts that make up this compoennt 
+     * @type {function}
+     */
+    _tree  : false,
     
      /**
      * render
@@ -52303,7 +52568,7 @@ Roo.extend(Roo.XComponent, Roo.util.Observable, {
         
         if (!this.parent) {
             
-            el = el ? Roo.get(el) : false;
+            el = el ? Roo.get(el) : false;     
             
             // it's a top level one..
             this.parent =  {
@@ -52323,15 +52588,17 @@ Roo.extend(Roo.XComponent, Roo.util.Observable, {
             }
         }
         
-        
+               
+               // The 'tree' method is  '_tree now' 
             
-        var tree = this.tree();
+        var tree = this._tree ? this._tree() : this.tree();
         tree.region = tree.region || this.region;
         this.el = this.parent.el.addxtype(tree);
         this.fireEvent('built', this);
         
         this.panel = this.el;
-        this.layout = this.panel.layout;    
+        this.layout = this.panel.layout;
+               this.parentLayout = this.parent.layout  || false;  
          
     }
     
@@ -52392,6 +52659,25 @@ Roo.apply(Roo.XComponent, {
      * * @param {Object} details about module
      */
     register : function(obj) {
+               
+               Roo.XComponent.event.fireEvent('register', obj);
+               switch(typeof(obj.disabled) ) {
+                       
+                       case 'undefined':
+                               break;
+                       
+                       case 'function':
+                               if ( obj.disabled() ) {
+                                       return;
+                               }
+                               break;
+                       default:
+                               if (obj.disabled) {
+                                       return;
+                               }
+                               break;
+               }
+               
         this.modules.push(obj);
          
     },
@@ -52448,20 +52734,26 @@ Roo.apply(Roo.XComponent, {
             try { 
                 obj.parent = this.toObject(opar);
             } catch(e) {
-                Roo.log(e.toString());
+                Roo.log("parent:toObject failed: " + e.toString());
                 return;
             }
             
             if (!obj.parent) {
+                               Roo.debug && Roo.log("GOT top level module");
+                               Roo.debug && Roo.log(obj);
+                               obj.modules = new Roo.util.MixedCollection(false, 
+                    function(o) { return o.order + '' }
+                );
                 this.topModule = obj;
                 return;
             }
+                       // parent is a string (usually a dom element name..)
             if (typeof(obj.parent) == 'string') {
                 this.elmodules.push(obj);
                 return;
             }
             if (obj.parent.constructor != Roo.XComponent) {
-                Roo.log("Object Parent is not instance of XComponent:" + obj.name)
+                Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
             }
             if (!obj.parent.modules) {
                 obj.parent.modules = new Roo.util.MixedCollection(false, 
@@ -52490,18 +52782,25 @@ Roo.apply(Roo.XComponent, {
         
         // make a flat list in order of modules to build.
         var mods = this.topModule ? [ this.topModule ] : [];
+               
+               // elmodules (is a list of DOM based modules )
         Roo.each(this.elmodules,function(e) { mods.push(e) });
 
         
         // add modules to their parents..
         var addMod = function(m) {
-           // Roo.debug && Roo.log(m.modKey);
+                       Roo.debug && Roo.log("build Order: add: " + m.name);
             
             mods.push(m);
             if (m.modules) {
+                               Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
                 m.modules.keySort('ASC',  cmp );
+                               Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
+
                 m.modules.each(addMod);
-            }
+            } else {
+                               Roo.debug && Roo.log("build Order: no child modules");
+                       }
             // not sure if this is used any more..
             if (m.finalize) {
                 m.finalize.name = m.name + " (clean up) ";
@@ -52537,12 +52836,12 @@ Roo.apply(Roo.XComponent, {
         }
         
         
-        
+        var msg = "Building Interface...";
         // flash it up as modal - so we store the mask!?
         Roo.MessageBox.show({ title: 'loading' });
         Roo.MessageBox.show({
            title: "Please wait...",
-           msg: "Building Interface...",
+           msg: msg,
            width:450,
            progress:true,
            closable:false,
@@ -52556,9 +52855,8 @@ Roo.apply(Roo.XComponent, {
             if (!mods.length) {
                 Roo.debug && Roo.log('hide?');
                 Roo.MessageBox.hide();
-                if (_this.topModule) { 
-                    _this.topModule.fireEvent('buildcomplete', _this.topModule);
-                }
+                Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
+                
                 // THE END...
                 return false;   
             }
@@ -52574,12 +52872,11 @@ Roo.apply(Roo.XComponent, {
             } 
             
             
-            
-            Roo.MessageBox.updateProgress(
-                (total  - mods.length)/total,  "Building Interface " + (total  - mods.length) + 
+            msg = "Building Interface " + (total  - mods.length) + 
                     " of " + total + 
-                    (m.name ? (' - ' + m.name) : '')
-                    );
+                    (m.name ? (' - ' + m.name) : '');
+                       Roo.debug && Roo.log(msg);
+            Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
             
          
             // is the module disabled?
@@ -52593,6 +52890,8 @@ Roo.apply(Roo.XComponent, {
             
             // now build 
             
+                       
+                       
             m.render();
             // it's 10 on top level, and 1 on others??? why...
             return progressRun.defer(10, _this);
@@ -52602,13 +52901,49 @@ Roo.apply(Roo.XComponent, {
      
         
         
-    }
-    
-     
+    },
+       
+       
+       /**
+        * Event Object.
+        *
+        *
+        */
+       event: false, 
+    /**
+        * wrapper for event.on - aliased later..  
+        * Typically use to register a event handler for register:
+        *
+        * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
+        *
+        */
+    on : false
    
     
     
 });
+
+Roo.XComponent.event = new Roo.util.Observable({
+               events : { 
+                       /**
+                        * @event register
+                        * Fires when an Component is registered,
+                        * set the disable property on the Component to stop registration.
+                        * @param {Roo.XComponent} c the component being registerd.
+                        * 
+                        */
+                       'register' : true,
+                       /**
+                        * @event buildcomplete
+                        * Fires on the top level element when all elements have been built
+                        * @param {Roo.XComponent} the top level component.
+                        */
+                       'buildcomplete' : true
+                       
+               }
+});
+
+Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
  //<script type="text/javascript">