fix #6962 - new editor
[roojs1] / roojs-debug.js
index 79b1a4f..f903c90 100644 (file)
@@ -19,7 +19,7 @@ window["undefined"] = window["undefined"];
 /**
  * @class Roo
  * Roo core utilities and functions.
- * @singleton
+ * @static
  */
 var Roo = {}; 
 /**
@@ -668,7 +668,30 @@ Roo.factory(conf, Roo.data);
         {
             var node = Roo.DomQuery.selectNode(selector,root);
             return node ? Roo.get(node) : new Roo.Element(false);
-        }
+        },
+               /**
+                * Find the current bootstrap width Grid size
+                * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
+                * @returns {String} (xs|sm|md|lg|xl)
+                */
+               
+               getGridSize : function()
+               {
+                       var w = Roo.lib.Dom.getViewWidth();
+                       switch(true) {
+                               case w > 1200:
+                                       return 'xl';
+                               case w > 992:
+                                       return 'lg';
+                               case w > 768:
+                                       return 'md';
+                               case w > 576:
+                                       return 'sm';
+                               default:
+                                       return 'xs'
+                       }
+                       
+               } 
         
     });
 
@@ -677,9 +700,8 @@ Roo.factory(conf, Roo.data);
 
 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
-                "Roo.app", "Roo.ux",
-                "Roo.bootstrap",
-                "Roo.bootstrap.dash");
+                "Roo.app", "Roo.ux" 
+               );
 /*
  * Based on:
  * Ext JS Library 1.1.1
@@ -932,6 +954,16 @@ String.prototype.unicodeClean = function () {
     );
 };
   
+
+/**
+  * Make the first letter of a string uppercase
+  *
+  * @return {String} The new string.
+  */
+String.prototype.toUpperCaseFirst = function () {
+    return this.charAt(0).toUpperCase() + this.slice(1);
+};  
+  
 /*
  * Based on:
  * Ext JS Library 1.1.1
@@ -1023,30 +1055,50 @@ Roo.applyIf(Array.prototype, {
      */
     equals : function(b)
     {
-        // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
-       if (this === b) {
-           return true;
-        }
-       if (b == null) {
-           return false;
-       }
-       if (this.length !== b.length) {
-           return false;
-       }
-      
-       // sort?? a.sort().equals(b.sort());
+            // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
+        if (this === b) {
+            return true;
+        }
+        if (b == null) {
+            return false;
+        }
+        if (this.length !== b.length) {
+            return false;
+        }
+          
+        // sort?? a.sort().equals(b.sort());
+          
+        for (var i = 0; i < this.length; ++i) {
+            if (this[i] !== b[i]) {
+            return false;
+            }
+        }
+        return true;
+    } 
+    
+    
+    
+    
+});
+
+Roo.applyIf(Array, {
+ /**
+     * from
+     * @static
+     * @param {Array} o Or Array like object (eg. nodelist)
+     * @returns {Array} 
+     */
+    from : function(o)
+    {
+        var ret= [];
+    
+        for (var i =0; i < o.length; i++) { 
+            ret[i] = o[i];
+        }
+        return ret;
       
-       for (var i = 0; i < this.length; ++i) {
-           if (this[i] !== b[i]) {
-               return false;
-           }
-       }
-       return true;
     }
 });
-
-
 /*
  * Based on:
  * Ext JS Library 1.1.1
@@ -1350,17 +1402,17 @@ Date.createParser = function(format) {
     }
 
     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
-        + "{v = new Date(y, m, d, h, i, s);}\n"
+        + "{v = new Date(y, m, d, h, i, s); v.setFullYear(y);}\n"
         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
-        + "{v = new Date(y, m, d, h, i);}\n"
+        + "{v = new Date(y, m, d, h, i); v.setFullYear(y);}\n"
         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
-        + "{v = new Date(y, m, d, h);}\n"
+        + "{v = new Date(y, m, d, h); v.setFullYear(y);}\n"
         + "else if (y >= 0 && m >= 0 && d > 0)\n"
-        + "{v = new Date(y, m, d);}\n"
+        + "{v = new Date(y, m, d); v.setFullYear(y);}\n"
         + "else if (y >= 0 && m >= 0)\n"
-        + "{v = new Date(y, m);}\n"
+        + "{v = new Date(y, m); v.setFullYear(y);}\n"
         + "else if (y >= 0)\n"
-        + "{v = new Date(y);}\n"
+        + "{v = new Date(y); v.setFullYear(y);}\n"
         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
@@ -1420,7 +1472,7 @@ Date.formatCodeToRegex = function(character, currentGroup) {
             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
     case "m":
         return {g:1,
-            c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
+            c:"m = Math.max(0,parseInt(results[" + currentGroup + "], 10) - 1);\n",
             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
     case "t":
         return {g:0,
@@ -1855,22 +1907,13 @@ Date.prototype.add = function(interval, value){
   }
   return d;
 };
-/*
- * 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.lib.Dom
+ * @licence LGPL
  * @static
  * 
  * Dom utils (from YIU afaik)
+ *
  * 
  **/
 Roo.lib.Dom = {
@@ -1891,17 +1934,26 @@ Roo.lib.Dom = {
     getViewHeight : function(full) {
         return full ? this.getDocumentHeight() : this.getViewportHeight();
     },
-
+    /**
+     * Get the Full Document height 
+     * @return {Number} The height
+     */
     getDocumentHeight: function() {
         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
         return Math.max(scrollHeight, this.getViewportHeight());
     },
-
+    /**
+     * Get the Full Document width
+     * @return {Number} The width
+     */
     getDocumentWidth: function() {
         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
         return Math.max(scrollWidth, this.getViewportWidth());
     },
-
+    /**
+     * Get the Window Viewport height
+     * @return {Number} The height
+     */
     getViewportHeight: function() {
         var height = self.innerHeight;
         var mode = document.compatMode;
@@ -1914,7 +1966,10 @@ Roo.lib.Dom = {
 
         return height;
     },
-
+    /**
+     * Get the Window Viewport width
+     * @return {Number} The width
+     */
     getViewportWidth: function() {
         var width = self.innerWidth;
         var mode = document.compatMode;
@@ -2578,18 +2633,20 @@ Roo.lib.Event = function() {
     E._tryPreloadAttach();
 })();
 
-/*
- * Portions of this file are based on pieces of Yahoo User Interface Library
- * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
- * YUI licensed under the BSD License:
- * http://developer.yahoo.net/yui/license.txt
- * <script type="text/javascript">
- *
- */
 
 (function() {
     /**
      * @class Roo.lib.Ajax
+     *
+     * provide a simple Ajax request utility functions
+     * 
+     * Portions of this file are based on pieces of Yahoo User Interface Library
+    * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+    * YUI licensed under the BSD License:
+    * http://developer.yahoo.net/yui/license.txt
+    * <script type="text/javascript">
+    *
      *
      */
     Roo.lib.Ajax = {
@@ -2615,7 +2672,13 @@ Roo.lib.Event = function() {
 
             return this.asyncRequest(method, uri, cb, data);
         },
-
+        /**
+         * serialize a form
+         *
+         * @static
+         * @param {DomForm} form element
+         * @return {String} urlencode form output.
+         */
         serializeForm : function(form) {
             if(typeof form == 'string') {
                 form = (document.getElementById(form) || document.forms[form]);
@@ -3637,7 +3700,683 @@ Roo.lib.Bezier = new function() {
             return [ tmp[0][0], tmp[0][1] ];
 
         };
-    };/*
+    }; 
+
+/**
+ * @class Roo.lib.Color
+ * @constructor
+ * An abstract Color implementation. Concrete Color implementations should use
+ * an instance of this function as their prototype, and implement the getRGB and
+ * getHSL functions. getRGB should return an object representing the RGB
+ * components of this Color, with the red, green, and blue components in the
+ * range [0,255] and the alpha component in the range [0,100]. getHSL should
+ * return an object representing the HSL components of this Color, with the hue
+ * component in the range [0,360), the saturation and lightness components in
+ * the range [0,100], and the alpha component in the range [0,1].
+ *
+ *
+ * Color.js
+ *
+ * Functions for Color handling and processing.
+ *
+ * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
+ *
+ * The author of this program, Safalra (Stephen Morley), irrevocably releases all
+ * rights to this program, with the intention of it becoming part of the public
+ * domain. Because this program is released into the public domain, it comes with
+ * no warranty either expressed or implied, to the extent permitted by law.
+ * 
+ * For more free and public domain JavaScript code by the same author, visit:
+ * http://www.safalra.com/web-design/javascript/
+ * 
+ */
+Roo.lib.Color = function() { }
+
+
+Roo.apply(Roo.lib.Color.prototype, {
+  
+  rgb : null,
+  hsv : null,
+  hsl : null,
+  
+  /**
+   * getIntegerRGB
+   * @return {Object} an object representing the RGBA components of this Color. The red,
+   * green, and blue components are converted to integers in the range [0,255].
+   * The alpha is a value in the range [0,1].
+   */
+  getIntegerRGB : function(){
+
+    // get the RGB components of this Color
+    var rgb = this.getRGB();
+
+    // return the integer components
+    return {
+      'r' : Math.round(rgb.r),
+      'g' : Math.round(rgb.g),
+      'b' : Math.round(rgb.b),
+      'a' : rgb.a
+    };
+
+  },
+
+  /**
+   * getPercentageRGB
+   * @return {Object} an object representing the RGBA components of this Color. The red,
+   * green, and blue components are converted to numbers in the range [0,100].
+   * The alpha is a value in the range [0,1].
+   */
+  getPercentageRGB : function(){
+
+    // get the RGB components of this Color
+    var rgb = this.getRGB();
+
+    // return the percentage components
+    return {
+      'r' : 100 * rgb.r / 255,
+      'g' : 100 * rgb.g / 255,
+      'b' : 100 * rgb.b / 255,
+      'a' : rgb.a
+    };
+
+  },
+
+  /**
+   * getCSSHexadecimalRGB
+   * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
+   * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
+   * are two-digit hexadecimal numbers.
+   */
+  getCSSHexadecimalRGB : function()
+  {
+
+    // get the integer RGB components
+    var rgb = this.getIntegerRGB();
+
+    // determine the hexadecimal equivalents
+    var r16 = rgb.r.toString(16);
+    var g16 = rgb.g.toString(16);
+    var b16 = rgb.b.toString(16);
+
+    // return the CSS RGB Color value
+    return '#'
+        + (r16.length == 2 ? r16 : '0' + r16)
+        + (g16.length == 2 ? g16 : '0' + g16)
+        + (b16.length == 2 ? b16 : '0' + b16);
+
+  },
+
+  /**
+   * getCSSIntegerRGB
+   * @return {String} a string representing this Color as a CSS integer RGB Color
+   * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
+   * are integers in the range [0,255].
+   */
+  getCSSIntegerRGB : function(){
+
+    // get the integer RGB components
+    var rgb = this.getIntegerRGB();
+
+    // return the CSS RGB Color value
+    return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
+
+  },
+
+  /**
+   * getCSSIntegerRGBA
+   * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
+   * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
+   * b are integers in the range [0,255] and a is in the range [0,1].
+   */
+  getCSSIntegerRGBA : function(){
+
+    // get the integer RGB components
+    var rgb = this.getIntegerRGB();
+
+    // return the CSS integer RGBA Color value
+    return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
+
+  },
+
+  /**
+   * getCSSPercentageRGB
+   * @return {String} a string representing this Color as a CSS percentage RGB Color
+   * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
+   * b are in the range [0,100].
+   */
+  getCSSPercentageRGB : function(){
+
+    // get the percentage RGB components
+    var rgb = this.getPercentageRGB();
+
+    // return the CSS RGB Color value
+    return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
+
+  },
+
+  /**
+   * getCSSPercentageRGBA
+   * @return {String} a string representing this Color as a CSS percentage RGBA Color
+   * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
+   * and b are in the range [0,100] and a is in the range [0,1].
+   */
+  getCSSPercentageRGBA : function(){
+
+    // get the percentage RGB components
+    var rgb = this.getPercentageRGB();
+
+    // return the CSS percentage RGBA Color value
+    return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
+
+  },
+
+  /**
+   * getCSSHSL
+   * @return {String} a string representing this Color as a CSS HSL Color value - that
+   * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
+   * s and l are in the range [0,100].
+   */
+  getCSSHSL : function(){
+
+    // get the HSL components
+    var hsl = this.getHSL();
+
+    // return the CSS HSL Color value
+    return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
+
+  },
+
+  /**
+   * getCSSHSLA
+   * @return {String} a string representing this Color as a CSS HSLA Color value - that
+   * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
+   * s and l are in the range [0,100], and a is in the range [0,1].
+   */
+  getCSSHSLA : function(){
+
+    // get the HSL components
+    var hsl = this.getHSL();
+
+    // return the CSS HSL Color value
+    return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
+
+  },
+
+  /**
+   * Sets the Color of the specified node to this Color. This functions sets
+   * the CSS 'color' property for the node. The parameter is:
+   * 
+   * @param {DomElement} node - the node whose Color should be set
+   */
+  setNodeColor : function(node){
+
+    // set the Color of the node
+    node.style.color = this.getCSSHexadecimalRGB();
+
+  },
+
+  /**
+   * Sets the background Color of the specified node to this Color. This
+   * functions sets the CSS 'background-color' property for the node. The
+   * parameter is:
+   *
+   * @param {DomElement} node - the node whose background Color should be set
+   */
+  setNodeBackgroundColor : function(node){
+
+    // set the background Color of the node
+    node.style.backgroundColor = this.getCSSHexadecimalRGB();
+
+  },
+  // convert between formats..
+  toRGB: function()
+  {
+    var r = this.getIntegerRGB();
+    return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
+    
+  },
+  toHSL : function()
+  {
+     var hsl = this.getHSL();
+  // return the CSS HSL Color value
+    return new Roo.lib.HSLColor(hsl.h,  hsl.s, hsl.l ,  hsl.a );
+    
+  },
+  
+  toHSV : function()
+  {
+    var rgb = this.toRGB();
+    var hsv = rgb.getHSV();
+   // return the CSS HSL Color value
+    return new Roo.lib.HSVColor(hsv.h,  hsv.s, hsv.v ,  hsv.a );
+    
+  },
+  
+  // modify  v = 0 ... 1 (eg. 0.5)
+  saturate : function(v)
+  {
+      var rgb = this.toRGB();
+      var hsv = rgb.getHSV();
+      return new Roo.lib.HSVColor(hsv.h,  hsv.s * v, hsv.v ,  hsv.a );
+      
+  
+  },
+  
+   
+  /**
+   * getRGB
+   * @return {Object} the RGB and alpha components of this Color as an object with r,
+   * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
+   * the range [0,1].
+   */
+  getRGB: function(){
+   
+    // return the RGB components
+    return {
+      'r' : this.rgb.r,
+      'g' : this.rgb.g,
+      'b' : this.rgb.b,
+      'a' : this.alpha
+    };
+
+  },
+
+  /**
+   * getHSV
+   * @return {Object} the HSV and alpha components of this Color as an object with h,
+   * s, v, and a properties. h is in the range [0,360), s and v are in the range
+   * [0,100], and a is in the range [0,1].
+   */
+  getHSV : function()
+  {
+    
+    // calculate the HSV components if necessary
+    if (this.hsv == null) {
+      this.calculateHSV();
+    }
+
+    // return the HSV components
+    return {
+      'h' : this.hsv.h,
+      's' : this.hsv.s,
+      'v' : this.hsv.v,
+      'a' : this.alpha
+    };
+
+  },
+
+  /**
+   * getHSL
+   * @return {Object} the HSL and alpha components of this Color as an object with h,
+   * s, l, and a properties. h is in the range [0,360), s and l are in the range
+   * [0,100], and a is in the range [0,1].
+   */
+  getHSL : function(){
+    
+     
+    // calculate the HSV components if necessary
+    if (this.hsl == null) { this.calculateHSL(); }
+
+    // return the HSL components
+    return {
+      'h' : this.hsl.h,
+      's' : this.hsl.s,
+      'l' : this.hsl.l,
+      'a' : this.alpha
+    };
+
+  }
+  
+
+});
+
+
+/**
+ * @class Roo.lib.RGBColor
+ * @extends Roo.lib.Color
+ * Creates a Color specified in the RGB Color space, with an optional alpha
+ * component. The parameters are:
+ * @constructor
+ * 
+
+ * @param {Number} r - the red component, clipped to the range [0,255]
+ * @param {Number} g - the green component, clipped to the range [0,255]
+ * @param {Number} b - the blue component, clipped to the range [0,255]
+ * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
+ *     optional and defaults to 1
+ */
+Roo.lib.RGBColor = function (r, g, b, a){
+
+  // store the alpha component after clipping it if necessary
+  this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
+
+  // store the RGB components after clipping them if necessary
+  this.rgb =
+      {
+        'r' : Math.max(0, Math.min(255, r)),
+        'g' : Math.max(0, Math.min(255, g)),
+        'b' : Math.max(0, Math.min(255, b))
+      };
+
+  // initialise the HSV and HSL components to null
+  
+
+  /* 
+   * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
+   * range [0,360). The parameters are:
+   *
+   * maximum - the maximum of the RGB component values
+   * range   - the range of the RGB component values
+   */
+   
+
+}
+// this does an 'exteds'
+Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
+
+  
+    getHue  : function(maximum, range)
+    {
+      var rgb = this.rgb;
+       
+      // check whether the range is zero
+      if (range == 0){
+  
+        // set the hue to zero (any hue is acceptable as the Color is grey)
+        var hue = 0;
+  
+      }else{
+  
+        // determine which of the components has the highest value and set the hue
+        switch (maximum){
+  
+          // red has the highest value
+          case rgb.r:
+            var hue = (rgb.g - rgb.b) / range * 60;
+            if (hue < 0) { hue += 360; }
+            break;
+  
+          // green has the highest value
+          case rgb.g:
+            var hue = (rgb.b - rgb.r) / range * 60 + 120;
+            break;
+  
+          // blue has the highest value
+          case rgb.b:
+            var hue = (rgb.r - rgb.g) / range * 60 + 240;
+            break;
+  
+        }
+  
+      }
+  
+      // return the hue
+      return hue;
+  
+    },
+
+  /* //private Calculates and stores the HSV components of this RGBColor so that they can
+   * be returned be the getHSV function.
+   */
+   calculateHSV : function(){
+    var rgb = this.rgb;
+    // get the maximum and range of the RGB component values
+    var maximum = Math.max(rgb.r, rgb.g, rgb.b);
+    var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
+
+    // store the HSV components
+    this.hsv =
+        {
+          'h' : this.getHue(maximum, range),
+          's' : (maximum == 0 ? 0 : 100 * range / maximum),
+          'v' : maximum / 2.55
+        };
+
+  },
+
+  /* //private Calculates and stores the HSL components of this RGBColor so that they can
+   * be returned be the getHSL function.
+   */
+   calculateHSL : function(){
+    var rgb = this.rgb;
+    // get the maximum and range of the RGB component values
+    var maximum = Math.max(rgb.r, rgb.g, rgb.b);
+    var range   = maximum - Math.min(rgb.r, rgb.g, rgb.b);
+
+    // determine the lightness in the range [0,1]
+    var l = maximum / 255 - range / 510;
+
+    // store the HSL components
+    this.hsl =
+        {
+          'h' : this.getHue(maximum, range),
+          's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
+          'l' : 100 * l
+        };
+
+  }
+
+});
+
+/**
+ * @class Roo.lib.HSVColor
+ * @extends Roo.lib.Color
+ * Creates a Color specified in the HSV Color space, with an optional alpha
+ * component. The parameters are:
+ * @constructor
+ *
+ * @param {Number} h - the hue component, wrapped to the range [0,360)
+ * @param {Number} s - the saturation component, clipped to the range [0,100]
+ * @param {Number} v - the value component, clipped to the range [0,100]
+ * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
+ *     optional and defaults to 1
+ */
+Roo.lib.HSVColor = function (h, s, v, a){
+
+  // store the alpha component after clipping it if necessary
+  this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
+
+  // store the HSV components after clipping or wrapping them if necessary
+  this.hsv =
+      {
+        'h' : (h % 360 + 360) % 360,
+        's' : Math.max(0, Math.min(100, s)),
+        'v' : Math.max(0, Math.min(100, v))
+      };
+
+  // initialise the RGB and HSL components to null
+  this.rgb = null;
+  this.hsl = null;
+}
+
+Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
+  /* Calculates and stores the RGB components of this HSVColor so that they can
+   * be returned be the getRGB function.
+   */
+  calculateRGB: function ()
+  {
+    var hsv = this.hsv;
+    // check whether the saturation is zero
+    if (hsv.s == 0){
+
+      // set the Color to the appropriate shade of grey
+      var r = hsv.v;
+      var g = hsv.v;
+      var b = hsv.v;
+
+    }else{
+
+      // set some temporary values
+      var f  = hsv.h / 60 - Math.floor(hsv.h / 60);
+      var p  = hsv.v * (1 - hsv.s / 100);
+      var q  = hsv.v * (1 - hsv.s / 100 * f);
+      var t  = hsv.v * (1 - hsv.s / 100 * (1 - f));
+
+      // set the RGB Color components to their temporary values
+      switch (Math.floor(hsv.h / 60)){
+        case 0: var r = hsv.v; var g = t; var b = p; break;
+        case 1: var r = q; var g = hsv.v; var b = p; break;
+        case 2: var r = p; var g = hsv.v; var b = t; break;
+        case 3: var r = p; var g = q; var b = hsv.v; break;
+        case 4: var r = t; var g = p; var b = hsv.v; break;
+        case 5: var r = hsv.v; var g = p; var b = q; break;
+      }
+
+    }
+
+    // store the RGB components
+    this.rgb =
+        {
+          'r' : r * 2.55,
+          'g' : g * 2.55,
+          'b' : b * 2.55
+        };
+
+  },
+
+  /* Calculates and stores the HSL components of this HSVColor so that they can
+   * be returned be the getHSL function.
+   */
+  calculateHSL : function (){
+
+    var hsv = this.hsv;
+    // determine the lightness in the range [0,100]
+    var l = (2 - hsv.s / 100) * hsv.v / 2;
+
+    // store the HSL components
+    this.hsl =
+        {
+          'h' : hsv.h,
+          's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
+          'l' : l
+        };
+
+    // correct a division-by-zero error
+    if (isNaN(hsl.s)) { hsl.s = 0; }
+
+  } 
+
+});
+
+/**
+ * @class Roo.lib.HSLColor
+ * @extends Roo.lib.Color
+ *
+ * @constructor
+ * Creates a Color specified in the HSL Color space, with an optional alpha
+ * component. The parameters are:
+ *
+ * @param {Number} h - the hue component, wrapped to the range [0,360)
+ * @param {Number} s - the saturation component, clipped to the range [0,100]
+ * @param {Number} l - the lightness component, clipped to the range [0,100]
+ * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
+ *     optional and defaults to 1
+ */
+
+Roo.lib.HSLColor = function(h, s, l, a){
+
+  // store the alpha component after clipping it if necessary
+  this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
+
+  // store the HSL components after clipping or wrapping them if necessary
+  this.hsl =
+      {
+        'h' : (h % 360 + 360) % 360,
+        's' : Math.max(0, Math.min(100, s)),
+        'l' : Math.max(0, Math.min(100, l))
+      };
+
+  // initialise the RGB and HSV components to null
+}
+
+Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
+
+  /* Calculates and stores the RGB components of this HSLColor so that they can
+   * be returned be the getRGB function.
+   */
+  calculateRGB: function (){
+
+    // check whether the saturation is zero
+    if (this.hsl.s == 0){
+
+      // store the RGB components representing the appropriate shade of grey
+      this.rgb =
+          {
+            'r' : this.hsl.l * 2.55,
+            'g' : this.hsl.l * 2.55,
+            'b' : this.hsl.l * 2.55
+          };
+
+    }else{
+
+      // set some temporary values
+      var p = this.hsl.l < 50
+            ? this.hsl.l * (1 + hsl.s / 100)
+            : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
+      var q = 2 * hsl.l - p;
+
+      // initialise the RGB components
+      this.rgb =
+          {
+            'r' : (h + 120) / 60 % 6,
+            'g' : h / 60,
+            'b' : (h + 240) / 60 % 6
+          };
+
+      // loop over the RGB components
+      for (var key in this.rgb){
+
+        // ensure that the property is not inherited from the root object
+        if (this.rgb.hasOwnProperty(key)){
+
+          // set the component to its value in the range [0,100]
+          if (this.rgb[key] < 1){
+            this.rgb[key] = q + (p - q) * this.rgb[key];
+          }else if (this.rgb[key] < 3){
+            this.rgb[key] = p;
+          }else if (this.rgb[key] < 4){
+            this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
+          }else{
+            this.rgb[key] = q;
+          }
+
+          // set the component to its value in the range [0,255]
+          this.rgb[key] *= 2.55;
+
+        }
+
+      }
+
+    }
+
+  },
+
+  /* Calculates and stores the HSV components of this HSLColor so that they can
+   * be returned be the getHSL function.
+   */
+   calculateHSV : function(){
+
+    // set a temporary value
+    var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
+
+    // store the HSV components
+    this.hsv =
+        {
+          'h' : this.hsl.h,
+          's' : 200 * t / (this.hsl.l + t),
+          'v' : t + this.hsl.l
+        };
+
+    // correct a division-by-zero error
+    if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
+
+  }
+
+});
+/*
  * Portions of this file are based on pieces of Yahoo User Interface Library
  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
  * YUI licensed under the BSD License:
@@ -4199,7 +4938,7 @@ Roo.lib.Easing = {
  * @class Roo.DomHelper
  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
  * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
- * @singleton
+ * @static
  */
 Roo.DomHelper = function(){
     var tempTableEl = null;
@@ -4336,7 +5075,7 @@ Roo.DomHelper = function(){
     var ieTable = function(depth, s, h, e){
         tempTableEl.innerHTML = [s, h, e].join('');
         var i = -1, el = tempTableEl;
-        while(++i < depth){
+        while(++i < depth && el.firstChild){
             el = el.firstChild;
         }
         return el;
@@ -4415,212 +5154,320 @@ Roo.DomHelper = function(){
         el.insertBefore(node, before);
         return node;
     };
+    
+    // this is a bit like the react update code...
+    // 
+    
+    var updateNode = function(from, to)
+    {
+        // should we handle non-standard elements?
+        Roo.log(["UpdateNode" , from, to]);
+        if (from.nodeType != to.nodeType) {
+            Roo.log(["ReplaceChild - mismatch notType" , to, from ]);
+            from.parentNode.replaceChild(to, from);
+        }
+        
+        if (from.nodeType == 3) {
+            // assume it's text?!
+            if (from.data == to.data) {
+                return;
+            }
+            from.data = to.data;
+            return;
+        }
+        if (!from.parentNode) {
+            // not sure why this is happening?
+            return;
+        }
+        // assume 'to' doesnt have '1/3 nodetypes!
+        // not sure why, by from, parent node might not exist?
+        if (from.nodeType !=1 || from.tagName != to.tagName) {
+            Roo.log(["ReplaceChild" , from, to ]);
+            
+            from.parentNode.replaceChild(to, from);
+            return;
+        }
+        // compare attributes
+        var ar = Array.from(from.attributes);
+        for(var i = 0; i< ar.length;i++) {
+            if (to.hasAttribute(ar[i].name)) {
+                continue;
+            }
+            if (ar[i].name == 'id') { // always keep ids?
+               continue;
+            }
+            //if (ar[i].name == 'style') {
+            //   throw "style removed?";
+            //}
+            Roo.log("removeAttribute" + ar[i].name);
+            from.removeAttribute(ar[i].name);
+        }
+        ar = to.attributes;
+        for(var i = 0; i< ar.length;i++) {
+            if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
+                Roo.log("skipAttribute " + ar[i].name  + '=' + to.getAttribute(ar[i].name));
+                continue;
+            }
+            Roo.log("updateAttribute " + ar[i].name + '=>' + to.getAttribute(ar[i].name));
+            from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
+        }
+        // children
+        var far = Array.from(from.childNodes);
+        var tar = Array.from(to.childNodes);
+        // if the lengths are different.. then it's probably a editable content change, rather than
+        // a change of the block definition..
+        
+        // this did notwork , as our rebuilt nodes did not include ID's so did not match at all.
+         /*if (from.innerHTML == to.innerHTML) {
+            return;
+        }
+        if (far.length != tar.length) {
+            from.innerHTML = to.innerHTML;
+            return;
+        }
+        */
+        
+        for(var i = 0; i < Math.max(tar.length, far.length); i++) {
+            if (i >= far.length) {
+                from.appendChild(tar[i]);
+                Roo.log(["add", tar[i]]);
+                
+            } else if ( i  >= tar.length) {
+                from.removeChild(far[i]);
+                Roo.log(["remove", far[i]]);
+            } else {
+                
+                updateNode(far[i], tar[i]);
+            }    
+        }
+        
+        
+        
+        
+    };
+    
+    
 
     return {
-    /** True to force the use of DOM instead of html fragments @type Boolean */
-    useDom : false,
-
-    /**
-     * Returns the markup for the passed Element(s) config
-     * @param {Object} o The Dom object spec (and children)
-     * @return {String}
-     */
-    markup : function(o){
-        return createHtml(o);
-    },
-
-    /**
-     * Applies a style specification to an element
-     * @param {String/HTMLElement} el The element to apply styles to
-     * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
-     * a function which returns such a specification.
-     */
-    applyStyles : function(el, styles){
-        if(styles){
-           el = Roo.fly(el);
-           if(typeof styles == "string"){
-               var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
-               var matches;
-               while ((matches = re.exec(styles)) != null){
-                   el.setStyle(matches[1], matches[2]);
-               }
-           }else if (typeof styles == "object"){
-               for (var style in styles){
-                  el.setStyle(style, styles[style]);
+        /** True to force the use of DOM instead of html fragments @type Boolean */
+        useDom : false,
+    
+        /**
+         * Returns the markup for the passed Element(s) config
+         * @param {Object} o The Dom object spec (and children)
+         * @return {String}
+         */
+        markup : function(o){
+            return createHtml(o);
+        },
+    
+        /**
+         * Applies a style specification to an element
+         * @param {String/HTMLElement} el The element to apply styles to
+         * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
+         * a function which returns such a specification.
+         */
+        applyStyles : function(el, styles){
+            if(styles){
+               el = Roo.fly(el);
+               if(typeof styles == "string"){
+                   var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
+                   var matches;
+                   while ((matches = re.exec(styles)) != null){
+                       el.setStyle(matches[1], matches[2]);
+                   }
+               }else if (typeof styles == "object"){
+                   for (var style in styles){
+                      el.setStyle(style, styles[style]);
+                   }
+               }else if (typeof styles == "function"){
+                    Roo.DomHelper.applyStyles(el, styles.call());
                }
-           }else if (typeof styles == "function"){
-                Roo.DomHelper.applyStyles(el, styles.call());
-           }
-        }
-    },
-
-    /**
-     * Inserts an HTML fragment into the Dom
-     * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
-     * @param {HTMLElement} el The context element
-     * @param {String} html The HTML fragmenet
-     * @return {HTMLElement} The new node
-     */
-    insertHtml : function(where, el, html){
-        where = where.toLowerCase();
-        if(el.insertAdjacentHTML){
-            if(tableRe.test(el.tagName)){
-                var rs;
-                if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
-                    return rs;
-                }
             }
+        },
+    
+        /**
+         * Inserts an HTML fragment into the Dom
+         * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
+         * @param {HTMLElement} el The context element
+         * @param {String} html The HTML fragmenet
+         * @return {HTMLElement} The new node
+         */
+        insertHtml : function(where, el, html){
+            where = where.toLowerCase();
+            if(el.insertAdjacentHTML){
+                if(tableRe.test(el.tagName)){
+                    var rs;
+                    if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
+                        return rs;
+                    }
+                }
+                switch(where){
+                    case "beforebegin":
+                        el.insertAdjacentHTML('BeforeBegin', html);
+                        return el.previousSibling;
+                    case "afterbegin":
+                        el.insertAdjacentHTML('AfterBegin', html);
+                        return el.firstChild;
+                    case "beforeend":
+                        el.insertAdjacentHTML('BeforeEnd', html);
+                        return el.lastChild;
+                    case "afterend":
+                        el.insertAdjacentHTML('AfterEnd', html);
+                        return el.nextSibling;
+                }
+                throw 'Illegal insertion point -> "' + where + '"';
+            }
+            var range = el.ownerDocument.createRange();
+            var frag;
             switch(where){
-                case "beforebegin":
-                    el.insertAdjacentHTML('BeforeBegin', html);
+                 case "beforebegin":
+                    range.setStartBefore(el);
+                    frag = range.createContextualFragment(html);
+                    el.parentNode.insertBefore(frag, el);
                     return el.previousSibling;
-                case "afterbegin":
-                    el.insertAdjacentHTML('AfterBegin', html);
-                    return el.firstChild;
+                 case "afterbegin":
+                    if(el.firstChild){
+                        range.setStartBefore(el.firstChild);
+                        frag = range.createContextualFragment(html);
+                        el.insertBefore(frag, el.firstChild);
+                        return el.firstChild;
+                    }else{
+                        el.innerHTML = html;
+                        return el.firstChild;
+                    }
                 case "beforeend":
-                    el.insertAdjacentHTML('BeforeEnd', html);
-                    return el.lastChild;
+                    if(el.lastChild){
+                        range.setStartAfter(el.lastChild);
+                        frag = range.createContextualFragment(html);
+                        el.appendChild(frag);
+                        return el.lastChild;
+                    }else{
+                        el.innerHTML = html;
+                        return el.lastChild;
+                    }
                 case "afterend":
-                    el.insertAdjacentHTML('AfterEnd', html);
-                    return el.nextSibling;
-            }
-            throw 'Illegal insertion point -> "' + where + '"';
-        }
-        var range = el.ownerDocument.createRange();
-        var frag;
-        switch(where){
-             case "beforebegin":
-                range.setStartBefore(el);
-                frag = range.createContextualFragment(html);
-                el.parentNode.insertBefore(frag, el);
-                return el.previousSibling;
-             case "afterbegin":
-                if(el.firstChild){
-                    range.setStartBefore(el.firstChild);
+                    range.setStartAfter(el);
                     frag = range.createContextualFragment(html);
-                    el.insertBefore(frag, el.firstChild);
-                    return el.firstChild;
-                }else{
-                    el.innerHTML = html;
-                    return el.firstChild;
+                    el.parentNode.insertBefore(frag, el.nextSibling);
+                    return el.nextSibling;
                 }
-            case "beforeend":
-                if(el.lastChild){
-                    range.setStartAfter(el.lastChild);
-                    frag = range.createContextualFragment(html);
-                    el.appendChild(frag);
-                    return el.lastChild;
-                }else{
-                    el.innerHTML = html;
-                    return el.lastChild;
+                throw 'Illegal insertion point -> "' + where + '"';
+        },
+    
+        /**
+         * Creates new Dom element(s) and inserts them before el
+         * @param {String/HTMLElement/Element} el The context element
+         * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
+         * @param {Boolean} returnElement (optional) true to return a Roo.Element
+         * @return {HTMLElement/Roo.Element} The new node
+         */
+        insertBefore : function(el, o, returnElement){
+            return this.doInsert(el, o, returnElement, "beforeBegin");
+        },
+    
+        /**
+         * Creates new Dom element(s) and inserts them after el
+         * @param {String/HTMLElement/Element} el The context element
+         * @param {Object} o The Dom object spec (and children)
+         * @param {Boolean} returnElement (optional) true to return a Roo.Element
+         * @return {HTMLElement/Roo.Element} The new node
+         */
+        insertAfter : function(el, o, returnElement){
+            return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
+        },
+    
+        /**
+         * Creates new Dom element(s) and inserts them as the first child of el
+         * @param {String/HTMLElement/Element} el The context element
+         * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
+         * @param {Boolean} returnElement (optional) true to return a Roo.Element
+         * @return {HTMLElement/Roo.Element} The new node
+         */
+        insertFirst : function(el, o, returnElement){
+            return this.doInsert(el, o, returnElement, "afterBegin");
+        },
+    
+        // private
+        doInsert : function(el, o, returnElement, pos, sibling){
+            el = Roo.getDom(el);
+            var newNode;
+            if(this.useDom || o.ns){
+                newNode = createDom(o, null);
+                el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
+            }else{
+                var html = createHtml(o);
+                newNode = this.insertHtml(pos, el, html);
+            }
+            return returnElement ? Roo.get(newNode, true) : newNode;
+        },
+    
+        /**
+         * Creates new Dom element(s) and appends them to el
+         * @param {String/HTMLElement/Element} el The context element
+         * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
+         * @param {Boolean} returnElement (optional) true to return a Roo.Element
+         * @return {HTMLElement/Roo.Element} The new node
+         */
+        append : function(el, o, returnElement){
+            el = Roo.getDom(el);
+            var newNode;
+            if(this.useDom || o.ns){
+                newNode = createDom(o, null);
+                el.appendChild(newNode);
+            }else{
+                var html = createHtml(o);
+                newNode = this.insertHtml("beforeEnd", el, html);
+            }
+            return returnElement ? Roo.get(newNode, true) : newNode;
+        },
+    
+        /**
+         * Creates new Dom element(s) and overwrites the contents of el with them
+         * @param {String/HTMLElement/Element} el The context element
+         * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
+         * @param {Boolean} returnElement (optional) true to return a Roo.Element
+         * @return {HTMLElement/Roo.Element} The new node
+         */
+        overwrite : function(el, o, returnElement)
+        {
+            el = Roo.getDom(el);
+            if (o.ns) {
+              
+                while (el.childNodes.length) {
+                    el.removeChild(el.firstChild);
                 }
-            case "afterend":
-                range.setStartAfter(el);
-                frag = range.createContextualFragment(html);
-                el.parentNode.insertBefore(frag, el.nextSibling);
-                return el.nextSibling;
+                createDom(o, el);
+            } else {
+                el.innerHTML = createHtml(o);   
             }
-            throw 'Illegal insertion point -> "' + where + '"';
-    },
-
-    /**
-     * Creates new Dom element(s) and inserts them before el
-     * @param {String/HTMLElement/Element} el The context element
-     * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
-     * @param {Boolean} returnElement (optional) true to return a Roo.Element
-     * @return {HTMLElement/Roo.Element} The new node
-     */
-    insertBefore : function(el, o, returnElement){
-        return this.doInsert(el, o, returnElement, "beforeBegin");
-    },
-
-    /**
-     * Creates new Dom element(s) and inserts them after el
-     * @param {String/HTMLElement/Element} el The context element
-     * @param {Object} o The Dom object spec (and children)
-     * @param {Boolean} returnElement (optional) true to return a Roo.Element
-     * @return {HTMLElement/Roo.Element} The new node
-     */
-    insertAfter : function(el, o, returnElement){
-        return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
-    },
-
-    /**
-     * Creates new Dom element(s) and inserts them as the first child of el
-     * @param {String/HTMLElement/Element} el The context element
-     * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
-     * @param {Boolean} returnElement (optional) true to return a Roo.Element
-     * @return {HTMLElement/Roo.Element} The new node
-     */
-    insertFirst : function(el, o, returnElement){
-        return this.doInsert(el, o, returnElement, "afterBegin");
-    },
-
-    // private
-    doInsert : function(el, o, returnElement, pos, sibling){
-        el = Roo.getDom(el);
-        var newNode;
-        if(this.useDom || o.ns){
-            newNode = createDom(o, null);
-            el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
-        }else{
-            var html = createHtml(o);
-            newNode = this.insertHtml(pos, el, html);
-        }
-        return returnElement ? Roo.get(newNode, true) : newNode;
-    },
-
-    /**
-     * Creates new Dom element(s) and appends them to el
-     * @param {String/HTMLElement/Element} el The context element
-     * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
-     * @param {Boolean} returnElement (optional) true to return a Roo.Element
-     * @return {HTMLElement/Roo.Element} The new node
-     */
-    append : function(el, o, returnElement){
-        el = Roo.getDom(el);
-        var newNode;
-        if(this.useDom || o.ns){
-            newNode = createDom(o, null);
-            el.appendChild(newNode);
-        }else{
+            
+            return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
+        },
+    
+        /**
+         * Creates a new Roo.DomHelper.Template from the Dom object spec
+         * @param {Object} o The Dom object spec (and children)
+         * @return {Roo.DomHelper.Template} The new template
+         */
+        createTemplate : function(o){
             var html = createHtml(o);
-            newNode = this.insertHtml("beforeEnd", el, html);
-        }
-        return returnElement ? Roo.get(newNode, true) : newNode;
-    },
-
-    /**
-     * Creates new Dom element(s) and overwrites the contents of el with them
-     * @param {String/HTMLElement/Element} el The context element
-     * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
-     * @param {Boolean} returnElement (optional) true to return a Roo.Element
-     * @return {HTMLElement/Roo.Element} The new node
-     */
-    overwrite : function(el, o, returnElement){
-        el = Roo.getDom(el);
-        if (o.ns) {
-          
-            while (el.childNodes.length) {
-                el.removeChild(el.firstChild);
-            }
-            createDom(o, el);
-        } else {
-            el.innerHTML = createHtml(o);   
+            return new Roo.Template(html);
+        },
+         /**
+         * Updates the first element with the spec from the o (replacing if necessary)
+         * This iterates through the children, and updates attributes / children etc..
+         * @param {String/HTMLElement/Element} el The context element
+         * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
+         */
+        
+        update : function(el, o)
+        {
+            updateNode(Roo.getDom(el), createDom(o));
+            
         }
         
-        return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
-    },
-
-    /**
-     * Creates a new Roo.DomHelper.Template from the Dom object spec
-     * @param {Object} o The Dom object spec (and children)
-     * @return {Roo.DomHelper.Template} The new template
-     */
-    createTemplate : function(o){
-        var html = createHtml(o);
-        return new Roo.Template(html);
-    }
+        
     };
 }();
 /*
@@ -5011,7 +5858,7 @@ All selectors, attribute filters and pseudos below can be combined infinitely in
     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
 </ul>
- * @singleton
+ * @static
  */
 Roo.DomQuery = function(){
     var cache = {}, simpleCache = {}, valueCache = {};
@@ -5066,7 +5913,11 @@ Roo.DomQuery = function(){
         }
         var r = [], ri = -1, cn;
         for(var i = 0, ci; ci = c[i]; i++){
-            if((' '+ci.className+' ').indexOf(v) != -1){
+           
+           
+            if((' '+
+               ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
+                +' ').indexOf(v) != -1){
                 r[++ri] = ci;
             }
         }
@@ -5084,7 +5935,7 @@ Roo.DomQuery = function(){
             return n.htmlFor;
         }
         if(attr == "class" || attr == "className"){
-            return n.className;
+           return (n instanceof SVGElement) ? n.className.baseVal : n.className;
         }
         return n.getAttribute(attr) || n[attr];
 
@@ -5188,7 +6039,7 @@ Roo.DomQuery = function(){
                 a = Roo.DomQuery.getStyle(ci, attr);
             }
             else if(attr == "class" || attr == "className"){
-                a = ci.className;
+                a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
             }else if(attr == "for"){
                 a = ci.htmlFor;
             }else if(attr == "href"){
@@ -6194,7 +7045,7 @@ Roo.extend(Roo.Document, Roo.util.Observable, {});/*
  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
  * several useful events directly.
  * See {@link Roo.EventObject} for more details on normalized event objects.
- * @singleton
+ * @static
  */
 Roo.EventManager = function(){
     var docReadyEvent, docReadyProcId, docReadyState = false;
@@ -6304,7 +7155,8 @@ Roo.EventManager = function(){
     
   
 
-    var listen = function(element, ename, opt, fn, scope){
+    var listen = function(element, ename, opt, fn, scope)
+    {
         var o = (!opt || typeof opt == "boolean") ? {} : opt;
         fn = fn || o.fn; scope = scope || o.scope;
         var el = Roo.getDom(element);
@@ -6361,7 +7213,9 @@ Roo.EventManager = function(){
         
         
          
-        E.on(el, ename, h);
+        E.on(el, ename, h); // this adds the actuall listener to the object..
+        
+        
         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
             el.addEventListener("DOMMouseScroll", h, false);
             E.on(window, 'unload', function(){
@@ -6547,16 +7401,18 @@ el.on({
          * @param {Object}   scope    An object that becomes the scope of the handler
          * @param {boolean}  options
          */
-        onWindowResize : function(fn, scope, options){
+        onWindowResize : function(fn, scope, options)
+        {
             if(!resizeEvent){
                 resizeEvent = new Roo.util.Event();
                 resizeTask = new Roo.util.DelayedTask(function(){
                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
                 });
-                E.on(window, "resize", function(){
-                    if(Roo.isIE){
+                E.on(window, "resize", function()
+                {
+                    if (Roo.isIE) {
                         resizeTask.delay(50);
-                    }else{
+                    } else {
                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
                     }
                 });
@@ -6753,7 +7609,7 @@ Roo.onReady(function(){
  Roo.EventManager.on("myDiv", 'click', handleClick);
  Roo.EventManager.addListener("myDiv", 'click', handleClick);
  </code></pre>
- * @singleton
+ * @static
  */
 Roo.EventObject = function(){
     
@@ -7146,9 +8002,13 @@ if(opt.anim.isAnimated()){
  * @param {String/HTMLElement} element
  * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
  */
-    Roo.Element = function(element, forceNew){
+    Roo.Element = function(element, forceNew)
+    {
         var dom = typeof element == "string" ?
                 document.getElementById(element) : element;
+        
+        this.listeners = {};
+        
         if(!dom){ // invalid id/element
             return null;
         }
@@ -7168,6 +8028,8 @@ if(opt.anim.isAnimated()){
          * @type String
          */
         this.id = id || Roo.id(dom);
+        
+        return this; // assumed for cctor?
     };
 
     var El = Roo.Element;
@@ -7675,7 +8537,11 @@ if(opt.anim.isAnimated()){
                 }
             }else{
                 if(className && !this.hasClass(className)){
-                    this.dom.className = this.dom.className + " " + className;
+                    if (this.dom instanceof SVGElement) {
+                        this.dom.className.baseVal =this.dom.className.baseVal  + " " + className;
+                    } else {
+                        this.dom.className = this.dom.className + " " + className;
+                    }
                 }
             }
             return this;
@@ -7704,7 +8570,9 @@ if(opt.anim.isAnimated()){
          * @return {Roo.Element} this
          */
         removeClass : function(className){
-            if(!className || !this.dom.className){
+            
+            var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
+            if(!className || !cn){
                 return this;
             }
             if(className instanceof Array){
@@ -7718,8 +8586,11 @@ if(opt.anim.isAnimated()){
                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
                        this.classReCache[className] = re;
                     }
-                    this.dom.className =
-                        this.dom.className.replace(re, " ");
+                    if (this.dom instanceof SVGElement) {
+                        this.dom.className.baseVal = cn.replace(re, " ");
+                    } else {
+                        this.dom.className = cn.replace(re, " ");
+                    }
                 }
             }
             return this;
@@ -7748,6 +8619,9 @@ if(opt.anim.isAnimated()){
          * @return {Boolean} True if the class exists, else false
          */
         hasClass : function(className){
+            if (this.dom instanceof SVGElement) {
+                return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1; 
+            } 
             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
         },
 
@@ -8229,13 +9103,30 @@ if(opt.anim.isAnimated()){
          * @param {Object} scope       (optional) The scope (this object) of the fn
          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
          */
-        addListener : function(eventName, fn, scope, options){
-            if (this.dom) {
-                Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
-            }
-            if (eventName == 'dblclick') {
+        addListener : function(eventName, fn, scope, options)
+        {
+            if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
                 this.addListener('touchstart', this.onTapHandler, this);
             }
+            
+            // we need to handle a special case where dom element is a svg element.
+            // in this case we do not actua
+            if (!this.dom) {
+                return;
+            }
+            
+            if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
+                if (typeof(this.listeners[eventName]) == 'undefined') {
+                    this.listeners[eventName] =  new Roo.util.Event(this, eventName);
+                }
+                this.listeners[eventName].addListener(fn, scope, options);
+                return;
+            }
+            
+                
+            Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
+            
+            
         },
         tapedTwice : false,
         onTapHandler : function(event)
@@ -8259,15 +9150,20 @@ if(opt.anim.isAnimated()){
             //action on double tap goes below
              
         }, 
-
         /**
          * Removes an event handler from this element
          * @param {String} eventName the type of event to remove
          * @param {Function} fn the method the event invokes
+         * @param {Function} scope (needed for svg fake listeners)
          * @return {Roo.Element} this
          */
-        removeListener : function(eventName, fn){
+        removeListener : function(eventName, fn, scope){
             Roo.EventManager.removeListener(this.dom,  eventName, fn);
+            if (typeof(this.listeners) == 'undefined'  || typeof(this.listeners[eventName]) == 'undefined') {
+                return this;
+            }
+            this.listeners[eventName].removeListener(fn, scope);
             return this;
         },
 
@@ -8277,6 +9173,7 @@ if(opt.anim.isAnimated()){
          */
         removeAllListeners : function(){
             E.purgeElement(this.dom);
+            this.listeners = {};
             return this;
         },
 
@@ -8286,6 +9183,7 @@ if(opt.anim.isAnimated()){
             });
         },
 
+        
         /**
          * Set the opacity of the element
          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
@@ -9190,7 +10088,7 @@ if(opt.anim.isAnimated()){
          * Puts a mask over this element to disable user interaction. Requires core.css.
          * This method can only be applied to elements which accept child nodes.
          * @param {String} msg (optional) A message to display in the mask
-         * @param {String} msgCls (optional) A css class to apply to the msg element
+         * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
          * @return {Element} The mask  element
          */
         mask : function(msg, msgCls)
@@ -9403,7 +10301,7 @@ if(opt.anim.isAnimated()){
           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
-            return;
+            return this;
           }
           var p = Roo.get(targetParent || this.dom.parentNode);
           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
@@ -12981,7 +13879,12 @@ Roo.util.DelayedTask = function(fn, scope, args){
  * Fork - LGPL
  * <script type="text/javascript">
  */
+/**
+ * @class Roo.util.TaskRunner
+ * Manage background tasks - not sure why this is better that setInterval?
+ * @static
+ *
+ */
  
 Roo.util.TaskRunner = function(interval){
     interval = interval || 10;
@@ -13041,6 +13944,12 @@ Roo.util.TaskRunner = function(interval){
     /**
      * Queues a new task.
      * @param {Object} task
+     *
+     * Task property : interval = how frequent to run.
+     * Task object should implement
+     * function run()
+     * Task object may implement
+     * function onStop()
      */
     this.start = function(task){
         tasks.push(task);
@@ -13050,12 +13959,17 @@ Roo.util.TaskRunner = function(interval){
         startThread();
         return task;
     };
-
+    /**
+     * Stop  new task.
+     * @param {Object} task
+     */
     this.stop = function(task){
         removeTask(task);
         return task;
     };
-
+    /**
+     * Stop all Tasks
+     */
     this.stopAll = function(){
         stopThread();
         for(var i = 0, len = tasks.length; i < len; i++){
@@ -13609,7 +14523,7 @@ Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item
  * Modified version of Douglas Crockford"s json.js that doesn"t
  * mess with the Object prototype 
  * http://www.json.org/js.html
- * @singleton
+ * @static
  */
 Roo.util.JSON = new (function(){
     var useHasOwn = {}.hasOwnProperty ? true : false;
@@ -13757,7 +14671,7 @@ Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.J
 /**
  * @class Roo.util.Format
  * Reusable data formatting functions
- * @singleton
+ * @static
  */
 Roo.util.Format = function(){
     var trimRe = /^\s+|\s+$/g;
@@ -13990,7 +14904,26 @@ Roo.util.Format = function(){
          */
         stripTags : function(v){
             return !v ? v : String(v).replace(this.stripTagsRE, "");
+        },
+        
+        /**
+         * Size in Mb,Gb etc.
+         * @param {Number} value The number to be formated
+         * @param {number} decimals how many decimal places
+         * @return {String} the formated string
+         */
+        size : function(value, decimals)
+        {
+            var sizes = ['b', 'k', 'M', 'G', 'T'];
+            if (value == 0) {
+                return 0;
+            }
+            var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
+            return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals)   + sizes[i];
         }
+        
+        
+        
     };
 }();
 Roo.util.Format.defaults = {
@@ -14162,7 +15095,8 @@ Roo.MasterTemplate.from = function(el, config){
 /**
  * @class Roo.util.CSS
  * Utility class for manipulating CSS rules
- * @singleton
+ * @static
+
  */
 Roo.util.CSS = function(){
        var rules = null;
@@ -14505,7 +15439,44 @@ Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
         this.el.removeClass(this.pressClass);
         this.fireEvent("mouseup", this);
     }
-});/*
+});/**
+ * @class Roo.util.Clipboard
+ * @static
+ * 
+ * Clipboard UTILS
+ * 
+ **/
+Roo.util.Clipboard = {
+    /**
+     * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
+     * @param {String} text to copy to clipboard
+     */
+    write : function(text) {
+        // navigator clipboard api needs a secure context (https)
+        if (navigator.clipboard && window.isSecureContext) {
+            // navigator clipboard api method'
+            navigator.clipboard.writeText(text);
+            return ;
+        } 
+        // text area method
+        var ta = document.createElement("textarea");
+        ta.value = text;
+        // make the textarea out of viewport
+        ta.style.position = "fixed";
+        ta.style.left = "-999999px";
+        ta.style.top = "-999999px";
+        document.body.appendChild(ta);
+        ta.focus();
+        ta.select();
+        document.execCommand('copy');
+        (function() {
+            ta.remove();
+        }).defer(100);
+        
+    }
+        
+}
+    /*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -14898,7 +15869,7 @@ map.addBinding({
  * @class Roo.util.TextMetrics
  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
  * wide, in pixels, a given block of text will be.
- * @singleton
+ * @static
  */
 Roo.util.TextMetrics = function(){
     var shared;
@@ -14935,9 +15906,17 @@ Roo.util.TextMetrics = function(){
     };
 }();
 
+/**
+ * @class Roo.util.TextMetrics.Instance
+ * Instance of  TextMetrics Calcuation
+ * @constructor
+ * Create a new TextMetrics Instance
+ * @param {Object} bindto
+ * @param {Boolean} fixedWidth
+ */
 
-Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
+Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
+{
     var ml = new Roo.Element(document.createElement('div'));
     document.body.appendChild(ml.dom);
     ml.position('absolute');
@@ -14951,7 +15930,6 @@ Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
     var instance = {
         /**
          * Returns the size of the specified text based on the internal element's style and width properties
-         * @memberOf Roo.util.TextMetrics.Instance#
          * @param {String} text The text to measure
          * @return {Object} An object containing the text's size {width: (width), height: (height)}
          */
@@ -14965,7 +15943,6 @@ Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
         /**
          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
          * that can affect the size of the rendered text
-         * @memberOf Roo.util.TextMetrics.Instance#
          * @param {String/HTMLElement} el The element, dom node or id
          */
         bind : function(el){
@@ -14977,7 +15954,6 @@ Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
         /**
          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
          * to set a fixed width in order to accurately measure the text height.
-         * @memberOf Roo.util.TextMetrics.Instance#
          * @param {Number} width The width to set on the element
          */
         setFixedWidth : function(width){
@@ -14986,7 +15962,6 @@ Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
 
         /**
          * Returns the measured width of the specified text
-         * @memberOf Roo.util.TextMetrics.Instance#
          * @param {String} text The text to measure
          * @return {Number} width The width in pixels
          */
@@ -14998,7 +15973,6 @@ Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
         /**
          * Returns the measured height of the specified text.  For multiline text, be sure to call
          * {@link #setFixedWidth} if necessary.
-         * @memberOf Roo.util.TextMetrics.Instance#
          * @param {String} text The text to measure
          * @return {Number} height The height in pixels
          */
@@ -15179,7 +16153,7 @@ init : function(){
    var dialog = new Roo.BasicDialog(...);
    dialog.restoreState();
  </code></pre>
- * @singleton
+ * @static
  */
 Roo.state.Manager = function(){
     var provider = new Roo.state.Provider();
@@ -15337,7 +16311,7 @@ Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
 /**
  * @class Roo.ComponentMgr
  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
- * @singleton
+ * @static
  */
 Roo.ComponentMgr = function(){
     var all = new Roo.util.MixedCollection();
@@ -15828,7 +16802,7 @@ Roo.extend(Roo.Component, Roo.util.Observable, {
  * @extends Roo.Component
  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
- * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
+ * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
  * layout containers.
  * @constructor
  * @param {Roo.Element/String/Object} config The configuration options.
@@ -19863,7 +20837,7 @@ if (!Roo.dd.DragDropMgr) {
  * all DragDrop items in the window.  Generally, you will not call
  * this class directly, but it does have helper methods that could
  * be useful in your DragDrop implementations.
- * @singleton
+ * @static
  */
 Roo.dd.DragDropMgr = function() {
 
@@ -21707,7 +22681,7 @@ Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
  * @class Roo.dd.ScrollManager
  * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
  * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
- * @singleton
+ * @static
  */
 Roo.dd.ScrollManager = function(){
     var ddm = Roo.dd.DragDropMgr;
@@ -21893,7 +22867,7 @@ Roo.dd.ScrollManager = function(){
  * @class Roo.dd.Registry
  * Provides easy access to all drag drop components that are registered on a page.  Items can be retrieved either
  * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
- * @singleton
+ * @static
  */
 Roo.dd.Registry = function(){
     var elements = {}; 
@@ -23046,7 +24020,7 @@ Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
 
 /**
  * @class Roo.data.SortTypes
- * @singleton
+ * @static
  * Defines the default sorting (casting?) comparison functions used when sorting data.
  */
 Roo.data.SortTypes = {
@@ -23545,13 +24519,13 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
     */
     
     /**
-    * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
+    * @cfg {Roo.data.DataProxy} proxy [required] The Proxy object which provides access to a data object.
     */
     /**
     * @cfg {Array} data Inline data to be loaded when the store is initialized.
     */
     /**
-    * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
+    * @cfg {Roo.data.DataReader} reader [required]  The Reader object which processes the data object and returns
     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
     */
     /**
@@ -23700,6 +24674,16 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
      * <p>
      * @param {Object} options An object containing properties which control loading options:<ul>
      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
+     * <li>params.data {Object} if you are using a MemoryProxy / JsonReader, use this as the data to load stuff..
+     * <pre>
+                {
+                    data : data,  // array of key=>value data like JsonReader
+                    total : data.length,
+                    success : true
+                    
+                }
+        </pre>
+            }.</li>
      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
      * passed the following arguments:<ul>
      * <li>r : Roo.data.Record[]</li>
@@ -23746,7 +24730,8 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
     // private
     // Called as a callback by the Reader during a load operation.
     loadRecords : function(o, options, success){
-        if(!o || success === false){
+         
+        if(!o){
             if(success !== false){
                 this.fireEvent("load", this, [], options, o);
             }
@@ -24134,6 +25119,8 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
  * @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
+ * @cfg {Roo.data.DataProxy} proxy [not-required]  
+ * @cfg {Roo.data.Reader} reader  [not-required] 
  * @constructor
  * @param {Object} config
  */
@@ -24305,6 +25292,7 @@ Roo.data.Field.prototype = {
 
 /**
  * @class Roo.data.DataReader
+ * @abstract
  * Base class for reading structured data from a data source.  This class is intended to be
  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
  */
@@ -24355,7 +25343,8 @@ Roo.data.DataReader.prototype = {
 
 /**
  * @class Roo.data.DataProxy
- * @extends Roo.data.Observable
+ * @extends Roo.util.Observable
+ * @abstract
  * This class is an abstract base class for implementations which provide retrieval of
  * unformatted data objects.<br>
  * <p>
@@ -24593,8 +25582,10 @@ Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
         try {
             result = o.reader.read(response);
         }catch(e){
+            o.success = false;
+            o.raw = { errorMsg : response.responseText };
             this.fireEvent("loadexception", this, o, response, e);
-            o.request.callback.call(o.request.scope, null, o.request.arg, false);
+            o.request.callback.call(o.request.scope, o, o.request.arg, false);
             return;
         }
         
@@ -25000,19 +25991,27 @@ Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
         }
         var records = [];
         for(var i = 0; i < c; i++){
-                var n = root[i];
+            var n = root[i];
             var values = {};
             var id = this.getId(n);
             for(var j = 0; j < fl; j++){
                 f = fi[j];
-            var v = this.ef[j](n);
-            if (!f.convert) {
-                Roo.log('missing convert for ' + f.name);
-                Roo.log(f);
-                continue;
-            }
-            values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
-            }
+                               var v = this.ef[j](n);
+                               if (!f.convert) {
+                                       Roo.log('missing convert for ' + f.name);
+                                       Roo.log(f);
+                                       continue;
+                               }
+                               values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
+            }
+                       if (!Record) {
+                               return {
+                                       raw : { errorMsg : "JSON Reader Error: fields or metadata not available to create Record" },
+                                       success : false,
+                                       records : [],
+                                       totalRecords : 0
+                               };
+                       }
             var record = new Record(values, id);
             record.json = n;
             records[i] = record;
@@ -25231,35 +26230,35 @@ Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
     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;
-       }
-       return {
-           records : records,
-           totalRecords : records.length
-       };
+        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;
+        }
+        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;
-       
+        // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
+        return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
+        
     }
     
     
@@ -26089,6 +27088,7 @@ Roo.Shadow.prototype = {
      * frame: Shadow displays equally on all four sides<br />
      * drop: Traditional bottom-right drop shadow (default)
      */
+    mode: false,
     /**
      * @cfg {String} offset
      * The number of pixels to offset the shadow from the element (defaults to 4)
@@ -29402,7 +30402,7 @@ Roo.extend(Roo.Button, Roo.util.Observable, {
      */
     enableToggle: false,
     /**
-     * @cfg {Mixed} menu
+     * @cfg {Roo.menu.Menu} menu
      * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
      */
     menu : undefined,
@@ -30024,6 +31024,7 @@ Roo.MenuButton = Roo.SplitButton;/*
 
 /**
  * @class Roo.Toolbar
+ * @children   Roo.Toolbar.Item Roo.Toolbar.Button Roo.Toolbar.SplitButton Roo.form.Field 
  * Basic Toolbar class.
  * @constructor
  * Creates a new Toolbar
@@ -30065,7 +31066,7 @@ Roo.Toolbar.prototype = {
      * @cfg {Array} items
      * array of button configs or elements to add (will be converted to a MixedCollection)
      */
-    
+    items: false,
     /**
      * @cfg {String/HTMLElement/Element} container
      * The id or element that will contain the toolbar
@@ -30559,7 +31560,23 @@ Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
      
     enable:Roo.emptyFn,
     disable:Roo.emptyFn,
-    focus:Roo.emptyFn
+    focus:Roo.emptyFn,
+     /**
+     * Shows this button
+     */
+    show: function(){
+        this.hidden = false;
+        this.el.style.display = "";
+    },
+    
+    /**
+     * Hides this button
+     */
+    hide: function(){
+        this.hidden = true;
+        this.el.style.display = "none";
+    }
+    
 });
 
 /**
@@ -30573,7 +31590,10 @@ Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
 Roo.Toolbar.Button = function(config){
     Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
 };
-Roo.extend(Roo.Toolbar.Button, Roo.Button, {
+Roo.extend(Roo.Toolbar.Button, Roo.Button,
+{
+    
+    
     render : function(td){
         this.td = td;
         Roo.Toolbar.Button.superclass.render.call(this, td);
@@ -30679,6 +31699,7 @@ Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
 /**
  * @class Roo.PagingToolbar
  * @extends Roo.Toolbar
+ * @children   Roo.Toolbar.Item Roo.Toolbar.Button Roo.Toolbar.SplitButton Roo.form.Field
  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
  * @constructor
  * Create a new PagingToolbar
@@ -30714,10 +31735,7 @@ Roo.PagingToolbar = function(el, ds, config)
 };
 
 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
-    /**
-     * @cfg {Roo.data.Store} dataSource
-     * The underlying data store providing the paged data
-     */
+   
     /**
      * @cfg {String/HTMLElement/Element} container
      * container The id or element that will contain the toolbar
@@ -30726,6 +31744,8 @@ Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
      * @cfg {Boolean} displayInfo
      * True to display the displayMsg (defaults to false)
      */
+    
+    
     /**
      * @cfg {Number} pageSize
      * The number of records to display per page (defaults to 20)
@@ -30922,7 +31942,11 @@ Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
             this.loading.disable();
         }
     },
-
+    /**
+     * event that occurs when you click on the navigation buttons - can be used to trigger load of a grid.
+     * @param {String} which (first|prev|next|last|refresh)  which button to press.
+     *
+     */
     // private
     onClick : function(which){
         var ds = this.ds;
@@ -32012,6 +33036,7 @@ Roo.extend(Roo.Editor, Roo.Component, {
 /**
  * @class Roo.BasicDialog
  * @extends Roo.util.Observable
+ * @parent none builder
  * Lightweight Dialog Class.  The code below shows the creation of a typical dialog using existing HTML markup:
  * <pre><code>
 var dlg = new Roo.BasicDialog("my-dlg", {
@@ -33121,6 +34146,8 @@ Roo.DialogManager = function(){
 /**
  * @class Roo.LayoutDialog
  * @extends Roo.BasicDialog
+ * @children Roo.ContentPanel
+ * @parent builder none
  * Dialog which provides adjustments for working with a layout in a Dialog.
  * Add your necessary layout config options to the dialog's config.<br>
  * Example usage (including a nested layout):
@@ -33206,6 +34233,28 @@ Roo.LayoutDialog = function(el, cfg){
     
 };
 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
+    
+    
+    /**
+     * @cfg {Roo.LayoutRegion} east  
+     */
+    /**
+     * @cfg {Roo.LayoutRegion} west
+     */
+    /**
+     * @cfg {Roo.LayoutRegion} south
+     */
+    /**
+     * @cfg {Roo.LayoutRegion} north
+     */
+    /**
+     * @cfg {Roo.LayoutRegion} center
+     */
+    /**
+     * @cfg {Roo.Button} buttons[]  Bottom buttons..
+     */
+    
+    
     /**
      * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
      * @deprecated
@@ -33265,6 +34314,7 @@ Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
  
 /**
  * @class Roo.MessageBox
+ * @static
  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
  * Example usage:
  *<pre><code>
@@ -33287,7 +34337,7 @@ Roo.Msg.show({
    animEl: 'elId'
 });
 </code></pre>
- * @singleton
+ * @static
  */
 Roo.MessageBox = function(){
     var dlg, opt, mask, waitTimer;
@@ -33374,6 +34424,7 @@ Roo.MessageBox = function(){
                         }
                     }
                 });
+              
                 dlg.on("hide", handleHide);
                 mask = dlg.mask;
                 dlg.addKeyListener(27, handleEsc);
@@ -33617,6 +34668,7 @@ Roo.Msg.show({
                 d.animateTarget = null;
                 d.show(options.animEl);
             }
+            dlg.toFront();
             return this;
         },
 
@@ -33816,7 +34868,7 @@ Roo.Msg = Roo.MessageBox;/*
 /**
  * @class Roo.QuickTips
  * Provides attractive and customizable tooltips for any element.
- * @singleton
+ * @static
  */
 Roo.QuickTips = function(){
     var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
@@ -34218,7 +35270,7 @@ Roo.QuickTips.tips = Roo.QuickTips.register;/*
 /**
  * @class Roo.tree.TreePanel
  * @extends Roo.data.Tree
-
+ * @cfg {Roo.tree.TreeNode} root The root node
  * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
  * @cfg {Boolean} lines false to disable tree lines (defaults to true)
  * @cfg {Boolean} enableDD true to enable drag and drop
@@ -34235,8 +35287,8 @@ Roo.QuickTips.tips = Roo.QuickTips.register;/*
  * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
  * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
  * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
- * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
- * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
+ * @cfg {Roo.tree.TreeLoader} loader A TreeLoader for use with this TreePanel
+ * @cfg {Roo.tree.TreeEditor} editor The TreeEditor to display when clicked.
  * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
  * @cfg {Function} renderer DEPRECATED - use TreeLoader:create event / Sets the rendering (formatting) function for the nodes. to return HTML markup for the tree view. The render function is called with  the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
  * @cfg {Function} rendererTip DEPRECATED - use TreeLoader:create event / Sets the rendering (formatting) function for the nodes hovertip to return HTML markup for the tree view. The render function is called with  the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
@@ -36981,7 +38033,7 @@ Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
  * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
  * 
  * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
- * @cfg {Roo.form.TextField|Object} field The field configuration
+ * @cfg {Roo.form.TextField} field [required] The field configuration
  *
  * 
  */
@@ -37287,7 +38339,7 @@ Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
 
 /**
  * @class Roo.tree.ColumnTree
- * @extends Roo.data.TreePanel
+ * @extends Roo.tree.TreePanel
  * @cfg {Object} columns  Including width, header, renderer, cls, dataIndex 
  * @cfg {int} borderWidth  compined right/left border allowance
  * @constructor
@@ -37398,6 +38450,7 @@ Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
 /**
  * @class Roo.menu.Menu
  * @extends Roo.util.Observable
+ * @children Roo.menu.Item Roo.menu.Separator Roo.menu.TextItem
  * A menu object.  This is the container to which you add all other menu items.  Menu can also serve a as a base class
  * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
  * @constructor
@@ -37967,7 +39020,7 @@ Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
 /**
  * @class Roo.menu.MenuMgr
  * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
- * @singleton
+ * @static
  */
 Roo.menu.MenuMgr = function(){
    var menus, active, groups = {}, attached = false, lastShow = new Date();
@@ -38155,6 +39208,7 @@ Roo.menu.MenuMgr = function(){
 /**
  * @class Roo.menu.BaseItem
  * @extends Roo.Component
+ * @abstract
  * The base class for all items that render into menus.  BaseItem provides default rendering, activated state
  * management and base configuration options shared by all menu components.
  * @constructor
@@ -38301,6 +39355,7 @@ Roo.extend(Roo.menu.BaseItem, Roo.Component, {
 /**
  * @class Roo.menu.Adapter
  * @extends Roo.menu.BaseItem
+ * @abstract
  * A base utility class that adapts a non-menu component so that it can be wrapped by a menu item and added to a menu.
  * It provides basic rendering, activation management and enable/disable logic required to work in menus.
  * @constructor
@@ -38380,7 +39435,7 @@ Roo.menu.TextItem = function(cfg){
 
 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
     /**
-     * @cfg {Boolean} text Text to show on item.
+     * @cfg {String} text Text to show on item.
      */
     text : '',
     
@@ -38470,14 +39525,17 @@ Roo.menu.Item = function(config){
     }
 };
 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
-    
+    /**
+     * @cfg {Roo.menu.Menu} menu
+     * A Sub menu
+     */
     /**
      * @cfg {String} text
      * The text to show on the menu item.
      */
     text: '',
      /**
-     * @cfg {String} HTML to render in menu
+     * @cfg {String} html to render in menu
      * The text to show on the menu item (HTML version).
      */
     html: '',
@@ -40550,6 +41608,16 @@ Roo.extend(Roo.form.DateField, Roo.form.TriggerField,  {
      * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
      */
     disabledDatesText : "Disabled",
+       
+       
+       /**
+     * @cfg {Date/String} zeroValue
+     * if the date is less that this number, then the field is rendered as empty
+     * default is 1800
+     */
+       zeroValue : '1800-01-01',
+       
+       
     /**
      * @cfg {Date/String} minValue
      * The minimum allowed date. Can be either a Javascript date object or a string date in a
@@ -40726,6 +41794,15 @@ dateField.setValue('2006-5-4');
 
     // private
     parseDate : function(value){
+               
+               if (value instanceof Date) {
+                       if (value < Date.parseDate(this.zeroValue, 'Y-m-d') ) {
+                               return  '';
+                       }
+                       return value;
+               }
+               
+               
         if(!value || value instanceof Date){
             return value;
         }
@@ -40741,6 +41818,9 @@ dateField.setValue('2006-5-4');
                 v = Date.parseDate(value, this.altFormatsArray[i]);
             }
         }
+               if (v < Date.parseDate(this.zeroValue, 'Y-m-d') ) {
+                       v = '';
+               }
         return v;
     },
 
@@ -42396,7 +43476,7 @@ Roo.form.ComboBoxArray = function(config)
 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
 { 
     /**
-     * @cfg {Roo.form.Combo} combo The combo box that is wrapped
+     * @cfg {Roo.form.ComboBox} combo [required] The combo box that is wrapped
      */
     
     lastData : false,
@@ -43598,7 +44678,8 @@ Roo.HtmlEditorCore = function(config){
          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
          * @param {Roo.HtmlEditorCore} this
          */
-        editorevent: true
+        editorevent: true 
+         
         
     });
     
@@ -43634,13 +44715,32 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
      * @cfg {Number} width (in pixels)
      */   
     width: 500,
+     /**
+     * @cfg {boolean} autoClean - default true - loading and saving will remove quite a bit of formating,
+     *         if you are doing an email editor, this probably needs disabling, it's designed
+     */
+    autoClean: true,
     
+    /**
+     * @cfg {boolean} enableBlocks - default true - if the block editor (table and figure should be enabled)
+     */
+    enableBlocks : true,
     /**
      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
      * 
      */
     stylesheets: false,
+     /**
+     * @cfg {String} language default en - language of text (usefull for rtl languages)
+     * 
+     */
+    language: 'en',
     
+    /**
+     * @cfg {boolean} allowComments - default false - allow comments in HTML source
+     *          - by default they are stripped - if you are editing email you may need this.
+     */
+    allowComments: false,
     // id of frame..
     frameId: false,
     
@@ -43662,6 +44762,8 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
      
     bodyCls : '',
 
+    
+    undoManager : false,
     /**
      * Protected method that will not generally be called directly. It
      * is called when the editor initializes the iframe with HTML contents. Override this method if you
@@ -43688,7 +44790,10 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
                    '</style>';
         } else {
-            for (var i in this.stylesheets) { 
+            for (var i in this.stylesheets) {
+                if (typeof(this.stylesheets[i]) != 'string') {
+                    continue;
+                }
                 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
             }
             
@@ -43697,14 +44802,16 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         st +=  '<style type="text/css">' +
             'IMG { cursor: pointer } ' +
         '</style>';
-
-        var cls = 'roo-htmleditor-body';
+        
+        st += '<meta name="google" content="notranslate">';
+        
+        var cls = 'notranslate roo-htmleditor-body';
         
         if(this.bodyCls.length){
             cls += ' ' + this.bodyCls;
         }
         
-        return '<html><head>' + st  +
+        return '<html  class="notranslate" translate="no"><head>' + st  +
             //<style type="text/css">' +
             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
             //'</style>' +
@@ -43747,7 +44854,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         
         this.iframe = iframe.dom;
 
-         this.assignDocWin();
+        this.assignDocWin();
         
         this.doc.designMode = 'on';
        
@@ -43763,6 +44870,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                 if(this.doc.body || this.doc.readyState == 'complete'){
                     try {
                         this.doc.designMode="on";
+                        
                     } catch (e) {
                         return;
                     }
@@ -43810,10 +44918,10 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         
         if(this.sourceEditMode){
  
-            Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
+            Roo.get(this.iframe).addClass(['x-hidden','hide', 'd-none']);     //FIXME - what's the BS styles for these
             
         }else{
-            Roo.get(this.iframe).removeClass(['x-hidden','hide']);
+            Roo.get(this.iframe).removeClass(['x-hidden','hide', 'd-none']);
             //this.iframe.className = '';
             this.deferFocus();
         }
@@ -43830,7 +44938,8 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
      * @param {String} html The HTML to be cleaned
      * return {String} The cleaned HTML
      */
-    cleanHtml : function(html){
+    cleanHtml : function(html)
+    {
         html = String(html);
         if(html.length > 5){
             if(Roo.isSafari){ // strip safari nonsense
@@ -43848,11 +44957,38 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
      * Protected method that will not generally be called directly. Syncs the contents
      * of the editor iframe with the textarea.
      */
-    syncValue : function(){
+    syncValue : function()
+    {
+        //Roo.log("HtmlEditorCore:syncValue (EDITOR->TEXT)");
         if(this.initialized){
+            
+            this.undoManager.addEvent();
+
+            
             var bd = (this.doc.body || this.doc.documentElement);
-            //this.cleanUpPaste(); -- this is done else where and causes havoc..
-            var html = bd.innerHTML;
+           
+            
+            var sel = this.win.getSelection();
+            
+            var div = document.createElement('div');
+            div.innerHTML = bd.innerHTML;
+            var gtx = div.getElementsByClassName('gtx-trans-icon'); // google translate - really annoying and difficult to get rid of.
+            if (gtx.length > 0) {
+                var rm = gtx.item(0).parentNode;
+                rm.parentNode.removeChild(rm);
+            }
+            
+           
+            if (this.enableBlocks) {
+                new Roo.htmleditor.FilterBlock({ node : div });
+            }
+            //?? tidy?
+            var tidy = new Roo.htmleditor.TidySerializer({
+                inner:  true
+            });
+            var html  = tidy.serialize(div);
+            
+            
             if(Roo.isSafari){
                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
@@ -43897,24 +45033,41 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
     },
 
     /**
+     * TEXTAREA -> EDITABLE
      * Protected method that will not generally be called directly. Pushes the value of the textarea
      * into the iframe editor.
      */
-    pushValue : function(){
+    pushValue : function()
+    {
+        //Roo.log("HtmlEditorCore:pushValue (TEXT->EDITOR)");
         if(this.initialized){
             var v = this.el.dom.value.trim();
             
-//            if(v.length < 1){
-//                v = '&#160;';
-//            }
             
             if(this.owner.fireEvent('beforepush', this, v) !== false){
                 var d = (this.doc.body || this.doc.documentElement);
                 d.innerHTML = v;
-                this.cleanUpPaste();
+                 
                 this.el.dom.value = d.innerHTML;
                 this.owner.fireEvent('push', this, v);
             }
+            if (this.autoClean) {
+                new Roo.htmleditor.FilterParagraph({node : this.doc.body}); // paragraphs
+                new Roo.htmleditor.FilterSpan({node : this.doc.body}); // empty spans
+            }
+            if (this.enableBlocks) {
+                Roo.htmleditor.Block.initAll(this.doc.body);
+            }
+            
+            this.updateLanguage();
+            
+            var lc = this.doc.body.lastChild;
+            if (lc && lc.nodeType == 1 && lc.getAttribute("contenteditable") == "false") {
+                // add an extra line at the end.
+                this.doc.body.appendChild(this.doc.createElement('br'));
+            }
+            
+            
         }
     },
 
@@ -43976,28 +45129,136 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
         //ss['background-attachment'] = 'fixed'; // w3c
         dbody.bgProperties = 'fixed'; // ie
+        dbody.setAttribute("translate", "no");
+        
         //Roo.DomHelper.applyStyles(dbody, ss);
         Roo.EventManager.on(this.doc, {
-            //'mousedown': this.onEditorEvent,
+             
             'mouseup': this.onEditorEvent,
             'dblclick': this.onEditorEvent,
             'click': this.onEditorEvent,
             'keyup': this.onEditorEvent,
+            
             buffer:100,
             scope: this
         });
+        Roo.EventManager.on(this.doc, {
+            'paste': this.onPasteEvent,
+            scope : this
+        });
         if(Roo.isGecko){
             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
         }
+        //??? needed???
         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
         }
         this.initialized = true;
 
+        
+        // initialize special key events - enter
+        new Roo.htmleditor.KeyEnter({core : this});
+        
+         
+        
         this.owner.fireEvent('initialize', this);
         this.pushValue();
     },
-
+    // this is to prevent a href clicks resulting in a redirect?
+   
+    onPasteEvent : function(e,v)
+    {
+        // I think we better assume paste is going to be a dirty load of rubish from word..
+        
+        // even pasting into a 'email version' of this widget will have to clean up that mess.
+        var cd = (e.browserEvent.clipboardData || window.clipboardData);
+        
+        // check what type of paste - if it's an image, then handle it differently.
+        if (cd.files.length > 0) {
+            // pasting images?
+            var urlAPI = (window.createObjectURL && window) || 
+                (window.URL && URL.revokeObjectURL && URL) || 
+                (window.webkitURL && webkitURL);
+    
+            var url = urlAPI.createObjectURL( cd.files[0]);
+            this.insertAtCursor('<img src=" + url + ">');
+            return false;
+        }
+        
+        var html = cd.getData('text/html'); // clipboard event
+        var parser = new Roo.rtf.Parser(cd.getData('text/rtf'));
+        var images = parser.doc ? parser.doc.getElementsByType('pict') : [];
+        Roo.log(images);
+        //Roo.log(imgs);
+        // fixme..
+        images = images.filter(function(g) { return !g.path.match(/^rtf\/(head|pgdsctbl|listtable)/); }) // ignore headers
+                       .map(function(g) { return g.toDataURL(); })
+                       .filter(function(g) { return g != 'about:blank'; });
+        
+        
+        html = this.cleanWordChars(html);
+        
+        var d = (new DOMParser().parseFromString(html, 'text/html')).body;
+        
+        
+        var sn = this.getParentElement();
+        // check if d contains a table, and prevent nesting??
+        //Roo.log(d.getElementsByTagName('table'));
+        //Roo.log(sn);
+        //Roo.log(sn.closest('table'));
+        if (d.getElementsByTagName('table').length && sn && sn.closest('table')) {
+            e.preventDefault();
+            this.insertAtCursor("You can not nest tables");
+            //Roo.log("prevent?"); // fixme - 
+            return false;
+        }
+        
+        if (images.length > 0) {
+            Roo.each(d.getElementsByTagName('img'), function(img, i) {
+                img.setAttribute('src', images[i]);
+            });
+        }
+        if (this.autoClean) {
+            new Roo.htmleditor.FilterStyleToTag({ node : d });
+            new Roo.htmleditor.FilterAttributes({
+                node : d,
+                attrib_white : ['href', 'src', 'name', 'align'],
+                attrib_clean : ['href', 'src' ] 
+            });
+            new Roo.htmleditor.FilterBlack({ node : d, tag : this.black});
+            // should be fonts..
+            new Roo.htmleditor.FilterKeepChildren({node : d, tag : [ 'FONT', 'O:P' ]} );
+            new Roo.htmleditor.FilterParagraph({ node : d });
+            new Roo.htmleditor.FilterSpan({ node : d });
+            new Roo.htmleditor.FilterLongBr({ node : d });
+        }
+        if (this.enableBlocks) {
+                
+            Array.from(d.getElementsByTagName('img')).forEach(function(img) {
+                if (img.closest('figure')) { // assume!! that it's aready
+                    return;
+                }
+                var fig  = new Roo.htmleditor.BlockFigure({
+                    image_src  : img.src
+                });
+                fig.updateElement(img); // replace it..
+                
+            });
+        }
+        
+        
+        this.insertAtCursor(d.innerHTML.replace(/&nbsp;/g,' '));
+        if (this.enableBlocks) {
+            Roo.htmleditor.Block.initAll(this.doc.body);
+        }
+        
+        
+        e.preventDefault();
+        return false;
+        // default behaveiour should be our local cleanup paste? (optional?)
+        // for simple editor - we want to hammer the paste and get rid of everything... - so over-rideable..
+        //this.owner.fireEvent('paste', e, v);
+    },
     // private
     onDestroy : function(){
         
@@ -44019,7 +45280,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
     onFirstFocus : function(){
         
         this.assignDocWin();
-        
+        this.undoManager = new Roo.lib.UndoManager(100,(this.doc.body || this.doc.documentElement));
         
         this.activated = true;
          
@@ -44064,10 +45325,48 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
 
     onEditorEvent : function(e)
     {
-        this.owner.fireEvent('editorevent', this, e);
+         
+        
+        if (e && (e.ctrlKey || e.metaKey) && e.keyCode === 90) {
+            return; // we do not handle this.. (undo manager does..)
+        }
+        // in theory this detects if the last element is not a br, then we try and do that.
+        // its so clicking in space at bottom triggers adding a br and moving the cursor.
+        if (e &&
+            e.target.nodeName == 'BODY' &&
+            e.type == "mouseup" &&
+            this.doc.body.lastChild
+           ) {
+            var lc = this.doc.body.lastChild;
+            // gtx-trans is google translate plugin adding crap.
+            while ((lc.nodeType == 3 && lc.nodeValue == '') || lc.id == 'gtx-trans') {
+                lc = lc.previousSibling;
+            }
+            if (lc.nodeType == 1 && lc.nodeName != 'BR') {
+            // if last element is <BR> - then dont do anything.
+            
+                var ns = this.doc.createElement('br');
+                this.doc.body.appendChild(ns);
+                range = this.doc.createRange();
+                range.setStartAfter(ns);
+                range.collapse(true);
+                var sel = this.win.getSelection();
+                sel.removeAllRanges();
+                sel.addRange(range);
+            }
+        }
+        
+        
+        
+        this.fireEditorEvent(e);
       //  this.updateToolbar();
         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
     },
+    
+    fireEditorEvent: function(e)
+    {
+        this.owner.fireEvent('editorevent', this, e);
+    },
 
     insertTag : function(tg)
     {
@@ -44089,7 +45388,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             
         }
         this.execCmd("formatblock",   tg);
-        
+        this.undoManager.addEvent(); 
     },
     
     insertText : function(txt)
@@ -44101,6 +45400,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                //alert(Sender.getAttribute('label'));
                
         range.insertNode(this.doc.createTextNode(txt));
+        this.undoManager.addEvent();
     } ,
     
      
@@ -44111,7 +45411,37 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
      * @param {String} cmd The Midas command
      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
      */
-    relayCmd : function(cmd, value){
+    relayCmd : function(cmd, value)
+    {
+        
+        switch (cmd) {
+            case 'justifyleft':
+            case 'justifyright':
+            case 'justifycenter':
+                // if we are in a cell, then we will adjust the
+                var n = this.getParentElement();
+                var td = n.closest('td');
+                if (td) {
+                    var bl = Roo.htmleditor.Block.factory(td);
+                    bl.textAlign = cmd.replace('justify','');
+                    bl.updateElement();
+                    this.owner.fireEvent('editorevent', this);
+                    return;
+                }
+                this.execCmd('styleWithCSS', true); // 
+                break;
+            case 'bold':
+            case 'italic':
+                // if there is no selection, then we insert, and set the curson inside it..
+                this.execCmd('styleWithCSS', false); 
+                break;
+                
+        
+            default:
+                break;
+        }
+        
+        
         this.win.focus();
         this.execCmd(cmd, value);
         this.owner.fireEvent('editorevent', this);
@@ -44144,20 +45474,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         if(!this.activated){
             return;
         }
-        /*
-        if(Roo.isIE){
-            this.win.focus();
-            var r = this.doc.selection.createRange();
-            if(r){
-                r.collapse(true);
-                r.pasteHTML(text);
-                this.syncValue();
-                this.deferFocus();
-            
-            }
-            return;
-        }
-        */
+         
         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
             this.win.focus();
             
@@ -44167,19 +45484,31 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             var win = this.win;
             
             if (win.getSelection && win.getSelection().getRangeAt) {
+                
+                // delete the existing?
+                
+                this.createRange(this.getSelection()).deleteContents();
                 range = win.getSelection().getRangeAt(0);
                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
                 range.insertNode(node);
+                range = range.cloneRange();
+                range.collapse(false);
+                 
+                win.getSelection().removeAllRanges();
+                win.getSelection().addRange(range);
+                
+                
+                
             } 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();
@@ -44204,15 +45533,17 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                         cmd = 'underline';
                         break;
                     
-                    case 'v':
-                        this.cleanUpPaste.defer(100, this);
-                        return;
+                    //case 'v':
+                      //  this.cleanUpPaste.defer(100, this);
+                      //  return;
                         
                 }
                 if(cmd){
-                    this.win.focus();
-                    this.execCmd(cmd);
-                    this.deferFocus();
+                    
+                    this.relayCmd(cmd);
+                    //this.win.focus();
+                    //this.execCmd(cmd);
+                    //this.deferFocus();
                     e.preventDefault();
                 }
                 
@@ -44222,6 +45553,8 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
 
     // private
     fixKeys : function(){ // load time branching for fastest keydown performance
+        
+        
         if(Roo.isIE){
             return function(e){
                 var k = e.getKey(), r;
@@ -44235,23 +45568,25 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                     }
                     return;
                 }
-                
+                /// this is handled by Roo.htmleditor.KeyEnter
+                 /*
                 if(k == e.ENTER){
                     r = this.doc.selection.createRange();
                     if(r){
                         var target = r.parentElement();
                         if(!target || target.tagName.toLowerCase() != 'li'){
                             e.stopEvent();
-                            r.pasteHTML('<br />');
+                            r.pasteHTML('<br/>');
                             r.collapse(false);
                             r.select();
                         }
                     }
                 }
-                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
-                    this.cleanUpPaste.defer(100, this);
-                    return;
-                }
+                */
+                //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
+                //    this.cleanUpPaste.defer(100, this);
+                //    return;
+                //}
                 
                 
             };
@@ -44264,10 +45599,11 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
                     this.deferFocus();
                 }
-                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
-                    this.cleanUpPaste.defer(100, this);
-                    return;
-                }
+               
+                //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
+                //    this.cleanUpPaste.defer(100, this);
+                 //   return;
+                //}
                 
             };
         }else if(Roo.isSafari){
@@ -44280,10 +45616,12 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                     this.deferFocus();
                     return;
                 }
-               if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
-                    this.cleanUpPaste.defer(100, this);
-                    return;
-                }
+                 this.mozKeyPress(e);
+                
+               //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
+                 //   this.cleanUpPaste.defer(100, this);
+                 //   return;
+               // }
                 
              };
         }
@@ -44313,7 +45651,27 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
     getSelection : function() 
     {
         this.assignDocWin();
-        return Roo.isIE ? this.doc.selection : this.win.getSelection();
+        return Roo.lib.Selection.wrap(Roo.isIE ? this.doc.selection : this.win.getSelection(), this.doc);
+    },
+    /**
+     * Select a dom node
+     * @param {DomElement} node the node to select
+     */
+    selectNode : function(node, collapse)
+    {
+        var nodeRange = node.ownerDocument.createRange();
+        try {
+            nodeRange.selectNode(node);
+        } catch (e) {
+            nodeRange.selectNodeContents(node);
+        }
+        if (collapse === true) {
+            nodeRange.collapse(true);
+        }
+        //
+        var s = this.win.getSelection();
+        s.removeAllRanges();
+        s.addRange(nodeRange);
     },
     
     getSelectedNode: function() 
@@ -44322,8 +45680,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         
         // should we cache this!!!!
         
-        
-        
+         
          
         var range = this.createRange(this.getSelection()).cloneRange();
         
@@ -44387,6 +45744,8 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         
         return nodes[0];
     },
+    
+    
     createRange: function(sel)
     {
         // this has strange effects when using with 
@@ -44504,26 +45863,21 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         // fully contined.
         return 3;
     },
-
-    // private? - in a new class?
-    cleanUpPaste :  function()
-    {
-        // cleans up the whole document..
-        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) {// change the chars to hex code
-        var he = Roo.HtmlEditorCore;
         
+       var swapCodes  = [ 
+            [    8211, "&#8211;" ], 
+            [    8212, "&#8212;" ], 
+            [    8216,  "'" ],  
+            [    8217, "'" ],  
+            [    8220, '"' ],  
+            [    8221, '"' ],  
+            [    8226, "*" ],  
+            [    8230, "..." ]
+        ]; 
         var output = input;
-        Roo.each(he.swapCodes, function(sw) { 
+        Roo.each(swapCodes, function(sw) { 
             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
             
             output = output.replace(swapper, sw[1]);
@@ -44532,485 +45886,60 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         return output;
     },
     
-    
-    cleanUpChildren : function (n)
-    {
-        if (!n.childNodes.length) {
-            return;
-        }
-        for (var i = n.childNodes.length-1; i > -1 ; i--) {
-           this.cleanUpChild(n.childNodes[i]);
-        }
-    },
-    
+     
     
         
     
     cleanUpChild : function (node)
     {
-        var ed = this;
-        //console.log(node);
-        if (node.nodeName == "#text") {
-            // clean up silly Windows -- stuff?
-            return; 
-        }
-        if (node.nodeName == "#comment") {
-            node.parentNode.removeChild(node);
-            // clean up silly Windows -- stuff?
-            return; 
-        }
-        var lcname = node.tagName.toLowerCase();
-        // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
-        // whitelist of tags..
-        
-        if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
-            // remove node.
-            node.parentNode.removeChild(node);
-            return;
-            
-        }
-        
-        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..
-        
-        //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) {
-                var cn = node.childNodes[0];
-                node.removeChild(cn);
-                node.parentNode.insertBefore(cn, node);
-            }
-            node.parentNode.removeChild(node);
-            return;
-        }
-        
-        if (!node.attributes || !node.attributes.length) {
-            
-          
-            
-            
-            this.cleanUpChildren(node);
-            return;
-        }
-        
-        function cleanAttr(n,v)
-        {
-            
-            if (v.match(/^\./) || v.match(/^\//)) {
-                return;
-            }
-            if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
-                return;
-            }
-            if (v.match(/^#/)) {
-                return;
-            }
-            if (v.match(/^\{/)) { // allow template editing.
-                return;
-            }
-//            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
-            node.removeAttribute(n);
-            
-        }
-        
-        var cwhite = this.cwhite;
-        var cblack = this.cblack;
-            
-        function cleanStyle(n,v)
-        {
-            if (v.match(/expression/)) { //XSS?? should we even bother..
-                node.removeAttribute(n);
-                return;
-            }
-            
-            var parts = v.split(/;/);
-            var clean = [];
-            
-            Roo.each(parts, function(p) {
-                p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
-                if (!p.length) {
-                    return true;
-                }
-                var l = p.split(':').shift().replace(/\s+/g,'');
-                l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
-                
-                if ( cwhite.length && cblack.indexOf(l) > -1) {
-//                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
-                    //node.removeAttribute(n);
-                    return true;
-                }
-                //Roo.log()
-                // only allow 'c whitelisted system attributes'
-                if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
-//                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
-                    //node.removeAttribute(n);
-                    return true;
-                }
-                
-                
-                 
-                
-                clean.push(p);
-                return true;
-            });
-            if (clean.length) { 
-                node.setAttribute(n, clean.join(';'));
-            } else {
-                node.removeAttribute(n);
-            }
-            
-        }
-        
-        
-        for (var i = node.attributes.length-1; i > -1 ; i--) {
-            var a = node.attributes[i];
-            //console.log(a);
-            
-            if (a.name.toLowerCase().substr(0,2)=='on')  {
-                node.removeAttribute(a.name);
-                continue;
-            }
-            if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
-                node.removeAttribute(a.name);
-                continue;
-            }
-            if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
-                cleanAttr(a.name,a.value); // fixme..
-                continue;
-            }
-            if (a.name == 'style') {
-                cleanStyle(a.name,a.value);
-                continue;
-            }
-            /// clean up MS crap..
-            // tecnically this should be a list of valid class'es..
-            
-            
-            if (a.name == 'class') {
-                if (a.value.match(/^Mso/)) {
-                    node.removeAttribute('class');
-                }
-                
-                if (a.value.match(/^body$/)) {
-                    node.removeAttribute('class');
-                }
-                continue;
-            }
-            
-            // style cleanup!?
-            // class cleanup?
-            
-        }
-        
-        
-        this.cleanUpChildren(node);
         
+        new Roo.htmleditor.FilterComment({node : node});
+        new Roo.htmleditor.FilterAttributes({
+                node : node,
+                attrib_black : this.ablack,
+                attrib_clean : this.aclean,
+                style_white : this.cwhite,
+                style_black : this.cblack
+        });
+        new Roo.htmleditor.FilterBlack({ node : node, tag : this.black});
+        new Roo.htmleditor.FilterKeepChildren({node : node, tag : this.tag_remove} );
+         
         
     },
     
     /**
      * Clean up MS wordisms...
+     * @deprecated - use filter directly
      */
     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; 
-        }
-        if (node.nodeName == "#comment") {
-            node.parentNode.removeChild(node);
-            // clean up silly Windows -- stuff?
-            return; 
-        }
-        
-        if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
-            node.parentNode.removeChild(node);
-            return;
-        }
-        //Roo.log(node.tagName);
-        // remove - but keep children..
-        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);
-            /// no need to iterate chidlren = it's got none..
-            //this.iterateChildren(node, this.cleanWord);
-            return;
-        }
-        // clean styles
-        if (node.className.length) {
-            
-            var cn = node.className.split(/\W+/);
-            var cna = [];
-            Roo.each(cn, function(cls) {
-                if (cls.match(/Mso[a-zA-Z]+/)) {
-                    return;
-                }
-                cna.push(cls);
-            });
-            node.className = cna.length ? cna.join(' ') : '';
-            if (!cna.length) {
-                node.removeAttribute("class");
-            }
-        }
-        
-        if (node.hasAttribute("lang")) {
-            node.removeAttribute("lang");
-        }
-        
-        if (node.hasAttribute("style")) {
-            
-            var styles = node.getAttribute("style").split(";");
-            var nstyle = [];
-            Roo.each(styles, function(s) {
-                if (!s.match(/:/)) {
-                    return;
-                }
-                var kv = s.split(":");
-                if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
-                    return;
-                }
-                // what ever is left... we allow.
-                nstyle.push(s);
-            });
-            node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
-            if (!nstyle.length) {
-                node.removeAttribute('style');
-            }
-        }
-        this.iterateChildren(node, this.cleanWord);
-        
-        
+        new Roo.htmleditor.FilterWord({ node : node ? node : this.doc.body });
         
     },
-    /**
-     * iterateChildren of a Node, calling fn each time, using this as the scole..
-     * @param {DomNode} node node to iterate children of.
-     * @param {Function} fn method of this class to call on each item.
-     */
-    iterateChildren : function(node, fn)
-    {
-        if (!node.childNodes.length) {
-                return;
-        }
-        for (var i = node.childNodes.length-1; i > -1 ; i--) {
-           fn.call(this, node.childNodes[i])
-        }
-    },
-    
+   
     
     /**
-     * cleanTableWidths.
-     *
-     * Quite often pasting from word etc.. results in tables with column and widths.
-     * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
-     *
+
+     * @deprecated - use filters
      */
     cleanTableWidths : function(node)
     {
-         
-         
-        if (!node) {
-            this.cleanTableWidths(this.doc.body);
-            return;
-        }
-        
-        // ignore list...
-        if (node.nodeName == "#text" || node.nodeName == "#comment") {
-            return; 
-        }
-        Roo.log(node.tagName);
-        if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
-            this.iterateChildren(node, this.cleanTableWidths);
-            return;
-        }
-        if (node.hasAttribute('width')) {
-            node.removeAttribute('width');
-        }
-        
-         
-        if (node.hasAttribute("style")) {
-            // pretty basic...
-            
-            var styles = node.getAttribute("style").split(";");
-            var nstyle = [];
-            Roo.each(styles, function(s) {
-                if (!s.match(/:/)) {
-                    return;
-                }
-                var kv = s.split(":");
-                if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
-                    return;
-                }
-                // what ever is left... we allow.
-                nstyle.push(s);
-            });
-            node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
-            if (!nstyle.length) {
-                node.removeAttribute('style');
-            }
-        }
-        
-        this.iterateChildren(node, this.cleanTableWidths);
-        
+        new Roo.htmleditor.FilterTableWidth({ node : node ? node : this.doc.body});
         
     },
     
-    
-    
-    
-    domToHTML : function(currentElement, depth, nopadtext) {
-        
-        depth = depth || 0;
-        nopadtext = nopadtext || false;
-    
-        if (!currentElement) {
-            return this.domToHTML(this.doc.body);
-        }
-        
-        //Roo.log(currentElement);
-        var j;
-        var allText = false;
-        var nodeName = currentElement.nodeName;
-        var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
-        
-        if  (nodeName == '#text') {
-            
-            return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
-        }
-        
-        
-        var ret = '';
-        if (nodeName != 'BODY') {
-             
-            var i = 0;
-            // Prints the node tagName, such as <A>, <IMG>, etc
-            if (tagName) {
-                var attr = [];
-                for(i = 0; i < currentElement.attributes.length;i++) {
-                    // quoting?
-                    var aname = currentElement.attributes.item(i).name;
-                    if (!currentElement.attributes.item(i).value.length) {
-                        continue;
-                    }
-                    attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
-                }
-                
-                ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
-            } 
-            else {
-                
-                // eack
-            }
-        } else {
-            tagName = false;
-        }
-        if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
-            return ret;
-        }
-        if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
-            nopadtext = true;
-        }
-        
-        
-        // Traverse the tree
-        i = 0;
-        var currentElementChild = currentElement.childNodes.item(i);
-        var allText = true;
-        var innerHTML  = '';
-        lastnode = '';
-        while (currentElementChild) {
-            // Formatting code (indent the tree so it looks nice on the screen)
-            var nopad = nopadtext;
-            if (lastnode == 'SPAN') {
-                nopad  = true;
-            }
-            // text
-            if  (currentElementChild.nodeName == '#text') {
-                var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
-                toadd = nopadtext ? toadd : toadd.trim();
-                if (!nopad && toadd.length > 80) {
-                    innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
-                }
-                innerHTML  += toadd;
-                
-                i++;
-                currentElementChild = currentElement.childNodes.item(i);
-                lastNode = '';
-                continue;
-            }
-            allText = false;
-            
-            innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
-                
-            // Recursively traverse the tree structure of the child node
-            innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
-            lastnode = currentElementChild.nodeName;
-            i++;
-            currentElementChild=currentElement.childNodes.item(i);
-        }
-        
-        ret += innerHTML;
-        
-        if (!allText) {
-                // The remaining code is mostly for formatting the tree
-            ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
-        }
-        
-        
-        if (tagName) {
-            ret+= "</"+tagName+">";
-        }
-        return ret;
-        
-    },
+     
         
     applyBlacklists : function()
     {
         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
         
+        this.aclean = typeof(this.owner.aclean) != 'undefined' && this.owner.aclean ? this.owner.aclean :  Roo.HtmlEditorCore.aclean;
+        this.ablack = typeof(this.owner.ablack) != 'undefined' && this.owner.ablack ? this.owner.ablack :  Roo.HtmlEditorCore.ablack;
+        this.tag_remove = typeof(this.owner.tag_remove) != 'undefined' && this.owner.tag_remove ? this.owner.tag_remove :  Roo.HtmlEditorCore.tag_remove;
+        
         this.white = [];
         this.black = [];
         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
@@ -45128,6 +46057,16 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         
     },
     
+    
+    updateLanguage : function()
+    {
+        if (!this.iframe || !this.iframe.contentDocument) {
+            return;
+        }
+        Roo.get(this.iframe.contentDocument.body).attr("lang", this.language);
+    },
+    
+    
     removeStylesheets : function()
     {
         var _this = this;
@@ -45192,36 +46131,40 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
 });
 
 Roo.HtmlEditorCore.white = [
-        'area', 'br', 'img', 'input', 'hr', 'wbr',
+        'AREA', 'BR', 'IMG', 'INPUT', 'HR', 'WBR',
         
-       'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
-       'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
-       'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
-       'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
-       'table',   'ul',         'xmp', 
+       'ADDRESS', 'BLOCKQUOTE', 'CENTER', 'DD',      'DIR',       'DIV', 
+       'DL',      'DT',         'H1',     'H2',      'H3',        'H4', 
+       'H5',      'H6',         'HR',     'ISINDEX', 'LISTING',   'MARQUEE', 
+       'MENU',    'MULTICOL',   'OL',     'P',       'PLAINTEXT', 'PRE', 
+       'TABLE',   'UL',         'XMP', 
        
-       'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
-      'thead',   'tr', 
+       'CAPTION', 'COL', 'COLGROUP', 'TBODY', 'TD', 'TFOOT', 'TH', 
+      'THEAD',   'TR', 
      
-      'dir', 'menu', 'ol', 'ul', 'dl',
+      'DIR', 'MENU', 'OL', 'UL', 'DL',
        
-      'embed',  'object'
+      'EMBED',  'OBJECT'
 ];
 
 
 Roo.HtmlEditorCore.black = [
     //    'embed',  'object', // enable - backend responsiblity to clean thiese
-        'applet', // 
-        'base',   'basefont', 'bgsound', 'blink',  'body', 
-        'frame',  'frameset', 'head',    'html',   'ilayer', 
-        'iframe', 'layer',  'link',     'meta',    'object',   
-        'script', 'style' ,'title',  'xml' // clean later..
+        'APPLET', // 
+        'BASE',   'BASEFONT', 'BGSOUND', 'BLINK',  'BODY', 
+        'FRAME',  'FRAMESET', 'HEAD',    'HTML',   'ILAYER', 
+        'IFRAME', 'LAYER',  'LINK',     'META',    'OBJECT',   
+        'SCRIPT', 'STYLE' ,'TITLE',  'XML',
+        //'FONT' // CLEAN LATER..
+        'COLGROUP', 'COL'   // messy tables.
+        
+        
 ];
-Roo.HtmlEditorCore.clean = [
-    'script', 'style', 'title', 'xml'
+Roo.HtmlEditorCore.clean = [ // ?? needed???
+     'SCRIPT', 'STYLE', 'TITLE', 'XML'
 ];
-Roo.HtmlEditorCore.remove = [
-    'font'
+Roo.HtmlEditorCore.tag_remove = [
+    'FONT', 'TBODY'  
 ];
 // attributes..
 
@@ -45252,16 +46195,7 @@ Roo.HtmlEditorCore.cblack= [
 ];
 
 
-Roo.HtmlEditorCore.swapCodes   =[ 
-    [    8211, "&#8211;" ], 
-    [    8212, "&#8212;" ], 
-    [    8216,  "'" ],  
-    [    8217, "'" ],  
-    [    8220, '"' ],  
-    [    8221, '"' ],  
-    [    8226, "*" ],  
-    [    8230, "..." ]
-]; 
+
 
     //<script type="text/javascript">
 
@@ -45324,7 +46258,7 @@ Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
     width: 500,
     
     /**
-     * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
+     * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets - this is usally a good idea  rootURL + '/roojs1/css/undoreset.css',   .
      * 
      */
     stylesheets: false,
@@ -45351,7 +46285,31 @@ Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
      * 
      */
     white: false,
+    /**
+     * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this.
+     */
+    allowComments: false,
+    /**
+     * @cfg {boolean} enableBlocks - default true - if the block editor (table and figure should be enabled)
+     */
+    enableBlocks : true,
     
+    /**
+     * @cfg {boolean} autoClean - default true - loading and saving will remove quite a bit of formating,
+     *         if you are doing an email editor, this probably needs disabling, it's designed
+     */
+    autoClean: true,
+    /**
+     * @cfg {string} bodyCls default '' default classes to add to body of editable area - usually undoreset is a good start..
+     */
+    bodyCls : '',
+    /**
+     * @cfg {String} language default en - language of text (usefull for rtl languages)
+     * 
+     */
+    language: 'en',
+    
+     
     // id of frame..
     frameId: false,
     
@@ -45456,7 +46414,13 @@ Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
             * Fires when press the Sytlesheets button
             * @param {Roo.HtmlEditorCore} this
             */
-            stylesheetsclick: true
+            stylesheetsclick: true,
+            /**
+            * @event paste
+            * Fires when press user pastes into the editor
+            * @param {Roo.HtmlEditorCore} this
+            */
+            paste: true 
         });
         this.defaultAutoCreate =  {
             tag: "textarea",
@@ -45487,8 +46451,19 @@ Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
          
         
     },
-
-     
+    /**
+     * get the Context selected node
+     * @returns {DomElement|boolean} selected node if active or false if none
+     * 
+     */
+    getSelectedNode : function()
+    {
+        if (this.toolbars.length < 2 || !this.toolbars[1].tb) {
+            return false;
+        }
+        return this.toolbars[1].tb.selectedNode;
+    
+    },
     // private
     onRender : function(ct, position)
     {
@@ -45709,6 +46684,8 @@ Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
             this.el.removeClass('x-hidden');
             this.el.dom.removeAttribute('tabIndex');
             this.el.focus();
+            this.el.dom.scrollTop = 0;
+            
             
             for (var i = 0; i < this.toolbars.length; i++) {
                 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
@@ -45776,7 +46753,17 @@ Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
         this.editorcore.pushValue();
     },
 
+    /**
+     * update the language in the body - really done by core
+     * @param {String} language - eg. en / ar / zh-CN etc..
+     */
+    updateLanguage : function(lang)
+    {
+        this.language = lang;
+        this.editorcore.language = lang;
+        this.editorcore.updateLanguage();
      
+    },
     // private
     deferFocus : function(){
         this.focus.defer(10, this);
@@ -45881,8 +46868,7 @@ Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
      */
 });
  
-    // <script type="text/javascript">
-/*
+    /*
  * Based on
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -45891,9 +46877,9 @@ Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
  */
 
 /**
- * @class Roo.form.HtmlEditorToolbar1
+ * @class Roo.form.HtmlEditor.ToolbarStandard
  * Basic Toolbar
- * 
+
  * Usage:
  *
  new Roo.form.HtmlEditor({
@@ -45907,7 +46893,7 @@ Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
      
  * 
  * @cfg {Object} disable List of elements to disable..
- * @cfg {Array} btns List of additional buttons.
+ * @cfg {Roo.Toolbar.Item|Roo.Toolbar.Button|Roo.Toolbar.SplitButton|Roo.form.Field} btns[] List of additional buttons.
  * 
  * 
  * NEEDS Extra CSS? 
@@ -45932,7 +46918,7 @@ Roo.form.HtmlEditor.ToolbarStandard = function(config)
     // dont call parent... till later.
 }
 
-Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
+Roo.form.HtmlEditor.ToolbarStandard.prototype = {
     
     tb: false,
     
@@ -46278,7 +47264,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
                     tabIndex:-1
                 });
             }
-             cmenu.menu.items.push({
+            cmenu.menu.items.push({
                 actiontype : 'tablewidths',
                 html: 'Remove Table Widths',
                 handler: function(a,b) {
@@ -46330,7 +47316,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
                 actiontype : 'tidy',
                 html: 'Tidy HTML Source',
                 handler: function(a,b) {
-                    editorcore.doc.body.innerHTML = editorcore.domToHTML();
+                    new Roo.htmleditor.Tidy(editorcore.doc.body);
                     editorcore.syncValue();
                 },
                 tabIndex:-1
@@ -46367,7 +47353,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
         
         if (this.btns) {
             for(var i =0; i< this.btns.length;i++) {
-                var b = Roo.factory(this.btns[i],Roo.form);
+                var b = Roo.factory(this.btns[i],this.btns[i].xns || Roo.form);
                 b.cls =  'x-edit-none';
                 
                 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
@@ -46408,11 +47394,45 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
     },
     // private used internally
     createLink : function(){
-        Roo.log("create link?");
-        var url = prompt(this.createLinkText, this.defaultLinkValue);
-        if(url && url != 'http:/'+'/'){
-            this.editorcore.relayCmd('createlink', url);
+        //Roo.log("create link?");
+        var ec = this.editorcore;
+        var ar = ec.getAllAncestors();
+        var n = false;
+        for(var i = 0;i< ar.length;i++) {
+            if (ar[i] && ar[i].nodeName == 'A') {
+                n = ar[i];
+                break;
+            }
         }
+        
+        (function() {
+            
+            Roo.MessageBox.show({
+                title : "Add / Edit Link URL",
+                msg : "Enter the url for the link",
+                buttons: Roo.MessageBox.OKCANCEL,
+                fn: function(btn, url){
+                    if (btn != 'ok') {
+                        return;
+                    }
+                    if(url && url != 'http:/'+'/'){
+                        if (n) {
+                            n.setAttribute('href', url);
+                        } else {
+                            ec.relayCmd('createlink', url);
+                        }
+                    }
+                },
+                minWidth:250,
+                prompt:true,
+                //multiline: multiline,
+                modal : true,
+                value :  n  ? n.getAttribute('href') : '' 
+            });
+            
+             
+        }).defer(100, this); // we have to defer this , otherwise the mouse click gives focus to the main window.
+        
     },
 
     
@@ -46525,6 +47545,11 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
                 this.tb.items.each(function(item){
                     item.enable();
                 });
+                // initialize 'blocks'
+                Roo.each(Roo.get(this.editorcore.doc.body).query('*[data-block]'), function(e) {
+                    Roo.htmleditor.Block.factory(e).updateElement(e);
+                },this);
+            
             }
             
         }
@@ -46651,7 +47676,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
            item.enable();
         });
     }
-});
+};
 
 
 
@@ -46699,189 +47724,138 @@ Roo.form.HtmlEditor.ToolbarContext = function(config)
  
 
 Roo.form.HtmlEditor.ToolbarContext.types = {
-    'IMG' : {
-        width : {
+    'IMG' : [
+        {
+            name : 'width',
             title: "Width",
             width: 40
         },
-        height:  {
+        {
+            name : 'height',
             title: "Height",
             width: 40
         },
-        align: {
+        {
+            name : 'align',
             title: "Align",
             opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
             width : 80
             
         },
-        border: {
+        {
+            name : 'border',
             title: "Border",
             width: 40
         },
-        alt: {
+        {
+            name : 'alt',
             title: "Alt",
             width: 120
         },
-        src : {
+        {
+            name : 'src',
             title: "Src",
             width: 220
         }
         
-    },
-    'A' : {
-        name : {
+    ],
+    
+    'FIGURE' : [
+        {
+            name : 'align',
+            title: "Align",
+            opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
+            width : 80  
+        }
+    ],
+    'A' : [
+        {
+            name : 'name',
             title: "Name",
             width: 50
         },
-        target:  {
+        {
+            name : 'target',
             title: "Target",
             width: 120
         },
-        href:  {
+        {
+            name : 'href',
             title: "Href",
             width: 220
         } // border?
         
-    },
-    'TABLE' : {
-        rows : {
-            title: "Rows",
-            width: 20
-        },
-        cols : {
-            title: "Cols",
-            width: 20
-        },
-        width : {
-            title: "Width",
-            width: 40
-        },
-        height : {
-            title: "Height",
-            width: 40
-        },
-        border : {
-            title: "Border",
-            width: 20
-        }
-    },
-    'TD' : {
-        width : {
-            title: "Width",
-            width: 40
-        },
-        height : {
-            title: "Height",
-            width: 40
-        },   
-        align: {
-            title: "Align",
-            opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
-            width: 80
-        },
-        valign: {
-            title: "Valign",
-            opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
-            width: 80
-        },
-        colspan: {
-            title: "Colspan",
-            width: 20
-            
-        },
-         'font-family'  : {
-            title : "Font",
-            style : 'fontFamily',
-            displayField: 'display',
-            optname : 'font-family',
-            width: 140
-        }
-    },
-    'INPUT' : {
-        name : {
+    ],
+    
+    'INPUT' : [
+        {
+            name : 'name',
             title: "name",
             width: 120
         },
-        value : {
+        {
+            name : 'value',
             title: "Value",
             width: 120
         },
-        width : {
+        {
+            name : 'width',
             title: "Width",
             width: 40
         }
-    },
-    'LABEL' : {
-        'for' : {
+    ],
+    'LABEL' : [
+         {
+            name : 'for',
             title: "For",
             width: 120
         }
-    },
-    'TEXTAREA' : {
-          name : {
+    ],
+    'TEXTAREA' : [
+        {
+            name : 'name',
             title: "name",
             width: 120
         },
-        rows : {
+        {
+            name : 'rows',
             title: "Rows",
             width: 20
         },
-        cols : {
+        {
+            name : 'cols',
             title: "Cols",
             width: 20
         }
-    },
-    'SELECT' : {
-        name : {
+    ],
+    'SELECT' : [
+        {
+            name : 'name',
             title: "name",
             width: 120
         },
-        selectoptions : {
+        {
+            name : 'selectoptions',
             title: "Options",
             width: 200
         }
-    },
+    ],
     
     // should we really allow this??
     // should this just be 
-    'BODY' : {
-        title : {
+    'BODY' : [
+        
+        {
+            name : 'title',
             title: "Title",
             width: 200,
             disabled : true
         }
-    },
-    'SPAN' : {
-        'font-family'  : {
-            title : "Font",
-            style : 'fontFamily',
-            displayField: 'display',
-            optname : 'font-family',
-            width: 140
-        }
-    },
-    'DIV' : {
-        'font-family'  : {
-            title : "Font",
-            style : 'fontFamily',
-            displayField: 'display',
-            optname : 'font-family',
-            width: 140
-        }
-    },
-     'P' : {
-        'font-family'  : {
-            title : "Font",
-            style : 'fontFamily',
-            displayField: 'display',
-            optname : 'font-family',
-            width: 140
-        }
-    },
-    
-    '*' : {
-        // empty..
-    }
+    ],
+    '*' : [
+        // empty.
+    ]
 
 };
 
@@ -46967,9 +47941,9 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
         // disable everything...
         var ty= Roo.form.HtmlEditor.ToolbarContext.types;
         this.toolbars = {};
-           
+        // block toolbars are built in updateToolbar when needed.
         for (var i in  ty) {
-          
+            
             this.toolbars[i] = this.buildToolbar(ty[i],i);
         }
         this.tb = this.toolbars.BODY;
@@ -46996,8 +47970,13 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
      *
      * Note you can force an update by calling on('editorevent', scope, false)
      */
-    updateToolbar: function(editor,ev,sel){
-
+    updateToolbar: function(editor ,ev, sel)
+    {
+        
+        if (ev) {
+            ev.stopEvent(); // se if we can stop this looping with mutiple events.
+        }
+        
         //Roo.log(ev);
         // capture mouse up - this is handy for selecting images..
         // perhaps should go somewhere else...
@@ -47005,38 +47984,40 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
              this.editor.onFirstFocus();
             return;
         }
-        
+        //Roo.log(ev ? ev.target : 'NOTARGET');
         
         
         // 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') {
+            ev.target && ev.target.tagName != 'BODY' ) { // && 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 = this.editorcore.win.getSelection();
-            s.removeAllRanges();
-            s.addRange(nodeRange);
-        }  
+            
+            // this triggers looping?
+            //this.editorcore.selectNode(sel);
+             
+        }
         
+        // this forces an id..
+        Array.from(this.editorcore.doc.body.querySelectorAll('.roo-ed-selection')).forEach(function(e) {
+             e.classList.remove('roo-ed-selection');
+        });
+        //Roo.select('.roo-ed-selection', false, this.editorcore.doc).removeClass('roo-ed-selection');
+        //Roo.get(node).addClass('roo-ed-selection');
       
-        var updateFooter = sel ? false : true;
+        //var updateFooter = sel ? false : true; 
         
         
         var ans = this.editorcore.getAllAncestors();
         
         // pick
-        var ty= Roo.form.HtmlEditor.ToolbarContext.types;
+        var ty = Roo.form.HtmlEditor.ToolbarContext.types;
         
         if (!sel) { 
             sel = ans.length ? (ans[0] ?  ans[0]  : ans[1]) : this.editorcore.doc.body;
@@ -47044,86 +48025,145 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
             sel = sel.tagName.length ? sel : this.editorcore.doc.body;
             
         }
-        // pick a menu that exists..
-        var tn = sel.tagName.toUpperCase();
-        //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
-        
-        tn = sel.tagName.toUpperCase();
         
+        var tn = sel.tagName.toUpperCase();
         var lastSel = this.tb.selectedNode;
-        
         this.tb.selectedNode = sel;
+        var left_label = tn;
         
-        // if current menu does not match..
+        // ok see if we are editing a block?
         
-        if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
-                
-            this.tb.el.hide();
-            ///console.log("show: " + tn);
-            this.tb =  typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
-            this.tb.el.show();
-            // update name
-            this.tb.items.first().el.innerHTML = tn + ':&nbsp;';
-            
-            
-            // update attributes
-            if (this.tb.fields) {
-                this.tb.fields.each(function(e) {
-                    if (e.stylename) {
-                        e.setValue(sel.style[e.stylename]);
-                        return;
-                    } 
-                   e.setValue(sel.getAttribute(e.attrname));
-                });
-            }
+        var db = false;
+        // you are not actually selecting the block.
+        if (sel && sel.hasAttribute('data-block')) {
+            db = sel;
+        } else if (sel && sel.closest('[data-block]')) {
             
-            var hasStyles = false;
-            for(var i in this.styles) {
-                hasStyles = true;
-                break;
-            }
+            db = sel.closest('[data-block]');
+            //var cepar = sel.closest('[contenteditable=true]');
+            //if (db && cepar && cepar.tagName != 'BODY') {
+            //   db = false; // we are inside an editable block.. = not sure how we are going to handle nested blocks!?
+            //}   
+        }
+        
+        
+        var block = false;
+        //if (db && !sel.hasAttribute('contenteditable') && sel.getAttribute('contenteditable') != 'true' ) {
+        if (db && this.editorcore.enableBlocks) {
+            block = Roo.htmleditor.Block.factory(db);
             
-            // update styles
-            if (hasStyles) { 
-                var st = this.tb.fields.item(0);
-                
-                st.store.removeAll();
-               
-                
-                var cn = sel.className.split(/\s+/);
+            
+            if (block) {
+                 db.className = (
+                        db.classList.length > 0  ? db.className + ' ' : ''
+                    )  + 'roo-ed-selection';
+                 
+                 // since we removed it earlier... its not there..
+                tn = 'BLOCK.' + db.getAttribute('data-block');
                 
-                var avs = [];
-                if (this.styles['*']) {
-                    
-                    Roo.each(this.styles['*'], function(v) {
-                        avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );         
-                    });
-                }
-                if (this.styles[tn]) { 
-                    Roo.each(this.styles[tn], function(v) {
-                        avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );         
-                    });
+                //this.editorcore.selectNode(db);
+                if (typeof(this.toolbars[tn]) == 'undefined') {
+                   this.toolbars[tn] = this.buildToolbar( false  ,tn ,block.friendly_name, block);
                 }
-                
-                st.store.loadData(avs);
-                st.collapse();
-                st.setValue(cn);
+                this.toolbars[tn].selectedNode = db;
+                left_label = block.friendly_name;
+                ans = this.editorcore.getAllAncestors();
             }
-            // flag our selected Node.
-            this.tb.selectedNode = sel;
-           
-           
-            Roo.menu.MenuMgr.hideAll();
-
+            
+                
+            
         }
         
-        if (!updateFooter) {
-            //this.footDisp.dom.innerHTML = ''; 
-            return;
+        
+        if (this.tb.name == tn && lastSel == this.tb.selectedNode && ev !== false) {
+            return; // no change?
         }
+        
+        
+          
+        this.tb.el.hide();
+        ///console.log("show: " + tn);
+        this.tb =  typeof(this.toolbars[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
+        
+        this.tb.el.show();
+        // update name
+        this.tb.items.first().el.innerHTML = left_label + ':&nbsp;';
+        
+        
+        // update attributes
+        if (block && this.tb.fields) {
+             
+            this.tb.fields.each(function(e) {
+                e.setValue(block[e.name]);
+            });
+            
+            
+        } else  if (this.tb.fields && this.tb.selectedNode) {
+            this.tb.fields.each( function(e) {
+                if (e.stylename) {
+                    e.setValue(this.tb.selectedNode.style[e.stylename]);
+                    return;
+                } 
+                e.setValue(this.tb.selectedNode.getAttribute(e.attrname));
+            }, this);
+            this.updateToolbarStyles(this.tb.selectedNode);  
+        }
+        
+        
+       
+        Roo.menu.MenuMgr.hideAll();
+
+        
+        
+    
         // update the footer
         //
+        this.updateFooter(ans);
+             
+    },
+    
+    updateToolbarStyles : function(sel)
+    {
+        var hasStyles = false;
+        for(var i in this.styles) {
+            hasStyles = true;
+            break;
+        }
+        
+        // update styles
+        if (hasStyles && this.tb.hasStyles) { 
+            var st = this.tb.fields.item(0);
+            
+            st.store.removeAll();
+            var cn = sel.className.split(/\s+/);
+            
+            var avs = [];
+            if (this.styles['*']) {
+                
+                Roo.each(this.styles['*'], function(v) {
+                    avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );         
+                });
+            }
+            if (this.styles[tn]) { 
+                Roo.each(this.styles[tn], function(v) {
+                    avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );         
+                });
+            }
+            
+            st.store.loadData(avs);
+            st.collapse();
+            st.setValue(cn);
+        }
+    },
+    
+     
+    updateFooter : function(ans)
+    {
         var html = '';
+        if (ans === false) {
+            this.footDisp.dom.innerHTML = '';
+            return;
+        }
         
         this.footerEls = ans.reverse();
         Roo.each(this.footerEls, function(a,i) {
@@ -47143,10 +48183,8 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
         
         this.footDisp.dom.innerHTML = html;
             
-        //this.editorsyncValue();
+        
     },
-     
-    
    
        
     // private
@@ -47171,7 +48209,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
            item.enable();
         });
     },
-    buildToolbar: function(tlist, nm)
+    buildToolbar: function(tlist, nm, friendly_name, block)
     {
         var editor = this.editor;
         var editorcore = this.editorcore;
@@ -47182,18 +48220,22 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
         
        
         var tb = new Roo.Toolbar(wdiv);
-        // add the name..
+        ///this.tb = tb; // << this sets the active toolbar..
+        if (tlist === false && block) {
+            tlist = block.contextMenu(this);
+        }
         
-        tb.add(nm+ ":&nbsp;");
+        tb.hasStyles = false;
+        tb.name = nm;
+        
+        tb.add((typeof(friendly_name) == 'undefined' ? nm : friendly_name) + ":&nbsp;");
+        
+        var styles = Array.from(this.styles);
         
-        var styles = [];
-        for(var i in this.styles) {
-            styles.push(i);
-        }
         
         // styles...
         if (styles && styles.length) {
-            
+            tb.hasStyles = true;
             // this needs a multi-select checkbox...
             tb.addField( new Roo.form.ComboBox({
                 store: new Roo.data.SimpleStore({
@@ -47223,9 +48265,18 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
         }
         
         var tbc = Roo.form.HtmlEditor.ToolbarContext;
-        var tbops = tbc.options;
         
-        for (var i in tlist) {
+        
+        for (var i = 0; i < tlist.length; i++) {
+            
+            // newer versions will use xtype cfg to create menus.
+            if (typeof(tlist[i].xtype) != 'undefined') {
+                
+                tb[typeof(tlist[i].name)== 'undefined' ? 'add' : 'addField'](Roo.factory(tlist[i]));
+                
+                
+                continue;
+            }
             
             var item = tlist[i];
             tb.add(item.title + ":&nbsp;");
@@ -47233,8 +48284,8 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
             
             //optname == used so you can configure the options available..
             var opts = item.opts ? item.opts : false;
-            if (item.optname) {
-                opts = tbops[item.optname];
+            if (item.optname) { // use the b
+                opts = Roo.form.HtmlEditor.ToolbarContext.options[item.optname];
            
             }
             
@@ -47246,13 +48297,15 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
                         fields: ['val', 'display'],
                         data : opts  
                     }),
-                    name : '-roo-edit-' + i,
-                    attrname : i,
+                    name : '-roo-edit-' + tlist[i].name,
+                    
+                    attrname : tlist[i].name,
                     stylename : item.style ? item.style : false,
+                    
                     displayField: item.displayField ? item.displayField : 'val',
                     valueField :  'val',
                     typeAhead: false,
-                    mode: typeof(tbc.stores[i]) != 'undefined'  ? 'remote' : 'local',
+                    mode: typeof(tbc.stores[tlist[i].name]) != 'undefined'  ? 'remote' : 'local',
                     editable : false,
                     triggerAction: 'all',
                     emptyText:'Select',
@@ -47260,11 +48313,20 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
                     width: item.width ? item.width  : 130,
                     listeners : {
                         'select': function(c, r, i) {
+                             
+                            
                             if (c.stylename) {
                                 tb.selectedNode.style[c.stylename] =  r.get('val');
+                                editorcore.syncValue();
+                                return;
+                            }
+                            if (r === false) {
+                                tb.selectedNode.removeAttribute(c.attrname);
+                                editorcore.syncValue();
                                 return;
                             }
                             tb.selectedNode.setAttribute(c.attrname, r.get('val'));
+                            editorcore.syncValue();
                         }
                     }
 
@@ -47272,7 +48334,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
                 continue;
                     
                  
-                
+                /*
                 tb.addField( new Roo.form.TextField({
                     name: i,
                     width: 100,
@@ -47280,16 +48342,19 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
                     value: ''
                 }));
                 continue;
+                */
             }
             tb.addField( new Roo.form.TextField({
-                name: '-roo-edit-' + i,
-                attrname : i,
+                name: '-roo-edit-' + tlist[i].name,
+                attrname : tlist[i].name,
                 
                 width: item.width,
                 //allowBlank:true,
                 value: '',
                 listeners: {
                     'change' : function(f, nv, ov) {
+                        
+                         
                         tb.selectedNode.setAttribute(f.attrname, nv);
                         editorcore.syncValue();
                     }
@@ -47299,8 +48364,9 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
         }
         
         var _this = this;
-        
+        var show_delete = !block || block.deleteTitle !== false;
         if(nm == 'BODY'){
+            show_delete = false;
             tb.addSeparator();
         
             tb.addButton( {
@@ -47316,60 +48382,61 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
         }
         
         tb.addFill();
-        tb.addButton( {
-            text: 'Remove Tag',
-    
-            listeners : {
-                click : function ()
-                {
-                    // remove
-                    // undo does not work.
-                     
-                    var sn = tb.selectedNode;
-                    
-                    var pn = sn.parentNode;
-                    
-                    var stn =  sn.childNodes[0];
-                    var en = sn.childNodes[sn.childNodes.length - 1 ];
-                    while (sn.childNodes.length) {
-                        var node = sn.childNodes[0];
-                        sn.removeChild(node);
-                        //Roo.log(node);
-                        pn.insertBefore(node, sn);
+        if (show_delete) {
+            tb.addButton({
+                text: block && block.deleteTitle ? block.deleteTitle  : 'Remove Block or Formating', // remove the tag, and puts the children outside...
+        
+                listeners : {
+                    click : function ()
+                    {
+                        var sn = tb.selectedNode;
+                        if (block) {
+                            sn = Roo.htmleditor.Block.factory(tb.selectedNode).removeNode();
+                            
+                        }
+                        if (!sn) {
+                            return;
+                        }
+                        var stn =  sn.childNodes[0] || sn.nextSibling || sn.previousSibling || sn.parentNode;
+                        if (sn.hasAttribute('data-block')) {
+                            stn =  sn.nextSibling || sn.previousSibling || sn.parentNode;
+                            sn.parentNode.removeChild(sn);
+                            
+                        } else if (sn && sn.tagName != 'BODY') {
+                            // remove and keep parents.
+                            a = new Roo.htmleditor.FilterKeepChildren({tag : false});
+                            a.replaceTag(sn);
+                        }
+                        
+                        
+                        var range = editorcore.createRange();
+            
+                        range.setStart(stn,0);
+                        range.setEnd(stn,0); 
+                        var selection = editorcore.getSelection();
+                        selection.removeAllRanges();
+                        selection.addRange(range);
+                        
+                        
+                        //_this.updateToolbar(null, null, pn);
+                        _this.updateToolbar(null, null, null);
+                        _this.updateFooter(false);
                         
                     }
-                    pn.removeChild(sn);
-                    var range = editorcore.createRange();
-        
-                    range.setStart(stn,0);
-                    range.setEnd(en,0); //????
-                    //range.selectNode(sel);
-                    
-                    
-                    var selection = editorcore.getSelection();
-                    selection.removeAllRanges();
-                    selection.addRange(range);
-                    
-                    
-                    
-                    //_this.updateToolbar(null, null, pn);
-                    _this.updateToolbar(null, null, null);
-                    _this.footDisp.dom.innerHTML = ''; 
                 }
-            }
-            
+                
+                        
                     
                 
-            
-        });
-        
+            });
+        }    
         
         tb.el.on('click', function(e){
             e.preventDefault(); // what does this do?
         });
         tb.el.setVisibilityMode( Roo.Element.DISPLAY);
         tb.el.hide();
-        tb.name = nm;
+        
         // dont need to disable them... as they will get hidden
         return tb;
          
@@ -47413,6 +48480,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
         
         
     },
+    // when the footer contect changes
     onContextClick : function (ev,dom)
     {
         ev.preventDefault();
@@ -47425,17 +48493,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
         var ans = this.footerEls;
         var sel = ans[n];
         
-         // pick
-        var range = this.editorcore.createRange();
-        
-        range.selectNodeContents(sel);
-        //range.selectNode(sel);
-        
-        
-        var selection = this.editorcore.getSelection();
-        selection.removeAllRanges();
-        selection.addRange(range);
-        
+        this.editorcore.selectNode(sel);
         
         
         this.updateToolbar(null, null, sel);
@@ -48004,11 +49062,12 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
      * @param {Boolean} asString
      * @return {Object}
      */
-    getValues : function(asString){
+    getValues : function(asString)
+    {
         if (this.childForms) {
             // copy values from the child forms
             Roo.each(this.childForms, function (f) {
-                this.setValues(f.getValues());
+                this.setValues(f.getFieldValues()); // get the full set of data, as we might be copying comboboxes from external into this one.
             }, this);
         }
         
@@ -48041,21 +49100,31 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
     /**
      * Returns the fields in this form as an object with key/value pairs. 
      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
+     * Normally this will not return readOnly data 
+     * @param {Boolean} with_readonly return readonly field data.
      * @return {Object}
      */
-    getFieldValues : function(with_hidden)
+    getFieldValues : function(with_readonly)
     {
         if (this.childForms) {
             // copy values from the child forms
             // should this call getFieldValues - probably not as we do not currently copy
             // hidden fields when we generate..
             Roo.each(this.childForms, function (f) {
-                this.setValues(f.getValues());
+                this.setValues(f.getFieldValues());
             }, this);
         }
         
         var ret = {};
         this.items.each(function(f){
+            
+            if (f.readOnly && with_readonly !== true) {
+                return; // skip read only values. - this is in theory to stop 'old' values being copied over new ones
+                        // if a subform contains a copy of them.
+                        // if you have subforms with the same editable data, you will need to copy the data back
+                        // and forth.
+            }
+            
             if (!f.getName()) {
                 return;
             }
@@ -48344,6 +49413,7 @@ Roo.apply(Roo.form.BasicForm, {
 /**
  * @class Roo.form.Form
  * @extends Roo.form.BasicForm
+ * @children Roo.form.Column Roo.form.FieldSet Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
  * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
  * @constructor
  * @param {Object} config Configuration options
@@ -48401,6 +49471,10 @@ Roo.form.Form = function(config){
 };
 
 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
+     /**
+     * @cfg {Roo.Button} buttons[] buttons at bottom of form
+     */
+    
     /**
      * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
      */
@@ -49140,6 +50214,7 @@ Roo.form.Action.ACTION_TYPES = {
 /**
  * @class Roo.form.Layout
  * @extends Roo.Component
+ * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem Roo.form.FieldSet
  * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
  * @constructor
  * @param {Object} config Configuration options
@@ -49290,6 +50365,7 @@ Roo.extend(Roo.form.Layout, Roo.Component, {
 /**
  * @class Roo.form.Column
  * @extends Roo.form.Layout
+ * @children Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem Roo.form.FieldSet
  * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
  * @constructor
  * @param {Object} config Configuration options
@@ -49324,6 +50400,7 @@ Roo.extend(Roo.form.Column, Roo.form.Layout, {
 /**
  * @class Roo.form.Row
  * @extends Roo.form.Layout
+ * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem Roo.form.FieldSet
  * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
  * @constructor
  * @param {Object} config Configuration options
@@ -49400,6 +50477,7 @@ Roo.extend(Roo.form.Row, Roo.form.Layout, {
 /**
  * @class Roo.form.FieldSet
  * @extends Roo.form.Layout
+ * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
  * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
  * @constructor
  * @param {Object} config Configuration options
@@ -49448,7 +50526,7 @@ Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
 /**
  * @class Roo.form.VTypes
  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
- * @singleton
+ * @static
  */
 Roo.form.VTypes = function(){
     // closure these in so they are only created once.
@@ -52045,6 +53123,7 @@ Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
 /**
  * @class Roo.BorderLayout
  * @extends Roo.LayoutManager
+ * @children Roo.ContentPanel
  * This class represents a common layout manager used in desktop applications. For screenshots and more details,
  * please see: <br><br>
  * <a href="http://www.jackslocum.com/yui/2006/10/19/cross-browser-web-20-layouts-with-yahoo-ui/">Cross Browser Layouts - Part 1</a><br>
@@ -52126,6 +53205,22 @@ Roo.BorderLayout = function(container, config){
 };
 
 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
+       
+       /**
+        * @cfg {Roo.LayoutRegion} east
+        */
+       /**
+        * @cfg {Roo.LayoutRegion} west
+        */
+       /**
+        * @cfg {Roo.LayoutRegion} north
+        */
+       /**
+        * @cfg {Roo.LayoutRegion} south
+        */
+       /**
+        * @cfg {Roo.LayoutRegion} center
+        */
     /**
      * Creates and adds a new region if it doesn't already exist.
      * @param {String} target The target region key (north, south, east, west or center).
@@ -54230,23 +55325,26 @@ Roo.LayoutStateManager.prototype = {
 /**
  * @class Roo.ContentPanel
  * @extends Roo.util.Observable
+ * @children Roo.form.Form Roo.JsonView Roo.View
+ * @parent Roo.BorderLayout Roo.LayoutDialog builder
  * A basic ContentPanel element.
  * @cfg {Boolean}   fitToFrame    True for this panel to adjust its size to fit when the region resizes  (defaults to false)
  * @cfg {Boolean}   fitContainer   When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container  (defaults to false)
- * @cfg {Boolean/Object} autoCreate True to auto generate the DOM element for this panel, or a {@link Roo.DomHelper} config of the element to create
+ * @cfg {Boolean|Object} autoCreate True to auto generate the DOM element for this panel, or a {@link Roo.DomHelper} config of the element to create
  * @cfg {Boolean}   closable      True if the panel can be closed/removed
  * @cfg {Boolean}   background    True if the panel should not be activated when it is added (defaults to false)
- * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
- * @cfg {Toolbar}   toolbar       A toolbar for this panel
+ * @cfg {String|HTMLElement|Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
+ * @cfg {Roo.Toolbar}   toolbar       A toolbar for this panel
  * @cfg {Boolean} autoScroll    True to scroll overflow in this panel (use with {@link #fitToFrame})
  * @cfg {String} title          The title for this panel
  * @cfg {Array} adjustments     Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
  * @cfg {String} url            Calls {@link #setUrl} with this value
- * @cfg {String} region         (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
- * @cfg {String/Object} params  When used with {@link #url}, calls {@link #setUrl} with this value
+ * @cfg {String} region (center|north|south|east|west) [required] which region to put this panel on (when used with xtype constructors)
+ * @cfg {String|Object} params  When used with {@link #url}, calls {@link #setUrl} with this value
  * @cfg {Boolean} loadOnce      When used with {@link #url}, calls {@link #setUrl} with this value
  * @cfg {String}    content        Raw content to fill content panel with (uses setContent on construction.)
- * @cfg {String}    style  Extra style to add to the content panel 
+ * @cfg {String}    style  Extra style to add to the content panel
+ * @cfg {Roo.menu.Menu} menu  popup menu
 
  * @constructor
  * Create a new ContentPanel.
@@ -54676,17 +55774,32 @@ layout.addxtype({
     }
 });
 
+
+
+
+
+
+
+
+
+
+
+
 /**
  * @class Roo.GridPanel
  * @extends Roo.ContentPanel
+ * @parent Roo.BorderLayout Roo.LayoutDialog builder
  * @constructor
  * Create a new GridPanel.
- * @param {Roo.grid.Grid} grid The grid for this panel
- * @param {String/Object} config A string to set only the panel's title, or a config object
+ * @cfg {Roo.grid.Grid} grid The grid for this panel
  */
 Roo.GridPanel = function(grid, config){
     
-  
+    // universal ctor...
+    if (typeof(grid.grid) != 'undefined') {
+        config = grid;
+        grid = config.grid;
+    }
     this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
         {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
         
@@ -54754,11 +55867,15 @@ Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
 /**
  * @class Roo.NestedLayoutPanel
  * @extends Roo.ContentPanel
+ * @parent Roo.BorderLayout Roo.LayoutDialog builder
+ * @cfg {Roo.BorderLayout} layout   [required] The layout for this panel
+ *
+ * 
  * @constructor
  * Create a new NestedLayoutPanel.
  * 
  * 
- * @param {Roo.BorderLayout} layout The layout for this panel
+ * @param {Roo.BorderLayout} layout [required] The layout for this panel
  * @param {String/Object} config A string to set only the title or a config object
  */
 Roo.NestedLayoutPanel = function(layout, config)
@@ -54790,6 +55907,8 @@ Roo.NestedLayoutPanel = function(layout, config)
 
 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
 
+    layout : false,
+
     setSize : function(width, height){
         if(!this.ignoreResize(width, height)){
             var size = this.adjustForComponents(width, height);
@@ -54840,7 +55959,7 @@ Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
     
     /**
      * Returns the nested BorderLayout for this panel
-     * @return {Roo.BorderLayout} 
+     * @return {Roo.BorderLayout}
      */
     getLayout : function(){
         return this.layout;
@@ -54939,19 +56058,15 @@ Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
 
 
 
-
-
-
-
-
-
 /**
  * @class Roo.TreePanel
  * @extends Roo.ContentPanel
+ * @parent Roo.BorderLayout Roo.LayoutDialog builder
+ * Treepanel component
+ * 
  * @constructor
  * Create a new TreePanel. - defaults to fit/scoll contents.
  * @param {String/Object} config A string to set only the panel's title, or a config object
- * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
  */
 Roo.TreePanel = function(config){
     var el = config.el;
@@ -54994,19 +56109,13 @@ Roo.TreePanel = function(config){
 
 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {   
     fitToFrame : true,
-    autoScroll : true
-});
-
-
-
-
-
-
-
-
-
-
+    autoScroll : true,
+    /*
+     * @cfg {Roo.tree.TreePanel} tree [required] The tree TreePanel, with config etc.
+     */
+    tree : false
 
+});
 /*
  * Based on:
  * Ext JS Library 1.1.1
@@ -55435,6 +56544,21 @@ Roo.grid.Grid = function(container, config){
 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
     
     /**
+        * @cfg {Roo.grid.AbstractSelectionModel} sm The selection Model (default = Roo.grid.RowSelectionModel)
+        */
+       /**
+        * @cfg {Roo.grid.GridView} view  The view that renders the grid (default = Roo.grid.GridView)
+        */
+       /**
+        * @cfg {Roo.grid.ColumnModel} cm[] The columns of the grid
+        */
+       /**
+        * @cfg {Roo.grid.Store} ds The data store for the grid
+        */
+       /**
+        * @cfg {Roo.Toolbar} toolbar a toolbar for buttons etc.
+        */
+       /**
      * @cfg {String} ddGroup - drag drop group.
      */
       /**
@@ -55540,8 +56664,10 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
     * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
     */
     dropTarget: false,
-    
-   
+     /**
+    * @cfg {boolean} sortColMenu Sort the column order menu when it shows (usefull for long lists..) default false
+    */ 
+    sortColMenu : false,
     
     // private
     rendered : false,
@@ -55900,7 +57026,13 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
  * Fork - LGPL
  * <script type="text/javascript">
  */
+ /**
+ * @class Roo.grid.AbstractGridView
+ * @extends Roo.util.Observable
+ * @abstract
+ * Abstract base class for grid Views
+ * @constructor
+ */
 Roo.grid.AbstractGridView = function(){
        this.grid = null;
        
@@ -57597,13 +58729,28 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
     beforeColMenuShow : function(){
         var cm = this.cm,  colCount = cm.getColumnCount();
         this.colMenu.removeAll();
+        
+        var items = [];
         for(var i = 0; i < colCount; i++){
-            this.colMenu.add(new Roo.menu.CheckItem({
+            items.push({
                 id: "col-"+cm.getColumnId(i),
                 text: cm.getColumnHeader(i),
                 checked: !cm.isHidden(i),
                 hideOnClick:false
-            }));
+            });
+        }
+        
+        if (this.grid.sortColMenu) {
+            items.sort(function(a,b) {
+                if (a.text == b.text) {
+                    return 0;
+                }
+                return a.text.toUpperCase() > b.text.toUpperCase() ? 1 : -1;
+            });
+        }
+        
+        for(var i = 0; i < colCount; i++){
+            this.colMenu.add(new Roo.menu.CheckItem(items[i]));
         }
     },
 
@@ -57958,19 +59105,34 @@ Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
  * Fork - LGPL
  * <script type="text/javascript">
  */
+ /**
+ * @extends Roo.dd.DDProxy
+ * @class Roo.grid.SplitDragZone
+ * Support for Column Header resizing
+ * @constructor
+ * @param {Object} config
+ */
 // private
 // This is a support class used internally by the Grid components
 Roo.grid.SplitDragZone = function(grid, hd, hd2){
     this.grid = grid;
     this.view = grid.getView();
     this.proxy = this.view.resizeProxy;
-    Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
-        "gridSplitters" + this.grid.getGridEl().id, {
-        dragElId : Roo.id(this.proxy.dom), resizeFrame:false
-    });
+    Roo.grid.SplitDragZone.superclass.constructor.call(
+        this,
+        hd, // ID
+        "gridSplitters" + this.grid.getGridEl().id, // SGROUP
+        {  // CONFIG
+            dragElId : Roo.id(this.proxy.dom),
+            resizeFrame:false
+        }
+    );
+    
     this.setHandleElId(Roo.id(hd));
-    this.setOuterHandleElId(Roo.id(hd2));
+    if (hd2 !== false) {
+        this.setOuterHandleElId(Roo.id(hd2));
+    }
+    
     this.scroll = false;
 };
 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
@@ -57978,8 +59140,25 @@ Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
 
     b4StartDrag : function(x, y){
         this.view.headersDisabled = true;
-        this.proxy.setHeight(this.view.mainWrap.getHeight());
+        var h = this.view.mainWrap ? this.view.mainWrap.getHeight() : (
+                    this.view.headEl.getHeight() + this.view.bodyEl.getHeight()
+        );
+        this.proxy.setHeight(h);
+        
+        // for old system colWidth really stored the actual width?
+        // in bootstrap we tried using xs/ms/etc.. to do % sizing?
+        // which in reality did not work.. - it worked only for fixed sizes
+        // for resizable we need to use actual sizes.
         var w = this.cm.getColumnWidth(this.cellIndex);
+        if (!this.view.mainWrap) {
+            // bootstrap.
+            w = this.view.getHeaderIndex(this.cellIndex).getWidth();
+        }
+        
+        
+        
+        // this was w-this.grid.minColumnWidth;
+        // doesnt really make sense? - w = thie curren width or the rendered one?
         var minw = Math.max(w-this.grid.minColumnWidth, 0);
         this.resetConstraints();
         this.setXConstraint(minw, 1000);
@@ -57987,6 +59166,10 @@ Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
         this.minX = x - minw;
         this.maxX = x + 1000;
         this.startPos = x;
+        if (!this.view.mainWrap) { // this is Bootstrap code..
+            this.getDragEl().style.display='block';
+        }
+        
         Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
     },
 
@@ -58008,7 +59191,12 @@ Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
         this.view.headersDisabled = false;
         var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
         var diff = endX - this.startPos;
-        this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
+        // 
+        var w = this.cm.getColumnWidth(this.cellIndex);
+        if (!this.view.mainWrap) {
+            w = 0;
+        }
+        this.view.onColumnSplitterMoved(this.cellIndex, w+diff);
     },
 
     autoOffset : function(){
@@ -58161,30 +59349,15 @@ Roo.grid.ColumnModel = function(config){
        /**
      * The config passed into the constructor
      */
-    this.config = config;
+    this.config = []; //config;
     this.lookup = {};
 
     // if no id, create one
     // if the column does not have a dataIndex mapping,
     // map it to the order it is in the config
     for(var i = 0, len = config.length; i < len; i++){
-        var c = config[i];
-        if(typeof c.dataIndex == "undefined"){
-            c.dataIndex = i;
-        }
-        if(typeof c.renderer == "string"){
-            c.renderer = Roo.util.Format[c.renderer];
-        }
-        if(typeof c.id == "undefined"){
-            c.id = Roo.id();
-        }
-        if(c.editor && c.editor.xtype){
-            c.editor  = Roo.factory(c.editor, Roo.grid);
-        }
-        if(c.editor && c.editor.isFormField){
-            c.editor = new Roo.grid.GridEditor(c.editor);
-        }
-        this.lookup[c.id] = c;
+       this.addColumn(config[i]);
+       
     }
 
     /**
@@ -58246,6 +59419,21 @@ Roo.grid.ColumnModel = function(config){
 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     /**
      * @cfg {String} header The header text to display in the Grid view.
+     */
+       /**
+     * @cfg {String} xsHeader Header at Bootsrap Extra Small width (default for all)
+     */
+       /**
+     * @cfg {String} smHeader Header at Bootsrap Small width
+     */
+       /**
+     * @cfg {String} mdHeader Header at Bootsrap Medium width
+     */
+       /**
+     * @cfg {String} lgHeader Header at Bootsrap Large width
+     */
+       /**
+     * @cfg {String} xlHeader Header at Bootsrap extra Large width
      */
     /**
      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
@@ -58295,16 +59483,19 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
      * @cfg {String} tooltip (Optional)
      */
     /**
-     * @cfg {Number} xs (Optional)
+     * @cfg {Number} xs (Optional) can be '0' for hidden at this size (number less than 12)
      */
     /**
-     * @cfg {Number} sm (Optional)
+     * @cfg {Number} sm (Optional) can be '0' for hidden at this size (number less than 12)
      */
     /**
-     * @cfg {Number} md (Optional)
+     * @cfg {Number} md (Optional) can be '0' for hidden at this size (number less than 12)
      */
     /**
-     * @cfg {Number} lg (Optional)
+     * @cfg {Number} lg (Optional) can be '0' for hidden at this size (number less than 12)
+     */
+       /**
+     * @cfg {Number} xl (Optional) can be '0' for hidden at this size (number less than 12)
      */
     /**
      * Returns the id of the column at the specified index.
@@ -58326,7 +59517,7 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
 
     
     /**
-     * Returns the column for a specified dataIndex.
+     * Returns the column Object for a specified dataIndex.
      * @param {String} dataIndex The column dataIndex
      * @return {Object|Boolean} the column or false if not found
      */
@@ -58487,10 +59678,29 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     /**
      * Returns the width for the specified column.
      * @param {Number} col The column index
+     * @param (optional) {String} gridSize bootstrap width size.
      * @return {Number}
      */
-    getColumnWidth : function(col){
-        return this.config[col].width * 1 || this.defaultWidth;
+    getColumnWidth : function(col, gridSize)
+       {
+               var cfg = this.config[col];
+               
+               if (typeof(gridSize) == 'undefined') {
+                       return cfg.width * 1 || this.defaultWidth;
+               }
+               if (gridSize === false) { // if we set it..
+                       return cfg.width || false;
+               }
+               var sizes = ['xl', 'lg', 'md', 'sm', 'xs'];
+               
+               for(var i = sizes.indexOf(gridSize); i < sizes.length; i++) {
+                       if (typeof(cfg[ sizes[i] ] ) == 'undefined') {
+                               continue;
+                       }
+                       return cfg[ sizes[i] ];
+               }
+               return 1;
+               
     },
 
     /**
@@ -58652,7 +59862,35 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
      */
     setEditor : function(col, editor){
         this.config[col].editor = editor;
+    },
+    /**
+     * Add a column (experimental...) - defaults to adding to the end..
+     * @param {Object} config 
+    */
+    addColumn : function(c)
+    {
+    
+       var i = this.config.length;
+       this.config[i] = c;
+       
+       if(typeof c.dataIndex == "undefined"){
+            c.dataIndex = i;
+        }
+        if(typeof c.renderer == "string"){
+            c.renderer = Roo.util.Format[c.renderer];
+        }
+        if(typeof c.id == "undefined"){
+            c.id = Roo.id();
+        }
+        if(c.editor && c.editor.xtype){
+            c.editor  = Roo.factory(c.editor, Roo.grid);
+        }
+        if(c.editor && c.editor.isFormField){
+            c.editor = new Roo.grid.GridEditor(c.editor);
+        }
+        this.lookup[c.id] = c;
     }
+    
 });
 
 Roo.grid.ColumnModel.defaultRenderer = function(value)
@@ -58683,6 +59921,7 @@ Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
 /**
  * @class Roo.grid.AbstractSelectionModel
  * @extends Roo.util.Observable
+ * @abstract
  * Abstract base class for grid SelectionModels.  It provides the interface that should be
  * implemented by descendant classes.  This class should not be directly instantiated.
  * @constructor
@@ -58749,39 +59988,39 @@ Roo.grid.RowSelectionModel = function(config){
 
     this.addEvents({
         /**
-            * @event selectionchange
-            * Fires when the selection changes
-            * @param {SelectionModel} this
-            */
-           "selectionchange" : true,
-        /**
-            * @event afterselectionchange
-            * Fires after the selection changes (eg. by key press or clicking)
-            * @param {SelectionModel} this
-            */
-           "afterselectionchange" : true,
-        /**
-            * @event beforerowselect
-            * Fires when a row is selected being selected, return false to cancel.
-            * @param {SelectionModel} this
-            * @param {Number} rowIndex The selected index
-            * @param {Boolean} keepExisting False if other selections will be cleared
-            */
-           "beforerowselect" : true,
-        /**
-            * @event rowselect
-            * Fires when a row is selected.
-            * @param {SelectionModel} this
-            * @param {Number} rowIndex The selected index
-            * @param {Roo.data.Record} r The record
-            */
-           "rowselect" : true,
-        /**
-            * @event rowdeselect
-            * Fires when a row is deselected.
-            * @param {SelectionModel} this
-            * @param {Number} rowIndex The selected index
-            */
+        * @event selectionchange
+        * Fires when the selection changes
+        * @param {SelectionModel} this
+        */
+       "selectionchange" : true,
+       /**
+        * @event afterselectionchange
+        * Fires after the selection changes (eg. by key press or clicking)
+        * @param {SelectionModel} this
+        */
+       "afterselectionchange" : true,
+       /**
+        * @event beforerowselect
+        * Fires when a row is selected being selected, return false to cancel.
+        * @param {SelectionModel} this
+        * @param {Number} rowIndex The selected index
+        * @param {Boolean} keepExisting False if other selections will be cleared
+        */
+       "beforerowselect" : true,
+       /**
+        * @event rowselect
+        * Fires when a row is selected.
+        * @param {SelectionModel} this
+        * @param {Number} rowIndex The selected index
+        * @param {Roo.data.Record} r The record
+        */
+       "rowselect" : true,
+       /**
+        * @event rowdeselect
+        * Fires when a row is deselected.
+        * @param {SelectionModel} this
+        * @param {Number} rowIndex The selected index
+        */
         "rowdeselect" : true
     });
     Roo.grid.RowSelectionModel.superclass.constructor.call(this);
@@ -58803,7 +60042,8 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
         }else{ // allow click to work like normal
             this.grid.on("rowclick", this.handleDragableRowClick, this);
         }
-
+        // bootstrap does not have a view..
+        var view = this.grid.view ? this.grid.view : this.grid;
         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
             "up" : function(e){
                 if(!e.shiftKey){
@@ -58811,7 +60051,7 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
                 }else if(this.last !== false && this.lastActive !== false){
                     var last = this.last;
                     this.selectRange(this.last,  this.lastActive-1);
-                    this.grid.getView().focusRow(this.lastActive);
+                    view.focusRow(this.lastActive);
                     if(last !== false){
                         this.last = last;
                     }
@@ -58826,7 +60066,7 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
                 }else if(this.last !== false && this.lastActive !== false){
                     var last = this.last;
                     this.selectRange(this.last,  this.lastActive+1);
-                    this.grid.getView().focusRow(this.lastActive);
+                    view.focusRow(this.lastActive);
                     if(last !== false){
                         this.last = last;
                     }
@@ -58838,7 +60078,7 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
             scope: this
         });
 
-        var view = this.grid.view;
+         
         view.on("refresh", this.onRefresh, this);
         view.on("rowupdated", this.onRowUpdated, this);
         view.on("rowremoved", this.onRemove, this);
@@ -58846,7 +60086,7 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
 
     // private
     onRefresh : function(){
-        var ds = this.grid.dataSource, i, v = this.grid.view;
+        var ds = this.grid.ds, i, v = this.grid.view;
         var s = this.selections;
         s.each(function(r){
             if((i = ds.indexOfId(r.id)) != -1){
@@ -58879,7 +60119,7 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
         if(!keepExisting){
             this.clearSelections();
         }
-        var ds = this.grid.dataSource;
+        var ds = this.grid.ds;
         for(var i = 0, len = records.length; i < len; i++){
             this.selectRow(ds.indexOf(records[i]), true);
         }
@@ -58905,7 +60145,7 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
      * @param {Boolean} keepExisting (optional) True to keep existing selections
      */
     selectLastRow : function(keepExisting){
-        this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
+        this.selectRow(this.grid.ds.getCount() - 1, keepExisting);
     },
 
     /**
@@ -58913,9 +60153,10 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
      * @param {Boolean} keepExisting (optional) True to keep existing selections
      */
     selectNext : function(keepExisting){
-        if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
+        if(this.last !== false && (this.last+1) < this.grid.ds.getCount()){
             this.selectRow(this.last+1, keepExisting);
-            this.grid.getView().focusRow(this.last);
+            var view = this.grid.view ? this.grid.view : this.grid;
+            view.focusRow(this.last);
         }
     },
 
@@ -58926,7 +60167,8 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
     selectPrevious : function(keepExisting){
         if(this.last){
             this.selectRow(this.last-1, keepExisting);
-            this.grid.getView().focusRow(this.last);
+            var view = this.grid.view ? this.grid.view : this.grid;
+            view.focusRow(this.last);
         }
     },
 
@@ -58955,7 +60197,7 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
             return;
         }
         if(fast !== true){
-            var ds = this.grid.dataSource;
+            var ds = this.grid.ds;
             var s = this.selections;
             s.each(function(r){
                 this.deselectRow(ds.indexOfId(r.id));
@@ -58976,7 +60218,7 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
             return;
         }
         this.selections.clear();
-        for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
+        for(var i = 0, len = this.grid.ds.getCount(); i < len; i++){
             this.selectRow(i, true);
         }
     },
@@ -58995,7 +60237,7 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
      * @return {Boolean}
      */
     isSelected : function(index){
-        var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
+        var r = typeof index == "number" ? this.grid.ds.getAt(index) : index;
         return (r && this.selections.key(r.id) ? true : false);
     },
 
@@ -59009,8 +60251,10 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
     },
 
     // private
-    handleMouseDown : function(e, t){
-        var view = this.grid.getView(), rowIndex;
+    handleMouseDown : function(e, t)
+    {
+        var view = this.grid.view ? this.grid.view : this.grid;
+        var rowIndex;
         if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
             return;
         };
@@ -59037,7 +60281,8 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
     {
         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
             this.selectRow(rowIndex, false);
-            grid.view.focusRow(rowIndex);
+            var view = this.grid.view ? this.grid.view : this.grid;
+            view.focusRow(rowIndex);
              this.fireEvent("afterselectionchange", this);
         }
     },
@@ -59100,18 +60345,19 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
      * @param {Boolean} keepExisting (optional) True to keep existing selections
      */
     selectRow : function(index, keepExisting, preventViewNotify){
-        if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
+        if(this.locked || (index < 0 || index >= this.grid.ds.getCount())) {
             return;
         }
         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
             if(!keepExisting || this.singleSelect){
                 this.clearSelections();
             }
-            var r = this.grid.dataSource.getAt(index);
+            var r = this.grid.ds.getAt(index);
             this.selections.add(r);
             this.last = this.lastActive = index;
             if(!preventViewNotify){
-                this.grid.getView().onRowSelect(index);
+                var view = this.grid.view ? this.grid.view : this.grid;
+                view.onRowSelect(index);
             }
             this.fireEvent("rowselect", this, index, r);
             this.fireEvent("selectionchange", this);
@@ -59132,10 +60378,11 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
         if(this.lastActive == index){
             this.lastActive = false;
         }
-        var r = this.grid.dataSource.getAt(index);
+        var r = this.grid.ds.getAt(index);
         this.selections.remove(r);
         if(!preventViewNotify){
-            this.grid.getView().onRowDeselect(index);
+            var view = this.grid.view ? this.grid.view : this.grid;
+            view.onRowDeselect(index);
         }
         this.fireEvent("rowdeselect", this, index);
         this.fireEvent("selectionchange", this);
@@ -60034,7 +61281,7 @@ Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
  
 /**
  * @class Roo.grid.Calendar
- * @extends Roo.util.Grid
+ * @extends Roo.grid.Grid
  * This class extends the Grid to provide a calendar widget
  * <br><br>Usage:<pre><code>
  var grid = new Roo.grid.Calendar("my-container-id", {
@@ -61349,6 +62596,7 @@ Roo.LoadMask.prototype = {
      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
      */
+    removeMask : false,
     /**
      * @cfg {String} msg
      * The text to display in a centered loading message box (defaults to 'Loading...')