fix broken commit
[roojs1] / roojs-debug.js
index b1268dc..e8dd42b 100644 (file)
@@ -19,7 +19,7 @@ window["undefined"] = window["undefined"];
 /**
  * @class Roo
  * Roo core utilities and functions.
- * @singleton
+ * @static
  */
 var Roo = {}; 
 /**
@@ -505,15 +505,18 @@ Roo.factory(conf, Roo.data);
             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
         },
 
-        // internal
-        callback : function(cb, scope, args, delay){
-            if(typeof cb == "function"){
-                if(delay){
-                    cb.defer(delay, scope, args || []);
-                }else{
-                    cb.apply(scope, args || []);
-                }
+        // internal (non-delayed, will get a return value..)
+        callback : function(cb, scope, args, delay)
+               {
+            if(typeof cb != "function"){
+                               return false;
+                       }
+                       if(delay){
+                               cb.defer(delay, scope, args || []);
+                               return false
             }
+                       return cb.apply(scope, args || []);
+
         },
 
         /**
@@ -668,7 +671,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 +703,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 +957,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
@@ -1015,12 +1050,58 @@ Roo.applyIf(Array.prototype, {
         }
 
         return res;
-    }
+    },
+    /**
+     * equals
+     * @param {Array} o The array to compare to
+     * @returns {Boolean} true if the same
+     */
+    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());
+          
+        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;
+      
+    }
+});
 /*
  * Based on:
  * Ext JS Library 1.1.1
@@ -1127,12 +1208,35 @@ document.write(dt.format(Date.patterns.ShortDate));
 /**
  Returns the number of milliseconds between this date and date
  @param {Date} date (optional) Defaults to now
- @return {Number} The diff in milliseconds
+ @param {String} interval (optional) Default Date.MILLI, A valid date interval enum value (eg. Date.DAY) 
+ @return {Number} The diff in milliseconds or units of interval
  @member Date getElapsed
  */
-Date.prototype.getElapsed = function(date) {
-       return Math.abs((date || new Date()).getTime()-this.getTime());
+Date.prototype.getElapsed = function(date, interval)
+{
+    date = date ||  new Date();
+    var ret = Math.abs(date.getTime()-this.getTime());
+    switch (interval) {
+       
+        case  Date.SECOND:
+            return Math.floor(ret / (1000));
+        case  Date.MINUTE:
+            return Math.floor(ret / (1000*60));
+        case  Date.HOUR:
+            return Math.floor(ret / (1000*60*60));
+        case  Date.DAY:
+            return Math.floor(ret / (1000*60*60*24));
+        case  Date.MONTH: // this does not give exact number...??
+            return ((date.format("Y") - this.format("Y")) * 12) + (date.format("m") - this.format("m"));
+        case  Date.YEAR: // this does not give exact number...??
+            return (date.format("Y") - this.format("Y"));
+       
+        case  Date.MILLI:
+        default:
+            return ret;
+    }
 };
 // was in date file..
 
 
@@ -1324,17 +1428,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
@@ -1394,7 +1498,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,
@@ -1829,22 +1933,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 = {
@@ -1865,17 +1960,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;
@@ -1888,7 +1992,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;
@@ -2552,18 +2659,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 = {
@@ -2589,7 +2698,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]);
@@ -3611,7 +3726,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:
@@ -4142,7 +4933,468 @@ Roo.lib.Easing = {
             }
         };
     })();
-/*
+/**
+ * Originally based of this code... - refactored for Roo...
+ * https://github.com/aaalsaleh/undo-manager
+ * undo-manager.js
+ * @author  Abdulrahman Alsaleh 
+ * @copyright 2015 Abdulrahman Alsaleh 
+ * @license  MIT License (c) 
+ *
+ * Hackily modifyed by alan@roojs.com
+ *
+ *
+ *  
+ *
+ *  TOTALLY UNTESTED...
+ *
+ *  Documentation to be done....
+ */
+
+/**
+* @class Roo.lib.UndoManager
+* An undo manager implementation in JavaScript. It follows the W3C UndoManager and DOM Transaction
+* Draft and the undocumented and disabled Mozilla Firefox's UndoManager implementation.
+
+ * Usage:
+ * <pre><code>
+
+
+editor.undoManager = new Roo.lib.UndoManager(1000, editor);
+</code></pre>
+
+* For more information see this blog post with examples:
+*  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
+     - Create Elements using DOM, HTML fragments and Templates</a>. 
+* @constructor
+* @param {Number} limit how far back to go ... use 1000?
+* @param {Object} scope usually use document..
+*/
+
+Roo.lib.UndoManager = function (limit, undoScopeHost)
+{
+    this.stack = [];
+    this.limit = limit;
+    this.scope = undoScopeHost;
+    this.fireEvent = typeof CustomEvent != 'undefined' && undoScopeHost && undoScopeHost.dispatchEvent;
+    if (this.fireEvent) {
+        this.bindEvents();
+    }
+    this.reset();
+    
+};
+        
+Roo.lib.UndoManager.prototype = {
+    
+    limit : false,
+    stack : false,
+    scope :  false,
+    fireEvent : false,
+    position : 0,
+    length : 0,
+    
+    
+     /**
+     * To push and execute a transaction, the method undoManager.transact
+     * must be called by passing a transaction object as the first argument, and a merge
+     * flag as the second argument. A transaction object has the following properties:
+     *
+     * Usage:
+<pre><code>
+undoManager.transact({
+    label: 'Typing',
+    execute: function() { ... },
+    undo: function() { ... },
+    // redo same as execute
+    redo: function() { this.execute(); }
+}, false);
+
+// merge transaction
+undoManager.transact({
+    label: 'Typing',
+    execute: function() { ... },  // this will be run...
+    undo: function() { ... }, // what to do when undo is run.
+    // redo same as execute
+    redo: function() { this.execute(); }
+}, true); 
+</code></pre> 
+     *
+     * 
+     * @param {Object} transaction The transaction to add to the stack.
+     * @return {String} The HTML fragment
+     */
+    
+    
+    transact : function (transaction, merge)
+    {
+        if (arguments.length < 2) {
+            throw new TypeError('Not enough arguments to UndoManager.transact.');
+        }
+
+        transaction.execute();
+
+        this.stack.splice(0, this.position);
+        if (merge && this.length) {
+            this.stack[0].push(transaction);
+        } else {
+            this.stack.unshift([transaction]);
+        }
+    
+        this.position = 0;
+
+        if (this.limit && this.stack.length > this.limit) {
+            this.length = this.stack.length = this.limit;
+        } else {
+            this.length = this.stack.length;
+        }
+
+        if (this.fireEvent) {
+            this.scope.dispatchEvent(
+                new CustomEvent('DOMTransaction', {
+                    detail: {
+                        transactions: this.stack[0].slice()
+                    },
+                    bubbles: true,
+                    cancelable: false
+                })
+            );
+        }
+        
+        //Roo.log("transaction: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
+      
+        
+    },
+
+    undo : function ()
+    {
+        //Roo.log("undo: pos:" + this.position + " len: " + this.length + " slen:" + this.stack.length);
+        
+        if (this.position < this.length) {
+            for (var i = this.stack[this.position].length - 1; i >= 0; i--) {
+                this.stack[this.position][i].undo();
+            }
+            this.position++;
+
+            if (this.fireEvent) {
+                this.scope.dispatchEvent(
+                    new CustomEvent('undo', {
+                        detail: {
+                            transactions: this.stack[this.position - 1].slice()
+                        },
+                        bubbles: true,
+                        cancelable: false
+                    })
+                );
+            }
+        }
+    },
+
+    redo : function ()
+    {
+        if (this.position > 0) {
+            for (var i = 0, n = this.stack[this.position - 1].length; i < n; i++) {
+                this.stack[this.position - 1][i].redo();
+            }
+            this.position--;
+
+            if (this.fireEvent) {
+                this.scope.dispatchEvent(
+                    new CustomEvent('redo', {
+                        detail: {
+                            transactions: this.stack[this.position].slice()
+                        },
+                        bubbles: true,
+                        cancelable: false
+                    })
+                );
+            }
+        }
+    },
+
+    item : function (index)
+    {
+        if (index >= 0 && index < this.length) {
+            return this.stack[index].slice();
+        }
+        return null;
+    },
+
+    clearUndo : function () {
+        this.stack.length = this.length = this.position;
+    },
+
+    clearRedo : function () {
+        this.stack.splice(0, this.position);
+        this.position = 0;
+        this.length = this.stack.length;
+    },
+    /**
+     * Reset the undo - probaly done on load to clear all history.
+     */
+    reset : function()
+    {
+        this.stack = [];
+        this.position = 0;
+        this.length = 0;
+        this.current_html = this.scope.innerHTML;
+        if (this.timer !== false) {
+            clearTimeout(this.timer);
+        }
+        this.timer = false;
+        this.merge = false;
+        this.addEvent();
+        
+    },
+    current_html : '',
+    timer : false,
+    merge : false,
+    
+    
+    // this will handle the undo/redo on the element.?
+    bindEvents : function()
+    {
+        var el  = this.scope;
+        el.undoManager = this;
+        
+        
+        this.scope.addEventListener('keydown', function(e) {
+            if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
+                if (e.shiftKey) {
+                    el.undoManager.redo(); // Ctrl/Command + Shift + Z
+                } else {
+                    el.undoManager.undo(); // Ctrl/Command + Z
+                }
+        
+                e.preventDefault();
+            }
+        });
+        /// ignore keyup..
+        this.scope.addEventListener('keyup', function(e) {
+            if ((e.ctrlKey || e.metaKey) && e.keyCode === 90) {
+                e.preventDefault();
+            }
+        });
+        
+        
+        
+        var t = this;
+        
+        el.addEventListener('input', function(e) {
+            if(el.innerHTML == t.current_html) {
+                return;
+            }
+            // only record events every second.
+            if (t.timer !== false) {
+               clearTimeout(t.timer);
+               t.timer = false;
+            }
+            t.timer = setTimeout(function() { t.merge = false; }, 1000);
+            
+            t.addEvent(t.merge);
+            t.merge = true; // ignore changes happening every second..
+        });
+       },
+    /**
+     * Manually add an event.
+     * Normall called without arguements - and it will just get added to the stack.
+     * 
+     */
+    
+    addEvent : function(merge)
+    {
+        //Roo.log("undomanager +" + (merge ? 'Y':'n'));
+        // not sure if this should clear the timer 
+        merge = typeof(merge) == 'undefined' ? false : merge; 
+        
+        this.scope.undoManager.transact({
+            scope : this.scope,
+            oldHTML: this.current_html,
+            newHTML: this.scope.innerHTML,
+            // nothing to execute (content already changed when input is fired)
+            execute: function() { },
+            undo: function() {
+                this.scope.innerHTML = this.current_html = this.oldHTML;
+            },
+            redo: function() {
+                this.scope.innerHTML = this.current_html = this.newHTML;
+            }
+        }, false); //merge);
+        
+        this.merge = merge;
+        
+        this.current_html = this.scope.innerHTML;
+    }
+    
+    
+     
+    
+    
+    
+};
+/**
+ * @class Roo.lib.Range
+ * @constructor
+ * This is a toolkit, normally used to copy features into a Dom Range element
+ * Roo.lib.Range.wrap(x);
+ *
+ *
+ *
+ */
+Roo.lib.Range = function() { };
+
+/**
+ * Wrap a Dom Range object, to give it new features...
+ * @static
+ * @param {Range} the range to wrap
+ */
+Roo.lib.Range.wrap = function(r) {
+    return Roo.apply(r, Roo.lib.Range.prototype);
+};
+/**
+ * find a parent node eg. LI / OL
+ * @param {string|Array} node name or array of nodenames
+ * @return {DomElement|false}
+ */
+Roo.apply(Roo.lib.Range.prototype,
+{
+    
+    closest : function(str)
+    {
+        if (typeof(str) != 'string') {
+            // assume it's a array.
+            for(var i = 0;i < str.length;i++) {
+                var r = this.closest(str[i]);
+                if (r !== false) {
+                    return r;
+                }
+                
+            }
+            return false;
+        }
+        str = str.toLowerCase();
+        var n = this.commonAncestorContainer; // might not be a node
+        while (n.nodeType != 1) {
+            n = n.parentNode;
+        }
+        
+        if (n.nodeName.toLowerCase() == str ) {
+            return n;
+        }
+        if (n.nodeName.toLowerCase() == 'body') {
+            return false;
+        }
+            
+        return n.closest(str) || false;
+        
+    },
+    cloneRange : function()
+    {
+        return Roo.lib.Range.wrap(Range.prototype.cloneRange.call(this));
+    }
+});/**
+ * @class Roo.lib.Selection
+ * @constructor
+ * This is a toolkit, normally used to copy features into a Dom Selection element
+ * Roo.lib.Selection.wrap(x);
+ *
+ *
+ *
+ */
+Roo.lib.Selection = function() { };
+
+/**
+ * Wrap a Dom Range object, to give it new features...
+ * @static
+ * @param {Range} the range to wrap
+ */
+Roo.lib.Selection.wrap = function(r, doc) {
+    Roo.apply(r, Roo.lib.Selection.prototype);
+    r.ownerDocument = doc; // usefull so we dont have to keep referening to it.
+    return r;
+};
+/**
+ * find a parent node eg. LI / OL
+ * @param {string|Array} node name or array of nodenames
+ * @return {DomElement|false}
+ */
+Roo.apply(Roo.lib.Selection.prototype,
+{
+    /**
+     * the owner document
+     */
+    ownerDocument : false,
+    
+    getRangeAt : function(n)
+    {
+        return Roo.lib.Range.wrap(Selection.prototype.getRangeAt.call(this,n));
+    },
+    
+    /**
+     * insert node at selection 
+     * @param {DomElement|string} node
+     * @param {string} cursor (after|in|none) where to place the cursor after inserting.
+     */
+    insertNode: function(node, cursor)
+    {
+        if (typeof(node) == 'string') {
+            node = this.ownerDocument.createElement(node);
+            if (cursor == 'in') {
+                node.innerHTML = '&nbsp;';
+            }
+        }
+        
+        var range = this.getRangeAt(0);
+        
+        if (this.type != 'Caret') {
+            range.deleteContents();
+        }
+        var sn = node.childNodes[0]; // select the contents.
+
+        
+        
+        range.insertNode(node);
+        if (cursor == 'after') {
+            node.insertAdjacentHTML('afterend', '&nbsp;');
+            sn = node.nextSibling;
+        }
+        
+        if (cursor == 'none') {
+            return;
+        }
+        
+        this.cursorText(sn);
+    },
+    
+    cursorText : function(n)
+    {
+       
+        //var range = this.getRangeAt(0);
+        range = Roo.lib.Range.wrap(new Range());
+        //range.selectNode(n);
+        
+        var ix = Array.from(n.parentNode.childNodes).indexOf(n);
+        range.setStart(n.parentNode,ix);
+        range.setEnd(n.parentNode,ix+1);
+        //range.collapse(false);
+         
+        this.removeAllRanges();
+        this.addRange(range);
+        
+        Roo.log([n, range, this,this.baseOffset,this.extentOffset, this.type]);
+    },
+    cursorAfter : function(n)
+    {
+        if (!n.nextSibling || n.nextSibling.nodeValue != '&nbsp;') {
+            n.insertAdjacentHTML('afterend', '&nbsp;');
+        }
+        this.cursorText (n.nextSibling);
+    }
+        
+    
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -4173,7 +5425,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;
@@ -4264,7 +5516,7 @@ Roo.DomHelper = function(){
         if (typeof(o) == 'string') {
             return parentNode.appendChild(document.createTextNode(o));
         }
-        o.tag = o.tag || div;
+        o.tag = o.tag || 'div';
         if (o.ns && Roo.isIE) {
             ns = false;
             o.tag = o.ns + ':' + o.tag;
@@ -4310,7 +5562,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;
@@ -4389,212 +5641,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);
-    }
+        
     };
 }();
 /*
@@ -4652,6 +6012,12 @@ Roo.Template = function(cfg){
 };
 Roo.Template.prototype = {
     
+    /**
+     * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
+     */
+    onLoad : false,
+    
+    
     /**
      * @cfg {String} url  The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
      *                    it should be fixed so that template is observable...
@@ -4661,12 +6027,20 @@ Roo.Template.prototype = {
      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
      */
     html : '',
+    
+    
+    compiled : false,
+    loaded : false,
     /**
      * Returns an HTML fragment of this template with the specified values applied.
      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
      * @return {String} The HTML fragment
      */
+    
+   
+    
     applyTemplate : function(values){
+        //Roo.log(["applyTemplate", values]);
         try {
            
             if(this.compiled){
@@ -4725,9 +6099,13 @@ Roo.Template.prototype = {
             method : 'GET',
             success : function (response) {
                 _t.loading = false;
-                _t.html = response.responseText;
                 _t.url = false;
-                _t.compile();
+                
+                _t.set(response.responseText,true);
+                _t.loaded = true;
+                if (_t.onLoad) {
+                    _t.onLoad();
+                }
              },
             failure : function(response) {
                 Roo.log("Template failed to load from " + _t.url);
@@ -4744,7 +6122,7 @@ Roo.Template.prototype = {
      */
     set : function(html, compile){
         this.html = html;
-        this.compiled = null;
+        this.compiled = false;
         if(compile){
             this.compile();
         }
@@ -4967,7 +6345,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 = {};
@@ -5022,7 +6400,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;
             }
         }
@@ -5040,7 +6422,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];
 
@@ -5144,7 +6526,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"){
@@ -5905,12 +7287,15 @@ Roo.util.Observable.prototype = {
     relayEvents : function(o, events){
         var createHandler = function(ename){
             return function(){
+                
                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
             };
         };
         for(var i = 0, len = events.length; i < len; i++){
             var ename = events[i];
-            if(!this.events[ename]){ this.events[ename] = true; };
+            if(!this.events[ename]){
+               this.events[ename] = true;
+           };
             o.on(ename, createHandler(ename), this);
         }
     },
@@ -6073,10 +7458,10 @@ Roo.util.Observable.releaseCapture = function(o){
             var ls = this.listeners, scope, len = ls.length;
             if(len > 0){
                 this.firing = true;
-                var args = Array.prototype.slice.call(arguments, 0);
+               var args = Array.prototype.slice.call(arguments, 0);                
                 for(var i = 0; i < len; i++){
-                    var l = ls[i];
-                    if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
+                   var l = ls[i];
+                    if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
                         this.firing = false;
                         return false;
                     }
@@ -6147,7 +7532,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;
@@ -6255,8 +7640,10 @@ 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);
@@ -6313,7 +7700,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(){
@@ -6499,16 +7888,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());
                     }
                 });
@@ -6705,7 +8096,7 @@ Roo.onReady(function(){
  Roo.EventManager.on("myDiv", 'click', handleClick);
  Roo.EventManager.addListener("myDiv", 'click', handleClick);
  </code></pre>
- * @singleton
+ * @static
  */
 Roo.EventObject = function(){
     
@@ -7098,9 +8489,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;
         }
@@ -7120,18 +8515,22 @@ if(opt.anim.isAnimated()){
          * @type String
          */
         this.id = id || Roo.id(dom);
+        
+        return this; // assumed for cctor?
     };
 
     var El = Roo.Element;
 
     El.prototype = {
         /**
-         * The element's default display mode  (defaults to "")
+         * The element's default display mode  (defaults to "") 
          * @type String
          */
         originalDisplay : "",
 
-        visibilityMode : 1,
+        
+        // note this is overridden in BS version..
+        visibilityMode : 1, 
         /**
          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
          * @type String
@@ -7625,7 +9024,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;
@@ -7654,7 +9057,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){
@@ -7668,8 +9073,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;
@@ -7698,6 +9106,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;
         },
 
@@ -8179,20 +9590,67 @@ 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);
+        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)
+        {
+            if(!this.tapedTwice) {
+                this.tapedTwice = true;
+                var s = this;
+                setTimeout( function() {
+                    s.tapedTwice = false;
+                }, 300 );
+                return;
+            }
+            event.preventDefault();
+            var revent = new MouseEvent('dblclick',  {
+                view: window,
+                bubbles: true,
+                cancelable: true
+            });
+             
+            this.dom.dispatchEvent(revent);
+            //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;
         },
 
@@ -8202,6 +9660,7 @@ if(opt.anim.isAnimated()){
          */
         removeAllListeners : function(){
             E.purgeElement(this.dom);
+            this.listeners = {};
             return this;
         },
 
@@ -8211,6 +9670,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
@@ -8559,7 +10019,8 @@ if(opt.anim.isAnimated()){
          * @param {Array} offsets (optional) Offset the positioning by [x, y]
          * @return {Array} [x, y]
          */
-        getAlignToXY : function(el, p, o){
+        getAlignToXY : function(el, p, o)
+        {
             el = Roo.get(el);
             var d = this.dom;
             if(!el.dom){
@@ -8600,7 +10061,7 @@ if(opt.anim.isAnimated()){
                 //otherwise swap the aligned el to the opposite border of the target.
                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
-               var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
+               var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t")  );
                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
 
                var doc = document;
@@ -9114,7 +10575,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)
@@ -9314,7 +10775,7 @@ if(opt.anim.isAnimated()){
         /**
          * @private
          */
-      fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
+        fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
 
         /**
          * Sizes this element to its parent element's dimensions performing
@@ -9327,7 +10788,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'));
@@ -11615,7 +13076,7 @@ Roo.extend(Roo.data.Connection, Roo.util.Observable, {
                 var enctype = form.getAttribute("enctype");
                 
                 if (o.formData) {
-                    return this.doFormDataUpload(o,p,url);
+                    return this.doFormDataUpload(o, url);
                 }
                 
                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
@@ -11624,6 +13085,16 @@ Roo.extend(Roo.data.Connection, Roo.util.Observable, {
                 var f = Roo.lib.Ajax.serializeForm(form);
                 p = p ? (p + '&' + f) : f;
             }
+            
+            if (!o.form && o.formData) {
+                o.formData = o.formData === true ? new FormData() : o.formData;
+                for (var k in o.params) {
+                    o.formData.append(k,o.params[k]);
+                }
+                    
+                return this.doFormDataUpload(o, url);
+            }
+            
 
             var hs = o.headers;
             if(this.defaultHeaders){
@@ -11659,7 +13130,9 @@ Roo.extend(Roo.data.Connection, Roo.util.Observable, {
                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
                 p = '';
             }
+            Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
+            Roo.lib.Ajax.useDefaultHeader == true;
             return this.transId;
         }else{
             Roo.callback(o.callback, o.scope, [o, null, null]);
@@ -11799,11 +13272,17 @@ Roo.extend(Roo.data.Connection, Roo.util.Observable, {
     // this is a 'formdata version???'
     
     
-    doFormDataUpload : function(o, ps, url)
+    doFormDataUpload : function(o,  url)
     {
-        var form = Roo.getDom(o.form);
-        form.enctype = form.encoding = 'multipart/form-data';
-        var formData = o.formData === true ? new FormData(form) : o.formData;
+        var formData;
+        if (o.form) {
+            var form =  Roo.getDom(o.form);
+            form.enctype = form.encoding = 'multipart/form-data';
+            formData = o.formData === true ? new FormData(form) : o.formData;
+        } else {
+            formData = o.formData === true ? new FormData() : o.formData;
+        }
+        
       
         var cb = {
             success: this.handleResponse,
@@ -11823,7 +13302,7 @@ Roo.extend(Roo.data.Connection, Roo.util.Observable, {
 
         //Roo.lib.Ajax.defaultPostHeader = null;
         Roo.lib.Ajax.useDefaultHeader = false;
-        this.transId = Roo.lib.Ajax.request( "POST", url, cb, o.formData, o);
+        this.transId = Roo.lib.Ajax.request( "POST", url, cb,  formData, o);
         Roo.lib.Ajax.useDefaultHeader = true;
  
          
@@ -12887,7 +14366,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;
@@ -12947,6 +14431,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);
@@ -12956,12 +14446,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++){
@@ -13299,6 +14794,9 @@ mc.add(otherEl);
  * @return {Object} The item associated with the passed key.
  */
     item : function(key){
+        if (key === 'length') {
+            return null;
+        }
         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
     },
@@ -13512,7 +15010,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;
@@ -13660,7 +15158,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;
@@ -13893,7 +15391,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 = {
@@ -14065,7 +15582,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;
@@ -14408,7 +15926,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.
@@ -14801,7 +16356,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;
@@ -14838,9 +16393,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');
@@ -14854,7 +16417,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)}
          */
@@ -14868,7 +16430,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){
@@ -14880,7 +16441,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){
@@ -14889,7 +16449,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
          */
@@ -14901,7 +16460,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
          */
@@ -15082,7 +16640,7 @@ init : function(){
    var dialog = new Roo.BasicDialog(...);
    dialog.restoreState();
  </code></pre>
- * @singleton
+ * @static
  */
 Roo.state.Manager = function(){
     var provider = new Roo.state.Provider();
@@ -15240,7 +16798,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();
@@ -15433,10 +16991,17 @@ Roo.extend(Roo.Component, Roo.util.Observable, {
     /**
      * @cfg {String} actionMode 
      * which property holds the element that used for  hide() / show() / disable() / enable()
-     * default is 'el' 
+     * default is 'el' for forms you probably want to set this to fieldEl 
      */
     actionMode : "el",
 
+        /**
+     * @cfg {String} style
+     * css styles to add to component
+     * eg. text-align:right;
+     */
+    style : false,
+       
     /** @private */
     getActionEl : function(){
         return this[this.actionMode];
@@ -15731,7 +17296,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.
@@ -15998,1890 +17563,1276 @@ Roo.extend(Roo.BoxComponent, Roo.Component, {
         return {x : x, y: y};
     }
 });/*
- * Original code for Roojs - LGPL
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
  * <script type="text/javascript">
  */
+ (function(){ 
 /**
- * @class Roo.XComponent
- * A delayed Element creator...
- * Or a way to group chunks of interface together.
- * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
- *  used in conjunction with XComponent.build() it will create an instance of each element,
- *  then call addxtype() to build the User interface.
- * 
- * Mypart.xyx = new Roo.XComponent({
-
-    parent : 'Mypart.xyz', // empty == document.element.!!
-    order : '001',
-    name : 'xxxx'
-    region : 'xxxx'
-    disabled : function() {} 
-     
-    tree : function() { // return an tree of xtype declared components
-        var MODULE = this;
-        return 
-        {
-            xtype : 'NestedLayoutPanel',
-            // technicall
-        }
-     ]
- *})
- *
- *
- * It can be used to build a big heiracy, with parent etc.
- * or you can just use this to render a single compoent to a dom element
- * MYPART.render(Roo.Element | String(id) | dom_element )
- *
- *
- * Usage patterns.
- *
- * Classic Roo
- *
- * Roo is designed primarily as a single page application, so the UI build for a standard interface will
- * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
- *
- * Each sub module is expected to have a parent pointing to the class name of it's parent module.
- *
- * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
- * - if mulitple topModules exist, the last one is defined as the top module.
- *
- * Embeded Roo
- * 
- * When the top level or multiple modules are to embedded into a existing HTML page,
- * the parent element can container '#id' of the element where the module will be drawn.
- *
- * Bootstrap Roo
- *
- * Unlike classic Roo, the bootstrap tends not to be used as a single page.
- * it relies more on a include mechanism, where sub modules are included into an outer page.
- * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
- * 
- * Bootstrap Roo Included elements
- *
- * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
- * hence confusing the component builder as it thinks there are multiple top level elements. 
- *
- * String Over-ride & Translations
- *
- * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
- * and also the 'overlaying of string values - needed when different versions of the same application with different text content
- * are needed. @see Roo.XComponent.overlayString  
- * 
- * 
- * 
- * @extends Roo.util.Observable
+ * @class Roo.Layer
+ * @extends Roo.Element
+ * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
+ * automatic maintaining of shadow/shim positions.
+ * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
+ * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
+ * you can pass a string with a CSS class name. False turns off the shadow.
+ * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
+ * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
+ * @cfg {String} cls CSS class to add to the element
+ * @cfg {Number} zindex Starting z-index (defaults to 11000)
+ * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
  * @constructor
- * @param cfg {Object} configuration of component
- * 
+ * @param {Object} config An object with config options.
+ * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
  */
-Roo.XComponent = function(cfg) {
-    Roo.apply(this, cfg);
-    this.addEvents({ 
-        /**
-            * @event built
-            * Fires when this the componnt is built
-            * @param {Roo.XComponent} c the component
-            */
-        'built' : true
-        
-    });
-    this.region = this.region || 'center'; // default..
-    Roo.XComponent.register(this);
-    this.modules = false;
-    this.el = false; // where the layout goes..
-    
-    
-}
-Roo.extend(Roo.XComponent, Roo.util.Observable, {
-    /**
-     * @property el
-     * The created element (with Roo.factory())
-     * @type {Roo.Layout}
-     */
-    el  : false,
-    
-    /**
-     * @property el
-     * for BC  - use el in new code
-     * @type {Roo.Layout}
-     */
-    panel : false,
-    
-    /**
-     * @property layout
-     * for BC  - use el in new code
-     * @type {Roo.Layout}
-     */
-    layout : false,
-    
-     /**
-     * @cfg {Function|boolean} disabled
-     * If this module is disabled by some rule, return true from the funtion
-     */
-    disabled : false,
-    
-    /**
-     * @cfg {String} parent 
-     * Name of parent element which it get xtype added to..
-     */
-    parent: false,
-    
-    /**
-     * @cfg {String} order
-     * Used to set the order in which elements are created (usefull for multiple tabs)
-     */
-    
-    order : false,
-    /**
-     * @cfg {String} name
-     * String to display while loading.
-     */
-    name : false,
-    /**
-     * @cfg {String} region
-     * Region to render component to (defaults to center)
-     */
-    region : 'center',
-    
-    /**
-     * @cfg {Array} items
-     * A single item array - the first element is the root of the tree..
-     * It's done this way to stay compatible with the Xtype system...
-     */
-    items : false,
-    
-    /**
-     * @property _tree
-     * The method that retuns the tree of parts that make up this compoennt 
-     * @type {function}
-     */
-    _tree  : false,
-    
-     /**
-     * render
-     * render element to dom or tree
-     * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
-     */
-    
-    render : function(el)
-    {
-        
-        el = el || false;
-        var hp = this.parent ? 1 : 0;
-        Roo.debug &&  Roo.log(this);
-        
-        var tree = this._tree ? this._tree() : this.tree();
 
-        
-        if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
-            // if parent is a '#.....' string, then let's use that..
-            var ename = this.parent.substr(1);
-            this.parent = false;
-            Roo.debug && Roo.log(ename);
-            switch (ename) {
-                case 'bootstrap-body':
-                    if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
-                        // this is the BorderLayout standard?
-                       this.parent = { el : true };
-                       break;
-                    }
-                    if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
-                        // need to insert stuff...
-                        this.parent =  {
-                             el : new Roo.bootstrap.layout.Border({
-                                 el : document.body, 
-                     
-                                 center: {
-                                    titlebar: false,
-                                    autoScroll:false,
-                                    closeOnTab: true,
-                                    tabPosition: 'top',
-                                      //resizeTabs: true,
-                                    alwaysShowTabs: true,
-                                    hideTabs: false
-                                     //minTabWidth: 140
-                                 }
-                             })
-                        
-                         };
-                         break;
-                    }
-                         
-                    if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
-                        this.parent = { el :  new  Roo.bootstrap.Body() };
-                        Roo.debug && Roo.log("setting el to doc body");
-                         
-                    } else {
-                        throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
-                    }
-                    break;
-                case 'bootstrap':
-                    this.parent = { el : true};
-                    // fall through
-                default:
-                    el = Roo.get(ename);
-                    if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
-                        this.parent = { el : true};
-                    }
-                    
-                    break;
-            }
-                
-            
-            if (!el && !this.parent) {
-                Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
-                return;
-            }
-        }
-        
-        Roo.debug && Roo.log("EL:");
-        Roo.debug && Roo.log(el);
-        Roo.debug && Roo.log("this.parent.el:");
-        Roo.debug && Roo.log(this.parent.el);
-        
+Roo.Layer = function(config, existingEl){
+    config = config || {};
+    var dh = Roo.DomHelper;
+    var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
+    if(existingEl){
+        this.dom = Roo.getDom(existingEl);
+    }
+    if(!this.dom){
+        var o = config.dh || {tag: "div", cls: "x-layer"};
+        this.dom = dh.append(pel, o);
+    }
+    if(config.cls){
+        this.addClass(config.cls);
+    }
+    this.constrain = config.constrain !== false;
+    this.visibilityMode = Roo.Element.VISIBILITY;
+    if(config.id){
+        this.id = this.dom.id = config.id;
+    }else{
+        this.id = Roo.id(this.dom);
+    }
+    this.zindex = config.zindex || this.getZIndex();
+    this.position("absolute", this.zindex);
+    if(config.shadow){
+        this.shadowOffset = config.shadowOffset || 4;
+        this.shadow = new Roo.Shadow({
+            offset : this.shadowOffset,
+            mode : config.shadow
+        });
+    }else{
+        this.shadowOffset = 0;
+    }
+    this.useShim = config.shim !== false && Roo.useShims;
+    this.useDisplay = config.useDisplay;
+    this.hide();
+};
 
-        // altertive root elements ??? - we need a better way to indicate these.
-        var is_alt = Roo.XComponent.is_alt ||
-                    (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
-                    (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
-                    (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
-        
-        
-        
-        if (!this.parent && is_alt) {
-            //el = Roo.get(document.body);
-            this.parent = { el : true };
+var supr = Roo.Element.prototype;
+
+// shims are shared among layer to keep from having 100 iframes
+var shims = [];
+
+Roo.extend(Roo.Layer, Roo.Element, {
+
+    getZIndex : function(){
+        return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
+    },
+
+    getShim : function(){
+        if(!this.useShim){
+            return null;
         }
-            
-            
-        
-        if (!this.parent) {
-            
-            Roo.debug && Roo.log("no parent - creating one");
-            
-            el = el ? Roo.get(el) : false;     
-            
-            if (typeof(Roo.BorderLayout) == 'undefined' ) {
-                
-                this.parent =  {
-                    el : new Roo.bootstrap.layout.Border({
-                        el: el || document.body,
-                    
-                        center: {
-                            titlebar: false,
-                            autoScroll:false,
-                            closeOnTab: true,
-                            tabPosition: 'top',
-                             //resizeTabs: true,
-                            alwaysShowTabs: false,
-                            hideTabs: true,
-                            minTabWidth: 140,
-                            overflow: 'visible'
-                         }
-                     })
-                };
-            } else {
-            
-                // it's a top level one..
-                this.parent =  {
-                    el : new Roo.BorderLayout(el || document.body, {
-                        center: {
-                            titlebar: false,
-                            autoScroll:false,
-                            closeOnTab: true,
-                            tabPosition: 'top',
-                             //resizeTabs: true,
-                            alwaysShowTabs: el && hp? false :  true,
-                            hideTabs: el || !hp ? true :  false,
-                            minTabWidth: 140
-                         }
-                    })
-                };
-            }
+        if(this.shim){
+            return this.shim;
         }
-        
-        if (!this.parent.el) {
-                // probably an old style ctor, which has been disabled.
-                return;
-
+        var shim = shims.shift();
+        if(!shim){
+            shim = this.createShim();
+            shim.enableDisplayMode('block');
+            shim.dom.style.display = 'none';
+            shim.dom.style.visibility = 'visible';
         }
-               // The 'tree' method is  '_tree now' 
-            
-        tree.region = tree.region || this.region;
-        var is_body = false;
-        if (this.parent.el === true) {
-            // bootstrap... - body..
-            if (el) {
-                tree.el = el;
-            }
-            this.parent.el = Roo.factory(tree);
-            is_body = true;
+        var pn = this.dom.parentNode;
+        if(shim.dom.parentNode != pn){
+            pn.insertBefore(shim.dom, this.dom);
         }
-        
-        this.el = this.parent.el.addxtype(tree, undefined, is_body);
-        this.fireEvent('built', this);
-        
-        this.panel = this.el;
-        this.layout = this.panel.layout;
-        this.parentLayout = this.parent.layout  || false;  
-         
-    }
-    
-});
+        shim.setStyle('z-index', this.getZIndex()-2);
+        this.shim = shim;
+        return shim;
+    },
 
-Roo.apply(Roo.XComponent, {
-    /**
-     * @property  hideProgress
-     * true to disable the building progress bar.. usefull on single page renders.
-     * @type Boolean
-     */
-    hideProgress : false,
-    /**
-     * @property  buildCompleted
-     * True when the builder has completed building the interface.
-     * @type Boolean
-     */
-    buildCompleted : false,
-     
-    /**
-     * @property  topModule
-     * the upper most module - uses document.element as it's constructor.
-     * @type Object
-     */
-     
-    topModule  : false,
-      
-    /**
-     * @property  modules
-     * array of modules to be created by registration system.
-     * @type {Array} of Roo.XComponent
-     */
-    
-    modules : [],
-    /**
-     * @property  elmodules
-     * array of modules to be created by which use #ID 
-     * @type {Array} of Roo.XComponent
-     */
-     
-    elmodules : [],
+    hideShim : function(){
+        if(this.shim){
+            this.shim.setDisplayed(false);
+            shims.push(this.shim);
+            delete this.shim;
+        }
+    },
 
-     /**
-     * @property  is_alt
-     * Is an alternative Root - normally used by bootstrap or other systems,
-     *    where the top element in the tree can wrap 'body' 
-     * @type {boolean}  (default false)
-     */
-     
-    is_alt : false,
-    /**
-     * @property  build_from_html
-     * Build elements from html - used by bootstrap HTML stuff 
-     *    - this is cleared after build is completed
-     * @type {boolean}    (default false)
-     */
-     
-    build_from_html : false,
-    /**
-     * Register components to be built later.
-     *
-     * This solves the following issues
-     * - Building is not done on page load, but after an authentication process has occured.
-     * - Interface elements are registered on page load
-     * - Parent Interface elements may not be loaded before child, so this handles that..
-     * 
-     *
-     * example:
-     * 
-     * MyApp.register({
-          order : '000001',
-          module : 'Pman.Tab.projectMgr',
-          region : 'center',
-          parent : 'Pman.layout',
-          disabled : false,  // or use a function..
-        })
-     
-     * * @param {Object} details about module
-     */
-    register : function(obj) {
-               
-        Roo.XComponent.event.fireEvent('register', obj);
-        switch(typeof(obj.disabled) ) {
-                
-            case 'undefined':
-                break;
-            
-            case 'function':
-                if ( obj.disabled() ) {
-                        return;
+    disableShadow : function(){
+        if(this.shadow){
+            this.shadowDisabled = true;
+            this.shadow.hide();
+            this.lastShadowOffset = this.shadowOffset;
+            this.shadowOffset = 0;
+        }
+    },
+
+    enableShadow : function(show){
+        if(this.shadow){
+            this.shadowDisabled = false;
+            this.shadowOffset = this.lastShadowOffset;
+            delete this.lastShadowOffset;
+            if(show){
+                this.sync(true);
+            }
+        }
+    },
+
+    // private
+    // this code can execute repeatedly in milliseconds (i.e. during a drag) so
+    // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
+    sync : function(doShow){
+        var sw = this.shadow;
+        if(!this.updating && this.isVisible() && (sw || this.useShim)){
+            var sh = this.getShim();
+
+            var w = this.getWidth(),
+                h = this.getHeight();
+
+            var l = this.getLeft(true),
+                t = this.getTop(true);
+
+            if(sw && !this.shadowDisabled){
+                if(doShow && !sw.isVisible()){
+                    sw.show(this);
+                }else{
+                    sw.realign(l, t, w, h);
                 }
-                break;
-            
-            default:
-                if (obj.disabled || obj.region == '#disabled') {
-                        return;
+                if(sh){
+                    if(doShow){
+                       sh.show();
+                    }
+                    // fit the shim behind the shadow, so it is shimmed too
+                    var a = sw.adjusts, s = sh.dom.style;
+                    s.left = (Math.min(l, l+a.l))+"px";
+                    s.top = (Math.min(t, t+a.t))+"px";
+                    s.width = (w+a.w)+"px";
+                    s.height = (h+a.h)+"px";
                 }
-                break;
+            }else if(sh){
+                if(doShow){
+                   sh.show();
+                }
+                sh.setSize(w, h);
+                sh.setLeftTop(l, t);
+            }
+            
         }
-               
-        this.modules.push(obj);
-         
     },
-    /**
-     * convert a string to an object..
-     * eg. 'AAA.BBB' -> finds AAA.BBB
 
-     */
-    
-    toObject : function(str)
-    {
-        if (!str || typeof(str) == 'object') {
-            return str;
+    // private
+    destroy : function(){
+        this.hideShim();
+        if(this.shadow){
+            this.shadow.hide();
         }
-        if (str.substring(0,1) == '#') {
-            return str;
+        this.removeAllListeners();
+        var pn = this.dom.parentNode;
+        if(pn){
+            pn.removeChild(this.dom);
         }
+        Roo.Element.uncache(this.id);
+    },
 
-        var ar = str.split('.');
-        var rt, o;
-        rt = ar.shift();
-            /** eval:var:o */
-        try {
-            eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
-        } catch (e) {
-            throw "Module not found : " + str;
-        }
-        
-        if (o === false) {
-            throw "Module not found : " + str;
+    remove : function(){
+        this.destroy();
+    },
+
+    // private
+    beginUpdate : function(){
+        this.updating = true;
+    },
+
+    // private
+    endUpdate : function(){
+        this.updating = false;
+        this.sync(true);
+    },
+
+    // private
+    hideUnders : function(negOffset){
+        if(this.shadow){
+            this.shadow.hide();
         }
-        Roo.each(ar, function(e) {
-            if (typeof(o[e]) == 'undefined') {
-                throw "Module not found : " + str;
-            }
-            o = o[e];
-        });
-        
-        return o;
-        
+        this.hideShim();
     },
-    
-    
-    /**
-     * move modules into their correct place in the tree..
-     * 
-     */
-    preBuild : function ()
-    {
-        var _t = this;
-        Roo.each(this.modules , function (obj)
-        {
-            Roo.XComponent.event.fireEvent('beforebuild', obj);
-            
-            var opar = obj.parent;
-            try { 
-                obj.parent = this.toObject(opar);
-            } catch(e) {
-                Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
-                return;
-            }
-            
-            if (!obj.parent) {
-                Roo.debug && Roo.log("GOT top level module");
-                Roo.debug && Roo.log(obj);
-                obj.modules = new Roo.util.MixedCollection(false, 
-                    function(o) { return o.order + '' }
-                );
-                this.topModule = obj;
-                return;
+
+    // private
+    constrainXY : function(){
+        if(this.constrain){
+            var vw = Roo.lib.Dom.getViewWidth(),
+                vh = Roo.lib.Dom.getViewHeight();
+            var s = Roo.get(document).getScroll();
+
+            var xy = this.getXY();
+            var x = xy[0], y = xy[1];   
+            var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
+            // only move it if it needs it
+            var moved = false;
+            // first validate right/bottom
+            if((x + w) > vw+s.left){
+                x = vw - w - this.shadowOffset;
+                moved = true;
             }
-                       // parent is a string (usually a dom element name..)
-            if (typeof(obj.parent) == 'string') {
-                this.elmodules.push(obj);
-                return;
+            if((y + h) > vh+s.top){
+                y = vh - h - this.shadowOffset;
+                moved = true;
             }
-            if (obj.parent.constructor != Roo.XComponent) {
-                Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
+            // then make sure top/left isn't negative
+            if(x < s.left){
+                x = s.left;
+                moved = true;
             }
-            if (!obj.parent.modules) {
-                obj.parent.modules = new Roo.util.MixedCollection(false, 
-                    function(o) { return o.order + '' }
-                );
+            if(y < s.top){
+                y = s.top;
+                moved = true;
             }
-            if (obj.parent.disabled) {
-                obj.disabled = true;
+            if(moved){
+                if(this.avoidY){
+                    var ay = this.avoidY;
+                    if(y <= ay && (y+h) >= ay){
+                        y = ay-h-5;   
+                    }
+                }
+                xy = [x, y];
+                this.storeXY(xy);
+                supr.setXY.call(this, xy);
+                this.sync();
             }
-            obj.parent.modules.add(obj);
-        }, this);
-    },
-    
-     /**
-     * make a list of modules to build.
-     * @return {Array} list of modules. 
-     */ 
-    
-    buildOrder : function()
-    {
-        var _this = this;
-        var cmp = function(a,b) {   
-            return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
-        };
-        if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
-            throw "No top level modules to build";
         }
-        
-        // make a flat list in order of modules to build.
-        var mods = this.topModule ? [ this.topModule ] : [];
-               
-        
-       // elmodules (is a list of DOM based modules )
-        Roo.each(this.elmodules, function(e) {
-            mods.push(e);
-            if (!this.topModule &&
-                typeof(e.parent) == 'string' &&
-                e.parent.substring(0,1) == '#' &&
-                Roo.get(e.parent.substr(1))
-               ) {
-                
-                _this.topModule = e;
-            }
-            
-        });
+    },
 
-        
-        // add modules to their parents..
-        var addMod = function(m) {
-            Roo.debug && Roo.log("build Order: add: " + m.name);
-                
-            mods.push(m);
-            if (m.modules && !m.disabled) {
-                Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
-                m.modules.keySort('ASC',  cmp );
-                Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
-    
-                m.modules.each(addMod);
-            } else {
-                Roo.debug && Roo.log("build Order: no child modules");
-            }
-            // not sure if this is used any more..
-            if (m.finalize) {
-                m.finalize.name = m.name + " (clean up) ";
-                mods.push(m.finalize);
-            }
-            
-        }
-        if (this.topModule && this.topModule.modules) { 
-            this.topModule.modules.keySort('ASC',  cmp );
-            this.topModule.modules.each(addMod);
-        } 
-        return mods;
+    isVisible : function(){
+        return this.visible;    
     },
-    
-     /**
-     * Build the registered modules.
-     * @param {Object} parent element.
-     * @param {Function} optional method to call after module has been added.
-     * 
-     */ 
-   
-    build : function(opts) 
-    {
-        
-        if (typeof(opts) != 'undefined') {
-            Roo.apply(this,opts);
+
+    // private
+    showAction : function(){
+        this.visible = true; // track visibility to prevent getStyle calls
+        if(this.useDisplay === true){
+            this.setDisplayed("");
+        }else if(this.lastXY){
+            supr.setXY.call(this, this.lastXY);
+        }else if(this.lastLT){
+            supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
         }
-        
-        this.preBuild();
-        var mods = this.buildOrder();
-      
-        //this.allmods = mods;
-        //Roo.debug && Roo.log(mods);
-        //return;
-        if (!mods.length) { // should not happen
-            throw "NO modules!!!";
+    },
+
+    // private
+    hideAction : function(){
+        this.visible = false;
+        if(this.useDisplay === true){
+            this.setDisplayed(false);
+        }else{
+            this.setLeftTop(-10000,-10000);
         }
-        
-        
-        var msg = "Building Interface...";
-        // flash it up as modal - so we store the mask!?
-        if (!this.hideProgress && Roo.MessageBox) {
-            Roo.MessageBox.show({ title: 'loading' });
-            Roo.MessageBox.show({
-               title: "Please wait...",
-               msg: msg,
-               width:450,
-               progress:true,
-              buttons : false,
-               closable:false,
-               modal: false
-              
-            });
+    },
+
+    // overridden Element method
+    setVisible : function(v, a, d, c, e){
+        if(v){
+            this.showAction();
         }
-        var total = mods.length;
-        
-        var _this = this;
-        var progressRun = function() {
-            if (!mods.length) {
-                Roo.debug && Roo.log('hide?');
-                if (!this.hideProgress && Roo.MessageBox) {
-                    Roo.MessageBox.hide();
+        if(a && v){
+            var cb = function(){
+                this.sync(true);
+                if(c){
+                    c();
                 }
-                Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
-                
-                Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
-                
-                // THE END...
-                return false;   
+            }.createDelegate(this);
+            supr.setVisible.call(this, true, true, d, cb, e);
+        }else{
+            if(!v){
+                this.hideUnders(true);
             }
-            
-            var m = mods.shift();
-            
-            
-            Roo.debug && Roo.log(m);
-            // not sure if this is supported any more.. - modules that are are just function
-            if (typeof(m) == 'function') { 
-                m.call(this);
-                return progressRun.defer(10, _this);
-            } 
-            
-            
-            msg = "Building Interface " + (total  - mods.length) + 
-                    " of " + total + 
-                    (m.name ? (' - ' + m.name) : '');
-                       Roo.debug && Roo.log(msg);
-            if (!_this.hideProgress &&  Roo.MessageBox) { 
-                Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
+            var cb = c;
+            if(a){
+                cb = function(){
+                    this.hideAction();
+                    if(c){
+                        c();
+                    }
+                }.createDelegate(this);
             }
-            
-         
-            // is the module disabled?
-            var disabled = (typeof(m.disabled) == 'function') ?
-                m.disabled.call(m.module.disabled) : m.disabled;    
-            
-            
-            if (disabled) {
-                return progressRun(); // we do not update the display!
+            supr.setVisible.call(this, v, a, d, cb, e);
+            if(v){
+                this.sync(true);
+            }else if(!a){
+                this.hideAction();
             }
-            
-            // now build 
-            
-                       
-                       
-            m.render();
-            // it's 10 on top level, and 1 on others??? why...
-            return progressRun.defer(10, _this);
-             
         }
-        progressRun.defer(1, _this);
-     
-        
-        
     },
-    /**
-     * Overlay a set of modified strings onto a component
-     * This is dependant on our builder exporting the strings and 'named strings' elements.
-     * 
-     * @param {Object} element to overlay on - eg. Pman.Dialog.Login
-     * @param {Object} associative array of 'named' string and it's new value.
-     * 
-     */
-       overlayStrings : function( component, strings )
-    {
-        if (typeof(component['_named_strings']) == 'undefined') {
-            throw "ERROR: component does not have _named_strings";
+
+    storeXY : function(xy){
+        delete this.lastLT;
+        this.lastXY = xy;
+    },
+
+    storeLeftTop : function(left, top){
+        delete this.lastXY;
+        this.lastLT = [left, top];
+    },
+
+    // private
+    beforeFx : function(){
+        this.beforeAction();
+        return Roo.Layer.superclass.beforeFx.apply(this, arguments);
+    },
+
+    // private
+    afterFx : function(){
+        Roo.Layer.superclass.afterFx.apply(this, arguments);
+        this.sync(this.isVisible());
+    },
+
+    // private
+    beforeAction : function(){
+        if(!this.updating && this.shadow){
+            this.shadow.hide();
         }
-        for ( var k in strings ) {
-            var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
-            if (md !== false) {
-                component['_strings'][md] = strings[k];
-            } else {
-                Roo.log('could not find named string: ' + k + ' in');
-                Roo.log(component);
+    },
+
+    // overridden Element method
+    setLeft : function(left){
+        this.storeLeftTop(left, this.getTop(true));
+        supr.setLeft.apply(this, arguments);
+        this.sync();
+    },
+
+    setTop : function(top){
+        this.storeLeftTop(this.getLeft(true), top);
+        supr.setTop.apply(this, arguments);
+        this.sync();
+    },
+
+    setLeftTop : function(left, top){
+        this.storeLeftTop(left, top);
+        supr.setLeftTop.apply(this, arguments);
+        this.sync();
+    },
+
+    setXY : function(xy, a, d, c, e){
+        this.fixDisplay();
+        this.beforeAction();
+        this.storeXY(xy);
+        var cb = this.createCB(c);
+        supr.setXY.call(this, xy, a, d, cb, e);
+        if(!a){
+            cb();
+        }
+    },
+
+    // private
+    createCB : function(c){
+        var el = this;
+        return function(){
+            el.constrainXY();
+            el.sync(true);
+            if(c){
+                c();
             }
-            
+        };
+    },
+
+    // overridden Element method
+    setX : function(x, a, d, c, e){
+        this.setXY([x, this.getY()], a, d, c, e);
+    },
+
+    // overridden Element method
+    setY : function(y, a, d, c, e){
+        this.setXY([this.getX(), y], a, d, c, e);
+    },
+
+    // overridden Element method
+    setSize : function(w, h, a, d, c, e){
+        this.beforeAction();
+        var cb = this.createCB(c);
+        supr.setSize.call(this, w, h, a, d, cb, e);
+        if(!a){
+            cb();
+        }
+    },
+
+    // overridden Element method
+    setWidth : function(w, a, d, c, e){
+        this.beforeAction();
+        var cb = this.createCB(c);
+        supr.setWidth.call(this, w, a, d, cb, e);
+        if(!a){
+            cb();
+        }
+    },
+
+    // overridden Element method
+    setHeight : function(h, a, d, c, e){
+        this.beforeAction();
+        var cb = this.createCB(c);
+        supr.setHeight.call(this, h, a, d, cb, e);
+        if(!a){
+            cb();
         }
-        
+    },
+
+    // overridden Element method
+    setBounds : function(x, y, w, h, a, d, c, e){
+        this.beforeAction();
+        var cb = this.createCB(c);
+        if(!a){
+            this.storeXY([x, y]);
+            supr.setXY.call(this, [x, y]);
+            supr.setSize.call(this, w, h, a, d, cb, e);
+            cb();
+        }else{
+            supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
+        }
+        return this;
     },
     
-       
-       /**
-        * Event Object.
-        *
-        *
-        */
-       event: false, 
     /**
-        * wrapper for event.on - aliased later..  
-        * Typically use to register a event handler for register:
-        *
-        * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
-        *
-        */
-    on : false
-   
-    
-    
-});
-
-Roo.XComponent.event = new Roo.util.Observable({
-               events : { 
-                       /**
-                        * @event register
-                        * Fires when an Component is registered,
-                        * set the disable property on the Component to stop registration.
-                        * @param {Roo.XComponent} c the component being registerd.
-                        * 
-                        */
-                       'register' : true,
-            /**
-                        * @event beforebuild
-                        * Fires before each Component is built
-                        * can be used to apply permissions.
-                        * @param {Roo.XComponent} c the component being registerd.
-                        * 
-                        */
-                       'beforebuild' : true,
-                       /**
-                        * @event buildcomplete
-                        * Fires on the top level element when all elements have been built
-                        * @param {Roo.XComponent} the top level component.
-                        */
-                       'buildcomplete' : true
-                       
-               }
+     * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
+     * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
+     * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
+     * @param {Number} zindex The new z-index to set
+     * @return {this} The Layer
+     */
+    setZIndex : function(zindex){
+        this.zindex = zindex;
+        this.setStyle("z-index", zindex + 2);
+        if(this.shadow){
+            this.shadow.setZIndex(zindex + 1);
+        }
+        if(this.shim){
+            this.shim.setStyle("z-index", zindex);
+        }
+    }
 });
-
-Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
- //
- /**
- * marked - a markdown parser
- * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
- * https://github.com/chjj/marked
+})();/*
+ * Original code for Roojs - LGPL
+ * <script type="text/javascript">
  */
-
-
 /**
+ * @class Roo.XComponent
+ * A delayed Element creator...
+ * Or a way to group chunks of interface together.
+ * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
+ *  used in conjunction with XComponent.build() it will create an instance of each element,
+ *  then call addxtype() to build the User interface.
+ * 
+ * Mypart.xyx = new Roo.XComponent({
+
+    parent : 'Mypart.xyz', // empty == document.element.!!
+    order : '001',
+    name : 'xxxx'
+    region : 'xxxx'
+    disabled : function() {} 
+     
+    tree : function() { // return an tree of xtype declared components
+        var MODULE = this;
+        return 
+        {
+            xtype : 'NestedLayoutPanel',
+            // technicall
+        }
+     ]
+ *})
  *
- * Roo.Markdown - is a very crude wrapper around marked..
  *
- * usage:
+ * It can be used to build a big heiracy, with parent etc.
+ * or you can just use this to render a single compoent to a dom element
+ * MYPART.render(Roo.Element | String(id) | dom_element )
+ *
+ *
+ * Usage patterns.
+ *
+ * Classic Roo
+ *
+ * Roo is designed primarily as a single page application, so the UI build for a standard interface will
+ * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
+ *
+ * Each sub module is expected to have a parent pointing to the class name of it's parent module.
+ *
+ * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
+ * - if mulitple topModules exist, the last one is defined as the top module.
+ *
+ * Embeded Roo
  * 
- * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
+ * When the top level or multiple modules are to embedded into a existing HTML page,
+ * the parent element can container '#id' of the element where the module will be drawn.
+ *
+ * Bootstrap Roo
+ *
+ * Unlike classic Roo, the bootstrap tends not to be used as a single page.
+ * it relies more on a include mechanism, where sub modules are included into an outer page.
+ * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
  * 
- * Note: move the sample code to the bottom of this
- * file before uncommenting it.
+ * Bootstrap Roo Included elements
+ *
+ * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
+ * hence confusing the component builder as it thinks there are multiple top level elements. 
  *
+ * String Over-ride & Translations
+ *
+ * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
+ * and also the 'overlaying of string values - needed when different versions of the same application with different text content
+ * are needed. @see Roo.XComponent.overlayString  
+ * 
+ * 
+ * 
+ * @extends Roo.util.Observable
+ * @constructor
+ * @param cfg {Object} configuration of component
+ * 
  */
-
-Roo.Markdown = {};
-Roo.Markdown.toHtml = function(text) {
-    
-    var c = new Roo.Markdown.marked.setOptions({
-            renderer: new Roo.Markdown.marked.Renderer(),
-            gfm: true,
-            tables: true,
-            breaks: false,
-            pedantic: false,
-            sanitize: false,
-            smartLists: true,
-            smartypants: false
-          });
-    // A FEW HACKS!!?
+Roo.XComponent = function(cfg) {
+    Roo.apply(this, cfg);
+    this.addEvents({ 
+        /**
+            * @event built
+            * Fires when this the componnt is built
+            * @param {Roo.XComponent} c the component
+            */
+        'built' : true
+        
+    });
+    this.region = this.region || 'center'; // default..
+    Roo.XComponent.register(this);
+    this.modules = false;
+    this.el = false; // where the layout goes..
     
-    text = text.replace(/\\\n/g,' ');
-    return Roo.Markdown.marked(text);
-};
-//
-// converter
-//
-// Wraps all "globals" so that the only thing
-// exposed is makeHtml().
-//
-(function() {
     
+}
+Roo.extend(Roo.XComponent, Roo.util.Observable, {
     /**
-     * Block-Level Grammar
+     * @property el
+     * The created element (with Roo.factory())
+     * @type {Roo.Layout}
      */
-    
-    var block = {
-      newline: /^\n+/,
-      code: /^( {4}[^\n]+\n*)+/,
-      fences: noop,
-      hr: /^( *[-*_]){3,} *(?:\n+|$)/,
-      heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
-      nptable: noop,
-      lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
-      blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
-      list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
-      html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
-      def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
-      table: noop,
-      paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
-      text: /^[^\n]+/
-    };
-    
-    block.bullet = /(?:[*+-]|\d+\.)/;
-    block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
-    block.item = replace(block.item, 'gm')
-      (/bull/g, block.bullet)
-      ();
-    
-    block.list = replace(block.list)
-      (/bull/g, block.bullet)
-      ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
-      ('def', '\\n+(?=' + block.def.source + ')')
-      ();
-    
-    block.blockquote = replace(block.blockquote)
-      ('def', block.def)
-      ();
-    
-    block._tag = '(?!(?:'
-      + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
-      + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
-      + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
-    
-    block.html = replace(block.html)
-      ('comment', /<!--[\s\S]*?-->/)
-      ('closed', /<(tag)[\s\S]+?<\/\1>/)
-      ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
-      (/tag/g, block._tag)
-      ();
-    
-    block.paragraph = replace(block.paragraph)
-      ('hr', block.hr)
-      ('heading', block.heading)
-      ('lheading', block.lheading)
-      ('blockquote', block.blockquote)
-      ('tag', '<' + block._tag)
-      ('def', block.def)
-      ();
+    el  : false,
     
     /**
-     * Normal Block Grammar
+     * @property el
+     * for BC  - use el in new code
+     * @type {Roo.Layout}
      */
-    
-    block.normal = merge({}, block);
+    panel : false,
     
     /**
-     * GFM Block Grammar
+     * @property layout
+     * for BC  - use el in new code
+     * @type {Roo.Layout}
      */
+    layout : false,
     
-    block.gfm = merge({}, block.normal, {
-      fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
-      paragraph: /^/,
-      heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
-    });
-    
-    block.gfm.paragraph = replace(block.paragraph)
-      ('(?!', '(?!'
-        + block.gfm.fences.source.replace('\\1', '\\2') + '|'
-        + block.list.source.replace('\\1', '\\3') + '|')
-      ();
+     /**
+     * @cfg {Function|boolean} disabled
+     * If this module is disabled by some rule, return true from the funtion
+     */
+    disabled : false,
     
     /**
-     * GFM + Tables Block Grammar
+     * @cfg {String} parent 
+     * Name of parent element which it get xtype added to..
      */
-    
-    block.tables = merge({}, block.gfm, {
-      nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
-      table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
-    });
+    parent: false,
     
     /**
-     * Block Lexer
+     * @cfg {String} order
+     * Used to set the order in which elements are created (usefull for multiple tabs)
      */
     
-    function Lexer(options) {
-      this.tokens = [];
-      this.tokens.links = {};
-      this.options = options || marked.defaults;
-      this.rules = block.normal;
-    
-      if (this.options.gfm) {
-        if (this.options.tables) {
-          this.rules = block.tables;
-        } else {
-          this.rules = block.gfm;
-        }
-      }
-    }
-    
+    order : false,
     /**
-     * Expose Block Rules
+     * @cfg {String} name
+     * String to display while loading.
      */
-    
-    Lexer.rules = block;
-    
+    name : false,
     /**
-     * Static Lex Method
+     * @cfg {String} region
+     * Region to render component to (defaults to center)
      */
-    
-    Lexer.lex = function(src, options) {
-      var lexer = new Lexer(options);
-      return lexer.lex(src);
-    };
+    region : 'center',
     
     /**
-     * Preprocessing
+     * @cfg {Array} items
+     * A single item array - the first element is the root of the tree..
+     * It's done this way to stay compatible with the Xtype system...
      */
-    
-    Lexer.prototype.lex = function(src) {
-      src = src
-        .replace(/\r\n|\r/g, '\n')
-        .replace(/\t/g, '    ')
-        .replace(/\u00a0/g, ' ')
-        .replace(/\u2424/g, '\n');
-    
-      return this.token(src, true);
-    };
+    items : false,
     
     /**
-     * Lexing
+     * @property _tree
+     * The method that retuns the tree of parts that make up this compoennt 
+     * @type {function}
      */
+    _tree  : false,
     
-    Lexer.prototype.token = function(src, top, bq) {
-      var src = src.replace(/^ +$/gm, '')
-        , next
-        , loose
-        , cap
-        , bull
-        , b
-        , item
-        , space
-        , i
-        , l;
-    
-      while (src) {
-        // newline
-        if (cap = this.rules.newline.exec(src)) {
-          src = src.substring(cap[0].length);
-          if (cap[0].length > 1) {
-            this.tokens.push({
-              type: 'space'
-            });
-          }
-        }
+     /**
+     * render
+     * render element to dom or tree
+     * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
+     */
     
-        // code
-        if (cap = this.rules.code.exec(src)) {
-          src = src.substring(cap[0].length);
-          cap = cap[0].replace(/^ {4}/gm, '');
-          this.tokens.push({
-            type: 'code',
-            text: !this.options.pedantic
-              ? cap.replace(/\n+$/, '')
-              : cap
-          });
-          continue;
-        }
-    
-        // fences (gfm)
-        if (cap = this.rules.fences.exec(src)) {
-          src = src.substring(cap[0].length);
-          this.tokens.push({
-            type: 'code',
-            lang: cap[2],
-            text: cap[3] || ''
-          });
-          continue;
-        }
-    
-        // heading
-        if (cap = this.rules.heading.exec(src)) {
-          src = src.substring(cap[0].length);
-          this.tokens.push({
-            type: 'heading',
-            depth: cap[1].length,
-            text: cap[2]
-          });
-          continue;
-        }
-    
-        // table no leading pipe (gfm)
-        if (top && (cap = this.rules.nptable.exec(src))) {
-          src = src.substring(cap[0].length);
-    
-          item = {
-            type: 'table',
-            header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
-            align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
-            cells: cap[3].replace(/\n$/, '').split('\n')
-          };
-    
-          for (i = 0; i < item.align.length; i++) {
-            if (/^ *-+: *$/.test(item.align[i])) {
-              item.align[i] = 'right';
-            } else if (/^ *:-+: *$/.test(item.align[i])) {
-              item.align[i] = 'center';
-            } else if (/^ *:-+ *$/.test(item.align[i])) {
-              item.align[i] = 'left';
-            } else {
-              item.align[i] = null;
-            }
-          }
-    
-          for (i = 0; i < item.cells.length; i++) {
-            item.cells[i] = item.cells[i].split(/ *\| */);
-          }
-    
-          this.tokens.push(item);
-    
-          continue;
-        }
-    
-        // lheading
-        if (cap = this.rules.lheading.exec(src)) {
-          src = src.substring(cap[0].length);
-          this.tokens.push({
-            type: 'heading',
-            depth: cap[2] === '=' ? 1 : 2,
-            text: cap[1]
-          });
-          continue;
-        }
-    
-        // hr
-        if (cap = this.rules.hr.exec(src)) {
-          src = src.substring(cap[0].length);
-          this.tokens.push({
-            type: 'hr'
-          });
-          continue;
-        }
-    
-        // blockquote
-        if (cap = this.rules.blockquote.exec(src)) {
-          src = src.substring(cap[0].length);
-    
-          this.tokens.push({
-            type: 'blockquote_start'
-          });
-    
-          cap = cap[0].replace(/^ *> ?/gm, '');
-    
-          // Pass `top` to keep the current
-          // "toplevel" state. This is exactly
-          // how markdown.pl works.
-          this.token(cap, top, true);
-    
-          this.tokens.push({
-            type: 'blockquote_end'
-          });
-    
-          continue;
-        }
-    
-        // list
-        if (cap = this.rules.list.exec(src)) {
-          src = src.substring(cap[0].length);
-          bull = cap[2];
-    
-          this.tokens.push({
-            type: 'list_start',
-            ordered: bull.length > 1
-          });
-    
-          // Get each top-level item.
-          cap = cap[0].match(this.rules.item);
-    
-          next = false;
-          l = cap.length;
-          i = 0;
-    
-          for (; i < l; i++) {
-            item = cap[i];
-    
-            // Remove the list item's bullet
-            // so it is seen as the next token.
-            space = item.length;
-            item = item.replace(/^ *([*+-]|\d+\.) +/, '');
-    
-            // Outdent whatever the
-            // list item contains. Hacky.
-            if (~item.indexOf('\n ')) {
-              space -= item.length;
-              item = !this.options.pedantic
-                ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
-                : item.replace(/^ {1,4}/gm, '');
-            }
-    
-            // Determine whether the next list item belongs here.
-            // Backpedal if it does not belong in this list.
-            if (this.options.smartLists && i !== l - 1) {
-              b = block.bullet.exec(cap[i + 1])[0];
-              if (bull !== b && !(bull.length > 1 && b.length > 1)) {
-                src = cap.slice(i + 1).join('\n') + src;
-                i = l - 1;
-              }
+    render : function(el)
+    {
+        
+        el = el || false;
+        var hp = this.parent ? 1 : 0;
+        Roo.debug &&  Roo.log(this);
+        
+        var tree = this._tree ? this._tree() : this.tree();
+
+        
+        if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
+            // if parent is a '#.....' string, then let's use that..
+            var ename = this.parent.substr(1);
+            this.parent = false;
+            Roo.debug && Roo.log(ename);
+            switch (ename) {
+                case 'bootstrap-body':
+                    if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
+                        // this is the BorderLayout standard?
+                       this.parent = { el : true };
+                       break;
+                    }
+                    if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
+                        // need to insert stuff...
+                        this.parent =  {
+                             el : new Roo.bootstrap.layout.Border({
+                                 el : document.body, 
+                     
+                                 center: {
+                                    titlebar: false,
+                                    autoScroll:false,
+                                    closeOnTab: true,
+                                    tabPosition: 'top',
+                                      //resizeTabs: true,
+                                    alwaysShowTabs: true,
+                                    hideTabs: false
+                                     //minTabWidth: 140
+                                 }
+                             })
+                        
+                         };
+                         break;
+                    }
+                         
+                    if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
+                        this.parent = { el :  new  Roo.bootstrap.Body() };
+                        Roo.debug && Roo.log("setting el to doc body");
+                         
+                    } else {
+                        throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
+                    }
+                    break;
+                case 'bootstrap':
+                    this.parent = { el : true};
+                    // fall through
+                default:
+                    el = Roo.get(ename);
+                    if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
+                        this.parent = { el : true};
+                    }
+                    
+                    break;
             }
-    
-            // Determine whether item is loose or not.
-            // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
-            // for discount behavior.
-            loose = next || /\n\n(?!\s*$)/.test(item);
-            if (i !== l - 1) {
-              next = item.charAt(item.length - 1) === '\n';
-              if (!loose) { loose = next; }
+                
+            
+            if (!el && !this.parent) {
+                Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
+                return;
             }
-    
-            this.tokens.push({
-              type: loose
-                ? 'loose_item_start'
-                : 'list_item_start'
-            });
-    
-            // Recurse.
-            this.token(item, false, bq);
-    
-            this.tokens.push({
-              type: 'list_item_end'
-            });
-          }
-    
-          this.tokens.push({
-            type: 'list_end'
-          });
-    
-          continue;
-        }
-    
-        // html
-        if (cap = this.rules.html.exec(src)) {
-          src = src.substring(cap[0].length);
-          this.tokens.push({
-            type: this.options.sanitize
-              ? 'paragraph'
-              : 'html',
-            pre: !this.options.sanitizer
-              && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
-            text: cap[0]
-          });
-          continue;
         }
-    
-        // def
-        if ((!bq && top) && (cap = this.rules.def.exec(src))) {
-          src = src.substring(cap[0].length);
-          this.tokens.links[cap[1].toLowerCase()] = {
-            href: cap[2],
-            title: cap[3]
-          };
-          continue;
+        
+        Roo.debug && Roo.log("EL:");
+        Roo.debug && Roo.log(el);
+        Roo.debug && Roo.log("this.parent.el:");
+        Roo.debug && Roo.log(this.parent.el);
+        
+
+        // altertive root elements ??? - we need a better way to indicate these.
+        var is_alt = Roo.XComponent.is_alt ||
+                    (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
+                    (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
+                    (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
+        
+        
+        
+        if (!this.parent && is_alt) {
+            //el = Roo.get(document.body);
+            this.parent = { el : true };
         }
-    
-        // table (gfm)
-        if (top && (cap = this.rules.table.exec(src))) {
-          src = src.substring(cap[0].length);
-    
-          item = {
-            type: 'table',
-            header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
-            align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
-            cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
-          };
-    
-          for (i = 0; i < item.align.length; i++) {
-            if (/^ *-+: *$/.test(item.align[i])) {
-              item.align[i] = 'right';
-            } else if (/^ *:-+: *$/.test(item.align[i])) {
-              item.align[i] = 'center';
-            } else if (/^ *:-+ *$/.test(item.align[i])) {
-              item.align[i] = 'left';
+            
+            
+        
+        if (!this.parent) {
+            
+            Roo.debug && Roo.log("no parent - creating one");
+            
+            el = el ? Roo.get(el) : false;     
+            
+            if (typeof(Roo.BorderLayout) == 'undefined' ) {
+                
+                this.parent =  {
+                    el : new Roo.bootstrap.layout.Border({
+                        el: el || document.body,
+                    
+                        center: {
+                            titlebar: false,
+                            autoScroll:false,
+                            closeOnTab: true,
+                            tabPosition: 'top',
+                             //resizeTabs: true,
+                            alwaysShowTabs: false,
+                            hideTabs: true,
+                            minTabWidth: 140,
+                            overflow: 'visible'
+                         }
+                     })
+                };
             } else {
-              item.align[i] = null;
+            
+                // it's a top level one..
+                this.parent =  {
+                    el : new Roo.BorderLayout(el || document.body, {
+                        center: {
+                            titlebar: false,
+                            autoScroll:false,
+                            closeOnTab: true,
+                            tabPosition: 'top',
+                             //resizeTabs: true,
+                            alwaysShowTabs: el && hp? false :  true,
+                            hideTabs: el || !hp ? true :  false,
+                            minTabWidth: 140
+                         }
+                    })
+                };
             }
-          }
-    
-          for (i = 0; i < item.cells.length; i++) {
-            item.cells[i] = item.cells[i]
-              .replace(/^ *\| *| *\| *$/g, '')
-              .split(/ *\| */);
-          }
-    
-          this.tokens.push(item);
-    
-          continue;
-        }
-    
-        // top-level paragraph
-        if (top && (cap = this.rules.paragraph.exec(src))) {
-          src = src.substring(cap[0].length);
-          this.tokens.push({
-            type: 'paragraph',
-            text: cap[1].charAt(cap[1].length - 1) === '\n'
-              ? cap[1].slice(0, -1)
-              : cap[1]
-          });
-          continue;
         }
-    
-        // text
-        if (cap = this.rules.text.exec(src)) {
-          // Top-level should never reach here.
-          src = src.substring(cap[0].length);
-          this.tokens.push({
-            type: 'text',
-            text: cap[0]
-          });
-          continue;
+        
+        if (!this.parent.el) {
+                // probably an old style ctor, which has been disabled.
+                return;
+
         }
-    
-        if (src) {
-          throw new
-            Error('Infinite loop on byte: ' + src.charCodeAt(0));
+               // The 'tree' method is  '_tree now' 
+            
+        tree.region = tree.region || this.region;
+        var is_body = false;
+        if (this.parent.el === true) {
+            // bootstrap... - body..
+            if (el) {
+                tree.el = el;
+            }
+            this.parent.el = Roo.factory(tree);
+            is_body = true;
         }
-      }
-    
-      return this.tokens;
-    };
+        
+        this.el = this.parent.el.addxtype(tree, undefined, is_body);
+        this.fireEvent('built', this);
+        
+        this.panel = this.el;
+        this.layout = this.panel.layout;
+        this.parentLayout = this.parent.layout  || false;  
+         
+    }
     
+});
+
+Roo.apply(Roo.XComponent, {
     /**
-     * Inline-Level Grammar
+     * @property  hideProgress
+     * true to disable the building progress bar.. usefull on single page renders.
+     * @type Boolean
      */
-    
-    var inline = {
-      escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
-      autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
-      url: noop,
-      tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
-      link: /^!?\[(inside)\]\(href\)/,
-      reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
-      nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
-      strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
-      em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
-      code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
-      br: /^ {2,}\n(?!\s*$)/,
-      del: noop,
-      text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
-    };
-    
-    inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
-    inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
-    
-    inline.link = replace(inline.link)
-      ('inside', inline._inside)
-      ('href', inline._href)
-      ();
-    
-    inline.reflink = replace(inline.reflink)
-      ('inside', inline._inside)
-      ();
-    
+    hideProgress : false,
     /**
-     * Normal Inline Grammar
+     * @property  buildCompleted
+     * True when the builder has completed building the interface.
+     * @type Boolean
      */
-    
-    inline.normal = merge({}, inline);
-    
+    buildCompleted : false,
+     
     /**
-     * Pedantic Inline Grammar
+     * @property  topModule
+     * the upper most module - uses document.element as it's constructor.
+     * @type Object
      */
-    
-    inline.pedantic = merge({}, inline.normal, {
-      strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
-      em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
-    });
-    
+     
+    topModule  : false,
+      
     /**
-     * GFM Inline Grammar
+     * @property  modules
+     * array of modules to be created by registration system.
+     * @type {Array} of Roo.XComponent
      */
     
-    inline.gfm = merge({}, inline.normal, {
-      escape: replace(inline.escape)('])', '~|])')(),
-      url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
-      del: /^~~(?=\S)([\s\S]*?\S)~~/,
-      text: replace(inline.text)
-        (']|', '~]|')
-        ('|', '|https?://|')
-        ()
-    });
-    
+    modules : [],
     /**
-     * GFM + Line Breaks Inline Grammar
+     * @property  elmodules
+     * array of modules to be created by which use #ID 
+     * @type {Array} of Roo.XComponent
      */
-    
-    inline.breaks = merge({}, inline.gfm, {
-      br: replace(inline.br)('{2,}', '*')(),
-      text: replace(inline.gfm.text)('{2,}', '*')()
-    });
-    
+     
+    elmodules : [],
+
+     /**
+     * @property  is_alt
+     * Is an alternative Root - normally used by bootstrap or other systems,
+     *    where the top element in the tree can wrap 'body' 
+     * @type {boolean}  (default false)
+     */
+     
+    is_alt : false,
     /**
-     * Inline Lexer & Compiler
+     * @property  build_from_html
+     * Build elements from html - used by bootstrap HTML stuff 
+     *    - this is cleared after build is completed
+     * @type {boolean}    (default false)
      */
-    
-    function InlineLexer(links, options) {
-      this.options = options || marked.defaults;
-      this.links = links;
-      this.rules = inline.normal;
-      this.renderer = this.options.renderer || new Renderer;
-      this.renderer.options = this.options;
-    
-      if (!this.links) {
-        throw new
-          Error('Tokens array requires a `links` property.');
-      }
-    
-      if (this.options.gfm) {
-        if (this.options.breaks) {
-          this.rules = inline.breaks;
-        } else {
-          this.rules = inline.gfm;
-        }
-      } else if (this.options.pedantic) {
-        this.rules = inline.pedantic;
-      }
-    }
-    
-    /**
-     * Expose Inline Rules
-     */
-    
-    InlineLexer.rules = inline;
-    
+     
+    build_from_html : false,
     /**
-     * Static Lexing/Compiling Method
+     * Register components to be built later.
+     *
+     * This solves the following issues
+     * - Building is not done on page load, but after an authentication process has occured.
+     * - Interface elements are registered on page load
+     * - Parent Interface elements may not be loaded before child, so this handles that..
+     * 
+     *
+     * example:
+     * 
+     * MyApp.register({
+          order : '000001',
+          module : 'Pman.Tab.projectMgr',
+          region : 'center',
+          parent : 'Pman.layout',
+          disabled : false,  // or use a function..
+        })
+     
+     * * @param {Object} details about module
      */
-    
-    InlineLexer.output = function(src, links, options) {
-      var inline = new InlineLexer(links, options);
-      return inline.output(src);
-    };
-    
+    register : function(obj) {
+               
+        Roo.XComponent.event.fireEvent('register', obj);
+        switch(typeof(obj.disabled) ) {
+                
+            case 'undefined':
+                break;
+            
+            case 'function':
+                if ( obj.disabled() ) {
+                        return;
+                }
+                break;
+            
+            default:
+                if (obj.disabled || obj.region == '#disabled') {
+                        return;
+                }
+                break;
+        }
+               
+        this.modules.push(obj);
+         
+    },
     /**
-     * Lexing/Compiling
+     * convert a string to an object..
+     * eg. 'AAA.BBB' -> finds AAA.BBB
+
      */
     
-    InlineLexer.prototype.output = function(src) {
-      var out = ''
-        , link
-        , text
-        , href
-        , cap;
-    
-      while (src) {
-        // escape
-        if (cap = this.rules.escape.exec(src)) {
-          src = src.substring(cap[0].length);
-          out += cap[1];
-          continue;
+    toObject : function(str)
+    {
+        if (!str || typeof(str) == 'object') {
+            return str;
         }
-    
-        // autolink
-        if (cap = this.rules.autolink.exec(src)) {
-          src = src.substring(cap[0].length);
-          if (cap[2] === '@') {
-            text = cap[1].charAt(6) === ':'
-              ? this.mangle(cap[1].substring(7))
-              : this.mangle(cap[1]);
-            href = this.mangle('mailto:') + text;
-          } else {
-            text = escape(cap[1]);
-            href = text;
-          }
-          out += this.renderer.link(href, null, text);
-          continue;
+        if (str.substring(0,1) == '#') {
+            return str;
         }
-    
-        // url (gfm)
-        if (!this.inLink && (cap = this.rules.url.exec(src))) {
-          src = src.substring(cap[0].length);
-          text = escape(cap[1]);
-          href = text;
-          out += this.renderer.link(href, null, text);
-          continue;
+
+        var ar = str.split('.');
+        var rt, o;
+        rt = ar.shift();
+            /** eval:var:o */
+        try {
+            eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
+        } catch (e) {
+            throw "Module not found : " + str;
         }
-    
-        // tag
-        if (cap = this.rules.tag.exec(src)) {
-          if (!this.inLink && /^<a /i.test(cap[0])) {
-            this.inLink = true;
-          } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
-            this.inLink = false;
-          }
-          src = src.substring(cap[0].length);
-          out += this.options.sanitize
-            ? this.options.sanitizer
-              ? this.options.sanitizer(cap[0])
-              : escape(cap[0])
-            : cap[0];
-          continue;
+        
+        if (o === false) {
+            throw "Module not found : " + str;
         }
+        Roo.each(ar, function(e) {
+            if (typeof(o[e]) == 'undefined') {
+                throw "Module not found : " + str;
+            }
+            o = o[e];
+        });
+        
+        return o;
+        
+    },
     
-        // link
-        if (cap = this.rules.link.exec(src)) {
-          src = src.substring(cap[0].length);
-          this.inLink = true;
-          out += this.outputLink(cap, {
-            href: cap[2],
-            title: cap[3]
-          });
-          this.inLink = false;
-          continue;
-        }
     
-        // reflink, nolink
-        if ((cap = this.rules.reflink.exec(src))
-            || (cap = this.rules.nolink.exec(src))) {
-          src = src.substring(cap[0].length);
-          link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
-          link = this.links[link.toLowerCase()];
-          if (!link || !link.href) {
-            out += cap[0].charAt(0);
-            src = cap[0].substring(1) + src;
-            continue;
-          }
-          this.inLink = true;
-          out += this.outputLink(cap, link);
-          this.inLink = false;
-          continue;
-        }
+    /**
+     * move modules into their correct place in the tree..
+     * 
+     */
+    preBuild : function ()
+    {
+        var _t = this;
+        Roo.each(this.modules , function (obj)
+        {
+            Roo.XComponent.event.fireEvent('beforebuild', obj);
+            
+            var opar = obj.parent;
+            try { 
+                obj.parent = this.toObject(opar);
+            } catch(e) {
+                Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
+                return;
+            }
+            
+            if (!obj.parent) {
+                Roo.debug && Roo.log("GOT top level module");
+                Roo.debug && Roo.log(obj);
+                obj.modules = new Roo.util.MixedCollection(false, 
+                    function(o) { return o.order + '' }
+                );
+                this.topModule = obj;
+                return;
+            }
+                       // parent is a string (usually a dom element name..)
+            if (typeof(obj.parent) == 'string') {
+                this.elmodules.push(obj);
+                return;
+            }
+            if (obj.parent.constructor != Roo.XComponent) {
+                Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
+            }
+            if (!obj.parent.modules) {
+                obj.parent.modules = new Roo.util.MixedCollection(false, 
+                    function(o) { return o.order + '' }
+                );
+            }
+            if (obj.parent.disabled) {
+                obj.disabled = true;
+            }
+            obj.parent.modules.add(obj);
+        }, this);
+    },
     
-        // strong
-        if (cap = this.rules.strong.exec(src)) {
-          src = src.substring(cap[0].length);
-          out += this.renderer.strong(this.output(cap[2] || cap[1]));
-          continue;
-        }
+     /**
+     * make a list of modules to build.
+     * @return {Array} list of modules. 
+     */ 
     
-        // em
-        if (cap = this.rules.em.exec(src)) {
-          src = src.substring(cap[0].length);
-          out += this.renderer.em(this.output(cap[2] || cap[1]));
-          continue;
+    buildOrder : function()
+    {
+        var _this = this;
+        var cmp = function(a,b) {   
+            return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
+        };
+        if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
+            throw "No top level modules to build";
         }
+        
+        // make a flat list in order of modules to build.
+        var mods = this.topModule ? [ this.topModule ] : [];
+               
+        
+       // elmodules (is a list of DOM based modules )
+        Roo.each(this.elmodules, function(e) {
+            mods.push(e);
+            if (!this.topModule &&
+                typeof(e.parent) == 'string' &&
+                e.parent.substring(0,1) == '#' &&
+                Roo.get(e.parent.substr(1))
+               ) {
+                
+                _this.topModule = e;
+            }
+            
+        });
+
+        
+        // add modules to their parents..
+        var addMod = function(m) {
+            Roo.debug && Roo.log("build Order: add: " + m.name);
+                
+            mods.push(m);
+            if (m.modules && !m.disabled) {
+                Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
+                m.modules.keySort('ASC',  cmp );
+                Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
     
-        // code
-        if (cap = this.rules.code.exec(src)) {
-          src = src.substring(cap[0].length);
-          out += this.renderer.codespan(escape(cap[2], true));
-          continue;
+                m.modules.each(addMod);
+            } else {
+                Roo.debug && Roo.log("build Order: no child modules");
+            }
+            // not sure if this is used any more..
+            if (m.finalize) {
+                m.finalize.name = m.name + " (clean up) ";
+                mods.push(m.finalize);
+            }
+            
         }
+        if (this.topModule && this.topModule.modules) { 
+            this.topModule.modules.keySort('ASC',  cmp );
+            this.topModule.modules.each(addMod);
+        } 
+        return mods;
+    },
     
-        // br
-        if (cap = this.rules.br.exec(src)) {
-          src = src.substring(cap[0].length);
-          out += this.renderer.br();
-          continue;
+     /**
+     * Build the registered modules.
+     * @param {Object} parent element.
+     * @param {Function} optional method to call after module has been added.
+     * 
+     */ 
+   
+    build : function(opts) 
+    {
+        
+        if (typeof(opts) != 'undefined') {
+            Roo.apply(this,opts);
         }
-    
-        // del (gfm)
-        if (cap = this.rules.del.exec(src)) {
-          src = src.substring(cap[0].length);
-          out += this.renderer.del(this.output(cap[1]));
-          continue;
+        
+        this.preBuild();
+        var mods = this.buildOrder();
+      
+        //this.allmods = mods;
+        //Roo.debug && Roo.log(mods);
+        //return;
+        if (!mods.length) { // should not happen
+            throw "NO modules!!!";
         }
-    
-        // text
-        if (cap = this.rules.text.exec(src)) {
-          src = src.substring(cap[0].length);
-          out += this.renderer.text(escape(this.smartypants(cap[0])));
-          continue;
+        
+        
+        var msg = "Building Interface...";
+        // flash it up as modal - so we store the mask!?
+        if (!this.hideProgress && Roo.MessageBox) {
+            Roo.MessageBox.show({ title: 'loading' });
+            Roo.MessageBox.show({
+               title: "Please wait...",
+               msg: msg,
+               width:450,
+               progress:true,
+              buttons : false,
+               closable:false,
+               modal: false
+              
+            });
         }
-    
-        if (src) {
-          throw new
-            Error('Infinite loop on byte: ' + src.charCodeAt(0));
+        var total = mods.length;
+        
+        var _this = this;
+        var progressRun = function() {
+            if (!mods.length) {
+                Roo.debug && Roo.log('hide?');
+                if (!this.hideProgress && Roo.MessageBox) {
+                    Roo.MessageBox.hide();
+                }
+                Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
+                
+                Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
+                
+                // THE END...
+                return false;   
+            }
+            
+            var m = mods.shift();
+            
+            
+            Roo.debug && Roo.log(m);
+            // not sure if this is supported any more.. - modules that are are just function
+            if (typeof(m) == 'function') { 
+                m.call(this);
+                return progressRun.defer(10, _this);
+            } 
+            
+            
+            msg = "Building Interface " + (total  - mods.length) + 
+                    " of " + total + 
+                    (m.name ? (' - ' + m.name) : '');
+                       Roo.debug && Roo.log(msg);
+            if (!_this.hideProgress &&  Roo.MessageBox) { 
+                Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
+            }
+            
+         
+            // is the module disabled?
+            var disabled = (typeof(m.disabled) == 'function') ?
+                m.disabled.call(m.module.disabled) : m.disabled;    
+            
+            
+            if (disabled) {
+                return progressRun(); // we do not update the display!
+            }
+            
+            // now build 
+            
+                       
+                       
+            m.render();
+            // it's 10 on top level, and 1 on others??? why...
+            return progressRun.defer(10, _this);
+             
         }
-      }
-    
-      return out;
-    };
-    
-    /**
-     * Compile Link
-     */
-    
-    InlineLexer.prototype.outputLink = function(cap, link) {
-      var href = escape(link.href)
-        , title = link.title ? escape(link.title) : null;
-    
-      return cap[0].charAt(0) !== '!'
-        ? this.renderer.link(href, title, this.output(cap[1]))
-        : this.renderer.image(href, title, escape(cap[1]));
-    };
-    
+        progressRun.defer(1, _this);
+     
+        
+        
+    },
     /**
-     * Smartypants Transformations
+     * Overlay a set of modified strings onto a component
+     * This is dependant on our builder exporting the strings and 'named strings' elements.
+     * 
+     * @param {Object} element to overlay on - eg. Pman.Dialog.Login
+     * @param {Object} associative array of 'named' string and it's new value.
+     * 
      */
+       overlayStrings : function( component, strings )
+    {
+        if (typeof(component['_named_strings']) == 'undefined') {
+            throw "ERROR: component does not have _named_strings";
+        }
+        for ( var k in strings ) {
+            var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
+            if (md !== false) {
+                component['_strings'][md] = strings[k];
+            } else {
+                Roo.log('could not find named string: ' + k + ' in');
+                Roo.log(component);
+            }
+            
+        }
+        
+    },
     
-    InlineLexer.prototype.smartypants = function(text) {
-      if (!this.options.smartypants)  { return text; }
-      return text
-        // em-dashes
-        .replace(/---/g, '\u2014')
-        // en-dashes
-        .replace(/--/g, '\u2013')
-        // opening singles
-        .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
-        // closing singles & apostrophes
-        .replace(/'/g, '\u2019')
-        // opening doubles
-        .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
-        // closing doubles
-        .replace(/"/g, '\u201d')
-        // ellipses
-        .replace(/\.{3}/g, '\u2026');
-    };
-    
+       
+       /**
+        * Event Object.
+        *
+        *
+        */
+       event: false, 
     /**
-     * Mangle Links
-     */
+        * wrapper for event.on - aliased later..  
+        * Typically use to register a event handler for register:
+        *
+        * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
+        *
+        */
+    on : false
+   
     
-    InlineLexer.prototype.mangle = function(text) {
-      if (!this.options.mangle) { return text; }
-      var out = ''
-        , l = text.length
-        , i = 0
-        , ch;
     
-      for (; i < l; i++) {
-        ch = text.charCodeAt(i);
-        if (Math.random() > 0.5) {
-          ch = 'x' + ch.toString(16);
-        }
-        out += '&#' + ch + ';';
-      }
-    
-      return out;
-    };
-    
-    /**
-     * Renderer
-     */
-    
-    function Renderer(options) {
-      this.options = options || {};
-    }
-    
-    Renderer.prototype.code = function(code, lang, escaped) {
-      if (this.options.highlight) {
-        var out = this.options.highlight(code, lang);
-        if (out != null && out !== code) {
-          escaped = true;
-          code = out;
-        }
-      } else {
-            // hack!!! - it's already escapeD?
-            escaped = true;
-      }
-    
-      if (!lang) {
-        return '<pre><code>'
-          + (escaped ? code : escape(code, true))
-          + '\n</code></pre>';
-      }
-    
-      return '<pre><code class="'
-        + this.options.langPrefix
-        + escape(lang, true)
-        + '">'
-        + (escaped ? code : escape(code, true))
-        + '\n</code></pre>\n';
-    };
-    
-    Renderer.prototype.blockquote = function(quote) {
-      return '<blockquote>\n' + quote + '</blockquote>\n';
-    };
-    
-    Renderer.prototype.html = function(html) {
-      return html;
-    };
-    
-    Renderer.prototype.heading = function(text, level, raw) {
-      return '<h'
-        + level
-        + ' id="'
-        + this.options.headerPrefix
-        + raw.toLowerCase().replace(/[^\w]+/g, '-')
-        + '">'
-        + text
-        + '</h'
-        + level
-        + '>\n';
-    };
-    
-    Renderer.prototype.hr = function() {
-      return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
-    };
-    
-    Renderer.prototype.list = function(body, ordered) {
-      var type = ordered ? 'ol' : 'ul';
-      return '<' + type + '>\n' + body + '</' + type + '>\n';
-    };
-    
-    Renderer.prototype.listitem = function(text) {
-      return '<li>' + text + '</li>\n';
-    };
-    
-    Renderer.prototype.paragraph = function(text) {
-      return '<p>' + text + '</p>\n';
-    };
-    
-    Renderer.prototype.table = function(header, body) {
-      return '<table class="table table-striped">\n'
-        + '<thead>\n'
-        + header
-        + '</thead>\n'
-        + '<tbody>\n'
-        + body
-        + '</tbody>\n'
-        + '</table>\n';
-    };
-    
-    Renderer.prototype.tablerow = function(content) {
-      return '<tr>\n' + content + '</tr>\n';
-    };
-    
-    Renderer.prototype.tablecell = function(content, flags) {
-      var type = flags.header ? 'th' : 'td';
-      var tag = flags.align
-        ? '<' + type + ' style="text-align:' + flags.align + '">'
-        : '<' + type + '>';
-      return tag + content + '</' + type + '>\n';
-    };
-    
-    // span level renderer
-    Renderer.prototype.strong = function(text) {
-      return '<strong>' + text + '</strong>';
-    };
-    
-    Renderer.prototype.em = function(text) {
-      return '<em>' + text + '</em>';
-    };
-    
-    Renderer.prototype.codespan = function(text) {
-      return '<code>' + text + '</code>';
-    };
-    
-    Renderer.prototype.br = function() {
-      return this.options.xhtml ? '<br/>' : '<br>';
-    };
-    
-    Renderer.prototype.del = function(text) {
-      return '<del>' + text + '</del>';
-    };
-    
-    Renderer.prototype.link = function(href, title, text) {
-      if (this.options.sanitize) {
-        try {
-          var prot = decodeURIComponent(unescape(href))
-            .replace(/[^\w:]/g, '')
-            .toLowerCase();
-        } catch (e) {
-          return '';
-        }
-        if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
-          return '';
-        }
-      }
-      var out = '<a href="' + href + '"';
-      if (title) {
-        out += ' title="' + title + '"';
-      }
-      out += '>' + text + '</a>';
-      return out;
-    };
-    
-    Renderer.prototype.image = function(href, title, text) {
-      var out = '<img src="' + href + '" alt="' + text + '"';
-      if (title) {
-        out += ' title="' + title + '"';
-      }
-      out += this.options.xhtml ? '/>' : '>';
-      return out;
-    };
-    
-    Renderer.prototype.text = function(text) {
-      return text;
-    };
-    
-    /**
-     * Parsing & Compiling
-     */
-    
-    function Parser(options) {
-      this.tokens = [];
-      this.token = null;
-      this.options = options || marked.defaults;
-      this.options.renderer = this.options.renderer || new Renderer;
-      this.renderer = this.options.renderer;
-      this.renderer.options = this.options;
-    }
-    
-    /**
-     * Static Parse Method
-     */
-    
-    Parser.parse = function(src, options, renderer) {
-      var parser = new Parser(options, renderer);
-      return parser.parse(src);
-    };
-    
-    /**
-     * Parse Loop
-     */
-    
-    Parser.prototype.parse = function(src) {
-      this.inline = new InlineLexer(src.links, this.options, this.renderer);
-      this.tokens = src.reverse();
-    
-      var out = '';
-      while (this.next()) {
-        out += this.tok();
-      }
-    
-      return out;
-    };
-    
-    /**
-     * Next Token
-     */
-    
-    Parser.prototype.next = function() {
-      return this.token = this.tokens.pop();
-    };
-    
-    /**
-     * Preview Next Token
-     */
-    
-    Parser.prototype.peek = function() {
-      return this.tokens[this.tokens.length - 1] || 0;
-    };
-    
-    /**
-     * Parse Text Tokens
-     */
-    
-    Parser.prototype.parseText = function() {
-      var body = this.token.text;
-    
-      while (this.peek().type === 'text') {
-        body += '\n' + this.next().text;
-      }
-    
-      return this.inline.output(body);
-    };
-    
-    /**
-     * Parse Current Token
-     */
-    
-    Parser.prototype.tok = function() {
-      switch (this.token.type) {
-        case 'space': {
-          return '';
-        }
-        case 'hr': {
-          return this.renderer.hr();
-        }
-        case 'heading': {
-          return this.renderer.heading(
-            this.inline.output(this.token.text),
-            this.token.depth,
-            this.token.text);
-        }
-        case 'code': {
-          return this.renderer.code(this.token.text,
-            this.token.lang,
-            this.token.escaped);
-        }
-        case 'table': {
-          var header = ''
-            , body = ''
-            , i
-            , row
-            , cell
-            , flags
-            , j;
-    
-          // header
-          cell = '';
-          for (i = 0; i < this.token.header.length; i++) {
-            flags = { header: true, align: this.token.align[i] };
-            cell += this.renderer.tablecell(
-              this.inline.output(this.token.header[i]),
-              { header: true, align: this.token.align[i] }
-            );
-          }
-          header += this.renderer.tablerow(cell);
-    
-          for (i = 0; i < this.token.cells.length; i++) {
-            row = this.token.cells[i];
-    
-            cell = '';
-            for (j = 0; j < row.length; j++) {
-              cell += this.renderer.tablecell(
-                this.inline.output(row[j]),
-                { header: false, align: this.token.align[j] }
-              );
-            }
-    
-            body += this.renderer.tablerow(cell);
-          }
-          return this.renderer.table(header, body);
-        }
-        case 'blockquote_start': {
-          var body = '';
-    
-          while (this.next().type !== 'blockquote_end') {
-            body += this.tok();
-          }
-    
-          return this.renderer.blockquote(body);
-        }
-        case 'list_start': {
-          var body = ''
-            , ordered = this.token.ordered;
-    
-          while (this.next().type !== 'list_end') {
-            body += this.tok();
-          }
-    
-          return this.renderer.list(body, ordered);
-        }
-        case 'list_item_start': {
-          var body = '';
-    
-          while (this.next().type !== 'list_item_end') {
-            body += this.token.type === 'text'
-              ? this.parseText()
-              : this.tok();
-          }
-    
-          return this.renderer.listitem(body);
-        }
-        case 'loose_item_start': {
-          var body = '';
+});
+
+Roo.XComponent.event = new Roo.util.Observable({
+               events : { 
+                       /**
+                        * @event register
+                        * Fires when an Component is registered,
+                        * set the disable property on the Component to stop registration.
+                        * @param {Roo.XComponent} c the component being registerd.
+                        * 
+                        */
+                       'register' : true,
+            /**
+                        * @event beforebuild
+                        * Fires before each Component is built
+                        * can be used to apply permissions.
+                        * @param {Roo.XComponent} c the component being registerd.
+                        * 
+                        */
+                       'beforebuild' : true,
+                       /**
+                        * @event buildcomplete
+                        * Fires on the top level element when all elements have been built
+                        * @param {Roo.XComponent} the top level component.
+                        */
+                       'buildcomplete' : true
+                       
+               }
+});
+
+Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
+ //
+ /**
+ * marked - a markdown parser
+ * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
+ * https://github.com/chjj/marked
+ */
+
+
+/**
+ *
+ * Roo.Markdown - is a very crude wrapper around marked..
+ *
+ * usage:
+ * 
+ * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
+ * 
+ * Note: move the sample code to the bottom of this
+ * file before uncommenting it.
+ *
+ */
+
+Roo.Markdown = {};
+Roo.Markdown.toHtml = function(text) {
     
-          while (this.next().type !== 'list_item_end') {
-            body += this.tok();
-          }
+    var c = new Roo.Markdown.marked.setOptions({
+            renderer: new Roo.Markdown.marked.Renderer(),
+            gfm: true,
+            tables: true,
+            breaks: false,
+            pedantic: false,
+            sanitize: false,
+            smartLists: true,
+            smartypants: false
+          });
+    // A FEW HACKS!!?
     
-          return this.renderer.listitem(body);
-        }
-        case 'html': {
-          var html = !this.token.pre && !this.options.pedantic
-            ? this.inline.output(this.token.text)
-            : this.token.text;
-          return this.renderer.html(html);
-        }
-        case 'paragraph': {
-          return this.renderer.paragraph(this.inline.output(this.token.text));
-        }
-        case 'text': {
-          return this.renderer.paragraph(this.parseText());
-        }
-      }
-    };
+    text = text.replace(/\\\n/g,' ');
+    return Roo.Markdown.marked(text);
+};
+//
+// converter
+//
+// Wraps all "globals" so that the only thing
+// exposed is makeHtml().
+//
+(function() {
     
+     /**
+         * eval:var:escape
+         * eval:var:unescape
+         * eval:var:replace
+         */
+      
     /**
      * Helpers
      */
     
-    function escape(html, encode) {
+    var escape = function (html, encode) {
       return html
         .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
         .replace(/</g, '&lt;')
@@ -17890,7 +18841,7 @@ Roo.Markdown.toHtml = function(text) {
         .replace(/'/g, '&#39;');
     }
     
-    function unescape(html) {
+    var unescape = function (html) {
         // explicitly match decimal, hex, and named HTML entities 
       return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
         n = n.toLowerCase();
@@ -17904,7 +18855,7 @@ Roo.Markdown.toHtml = function(text) {
       });
     }
     
-    function replace(regex, opt) {
+    var replace = function (regex, opt) {
       regex = regex.source;
       opt = opt || '';
       return function self(name, val) {
@@ -17915,11 +18866,18 @@ Roo.Markdown.toHtml = function(text) {
         return self;
       };
     }
-    
-    function noop() {}
+
+
+         /**
+         * eval:var:noop
+    */
+    var noop = function () {}
     noop.exec = noop;
     
-    function merge(obj) {
+         /**
+         * eval:var:merge
+    */
+    var merge = function (obj) {
       var i = 1
         , target
         , key;
@@ -17938,488 +18896,1580 @@ Roo.Markdown.toHtml = function(text) {
     
     
     /**
-     * Marked
+     * Block-Level Grammar
      */
     
-    function marked(src, opt, callback) {
-      if (callback || typeof opt === 'function') {
-        if (!callback) {
-          callback = opt;
-          opt = null;
-        }
-    
-        opt = merge({}, marked.defaults, opt || {});
     
-        var highlight = opt.highlight
-          , tokens
-          , pending
-          , i = 0;
     
-        try {
-          tokens = Lexer.lex(src, opt)
-        } catch (e) {
-          return callback(e);
-        }
     
-        pending = tokens.length;
+    var block = {
+      newline: /^\n+/,
+      code: /^( {4}[^\n]+\n*)+/,
+      fences: noop,
+      hr: /^( *[-*_]){3,} *(?:\n+|$)/,
+      heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
+      nptable: noop,
+      lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
+      blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
+      list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
+      html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
+      def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
+      table: noop,
+      paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
+      text: /^[^\n]+/
+    };
     
-        var done = function(err) {
-          if (err) {
-            opt.highlight = highlight;
-            return callback(err);
-          }
+    block.bullet = /(?:[*+-]|\d+\.)/;
+    block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
+    block.item = replace(block.item, 'gm')
+      (/bull/g, block.bullet)
+      ();
     
-          var out;
+    block.list = replace(block.list)
+      (/bull/g, block.bullet)
+      ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
+      ('def', '\\n+(?=' + block.def.source + ')')
+      ();
     
-          try {
-            out = Parser.parse(tokens, opt);
-          } catch (e) {
-            err = e;
-          }
+    block.blockquote = replace(block.blockquote)
+      ('def', block.def)
+      ();
     
-          opt.highlight = highlight;
+    block._tag = '(?!(?:'
+      + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
+      + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
+      + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
     
-          return err
-            ? callback(err)
-            : callback(null, out);
-        };
+    block.html = replace(block.html)
+      ('comment', /<!--[\s\S]*?-->/)
+      ('closed', /<(tag)[\s\S]+?<\/\1>/)
+      ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
+      (/tag/g, block._tag)
+      ();
     
-        if (!highlight || highlight.length < 3) {
-          return done();
-        }
+    block.paragraph = replace(block.paragraph)
+      ('hr', block.hr)
+      ('heading', block.heading)
+      ('lheading', block.lheading)
+      ('blockquote', block.blockquote)
+      ('tag', '<' + block._tag)
+      ('def', block.def)
+      ();
     
-        delete opt.highlight;
+    /**
+     * Normal Block Grammar
+     */
     
-        if (!pending) { return done(); }
+    block.normal = merge({}, block);
     
-        for (; i < tokens.length; i++) {
-          (function(token) {
-            if (token.type !== 'code') {
-              return --pending || done();
-            }
-            return highlight(token.text, token.lang, function(err, code) {
-              if (err) { return done(err); }
-              if (code == null || code === token.text) {
-                return --pending || done();
-              }
-              token.text = code;
-              token.escaped = true;
-              --pending || done();
-            });
-          })(tokens[i]);
-        }
+    /**
+     * GFM Block Grammar
+     */
     
-        return;
-      }
-      try {
-        if (opt) { opt = merge({}, marked.defaults, opt); }
-        return Parser.parse(Lexer.lex(src, opt), opt);
-      } catch (e) {
-        e.message += '\nPlease report this to https://github.com/chjj/marked.';
-        if ((opt || marked.defaults).silent) {
-          return '<p>An error occured:</p><pre>'
-            + escape(e.message + '', true)
-            + '</pre>';
+    block.gfm = merge({}, block.normal, {
+      fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
+      paragraph: /^/,
+      heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
+    });
+    
+    block.gfm.paragraph = replace(block.paragraph)
+      ('(?!', '(?!'
+        + block.gfm.fences.source.replace('\\1', '\\2') + '|'
+        + block.list.source.replace('\\1', '\\3') + '|')
+      ();
+    
+    /**
+     * GFM + Tables Block Grammar
+     */
+    
+    block.tables = merge({}, block.gfm, {
+      nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
+      table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
+    });
+    
+    /**
+     * Block Lexer
+     */
+    
+    var Lexer = function (options) {
+      this.tokens = [];
+      this.tokens.links = {};
+      this.options = options || marked.defaults;
+      this.rules = block.normal;
+    
+      if (this.options.gfm) {
+        if (this.options.tables) {
+          this.rules = block.tables;
+        } else {
+          this.rules = block.gfm;
         }
-        throw e;
       }
     }
     
     /**
-     * Options
+     * Expose Block Rules
      */
     
-    marked.options =
-    marked.setOptions = function(opt) {
-      merge(marked.defaults, opt);
-      return marked;
+    Lexer.rules = block;
+    
+    /**
+     * Static Lex Method
+     */
+    
+    Lexer.lex = function(src, options) {
+      var lexer = new Lexer(options);
+      return lexer.lex(src);
     };
     
-    marked.defaults = {
-      gfm: true,
-      tables: true,
-      breaks: false,
-      pedantic: false,
-      sanitize: false,
-      sanitizer: null,
-      mangle: true,
-      smartLists: false,
-      silent: false,
-      highlight: null,
-      langPrefix: 'lang-',
-      smartypants: false,
-      headerPrefix: '',
-      renderer: new Renderer,
-      xhtml: false
+    /**
+     * Preprocessing
+     */
+    
+    Lexer.prototype.lex = function(src) {
+      src = src
+        .replace(/\r\n|\r/g, '\n')
+        .replace(/\t/g, '    ')
+        .replace(/\u00a0/g, ' ')
+        .replace(/\u2424/g, '\n');
+    
+      return this.token(src, true);
     };
     
     /**
-     * Expose
+     * Lexing
      */
     
-    marked.Parser = Parser;
-    marked.parser = Parser.parse;
+    Lexer.prototype.token = function(src, top, bq) {
+      var src = src.replace(/^ +$/gm, '')
+        , next
+        , loose
+        , cap
+        , bull
+        , b
+        , item
+        , space
+        , i
+        , l;
     
-    marked.Renderer = Renderer;
+      while (src) {
+        // newline
+        if (cap = this.rules.newline.exec(src)) {
+          src = src.substring(cap[0].length);
+          if (cap[0].length > 1) {
+            this.tokens.push({
+              type: 'space'
+            });
+          }
+        }
     
-    marked.Lexer = Lexer;
-    marked.lexer = Lexer.lex;
+        // code
+        if (cap = this.rules.code.exec(src)) {
+          src = src.substring(cap[0].length);
+          cap = cap[0].replace(/^ {4}/gm, '');
+          this.tokens.push({
+            type: 'code',
+            text: !this.options.pedantic
+              ? cap.replace(/\n+$/, '')
+              : cap
+          });
+          continue;
+        }
     
-    marked.InlineLexer = InlineLexer;
-    marked.inlineLexer = InlineLexer.output;
+        // fences (gfm)
+        if (cap = this.rules.fences.exec(src)) {
+          src = src.substring(cap[0].length);
+          this.tokens.push({
+            type: 'code',
+            lang: cap[2],
+            text: cap[3] || ''
+          });
+          continue;
+        }
     
-    marked.parse = marked;
+        // heading
+        if (cap = this.rules.heading.exec(src)) {
+          src = src.substring(cap[0].length);
+          this.tokens.push({
+            type: 'heading',
+            depth: cap[1].length,
+            text: cap[2]
+          });
+          continue;
+        }
     
-    Roo.Markdown.marked = marked;
-
-})();/*
- * 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">
- */
-
-
-
-/*
- * These classes are derivatives of the similarly named classes in the YUI Library.
- * The original license:
- * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
- * Code licensed under the BSD License:
- * http://developer.yahoo.net/yui/license.txt
- */
-
-(function() {
-
-var Event=Roo.EventManager;
-var Dom=Roo.lib.Dom;
-
-/**
- * @class Roo.dd.DragDrop
- * @extends Roo.util.Observable
- * Defines the interface and base operation of items that that can be
- * dragged or can be drop targets.  It was designed to be extended, overriding
- * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
- * Up to three html elements can be associated with a DragDrop instance:
- * <ul>
- * <li>linked element: the element that is passed into the constructor.
- * This is the element which defines the boundaries for interaction with
- * other DragDrop objects.</li>
- * <li>handle element(s): The drag operation only occurs if the element that
- * was clicked matches a handle element.  By default this is the linked
- * element, but there are times that you will want only a portion of the
- * linked element to initiate the drag operation, and the setHandleElId()
- * method provides a way to define this.</li>
- * <li>drag element: this represents the element that would be moved along
- * with the cursor during a drag operation.  By default, this is the linked
- * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
- * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
- * </li>
- * </ul>
- * This class should not be instantiated until the onload event to ensure that
- * the associated elements are available.
- * The following would define a DragDrop obj that would interact with any
- * other DragDrop obj in the "group1" group:
- * <pre>
- *  dd = new Roo.dd.DragDrop("div1", "group1");
- * </pre>
- * Since none of the event handlers have been implemented, nothing would
- * actually happen if you were to run the code above.  Normally you would
- * override this class or one of the default implementations, but you can
- * also override the methods you want on an instance of the class...
- * <pre>
- *  dd.onDragDrop = function(e, id) {
- *  &nbsp;&nbsp;alert("dd was dropped on " + id);
- *  }
- * </pre>
- * @constructor
- * @param {String} id of the element that is linked to this instance
- * @param {String} sGroup the group of related DragDrop objects
- * @param {object} config an object containing configurable attributes
- *                Valid properties for DragDrop:
- *                    padding, isTarget, maintainOffset, primaryButtonOnly
- */
-Roo.dd.DragDrop = function(id, sGroup, config) {
-    if (id) {
-        this.init(id, sGroup, config);
-    }
+        // table no leading pipe (gfm)
+        if (top && (cap = this.rules.nptable.exec(src))) {
+          src = src.substring(cap[0].length);
+    
+          item = {
+            type: 'table',
+            header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
+            align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
+            cells: cap[3].replace(/\n$/, '').split('\n')
+          };
+    
+          for (i = 0; i < item.align.length; i++) {
+            if (/^ *-+: *$/.test(item.align[i])) {
+              item.align[i] = 'right';
+            } else if (/^ *:-+: *$/.test(item.align[i])) {
+              item.align[i] = 'center';
+            } else if (/^ *:-+ *$/.test(item.align[i])) {
+              item.align[i] = 'left';
+            } else {
+              item.align[i] = null;
+            }
+          }
+    
+          for (i = 0; i < item.cells.length; i++) {
+            item.cells[i] = item.cells[i].split(/ *\| */);
+          }
+    
+          this.tokens.push(item);
+    
+          continue;
+        }
+    
+        // lheading
+        if (cap = this.rules.lheading.exec(src)) {
+          src = src.substring(cap[0].length);
+          this.tokens.push({
+            type: 'heading',
+            depth: cap[2] === '=' ? 1 : 2,
+            text: cap[1]
+          });
+          continue;
+        }
+    
+        // hr
+        if (cap = this.rules.hr.exec(src)) {
+          src = src.substring(cap[0].length);
+          this.tokens.push({
+            type: 'hr'
+          });
+          continue;
+        }
+    
+        // blockquote
+        if (cap = this.rules.blockquote.exec(src)) {
+          src = src.substring(cap[0].length);
+    
+          this.tokens.push({
+            type: 'blockquote_start'
+          });
+    
+          cap = cap[0].replace(/^ *> ?/gm, '');
+    
+          // Pass `top` to keep the current
+          // "toplevel" state. This is exactly
+          // how markdown.pl works.
+          this.token(cap, top, true);
+    
+          this.tokens.push({
+            type: 'blockquote_end'
+          });
+    
+          continue;
+        }
+    
+        // list
+        if (cap = this.rules.list.exec(src)) {
+          src = src.substring(cap[0].length);
+          bull = cap[2];
+    
+          this.tokens.push({
+            type: 'list_start',
+            ordered: bull.length > 1
+          });
+    
+          // Get each top-level item.
+          cap = cap[0].match(this.rules.item);
+    
+          next = false;
+          l = cap.length;
+          i = 0;
+    
+          for (; i < l; i++) {
+            item = cap[i];
+    
+            // Remove the list item's bullet
+            // so it is seen as the next token.
+            space = item.length;
+            item = item.replace(/^ *([*+-]|\d+\.) +/, '');
+    
+            // Outdent whatever the
+            // list item contains. Hacky.
+            if (~item.indexOf('\n ')) {
+              space -= item.length;
+              item = !this.options.pedantic
+                ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
+                : item.replace(/^ {1,4}/gm, '');
+            }
+    
+            // Determine whether the next list item belongs here.
+            // Backpedal if it does not belong in this list.
+            if (this.options.smartLists && i !== l - 1) {
+              b = block.bullet.exec(cap[i + 1])[0];
+              if (bull !== b && !(bull.length > 1 && b.length > 1)) {
+                src = cap.slice(i + 1).join('\n') + src;
+                i = l - 1;
+              }
+            }
+    
+            // Determine whether item is loose or not.
+            // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
+            // for discount behavior.
+            loose = next || /\n\n(?!\s*$)/.test(item);
+            if (i !== l - 1) {
+              next = item.charAt(item.length - 1) === '\n';
+              if (!loose) { loose = next; }
+            }
+    
+            this.tokens.push({
+              type: loose
+                ? 'loose_item_start'
+                : 'list_item_start'
+            });
+    
+            // Recurse.
+            this.token(item, false, bq);
+    
+            this.tokens.push({
+              type: 'list_item_end'
+            });
+          }
+    
+          this.tokens.push({
+            type: 'list_end'
+          });
+    
+          continue;
+        }
+    
+        // html
+        if (cap = this.rules.html.exec(src)) {
+          src = src.substring(cap[0].length);
+          this.tokens.push({
+            type: this.options.sanitize
+              ? 'paragraph'
+              : 'html',
+            pre: !this.options.sanitizer
+              && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
+            text: cap[0]
+          });
+          continue;
+        }
+    
+        // def
+        if ((!bq && top) && (cap = this.rules.def.exec(src))) {
+          src = src.substring(cap[0].length);
+          this.tokens.links[cap[1].toLowerCase()] = {
+            href: cap[2],
+            title: cap[3]
+          };
+          continue;
+        }
+    
+        // table (gfm)
+        if (top && (cap = this.rules.table.exec(src))) {
+          src = src.substring(cap[0].length);
+    
+          item = {
+            type: 'table',
+            header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
+            align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
+            cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
+          };
+    
+          for (i = 0; i < item.align.length; i++) {
+            if (/^ *-+: *$/.test(item.align[i])) {
+              item.align[i] = 'right';
+            } else if (/^ *:-+: *$/.test(item.align[i])) {
+              item.align[i] = 'center';
+            } else if (/^ *:-+ *$/.test(item.align[i])) {
+              item.align[i] = 'left';
+            } else {
+              item.align[i] = null;
+            }
+          }
+    
+          for (i = 0; i < item.cells.length; i++) {
+            item.cells[i] = item.cells[i]
+              .replace(/^ *\| *| *\| *$/g, '')
+              .split(/ *\| */);
+          }
+    
+          this.tokens.push(item);
+    
+          continue;
+        }
+    
+        // top-level paragraph
+        if (top && (cap = this.rules.paragraph.exec(src))) {
+          src = src.substring(cap[0].length);
+          this.tokens.push({
+            type: 'paragraph',
+            text: cap[1].charAt(cap[1].length - 1) === '\n'
+              ? cap[1].slice(0, -1)
+              : cap[1]
+          });
+          continue;
+        }
+    
+        // text
+        if (cap = this.rules.text.exec(src)) {
+          // Top-level should never reach here.
+          src = src.substring(cap[0].length);
+          this.tokens.push({
+            type: 'text',
+            text: cap[0]
+          });
+          continue;
+        }
+    
+        if (src) {
+          throw new
+            Error('Infinite loop on byte: ' + src.charCodeAt(0));
+        }
+      }
+    
+      return this.tokens;
+    };
     
-};
-
-Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
-
-    /**
-     * The id of the element associated with this object.  This is what we
-     * refer to as the "linked element" because the size and position of
-     * this element is used to determine when the drag and drop objects have
-     * interacted.
-     * @property id
-     * @type String
-     */
-    id: null,
-
     /**
-     * Configuration attributes passed into the constructor
-     * @property config
-     * @type object
+     * Inline-Level Grammar
      */
-    config: null,
-
-    /**
-     * The id of the element that will be dragged.  By default this is same
-     * as the linked element , but could be changed to another element. Ex:
-     * Roo.dd.DDProxy
-     * @property dragElId
-     * @type String
-     * @private
-     */
-    dragElId: null,
-
+    
+    var inline = {
+      escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
+      autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
+      url: noop,
+      tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
+      link: /^!?\[(inside)\]\(href\)/,
+      reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
+      nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
+      strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
+      em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
+      code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
+      br: /^ {2,}\n(?!\s*$)/,
+      del: noop,
+      text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
+    };
+    
+    inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
+    inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
+    
+    inline.link = replace(inline.link)
+      ('inside', inline._inside)
+      ('href', inline._href)
+      ();
+    
+    inline.reflink = replace(inline.reflink)
+      ('inside', inline._inside)
+      ();
+    
     /**
-     * the id of the element that initiates the drag operation.  By default
-     * this is the linked element, but could be changed to be a child of this
-     * element.  This lets us do things like only starting the drag when the
-     * header element within the linked html element is clicked.
-     * @property handleElId
-     * @type String
-     * @private
+     * Normal Inline Grammar
      */
-    handleElId: null,
-
+    
+    inline.normal = merge({}, inline);
+    
     /**
-     * An associative array of HTML tags that will be ignored if clicked.
-     * @property invalidHandleTypes
-     * @type {string: string}
+     * Pedantic Inline Grammar
      */
-    invalidHandleTypes: null,
-
+    
+    inline.pedantic = merge({}, inline.normal, {
+      strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
+      em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
+    });
+    
     /**
-     * An associative array of ids for elements that will be ignored if clicked
-     * @property invalidHandleIds
-     * @type {string: string}
+     * GFM Inline Grammar
      */
-    invalidHandleIds: null,
-
+    
+    inline.gfm = merge({}, inline.normal, {
+      escape: replace(inline.escape)('])', '~|])')(),
+      url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
+      del: /^~~(?=\S)([\s\S]*?\S)~~/,
+      text: replace(inline.text)
+        (']|', '~]|')
+        ('|', '|https?://|')
+        ()
+    });
+    
     /**
-     * An indexted array of css class names for elements that will be ignored
-     * if clicked.
-     * @property invalidHandleClasses
-     * @type string[]
+     * GFM + Line Breaks Inline Grammar
      */
-    invalidHandleClasses: null,
-
+    
+    inline.breaks = merge({}, inline.gfm, {
+      br: replace(inline.br)('{2,}', '*')(),
+      text: replace(inline.gfm.text)('{2,}', '*')()
+    });
+    
     /**
-     * The linked element's absolute X position at the time the drag was
-     * started
-     * @property startPageX
-     * @type int
-     * @private
+     * Inline Lexer & Compiler
      */
-    startPageX: 0,
-
+    
+    var InlineLexer  = function (links, options) {
+      this.options = options || marked.defaults;
+      this.links = links;
+      this.rules = inline.normal;
+      this.renderer = this.options.renderer || new Renderer;
+      this.renderer.options = this.options;
+    
+      if (!this.links) {
+        throw new
+          Error('Tokens array requires a `links` property.');
+      }
+    
+      if (this.options.gfm) {
+        if (this.options.breaks) {
+          this.rules = inline.breaks;
+        } else {
+          this.rules = inline.gfm;
+        }
+      } else if (this.options.pedantic) {
+        this.rules = inline.pedantic;
+      }
+    }
+    
     /**
-     * The linked element's absolute X position at the time the drag was
-     * started
-     * @property startPageY
-     * @type int
-     * @private
+     * Expose Inline Rules
      */
-    startPageY: 0,
-
+    
+    InlineLexer.rules = inline;
+    
     /**
-     * The group defines a logical collection of DragDrop objects that are
-     * related.  Instances only get events when interacting with other
-     * DragDrop object in the same group.  This lets us define multiple
-     * groups using a single DragDrop subclass if we want.
-     * @property groups
-     * @type {string: string}
+     * Static Lexing/Compiling Method
      */
-    groups: null,
-
+    
+    InlineLexer.output = function(src, links, options) {
+      var inline = new InlineLexer(links, options);
+      return inline.output(src);
+    };
+    
     /**
-     * Individual drag/drop instances can be locked.  This will prevent
-     * onmousedown start drag.
-     * @property locked
-     * @type boolean
-     * @private
+     * Lexing/Compiling
      */
-    locked: false,
-
+    
+    InlineLexer.prototype.output = function(src) {
+      var out = ''
+        , link
+        , text
+        , href
+        , cap;
+    
+      while (src) {
+        // escape
+        if (cap = this.rules.escape.exec(src)) {
+          src = src.substring(cap[0].length);
+          out += cap[1];
+          continue;
+        }
+    
+        // autolink
+        if (cap = this.rules.autolink.exec(src)) {
+          src = src.substring(cap[0].length);
+          if (cap[2] === '@') {
+            text = cap[1].charAt(6) === ':'
+              ? this.mangle(cap[1].substring(7))
+              : this.mangle(cap[1]);
+            href = this.mangle('mailto:') + text;
+          } else {
+            text = escape(cap[1]);
+            href = text;
+          }
+          out += this.renderer.link(href, null, text);
+          continue;
+        }
+    
+        // url (gfm)
+        if (!this.inLink && (cap = this.rules.url.exec(src))) {
+          src = src.substring(cap[0].length);
+          text = escape(cap[1]);
+          href = text;
+          out += this.renderer.link(href, null, text);
+          continue;
+        }
+    
+        // tag
+        if (cap = this.rules.tag.exec(src)) {
+          if (!this.inLink && /^<a /i.test(cap[0])) {
+            this.inLink = true;
+          } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
+            this.inLink = false;
+          }
+          src = src.substring(cap[0].length);
+          out += this.options.sanitize
+            ? this.options.sanitizer
+              ? this.options.sanitizer(cap[0])
+              : escape(cap[0])
+            : cap[0];
+          continue;
+        }
+    
+        // link
+        if (cap = this.rules.link.exec(src)) {
+          src = src.substring(cap[0].length);
+          this.inLink = true;
+          out += this.outputLink(cap, {
+            href: cap[2],
+            title: cap[3]
+          });
+          this.inLink = false;
+          continue;
+        }
+    
+        // reflink, nolink
+        if ((cap = this.rules.reflink.exec(src))
+            || (cap = this.rules.nolink.exec(src))) {
+          src = src.substring(cap[0].length);
+          link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
+          link = this.links[link.toLowerCase()];
+          if (!link || !link.href) {
+            out += cap[0].charAt(0);
+            src = cap[0].substring(1) + src;
+            continue;
+          }
+          this.inLink = true;
+          out += this.outputLink(cap, link);
+          this.inLink = false;
+          continue;
+        }
+    
+        // strong
+        if (cap = this.rules.strong.exec(src)) {
+          src = src.substring(cap[0].length);
+          out += this.renderer.strong(this.output(cap[2] || cap[1]));
+          continue;
+        }
+    
+        // em
+        if (cap = this.rules.em.exec(src)) {
+          src = src.substring(cap[0].length);
+          out += this.renderer.em(this.output(cap[2] || cap[1]));
+          continue;
+        }
+    
+        // code
+        if (cap = this.rules.code.exec(src)) {
+          src = src.substring(cap[0].length);
+          out += this.renderer.codespan(escape(cap[2], true));
+          continue;
+        }
+    
+        // br
+        if (cap = this.rules.br.exec(src)) {
+          src = src.substring(cap[0].length);
+          out += this.renderer.br();
+          continue;
+        }
+    
+        // del (gfm)
+        if (cap = this.rules.del.exec(src)) {
+          src = src.substring(cap[0].length);
+          out += this.renderer.del(this.output(cap[1]));
+          continue;
+        }
+    
+        // text
+        if (cap = this.rules.text.exec(src)) {
+          src = src.substring(cap[0].length);
+          out += this.renderer.text(escape(this.smartypants(cap[0])));
+          continue;
+        }
+    
+        if (src) {
+          throw new
+            Error('Infinite loop on byte: ' + src.charCodeAt(0));
+        }
+      }
+    
+      return out;
+    };
+    
     /**
-     * Lock this instance
-     * @method lock
+     * Compile Link
      */
-    lock: function() { this.locked = true; },
-
+    
+    InlineLexer.prototype.outputLink = function(cap, link) {
+      var href = escape(link.href)
+        , title = link.title ? escape(link.title) : null;
+    
+      return cap[0].charAt(0) !== '!'
+        ? this.renderer.link(href, title, this.output(cap[1]))
+        : this.renderer.image(href, title, escape(cap[1]));
+    };
+    
     /**
-     * Unlock this instace
-     * @method unlock
+     * Smartypants Transformations
      */
-    unlock: function() { this.locked = false; },
-
+    
+    InlineLexer.prototype.smartypants = function(text) {
+      if (!this.options.smartypants)  { return text; }
+      return text
+        // em-dashes
+        .replace(/---/g, '\u2014')
+        // en-dashes
+        .replace(/--/g, '\u2013')
+        // opening singles
+        .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
+        // closing singles & apostrophes
+        .replace(/'/g, '\u2019')
+        // opening doubles
+        .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
+        // closing doubles
+        .replace(/"/g, '\u201d')
+        // ellipses
+        .replace(/\.{3}/g, '\u2026');
+    };
+    
     /**
-     * By default, all insances can be a drop target.  This can be disabled by
-     * setting isTarget to false.
-     * @method isTarget
-     * @type boolean
+     * Mangle Links
      */
-    isTarget: true,
-
+    
+    InlineLexer.prototype.mangle = function(text) {
+      if (!this.options.mangle) { return text; }
+      var out = ''
+        , l = text.length
+        , i = 0
+        , ch;
+    
+      for (; i < l; i++) {
+        ch = text.charCodeAt(i);
+        if (Math.random() > 0.5) {
+          ch = 'x' + ch.toString(16);
+        }
+        out += '&#' + ch + ';';
+      }
+    
+      return out;
+    };
+    
     /**
-     * The padding configured for this drag and drop object for calculating
-     * the drop zone intersection with this object.
-     * @method padding
-     * @type int[]
+     * Renderer
      */
-    padding: null,
-
+    
+     /**
+         * eval:var:Renderer
+    */
+    
+    var Renderer   = function (options) {
+      this.options = options || {};
+    }
+    
+    Renderer.prototype.code = function(code, lang, escaped) {
+      if (this.options.highlight) {
+        var out = this.options.highlight(code, lang);
+        if (out != null && out !== code) {
+          escaped = true;
+          code = out;
+        }
+      } else {
+            // hack!!! - it's already escapeD?
+            escaped = true;
+      }
+    
+      if (!lang) {
+        return '<pre><code>'
+          + (escaped ? code : escape(code, true))
+          + '\n</code></pre>';
+      }
+    
+      return '<pre><code class="'
+        + this.options.langPrefix
+        + escape(lang, true)
+        + '">'
+        + (escaped ? code : escape(code, true))
+        + '\n</code></pre>\n';
+    };
+    
+    Renderer.prototype.blockquote = function(quote) {
+      return '<blockquote>\n' + quote + '</blockquote>\n';
+    };
+    
+    Renderer.prototype.html = function(html) {
+      return html;
+    };
+    
+    Renderer.prototype.heading = function(text, level, raw) {
+      return '<h'
+        + level
+        + ' id="'
+        + this.options.headerPrefix
+        + raw.toLowerCase().replace(/[^\w]+/g, '-')
+        + '">'
+        + text
+        + '</h'
+        + level
+        + '>\n';
+    };
+    
+    Renderer.prototype.hr = function() {
+      return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
+    };
+    
+    Renderer.prototype.list = function(body, ordered) {
+      var type = ordered ? 'ol' : 'ul';
+      return '<' + type + '>\n' + body + '</' + type + '>\n';
+    };
+    
+    Renderer.prototype.listitem = function(text) {
+      return '<li>' + text + '</li>\n';
+    };
+    
+    Renderer.prototype.paragraph = function(text) {
+      return '<p>' + text + '</p>\n';
+    };
+    
+    Renderer.prototype.table = function(header, body) {
+      return '<table class="table table-striped">\n'
+        + '<thead>\n'
+        + header
+        + '</thead>\n'
+        + '<tbody>\n'
+        + body
+        + '</tbody>\n'
+        + '</table>\n';
+    };
+    
+    Renderer.prototype.tablerow = function(content) {
+      return '<tr>\n' + content + '</tr>\n';
+    };
+    
+    Renderer.prototype.tablecell = function(content, flags) {
+      var type = flags.header ? 'th' : 'td';
+      var tag = flags.align
+        ? '<' + type + ' style="text-align:' + flags.align + '">'
+        : '<' + type + '>';
+      return tag + content + '</' + type + '>\n';
+    };
+    
+    // span level renderer
+    Renderer.prototype.strong = function(text) {
+      return '<strong>' + text + '</strong>';
+    };
+    
+    Renderer.prototype.em = function(text) {
+      return '<em>' + text + '</em>';
+    };
+    
+    Renderer.prototype.codespan = function(text) {
+      return '<code>' + text + '</code>';
+    };
+    
+    Renderer.prototype.br = function() {
+      return this.options.xhtml ? '<br/>' : '<br>';
+    };
+    
+    Renderer.prototype.del = function(text) {
+      return '<del>' + text + '</del>';
+    };
+    
+    Renderer.prototype.link = function(href, title, text) {
+      if (this.options.sanitize) {
+        try {
+          var prot = decodeURIComponent(unescape(href))
+            .replace(/[^\w:]/g, '')
+            .toLowerCase();
+        } catch (e) {
+          return '';
+        }
+        if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
+          return '';
+        }
+      }
+      var out = '<a href="' + href + '"';
+      if (title) {
+        out += ' title="' + title + '"';
+      }
+      out += '>' + text + '</a>';
+      return out;
+    };
+    
+    Renderer.prototype.image = function(href, title, text) {
+      var out = '<img src="' + href + '" alt="' + text + '"';
+      if (title) {
+        out += ' title="' + title + '"';
+      }
+      out += this.options.xhtml ? '/>' : '>';
+      return out;
+    };
+    
+    Renderer.prototype.text = function(text) {
+      return text;
+    };
+    
     /**
-     * Cached reference to the linked element
-     * @property _domRef
-     * @private
+     * Parsing & Compiling
      */
-    _domRef: null,
-
+         /**
+         * eval:var:Parser
+    */
+    
+    var Parser= function (options) {
+      this.tokens = [];
+      this.token = null;
+      this.options = options || marked.defaults;
+      this.options.renderer = this.options.renderer || new Renderer;
+      this.renderer = this.options.renderer;
+      this.renderer.options = this.options;
+    }
+    
     /**
-     * Internal typeof flag
-     * @property __ygDragDrop
-     * @private
+     * Static Parse Method
      */
-    __ygDragDrop: true,
-
+    
+    Parser.parse = function(src, options, renderer) {
+      var parser = new Parser(options, renderer);
+      return parser.parse(src);
+    };
+    
     /**
-     * Set to true when horizontal contraints are applied
-     * @property constrainX
-     * @type boolean
-     * @private
+     * Parse Loop
      */
-    constrainX: false,
-
+    
+    Parser.prototype.parse = function(src) {
+      this.inline = new InlineLexer(src.links, this.options, this.renderer);
+      this.tokens = src.reverse();
+    
+      var out = '';
+      while (this.next()) {
+        out += this.tok();
+      }
+    
+      return out;
+    };
+    
     /**
-     * Set to true when vertical contraints are applied
-     * @property constrainY
-     * @type boolean
-     * @private
+     * Next Token
      */
-    constrainY: false,
-
+    
+    Parser.prototype.next = function() {
+      return this.token = this.tokens.pop();
+    };
+    
     /**
-     * The left constraint
-     * @property minX
-     * @type int
-     * @private
+     * Preview Next Token
      */
-    minX: 0,
-
+    
+    Parser.prototype.peek = function() {
+      return this.tokens[this.tokens.length - 1] || 0;
+    };
+    
     /**
-     * The right constraint
-     * @property maxX
-     * @type int
-     * @private
+     * Parse Text Tokens
      */
-    maxX: 0,
-
+    
+    Parser.prototype.parseText = function() {
+      var body = this.token.text;
+    
+      while (this.peek().type === 'text') {
+        body += '\n' + this.next().text;
+      }
+    
+      return this.inline.output(body);
+    };
+    
     /**
-     * The up constraint
-     * @property minY
-     * @type int
-     * @type int
-     * @private
+     * Parse Current Token
      */
-    minY: 0,
-
+    
+    Parser.prototype.tok = function() {
+      switch (this.token.type) {
+        case 'space': {
+          return '';
+        }
+        case 'hr': {
+          return this.renderer.hr();
+        }
+        case 'heading': {
+          return this.renderer.heading(
+            this.inline.output(this.token.text),
+            this.token.depth,
+            this.token.text);
+        }
+        case 'code': {
+          return this.renderer.code(this.token.text,
+            this.token.lang,
+            this.token.escaped);
+        }
+        case 'table': {
+          var header = ''
+            , body = ''
+            , i
+            , row
+            , cell
+            , flags
+            , j;
+    
+          // header
+          cell = '';
+          for (i = 0; i < this.token.header.length; i++) {
+            flags = { header: true, align: this.token.align[i] };
+            cell += this.renderer.tablecell(
+              this.inline.output(this.token.header[i]),
+              { header: true, align: this.token.align[i] }
+            );
+          }
+          header += this.renderer.tablerow(cell);
+    
+          for (i = 0; i < this.token.cells.length; i++) {
+            row = this.token.cells[i];
+    
+            cell = '';
+            for (j = 0; j < row.length; j++) {
+              cell += this.renderer.tablecell(
+                this.inline.output(row[j]),
+                { header: false, align: this.token.align[j] }
+              );
+            }
+    
+            body += this.renderer.tablerow(cell);
+          }
+          return this.renderer.table(header, body);
+        }
+        case 'blockquote_start': {
+          var body = '';
+    
+          while (this.next().type !== 'blockquote_end') {
+            body += this.tok();
+          }
+    
+          return this.renderer.blockquote(body);
+        }
+        case 'list_start': {
+          var body = ''
+            , ordered = this.token.ordered;
+    
+          while (this.next().type !== 'list_end') {
+            body += this.tok();
+          }
+    
+          return this.renderer.list(body, ordered);
+        }
+        case 'list_item_start': {
+          var body = '';
+    
+          while (this.next().type !== 'list_item_end') {
+            body += this.token.type === 'text'
+              ? this.parseText()
+              : this.tok();
+          }
+    
+          return this.renderer.listitem(body);
+        }
+        case 'loose_item_start': {
+          var body = '';
+    
+          while (this.next().type !== 'list_item_end') {
+            body += this.tok();
+          }
+    
+          return this.renderer.listitem(body);
+        }
+        case 'html': {
+          var html = !this.token.pre && !this.options.pedantic
+            ? this.inline.output(this.token.text)
+            : this.token.text;
+          return this.renderer.html(html);
+        }
+        case 'paragraph': {
+          return this.renderer.paragraph(this.inline.output(this.token.text));
+        }
+        case 'text': {
+          return this.renderer.paragraph(this.parseText());
+        }
+      }
+    };
+  
+    
     /**
-     * The down constraint
-     * @property maxY
-     * @type int
-     * @private
+     * Marked
      */
-    maxY: 0,
-
+         /**
+         * eval:var:marked
+    */
+    var marked = function (src, opt, callback) {
+      if (callback || typeof opt === 'function') {
+        if (!callback) {
+          callback = opt;
+          opt = null;
+        }
+    
+        opt = merge({}, marked.defaults, opt || {});
+    
+        var highlight = opt.highlight
+          , tokens
+          , pending
+          , i = 0;
+    
+        try {
+          tokens = Lexer.lex(src, opt)
+        } catch (e) {
+          return callback(e);
+        }
+    
+        pending = tokens.length;
+         /**
+         * eval:var:done
+    */
+        var done = function(err) {
+          if (err) {
+            opt.highlight = highlight;
+            return callback(err);
+          }
+    
+          var out;
+    
+          try {
+            out = Parser.parse(tokens, opt);
+          } catch (e) {
+            err = e;
+          }
+    
+          opt.highlight = highlight;
+    
+          return err
+            ? callback(err)
+            : callback(null, out);
+        };
+    
+        if (!highlight || highlight.length < 3) {
+          return done();
+        }
+    
+        delete opt.highlight;
+    
+        if (!pending) { return done(); }
+    
+        for (; i < tokens.length; i++) {
+          (function(token) {
+            if (token.type !== 'code') {
+              return --pending || done();
+            }
+            return highlight(token.text, token.lang, function(err, code) {
+              if (err) { return done(err); }
+              if (code == null || code === token.text) {
+                return --pending || done();
+              }
+              token.text = code;
+              token.escaped = true;
+              --pending || done();
+            });
+          })(tokens[i]);
+        }
+    
+        return;
+      }
+      try {
+        if (opt) { opt = merge({}, marked.defaults, opt); }
+        return Parser.parse(Lexer.lex(src, opt), opt);
+      } catch (e) {
+        e.message += '\nPlease report this to https://github.com/chjj/marked.';
+        if ((opt || marked.defaults).silent) {
+          return '<p>An error occured:</p><pre>'
+            + escape(e.message + '', true)
+            + '</pre>';
+        }
+        throw e;
+      }
+    }
+    
     /**
-     * Maintain offsets when we resetconstraints.  Set to true when you want
-     * the position of the element relative to its parent to stay the same
-     * when the page changes
-     *
-     * @property maintainOffset
-     * @type boolean
+     * Options
      */
-    maintainOffset: false,
-
+    
+    marked.options =
+    marked.setOptions = function(opt) {
+      merge(marked.defaults, opt);
+      return marked;
+    };
+    
+    marked.defaults = {
+      gfm: true,
+      tables: true,
+      breaks: false,
+      pedantic: false,
+      sanitize: false,
+      sanitizer: null,
+      mangle: true,
+      smartLists: false,
+      silent: false,
+      highlight: null,
+      langPrefix: 'lang-',
+      smartypants: false,
+      headerPrefix: '',
+      renderer: new Renderer,
+      xhtml: false
+    };
+    
     /**
-     * Array of pixel locations the element will snap to if we specified a
-     * horizontal graduation/interval.  This array is generated automatically
-     * when you define a tick interval.
-     * @property xTicks
-     * @type int[]
+     * Expose
      */
-    xTicks: null,
+    
+    marked.Parser = Parser;
+    marked.parser = Parser.parse;
+    
+    marked.Renderer = Renderer;
+    
+    marked.Lexer = Lexer;
+    marked.lexer = Lexer.lex;
+    
+    marked.InlineLexer = InlineLexer;
+    marked.inlineLexer = InlineLexer.output;
+    
+    marked.parse = marked;
+    
+    Roo.Markdown.marked = marked;
 
-    /**
-     * Array of pixel locations the element will snap to if we specified a
-     * vertical graduation/interval.  This array is generated automatically
-     * when you define a tick interval.
-     * @property yTicks
-     * @type int[]
-     */
-    yTicks: null,
+})();/*
+ * 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">
+ */
+
+
+
+/*
+ * These classes are derivatives of the similarly named classes in the YUI Library.
+ * The original license:
+ * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+ * Code licensed under the BSD License:
+ * http://developer.yahoo.net/yui/license.txt
+ */
+
+(function() {
+
+var Event=Roo.EventManager;
+var Dom=Roo.lib.Dom;
+
+/**
+ * @class Roo.dd.DragDrop
+ * @extends Roo.util.Observable
+ * Defines the interface and base operation of items that that can be
+ * dragged or can be drop targets.  It was designed to be extended, overriding
+ * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
+ * Up to three html elements can be associated with a DragDrop instance:
+ * <ul>
+ * <li>linked element: the element that is passed into the constructor.
+ * This is the element which defines the boundaries for interaction with
+ * other DragDrop objects.</li>
+ * <li>handle element(s): The drag operation only occurs if the element that
+ * was clicked matches a handle element.  By default this is the linked
+ * element, but there are times that you will want only a portion of the
+ * linked element to initiate the drag operation, and the setHandleElId()
+ * method provides a way to define this.</li>
+ * <li>drag element: this represents the element that would be moved along
+ * with the cursor during a drag operation.  By default, this is the linked
+ * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
+ * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
+ * </li>
+ * </ul>
+ * This class should not be instantiated until the onload event to ensure that
+ * the associated elements are available.
+ * The following would define a DragDrop obj that would interact with any
+ * other DragDrop obj in the "group1" group:
+ * <pre>
+ *  dd = new Roo.dd.DragDrop("div1", "group1");
+ * </pre>
+ * Since none of the event handlers have been implemented, nothing would
+ * actually happen if you were to run the code above.  Normally you would
+ * override this class or one of the default implementations, but you can
+ * also override the methods you want on an instance of the class...
+ * <pre>
+ *  dd.onDragDrop = function(e, id) {
+ *  &nbsp;&nbsp;alert("dd was dropped on " + id);
+ *  }
+ * </pre>
+ * @constructor
+ * @param {String} id of the element that is linked to this instance
+ * @param {String} sGroup the group of related DragDrop objects
+ * @param {object} config an object containing configurable attributes
+ *                Valid properties for DragDrop:
+ *                    padding, isTarget, maintainOffset, primaryButtonOnly
+ */
+Roo.dd.DragDrop = function(id, sGroup, config) {
+    if (id) {
+        this.init(id, sGroup, config);
+    }
+    
+};
+
+Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
 
     /**
-     * By default the drag and drop instance will only respond to the primary
-     * button click (left button for a right-handed mouse).  Set to true to
-     * allow drag and drop to start with any mouse click that is propogated
-     * by the browser
-     * @property primaryButtonOnly
-     * @type boolean
+     * The id of the element associated with this object.  This is what we
+     * refer to as the "linked element" because the size and position of
+     * this element is used to determine when the drag and drop objects have
+     * interacted.
+     * @property id
+     * @type String
      */
-    primaryButtonOnly: true,
+    id: null,
 
     /**
-     * The availabe property is false until the linked dom element is accessible.
-     * @property available
-     * @type boolean
+     * Configuration attributes passed into the constructor
+     * @property config
+     * @type object
      */
-    available: false,
+    config: null,
 
     /**
-     * By default, drags can only be initiated if the mousedown occurs in the
-     * region the linked element is.  This is done in part to work around a
-     * bug in some browsers that mis-report the mousedown if the previous
-     * mouseup happened outside of the window.  This property is set to true
-     * if outer handles are defined.
-     *
-     * @property hasOuterHandles
-     * @type boolean
-     * @default false
+     * The id of the element that will be dragged.  By default this is same
+     * as the linked element , but could be changed to another element. Ex:
+     * Roo.dd.DDProxy
+     * @property dragElId
+     * @type String
+     * @private
      */
-    hasOuterHandles: false,
+    dragElId: null,
 
     /**
-     * Code that executes immediately before the startDrag event
-     * @method b4StartDrag
+     * the id of the element that initiates the drag operation.  By default
+     * this is the linked element, but could be changed to be a child of this
+     * element.  This lets us do things like only starting the drag when the
+     * header element within the linked html element is clicked.
+     * @property handleElId
+     * @type String
      * @private
      */
-    b4StartDrag: function(x, y) { },
+    handleElId: null,
 
     /**
-     * Abstract method called after a drag/drop object is clicked
-     * and the drag or mousedown time thresholds have beeen met.
-     * @method startDrag
-     * @param {int} X click location
-     * @param {int} Y click location
+     * An associative array of HTML tags that will be ignored if clicked.
+     * @property invalidHandleTypes
+     * @type {string: string}
      */
-    startDrag: function(x, y) { /* override this */ },
+    invalidHandleTypes: null,
 
     /**
-     * Code that executes immediately before the onDrag event
-     * @method b4Drag
-     * @private
+     * An associative array of ids for elements that will be ignored if clicked
+     * @property invalidHandleIds
+     * @type {string: string}
      */
-    b4Drag: function(e) { },
+    invalidHandleIds: null,
+
+    /**
+     * An indexted array of css class names for elements that will be ignored
+     * if clicked.
+     * @property invalidHandleClasses
+     * @type string[]
+     */
+    invalidHandleClasses: null,
+
+    /**
+     * The linked element's absolute X position at the time the drag was
+     * started
+     * @property startPageX
+     * @type int
+     * @private
+     */
+    startPageX: 0,
+
+    /**
+     * The linked element's absolute X position at the time the drag was
+     * started
+     * @property startPageY
+     * @type int
+     * @private
+     */
+    startPageY: 0,
+
+    /**
+     * The group defines a logical collection of DragDrop objects that are
+     * related.  Instances only get events when interacting with other
+     * DragDrop object in the same group.  This lets us define multiple
+     * groups using a single DragDrop subclass if we want.
+     * @property groups
+     * @type {string: string}
+     */
+    groups: null,
+
+    /**
+     * Individual drag/drop instances can be locked.  This will prevent
+     * onmousedown start drag.
+     * @property locked
+     * @type boolean
+     * @private
+     */
+    locked: false,
+
+    /**
+     * Lock this instance
+     * @method lock
+     */
+    lock: function() { this.locked = true; },
+
+    /**
+     * Unlock this instace
+     * @method unlock
+     */
+    unlock: function() { this.locked = false; },
+
+    /**
+     * By default, all insances can be a drop target.  This can be disabled by
+     * setting isTarget to false.
+     * @method isTarget
+     * @type boolean
+     */
+    isTarget: true,
+
+    /**
+     * The padding configured for this drag and drop object for calculating
+     * the drop zone intersection with this object.
+     * @method padding
+     * @type int[]
+     */
+    padding: null,
+
+    /**
+     * Cached reference to the linked element
+     * @property _domRef
+     * @private
+     */
+    _domRef: null,
+
+    /**
+     * Internal typeof flag
+     * @property __ygDragDrop
+     * @private
+     */
+    __ygDragDrop: true,
+
+    /**
+     * Set to true when horizontal contraints are applied
+     * @property constrainX
+     * @type boolean
+     * @private
+     */
+    constrainX: false,
+
+    /**
+     * Set to true when vertical contraints are applied
+     * @property constrainY
+     * @type boolean
+     * @private
+     */
+    constrainY: false,
+
+    /**
+     * The left constraint
+     * @property minX
+     * @type int
+     * @private
+     */
+    minX: 0,
+
+    /**
+     * The right constraint
+     * @property maxX
+     * @type int
+     * @private
+     */
+    maxX: 0,
+
+    /**
+     * The up constraint
+     * @property minY
+     * @type int
+     * @type int
+     * @private
+     */
+    minY: 0,
+
+    /**
+     * The down constraint
+     * @property maxY
+     * @type int
+     * @private
+     */
+    maxY: 0,
+
+    /**
+     * Maintain offsets when we resetconstraints.  Set to true when you want
+     * the position of the element relative to its parent to stay the same
+     * when the page changes
+     *
+     * @property maintainOffset
+     * @type boolean
+     */
+    maintainOffset: false,
+
+    /**
+     * Array of pixel locations the element will snap to if we specified a
+     * horizontal graduation/interval.  This array is generated automatically
+     * when you define a tick interval.
+     * @property xTicks
+     * @type int[]
+     */
+    xTicks: null,
+
+    /**
+     * Array of pixel locations the element will snap to if we specified a
+     * vertical graduation/interval.  This array is generated automatically
+     * when you define a tick interval.
+     * @property yTicks
+     * @type int[]
+     */
+    yTicks: null,
+
+    /**
+     * By default the drag and drop instance will only respond to the primary
+     * button click (left button for a right-handed mouse).  Set to true to
+     * allow drag and drop to start with any mouse click that is propogated
+     * by the browser
+     * @property primaryButtonOnly
+     * @type boolean
+     */
+    primaryButtonOnly: true,
+
+    /**
+     * The availabe property is false until the linked dom element is accessible.
+     * @property available
+     * @type boolean
+     */
+    available: false,
+
+    /**
+     * By default, drags can only be initiated if the mousedown occurs in the
+     * region the linked element is.  This is done in part to work around a
+     * bug in some browsers that mis-report the mousedown if the previous
+     * mouseup happened outside of the window.  This property is set to true
+     * if outer handles are defined.
+     *
+     * @property hasOuterHandles
+     * @type boolean
+     * @default false
+     */
+    hasOuterHandles: false,
+
+    /**
+     * Code that executes immediately before the startDrag event
+     * @method b4StartDrag
+     * @private
+     */
+    b4StartDrag: function(x, y) { },
+
+    /**
+     * Abstract method called after a drag/drop object is clicked
+     * and the drag or mousedown time thresholds have beeen met.
+     * @method startDrag
+     * @param {int} X click location
+     * @param {int} Y click location
+     */
+    startDrag: function(x, y) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDrag event
+     * @method b4Drag
+     * @private
+     */
+    b4Drag: function(e) { },
 
     /**
      * Abstract method called during the onMouseMove event while dragging an
@@ -19281,7 +21331,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() {
 
@@ -21095,8 +23145,8 @@ Roo.dd.DDTarget = function(id, sGroup, config) {
     if (id) {
         this.initTarget(id, sGroup, config);
     }
-    if (config.listeners || config.events) { 
-       Roo.dd.DragDrop.superclass.constructor.call(this,  { 
+    if (config && (config.listeners || config.events)) { 
+        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
             listeners : config.listeners || {}, 
             events : config.events || {} 
         });    
@@ -21125,7 +23175,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;
@@ -21311,7 +23361,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 = {}; 
@@ -22011,7 +24061,7 @@ Roo.dd.DropTarget = function(el, config){
          * target.  This default implementation adds the CSS class specified by overClass (if any) to the drop element
          * and returns the dropAllowed config value.  This method should be overridden if drop validation is required.
          * 
-         * IMPORTANT : it should set this.overClass and this.dropAllowed
+         * IMPORTANT : it should set  this.valid to true|false
          * 
          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
          * @param {Event} e The event
@@ -22025,7 +24075,7 @@ Roo.dd.DropTarget = function(el, config){
          * This method will be called on every mouse movement while the drag source is over the drop target.
          * This default implementation simply returns the dropAllowed config value.
          * 
-         * IMPORTANT : it should set this.dropAllowed
+         * IMPORTANT : it should set  this.valid to true|false
          * 
          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
          * @param {Event} e The event
@@ -22039,6 +24089,7 @@ Roo.dd.DropTarget = function(el, config){
          * out of the target without dropping.  This default implementation simply removes the CSS class specified by
          * overClass (if any) from the drop element.
          * 
+         * 
          * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
          * @param {Event} e The event
          * @param {Object} data An object containing arbitrary data supplied by the drag source
@@ -22463,7 +24514,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 = {
@@ -22932,8 +24983,8 @@ Roo.data.Store = function(config){
          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
          * 
          * @param {Proxy} 
-         * @param {Object} return from JsonData.reader() - success, totalRecords, records
-         * @param {Object} load options 
+         * @param {Object} ret return data from JsonData.reader() - success, totalRecords, records
+         * @param {Object} opts - load Options
          * @param {Object} jsonData from your request (normally this contains the Exception)
          */
         loadexception : true
@@ -22962,13 +25013,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.
     */
     /**
@@ -23117,6 +25168,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>
@@ -23163,7 +25224,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);
             }
@@ -23235,6 +25297,16 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
         var r = this.reader.readRecords(o);
         this.loadRecords(r, {add: append}, true);
     },
+    
+     /**
+     * using 'cn' the nested child reader read the child array into it's child stores.
+     * @param {Object} rec The record with a 'children array
+     */
+    loadDataFromChildren : function(rec)
+    {
+        this.loadData(this.reader.toLoadData(rec));
+    },
+    
 
     /**
      * Gets the number of cached records.
@@ -23539,14 +25611,18 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
  * Small helper class to make creating Stores from Array data easier.
  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
  * @cfg {Array} fields An array of field definition objects, or field name strings.
+ * @cfg {Object} an existing reader (eg. copied from another store)
  * @cfg {Array} data The multi-dimensional array of data
+ * @cfg {Roo.data.DataProxy} proxy [not-required]  
+ * @cfg {Roo.data.Reader} reader  [not-required] 
  * @constructor
  * @param {Object} config
  */
-Roo.data.SimpleStore = function(config){
+Roo.data.SimpleStore = function(config)
+{
     Roo.data.SimpleStore.superclass.constructor.call(this, {
         isLocal : true,
-        reader: new Roo.data.ArrayReader({
+        reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
                 id: config.id
             },
             Roo.data.Record.create(config.fields)
@@ -23710,6 +25786,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.
  */
@@ -23723,6 +25800,9 @@ Roo.data.DataReader = function(meta, recordType){
 };
 
 Roo.data.DataReader.prototype = {
+    
+    
+    readerType : 'Data',
      /**
      * Create an empty record
      * @param {Object} data (optional) - overlay some values
@@ -23743,6 +25823,7 @@ Roo.data.DataReader.prototype = {
         return new this.recordType(Roo.apply(da, d));
     }
     
+    
 };/*
  * Based on:
  * Ext JS Library 1.1.1
@@ -23756,7 +25837,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>
@@ -23814,14 +25896,16 @@ Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
  */
 /**
  * @class Roo.data.MemoryProxy
+ * @extends Roo.data.DataProxy
  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
  * to the Reader when its load method is called.
  * @constructor
- * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
+ * @param {Object} config  A config object containing the objects needed for the Store to access data,
  */
-Roo.data.MemoryProxy = function(data){
-    if (data.data) {
-        data = data.data;
+Roo.data.MemoryProxy = function(config){
+    var data = config;
+    if (typeof(config) != 'undefined' && typeof(config.data) != 'undefined') {
+        data = config.data;
     }
     Roo.data.MemoryProxy.superclass.constructor.call(this);
     this.data = data;
@@ -23829,6 +25913,9 @@ Roo.data.MemoryProxy = function(data){
 
 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
     
+    /**
+     *  @cfg {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
+     */
     /**
      * Load data from the requested source (in this case an in-memory
      * data object passed to the constructor), read the data object into
@@ -23903,24 +25990,24 @@ Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
     // thse are take from connection...
     
     /**
-     * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
+     * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
      */
     /**
-     * @cfg {Object} extraParams (Optional) An object containing properties which are used as
+     * @cfg {Object} extraParams  An object containing properties which are used as
      * extra parameters to each request made by this object. (defaults to undefined)
      */
     /**
-     * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
+     * @cfg {Object} defaultHeaders   An object containing request headers which are added
      *  to each request made by this object. (defaults to undefined)
      */
     /**
-     * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
+     * @cfg {String} method (GET|POST)  The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
      */
     /**
-     * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
+     * @cfg {Number} timeout The timeout in milliseconds to be used for requests. (defaults to 30000)
      */
      /**
-     * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
+     * @cfg {Boolean} autoAbort Whether this request should abort any pending requests. (defaults to false)
      * @type Boolean
      */
   
@@ -23994,8 +26081,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;
         }
         
@@ -24281,6 +26370,8 @@ Roo.data.JsonReader = function(meta, recordType){
 };
 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
     
+    readerType : 'Json',
+    
     /**
      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
      * Used by Store query builder to append _requestMeta to params.
@@ -24399,19 +26490,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;
@@ -24422,6 +26521,14 @@ Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
             records : records,
             totalRecords : totalRecords
         };
+    },
+    // used when loading children.. @see loadDataFromChildren
+    toLoadData: function(rec)
+    {
+       // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
+       var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
+       return { data : data, total : data.length };
+       
     }
 });/*
  * Based on:
@@ -24492,6 +26599,9 @@ Roo.data.XmlReader = function(meta, recordType){
     Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
 };
 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
+    
+    readerType : 'Xml',
+    
     /**
      * This method is only used by a DataProxy which has retrieved data from a remote server.
         * @param {Object} response The XHR object which contains the parsed XML document.  The response is expected
@@ -24603,44 +26713,54 @@ var myReader = new Roo.data.ArrayReader({
  * 
  * created using {@link Roo.data.Record#create}.
  */
-Roo.data.ArrayReader = function(meta, recordType){
-    
-     
+Roo.data.ArrayReader = function(meta, recordType)
+{    
     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
 };
 
 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
-    /**
+    
+      /**
      * Create a data block containing Roo.data.Records from an XML document.
      * @param {Object} o An Array of row objects which represents the dataset.
      * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
      * a cache of Roo.data.Records.
      */
-    readRecords : function(o){
+    readRecords : function(o)
+    {
         var sid = this.meta ? this.meta.id : null;
-       var recordType = this.recordType, fields = recordType.prototype.fields;
-       var records = [];
-       var root = o;
-           for(var i = 0; i < root.length; i++){
-                   var n = root[i];
-               var values = {};
-               var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
-               for(var j = 0, jlen = fields.length; j < jlen; j++){
+        var 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 record = new recordType(values, id);
+            record.json = n;
+            records[records.length] = record;
+        }
+        return {
+            records : records,
+            totalRecords : records.length
+        };
+    },
+    // used when loading children.. @see loadDataFromChildren
+    toLoadData: function(rec)
+    {
+        // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
+        return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
+        
     }
+    
+    
 });/*
  * Based on:
  * Ext JS Library 1.1.1
@@ -25396,463 +27516,6 @@ Roo.extend(Roo.data.Node, Roo.util.Observable, {
  * Fork - LGPL
  * <script type="text/javascript">
  */
- (function(){ 
-/**
- * @class Roo.Layer
- * @extends Roo.Element
- * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
- * automatic maintaining of shadow/shim positions.
- * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
- * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
- * you can pass a string with a CSS class name. False turns off the shadow.
- * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
- * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
- * @cfg {String} cls CSS class to add to the element
- * @cfg {Number} zindex Starting z-index (defaults to 11000)
- * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
- * @constructor
- * @param {Object} config An object with config options.
- * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
- */
-
-Roo.Layer = function(config, existingEl){
-    config = config || {};
-    var dh = Roo.DomHelper;
-    var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
-    if(existingEl){
-        this.dom = Roo.getDom(existingEl);
-    }
-    if(!this.dom){
-        var o = config.dh || {tag: "div", cls: "x-layer"};
-        this.dom = dh.append(pel, o);
-    }
-    if(config.cls){
-        this.addClass(config.cls);
-    }
-    this.constrain = config.constrain !== false;
-    this.visibilityMode = Roo.Element.VISIBILITY;
-    if(config.id){
-        this.id = this.dom.id = config.id;
-    }else{
-        this.id = Roo.id(this.dom);
-    }
-    this.zindex = config.zindex || this.getZIndex();
-    this.position("absolute", this.zindex);
-    if(config.shadow){
-        this.shadowOffset = config.shadowOffset || 4;
-        this.shadow = new Roo.Shadow({
-            offset : this.shadowOffset,
-            mode : config.shadow
-        });
-    }else{
-        this.shadowOffset = 0;
-    }
-    this.useShim = config.shim !== false && Roo.useShims;
-    this.useDisplay = config.useDisplay;
-    this.hide();
-};
-
-var supr = Roo.Element.prototype;
-
-// shims are shared among layer to keep from having 100 iframes
-var shims = [];
-
-Roo.extend(Roo.Layer, Roo.Element, {
-
-    getZIndex : function(){
-        return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
-    },
-
-    getShim : function(){
-        if(!this.useShim){
-            return null;
-        }
-        if(this.shim){
-            return this.shim;
-        }
-        var shim = shims.shift();
-        if(!shim){
-            shim = this.createShim();
-            shim.enableDisplayMode('block');
-            shim.dom.style.display = 'none';
-            shim.dom.style.visibility = 'visible';
-        }
-        var pn = this.dom.parentNode;
-        if(shim.dom.parentNode != pn){
-            pn.insertBefore(shim.dom, this.dom);
-        }
-        shim.setStyle('z-index', this.getZIndex()-2);
-        this.shim = shim;
-        return shim;
-    },
-
-    hideShim : function(){
-        if(this.shim){
-            this.shim.setDisplayed(false);
-            shims.push(this.shim);
-            delete this.shim;
-        }
-    },
-
-    disableShadow : function(){
-        if(this.shadow){
-            this.shadowDisabled = true;
-            this.shadow.hide();
-            this.lastShadowOffset = this.shadowOffset;
-            this.shadowOffset = 0;
-        }
-    },
-
-    enableShadow : function(show){
-        if(this.shadow){
-            this.shadowDisabled = false;
-            this.shadowOffset = this.lastShadowOffset;
-            delete this.lastShadowOffset;
-            if(show){
-                this.sync(true);
-            }
-        }
-    },
-
-    // private
-    // this code can execute repeatedly in milliseconds (i.e. during a drag) so
-    // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
-    sync : function(doShow){
-        var sw = this.shadow;
-        if(!this.updating && this.isVisible() && (sw || this.useShim)){
-            var sh = this.getShim();
-
-            var w = this.getWidth(),
-                h = this.getHeight();
-
-            var l = this.getLeft(true),
-                t = this.getTop(true);
-
-            if(sw && !this.shadowDisabled){
-                if(doShow && !sw.isVisible()){
-                    sw.show(this);
-                }else{
-                    sw.realign(l, t, w, h);
-                }
-                if(sh){
-                    if(doShow){
-                       sh.show();
-                    }
-                    // fit the shim behind the shadow, so it is shimmed too
-                    var a = sw.adjusts, s = sh.dom.style;
-                    s.left = (Math.min(l, l+a.l))+"px";
-                    s.top = (Math.min(t, t+a.t))+"px";
-                    s.width = (w+a.w)+"px";
-                    s.height = (h+a.h)+"px";
-                }
-            }else if(sh){
-                if(doShow){
-                   sh.show();
-                }
-                sh.setSize(w, h);
-                sh.setLeftTop(l, t);
-            }
-            
-        }
-    },
-
-    // private
-    destroy : function(){
-        this.hideShim();
-        if(this.shadow){
-            this.shadow.hide();
-        }
-        this.removeAllListeners();
-        var pn = this.dom.parentNode;
-        if(pn){
-            pn.removeChild(this.dom);
-        }
-        Roo.Element.uncache(this.id);
-    },
-
-    remove : function(){
-        this.destroy();
-    },
-
-    // private
-    beginUpdate : function(){
-        this.updating = true;
-    },
-
-    // private
-    endUpdate : function(){
-        this.updating = false;
-        this.sync(true);
-    },
-
-    // private
-    hideUnders : function(negOffset){
-        if(this.shadow){
-            this.shadow.hide();
-        }
-        this.hideShim();
-    },
-
-    // private
-    constrainXY : function(){
-        if(this.constrain){
-            var vw = Roo.lib.Dom.getViewWidth(),
-                vh = Roo.lib.Dom.getViewHeight();
-            var s = Roo.get(document).getScroll();
-
-            var xy = this.getXY();
-            var x = xy[0], y = xy[1];   
-            var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
-            // only move it if it needs it
-            var moved = false;
-            // first validate right/bottom
-            if((x + w) > vw+s.left){
-                x = vw - w - this.shadowOffset;
-                moved = true;
-            }
-            if((y + h) > vh+s.top){
-                y = vh - h - this.shadowOffset;
-                moved = true;
-            }
-            // then make sure top/left isn't negative
-            if(x < s.left){
-                x = s.left;
-                moved = true;
-            }
-            if(y < s.top){
-                y = s.top;
-                moved = true;
-            }
-            if(moved){
-                if(this.avoidY){
-                    var ay = this.avoidY;
-                    if(y <= ay && (y+h) >= ay){
-                        y = ay-h-5;   
-                    }
-                }
-                xy = [x, y];
-                this.storeXY(xy);
-                supr.setXY.call(this, xy);
-                this.sync();
-            }
-        }
-    },
-
-    isVisible : function(){
-        return this.visible;    
-    },
-
-    // private
-    showAction : function(){
-        this.visible = true; // track visibility to prevent getStyle calls
-        if(this.useDisplay === true){
-            this.setDisplayed("");
-        }else if(this.lastXY){
-            supr.setXY.call(this, this.lastXY);
-        }else if(this.lastLT){
-            supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
-        }
-    },
-
-    // private
-    hideAction : function(){
-        this.visible = false;
-        if(this.useDisplay === true){
-            this.setDisplayed(false);
-        }else{
-            this.setLeftTop(-10000,-10000);
-        }
-    },
-
-    // overridden Element method
-    setVisible : function(v, a, d, c, e){
-        if(v){
-            this.showAction();
-        }
-        if(a && v){
-            var cb = function(){
-                this.sync(true);
-                if(c){
-                    c();
-                }
-            }.createDelegate(this);
-            supr.setVisible.call(this, true, true, d, cb, e);
-        }else{
-            if(!v){
-                this.hideUnders(true);
-            }
-            var cb = c;
-            if(a){
-                cb = function(){
-                    this.hideAction();
-                    if(c){
-                        c();
-                    }
-                }.createDelegate(this);
-            }
-            supr.setVisible.call(this, v, a, d, cb, e);
-            if(v){
-                this.sync(true);
-            }else if(!a){
-                this.hideAction();
-            }
-        }
-    },
-
-    storeXY : function(xy){
-        delete this.lastLT;
-        this.lastXY = xy;
-    },
-
-    storeLeftTop : function(left, top){
-        delete this.lastXY;
-        this.lastLT = [left, top];
-    },
-
-    // private
-    beforeFx : function(){
-        this.beforeAction();
-        return Roo.Layer.superclass.beforeFx.apply(this, arguments);
-    },
-
-    // private
-    afterFx : function(){
-        Roo.Layer.superclass.afterFx.apply(this, arguments);
-        this.sync(this.isVisible());
-    },
-
-    // private
-    beforeAction : function(){
-        if(!this.updating && this.shadow){
-            this.shadow.hide();
-        }
-    },
-
-    // overridden Element method
-    setLeft : function(left){
-        this.storeLeftTop(left, this.getTop(true));
-        supr.setLeft.apply(this, arguments);
-        this.sync();
-    },
-
-    setTop : function(top){
-        this.storeLeftTop(this.getLeft(true), top);
-        supr.setTop.apply(this, arguments);
-        this.sync();
-    },
-
-    setLeftTop : function(left, top){
-        this.storeLeftTop(left, top);
-        supr.setLeftTop.apply(this, arguments);
-        this.sync();
-    },
-
-    setXY : function(xy, a, d, c, e){
-        this.fixDisplay();
-        this.beforeAction();
-        this.storeXY(xy);
-        var cb = this.createCB(c);
-        supr.setXY.call(this, xy, a, d, cb, e);
-        if(!a){
-            cb();
-        }
-    },
-
-    // private
-    createCB : function(c){
-        var el = this;
-        return function(){
-            el.constrainXY();
-            el.sync(true);
-            if(c){
-                c();
-            }
-        };
-    },
-
-    // overridden Element method
-    setX : function(x, a, d, c, e){
-        this.setXY([x, this.getY()], a, d, c, e);
-    },
-
-    // overridden Element method
-    setY : function(y, a, d, c, e){
-        this.setXY([this.getX(), y], a, d, c, e);
-    },
-
-    // overridden Element method
-    setSize : function(w, h, a, d, c, e){
-        this.beforeAction();
-        var cb = this.createCB(c);
-        supr.setSize.call(this, w, h, a, d, cb, e);
-        if(!a){
-            cb();
-        }
-    },
-
-    // overridden Element method
-    setWidth : function(w, a, d, c, e){
-        this.beforeAction();
-        var cb = this.createCB(c);
-        supr.setWidth.call(this, w, a, d, cb, e);
-        if(!a){
-            cb();
-        }
-    },
-
-    // overridden Element method
-    setHeight : function(h, a, d, c, e){
-        this.beforeAction();
-        var cb = this.createCB(c);
-        supr.setHeight.call(this, h, a, d, cb, e);
-        if(!a){
-            cb();
-        }
-    },
-
-    // overridden Element method
-    setBounds : function(x, y, w, h, a, d, c, e){
-        this.beforeAction();
-        var cb = this.createCB(c);
-        if(!a){
-            this.storeXY([x, y]);
-            supr.setXY.call(this, [x, y]);
-            supr.setSize.call(this, w, h, a, d, cb, e);
-            cb();
-        }else{
-            supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
-        }
-        return this;
-    },
-    
-    /**
-     * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
-     * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
-     * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
-     * @param {Number} zindex The new z-index to set
-     * @return {this} The Layer
-     */
-    setZIndex : function(zindex){
-        this.zindex = zindex;
-        this.setStyle("z-index", zindex + 2);
-        if(this.shadow){
-            this.shadow.setZIndex(zindex + 1);
-        }
-        if(this.shim){
-            this.shim.setStyle("z-index", zindex);
-        }
-    }
-});
-})();/*
- * 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">
- */
 
 
 /**
@@ -25924,6 +27587,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)
@@ -29237,7 +30901,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,
@@ -29485,7 +31149,23 @@ Roo.extend(Roo.Button, Roo.util.Observable, {
             this.hide();
         }
     },
-    
+    /**
+        * Similar to toggle, but does not trigger event.
+        * @param {Boolean} state [required] Force a particular state
+        */
+       setPressed : function(state)
+       {
+           if(state != this.pressed){
+            if(state){
+                this.el.addClass("x-btn-pressed");
+                this.pressed = true;
+            }else{
+                this.el.removeClass("x-btn-pressed");
+                this.pressed = false;
+            }
+        }
+       },
+       
     /**
      * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
      * @param {Boolean} state (optional) Force a particular state
@@ -29508,6 +31188,8 @@ Roo.extend(Roo.Button, Roo.util.Observable, {
         }
     },
     
+       
+       
     /**
      * Focus the button
      */
@@ -29859,6 +31541,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
@@ -29900,7 +31583,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
@@ -30371,7 +32054,7 @@ Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
  * A simple class that renders text directly into a toolbar.
  * @constructor
  * Creates a new TextItem
- * @param {String} text
+ * @cfg {string} text 
  */
 Roo.Toolbar.TextItem = function(cfg){
     var  text = cfg || "";
@@ -30394,7 +32077,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";
+    }
+    
 });
 
 /**
@@ -30408,7 +32107,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);
@@ -30514,6 +32216,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
@@ -30549,10 +32252,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
@@ -30561,6 +32261,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)
@@ -30757,7 +32459,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;
@@ -31847,6 +33553,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", {
@@ -32956,6 +34663,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):
@@ -33041,6 +34750,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
@@ -33100,6 +34831,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>
@@ -33122,7 +34854,7 @@ Roo.Msg.show({
    animEl: 'elId'
 });
 </code></pre>
- * @singleton
+ * @static
  */
 Roo.MessageBox = function(){
     var dlg, opt, mask, waitTimer;
@@ -33209,6 +34941,7 @@ Roo.MessageBox = function(){
                         }
                     }
                 });
+              
                 dlg.on("hide", handleHide);
                 mask = dlg.mask;
                 dlg.addKeyListener(27, handleEsc);
@@ -33452,6 +35185,7 @@ Roo.Msg.show({
                 d.animateTarget = null;
                 d.show(options.animEl);
             }
+            dlg.toFront();
             return this;
         },
 
@@ -33651,7 +35385,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;
@@ -34053,7 +35787,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
@@ -34070,8 +35804,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>
@@ -36816,7 +38550,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
  *
  * 
  */
@@ -37122,7 +38856,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
@@ -37233,6 +38967,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
@@ -37802,7 +39537,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();
@@ -37990,6 +39725,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
@@ -38136,6 +39872,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
@@ -38215,7 +39952,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 : '',
     
@@ -38305,14 +40042,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: '',
@@ -38773,6 +40513,14 @@ Roo.extend(Roo.form.TextItem, Roo.BoxComponent,  {
             }
             this.el = ct.createChild(cfg, position);
         }
+    },
+    /*
+     * setHTML
+     * @param {String} html update the Contents of the element.
+     */
+    setHTML : function(html)
+    {
+        this.fieldEl.dom.innerHTML = html;
     }
     
 });/*
@@ -39441,6 +41189,10 @@ Roo.extend(Roo.form.TextField, Roo.form.Field,  {
      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
      */
     selectOnFocus : false,
+    /**
+     * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space 
+     */    
+    allowLeadingSpace : false,
     /**
      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
      */
@@ -39485,8 +41237,11 @@ Roo.extend(Roo.form.TextField, Roo.form.Field,  {
         
         if(this.selectOnFocus){
             this.on("focus", this.preFocus, this);
-            
         }
+       if (!this.allowLeadingSpace) {
+           this.on('blur', this.cleanLeadingSpace, this);
+       }
+       
         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
             this.el.on("keypress", this.filterKeys, this);
         }
@@ -39522,7 +41277,15 @@ Roo.extend(Roo.form.TextField, Roo.form.Field,  {
             this.autoSize();
         }
     },
-
+    // private - clean the leading white space
+    cleanLeadingSpace : function(e)
+    {
+        if ( this.inputType == 'file') {
+            return;
+        }
+        
+        this.setValue((this.getValue() + '').replace(/^\s+/,''));
+    },
     /**
      * Resets the current field value to the originally-loaded value and clears any validation messages.
      *  
@@ -39530,9 +41293,7 @@ Roo.extend(Roo.form.TextField, Roo.form.Field,  {
     reset : function(){
         Roo.form.TextField.superclass.reset.call(this);
        
-    },
-
-    
+    }, 
     // private
     preFocus : function(){
         
@@ -40284,7 +42045,8 @@ Roo.extend(Roo.form.NumberField, Roo.form.TextField,  {
 * Create a new DateField
 * @param {Object} config
  */
-Roo.form.DateField = function(config){
+Roo.form.DateField = function(config)
+{
     Roo.form.DateField.superclass.constructor.call(this, config);
     
       this.addEvents({
@@ -40363,6 +42125,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
@@ -40539,6 +42311,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;
         }
@@ -40554,6 +42335,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;
     },
 
@@ -40632,7 +42416,13 @@ dateField.setValue('2006-5-4');
         
         return String(this.getValue()) !== String(this.startValue);
         
+    },
+    // @overide
+    cleanLeadingSpace : function(e)
+    {
+       return;
     }
+    
 });/*
  * Based on:
  * Ext JS Library 1.1.1
@@ -41345,9 +43135,11 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
     // element that contains real text value.. (when hidden is used..)
      
     // private
-    onRender : function(ct, position){
+    onRender : function(ct, position)
+    {
         Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
-        if(this.hiddenName){
+        
+       if(this.hiddenName){
             this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id:  (this.hiddenId||this.hiddenName)},
                     'before', true);
             this.hiddenField.value =
@@ -41359,6 +43151,7 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
              
              
         }
+       
         if(Roo.isGecko){
             this.el.dom.setAttribute('autocomplete', 'off');
         }
@@ -41419,7 +43212,9 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
         }
 
         this.view = new Roo.View(this.innerList, this.tpl, {
-            singleSelect:true, store: this.store, selectedClass: this.selectedClass
+            singleSelect:true,
+           store: this.store,
+           selectedClass: this.selectedClass
         });
 
         this.view.on('click', this.onViewClick, this);
@@ -42106,7 +43901,7 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
         this.view.select(match);
         var sn = Roo.get(this.view.getSelectedNodes()[0]);
         sn.scrollIntoView(sn.dom.parentNode, false);
-    }
+    } 
 
     /** 
     * @cfg {Boolean} grow 
@@ -42198,7 +43993,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,
@@ -42220,7 +44015,10 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
      * @cfg {String} hiddenName    The hidden name of the field, often contains an comma seperated list of names
      */
     hiddenName : false,
-    
+      /**
+     * @cfg {String} seperator    The value seperator normally ',' 
+     */
+    seperator : ',',
     
     // private the array of items that are displayed..
     items  : false,
@@ -42241,7 +44039,7 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
         
         // give fake names to child combo;
         this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
-        this.combo.name = this.name? (this.name+'-subcombo') : this.name;
+        this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
         
         this.combo = Roo.factory(this.combo, Roo.form);
         this.combo.onRender(ct, position);
@@ -42362,6 +44160,7 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
     {
         var valueField = this.combo.valueField;
         var displayField = this.combo.displayField;
+       
         if (this.items.indexOfKey(rec[valueField]) > -1) {
             //console.log("GOT " + rec.data.id);
             return;
@@ -42393,9 +44192,8 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
         
         this.items.each(function(f) {
             ar.push(f.data[idField]);
-           
         });
-        this.hiddenEl.dom.value = ar.join(',');
+        this.hiddenEl.dom.value = ar.join(this.seperator);
         this.validate();
     },
     
@@ -42419,17 +44217,15 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
     },
     setValue: function(v) // not a valid action - must use addItems..
     {
-         
-        this.reset();
-        
-        
         
+        this.reset();
+         
         if (this.store.isLocal && (typeof(v) == 'string')) {
             // then we can use the store to find the values..
             // comma seperated at present.. this needs to allow JSON based encoding..
             this.hiddenEl.value  = v;
             var v_ar = [];
-            Roo.each(v.split(','), function(k) {
+            Roo.each(v.split(this.seperator), function(k) {
                 Roo.log("CHECK " + this.valueField + ',' + k);
                 var li = this.store.query(this.valueField, k);
                 if (!li.length) {
@@ -42446,7 +44242,13 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
         if (typeof(v) == 'object' ) {
             // then let's assume it's an array of objects..
             Roo.each(v, function(l) {
-                this.addItem(l);
+                var add = l;
+                if (typeof(l) == 'string') {
+                    add = {};
+                    add[this.valueField] = l;
+                    add[this.displayField] = l
+                }
+                this.addItem(add);
             }, this);
              
         }
@@ -42468,10 +44270,9 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
         dv = typeof(dv) != 'string' ? '' : dv;
         
         
-        var keys = kv.split(',');
-        var display = dv.split(',');
+        var keys = kv.split(this.seperator);
+        var display = dv.split(this.seperator);
         for (var i = 0 ; i < keys.length; i++) {
-            
             add = {};
             add[this.valueField] = keys[i];
             add[this.displayField] = display[i];
@@ -42519,7 +44320,7 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
             originalValue.push(d[i][this.valueField]);
         }
         
-        return String(this.getValue()) !== String(originalValue.join(','));
+        return String(this.getValue()) !== String(originalValue.join(this.seperator));
         
     }
     
@@ -42607,6 +44408,434 @@ Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
         }
         
     }
+});/*
+ * RooJS Library 1.1.1
+ * Copyright(c) 2008-2011  Alan Knowles
+ *
+ * License - LGPL
+ */
+
+/**
+ * @class Roo.form.ComboNested
+ * @extends Roo.form.ComboBox
+ * A combobox for that allows selection of nested items in a list,
+ * eg.
+ *
+ *  Book
+ *    -> red
+ *    -> green
+ *  Table
+ *    -> square
+ *      ->red
+ *      ->green
+ *    -> rectangle
+ *      ->green
+ *      
+ * 
+ * @constructor
+ * Create a new ComboNested
+ * @param {Object} config Configuration options
+ */
+Roo.form.ComboNested = function(config){
+    Roo.form.ComboCheck.superclass.constructor.call(this, config);
+    // should verify some data...
+    // like
+    // hiddenName = required..
+    // displayField = required
+    // valudField == required
+    var req= [ 'hiddenName', 'displayField', 'valueField' ];
+    var _t = this;
+    Roo.each(req, function(e) {
+        if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
+            throw "Roo.form.ComboNested : missing value for: " + e;
+        }
+    });
+     
+    
+};
+
+Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
+   
+    /*
+     * @config {Number} max Number of columns to show
+     */
+    
+    maxColumns : 3,
+   
+    list : null, // the outermost div..
+    innerLists : null, // the
+    views : null,
+    stores : null,
+    // private
+    loadingChildren : false,
+    
+    onRender : function(ct, position)
+    {
+        Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
+        
+        if(this.hiddenName){
+            this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id:  (this.hiddenId||this.hiddenName)},
+                    'before', true);
+            this.hiddenField.value =
+                this.hiddenValue !== undefined ? this.hiddenValue :
+                this.value !== undefined ? this.value : '';
+
+            // prevent input submission
+            this.el.dom.removeAttribute('name');
+             
+             
+        }
+       
+        if(Roo.isGecko){
+            this.el.dom.setAttribute('autocomplete', 'off');
+        }
+
+        var cls = 'x-combo-list';
+
+        this.list = new Roo.Layer({
+            shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
+        });
+
+        var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
+        this.list.setWidth(lw);
+        this.list.swallowEvent('mousewheel');
+        this.assetHeight = 0;
+
+        if(this.title){
+            this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
+            this.assetHeight += this.header.getHeight();
+        }
+        this.innerLists = [];
+        this.views = [];
+        this.stores = [];
+        for (var i =0 ; i < this.maxColumns; i++) {
+            this.onRenderList( cls, i);
+        }
+        
+        // always needs footer, as we are going to have an 'OK' button.
+        this.footer = this.list.createChild({cls:cls+'-ft'});
+        this.pageTb = new Roo.Toolbar(this.footer);  
+        var _this = this;
+        this.pageTb.add(  {
+            
+            text: 'Done',
+            handler: function()
+            {
+                _this.collapse();
+            }
+        });
+        
+        if ( this.allowBlank && !this.disableClear) {
+            
+            this.pageTb.add(new Roo.Toolbar.Fill(), {
+                cls: 'x-btn-icon x-btn-clear',
+                text: '&#160;',
+                handler: function()
+                {
+                    _this.collapse();
+                    _this.clearValue();
+                    _this.onSelect(false, -1);
+                }
+            });
+        }
+        if (this.footer) {
+            this.assetHeight += this.footer.getHeight();
+        }
+        
+    },
+    onRenderList : function (  cls, i)
+    {
+        
+        var lw = Math.floor(
+                ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
+        );
+        
+        this.list.setWidth(lw); // default to '1'
+
+        var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
+        //il.on('mouseover', this.onViewOver, this, { list:  i });
+        //il.on('mousemove', this.onViewMove, this, { list:  i });
+        il.setWidth(lw);
+        il.setStyle({ 'overflow-x' : 'hidden'});
+
+        if(!this.tpl){
+            this.tpl = new Roo.Template({
+                html :  '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
+                isEmpty: function (value, allValues) {
+                    //Roo.log(value);
+                    var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
+                    return dl ? 'has-children' : 'no-children'
+                }
+            });
+        }
+        
+        var store  = this.store;
+        if (i > 0) {
+            store  = new Roo.data.SimpleStore({
+                //fields : this.store.reader.meta.fields,
+                reader : this.store.reader,
+                data : [ ]
+            });
+        }
+        this.stores[i]  = store;
+                  
+        var view = this.views[i] = new Roo.View(
+            il,
+            this.tpl,
+            {
+                singleSelect:true,
+                store: store,
+                selectedClass: this.selectedClass
+            }
+        );
+        view.getEl().setWidth(lw);
+        view.getEl().setStyle({
+            position: i < 1 ? 'relative' : 'absolute',
+            top: 0,
+            left: (i * lw ) + 'px',
+            display : i > 0 ? 'none' : 'block'
+        });
+        view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
+        view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
+        //view.on('click', this.onViewClick, this, { list : i });
+
+        store.on('beforeload', this.onBeforeLoad, this);
+        store.on('load',  this.onLoad, this, { list  : i});
+        store.on('loadexception', this.onLoadException, this);
+
+        // hide the other vies..
+        
+        
+        
+    },
+      
+    restrictHeight : function()
+    {
+        var mh = 0;
+        Roo.each(this.innerLists, function(il,i) {
+            var el = this.views[i].getEl();
+            el.dom.style.height = '';
+            var inner = el.dom;
+            var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
+            // only adjust heights on other ones..
+            mh = Math.max(h, mh);
+            if (i < 1) {
+                
+                el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
+                il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
+               
+            }
+            
+            
+        }, this);
+        
+        this.list.beginUpdate();
+        this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
+        this.list.alignTo(this.el, this.listAlign);
+        this.list.endUpdate();
+        
+    },
+     
+    
+    // -- store handlers..
+    // private
+    onBeforeLoad : function()
+    {
+        if(!this.hasFocus){
+            return;
+        }
+        this.innerLists[0].update(this.loadingText ?
+               '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
+        this.restrictHeight();
+        this.selectedIndex = -1;
+    },
+    // private
+    onLoad : function(a,b,c,d)
+    {
+        if (!this.loadingChildren) {
+            // then we are loading the top level. - hide the children
+            for (var i = 1;i < this.views.length; i++) {
+                this.views[i].getEl().setStyle({ display : 'none' });
+            }
+            var lw = Math.floor(
+                ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
+            );
+        
+             this.list.setWidth(lw); // default to '1'
+
+            
+        }
+        if(!this.hasFocus){
+            return;
+        }
+        
+        if(this.store.getCount() > 0) {
+            this.expand();
+            this.restrictHeight();   
+        } else {
+            this.onEmptyResults();
+        }
+        
+        if (!this.loadingChildren) {
+            this.selectActive();
+        }
+        /*
+        this.stores[1].loadData([]);
+        this.stores[2].loadData([]);
+        this.views
+        */    
+    
+        //this.el.focus();
+    },
+    
+    
+    // private
+    onLoadException : function()
+    {
+        this.collapse();
+        Roo.log(this.store.reader.jsonData);
+        if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
+            Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
+        }
+        
+        
+    },
+    // no cleaning of leading spaces on blur here.
+    cleanLeadingSpace : function(e) { },
+    
+
+    onSelectChange : function (view, sels, opts )
+    {
+        var ix = view.getSelectedIndexes();
+         
+        if (opts.list > this.maxColumns - 2) {
+            if (view.store.getCount()<  1) {
+                this.views[opts.list ].getEl().setStyle({ display :   'none' });
+
+            } else  {
+                if (ix.length) {
+                    // used to clear ?? but if we are loading unselected 
+                    this.setFromData(view.store.getAt(ix[0]).data);
+                }
+                
+            }
+            
+            return;
+        }
+        
+        if (!ix.length) {
+            // this get's fired when trigger opens..
+           // this.setFromData({});
+            var str = this.stores[opts.list+1];
+            str.data.clear(); // removeall wihtout the fire events..
+            return;
+        }
+        
+        var rec = view.store.getAt(ix[0]);
+         
+        this.setFromData(rec.data);
+        this.fireEvent('select', this, rec, ix[0]);
+        
+        var lw = Math.floor(
+             (
+                (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
+             ) / this.maxColumns
+        );
+        this.loadingChildren = true;
+        this.stores[opts.list+1].loadDataFromChildren( rec );
+        this.loadingChildren = false;
+        var dl = this.stores[opts.list+1]. getTotalCount();
+        
+        this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
+        
+        this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
+        for (var i = opts.list+2; i < this.views.length;i++) {
+            this.views[i].getEl().setStyle({ display : 'none' });
+        }
+        
+        this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
+        this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
+        
+        if (this.isLoading) {
+           // this.selectActive(opts.list);
+        }
+         
+    },
+    
+    
+    
+    
+    onDoubleClick : function()
+    {
+        this.collapse(); //??
+    },
+    
+     
+    
+    
+    
+    // private
+    recordToStack : function(store, prop, value, stack)
+    {
+        var cstore = new Roo.data.SimpleStore({
+            //fields : this.store.reader.meta.fields, // we need array reader.. for
+            reader : this.store.reader,
+            data : [ ]
+        });
+        var _this = this;
+        var record  = false;
+        var srec = false;
+        if(store.getCount() < 1){
+            return false;
+        }
+        store.each(function(r){
+            if(r.data[prop] == value){
+                record = r;
+            srec = r;
+                return false;
+            }
+            if (r.data.cn && r.data.cn.length) {
+                cstore.loadDataFromChildren( r);
+                var cret = _this.recordToStack(cstore, prop, value, stack);
+                if (cret !== false) {
+                    record = cret;
+                    srec = r;
+                    return false;
+                }
+            }
+             
+            return true;
+        });
+        if (record == false) {
+            return false
+        }
+        stack.unshift(srec);
+        return record;
+    },
+    
+    /*
+     * find the stack of stores that match our value.
+     *
+     * 
+     */
+    
+    selectActive : function ()
+    {
+       // if store is not loaded, then we will need to wait for that to happen first.
+        var stack = [];
+        this.recordToStack(this.store, this.valueField, this.getValue(), stack);
+        for (var i = 0; i < stack.length; i++ ) {
+            this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
+        }
+       
+    }
+       
+        
+    
+    
+    
+    
 });/*
  * Based on:
  * Ext JS Library 1.1.1
@@ -42799,7 +45028,9 @@ Roo.extend(Roo.form.Checkbox, Roo.form.Field,  {
             this.fireEvent('check', this, state);
         }
         this.inSetChecked = true;
-        this.el.dom.value = state ? this.inputValue : this.valueOff;
+                
+               this.el.dom.value = state ? this.inputValue : this.valueOff;
+                
         this.inSetChecked = false;
         
     },
@@ -42890,1222 +45121,1108 @@ Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
             this.el.dom.checked =   'checked' ;
         }
          
+    },
+    /**
+     * Sets the checked state of the checkbox.
+     * On is always based on a string comparison between inputValue and the param.
+     * @param {Boolean/String} value - the value to set 
+     * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
+     */
+    setValue : function(v,suppressEvent){
+        
+        
+        //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
+        //if(this.el && this.el.dom){
+        //    this.el.dom.checked = this.checked;
+        //    this.el.dom.defaultChecked = this.checked;
+        //}
+        this.setChecked(String(v) === String(this.inputValue), suppressEvent);
+        
+        this.el.dom.form[this.name].value = v;
+     
+        //this.fireEvent("check", this, this.checked);
+    },
+    // private..
+    setChecked : function(state,suppressEvent)
+    {
+         
+        if(this.wrap){
+            this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
+        }
+        this.checked = state;
+        if(suppressEvent !== true){
+            this.fireEvent('check', this, state);
+        }
+                
+                 
+       
+        
+    },
+    reset : function(){
+        // this.setValue(this.resetValue);
+        //this.originalValue = this.getValue();
+        this.clearInvalid();
     } 
     
-    
-});//<script type="text/javascript">
-
-/*
- * Based  Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- * LGPL
- *
- */
-/**
- * @class Roo.HtmlEditorCore
- * @extends Roo.Component
- * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
- *
- * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
- */
+});Roo.rtf = {}; // namespace
+Roo.rtf.Hex = function(hex)
+{
+    this.hexstr = hex;
+};
+Roo.rtf.Paragraph = function(opts)
+{
+    this.content = []; ///??? is that used?
+};Roo.rtf.Span = function(opts)
+{
+    this.value = opts.value;
+};
 
-Roo.HtmlEditorCore = function(config){
-    
-    
-    Roo.HtmlEditorCore.superclass.constructor.call(this, config);
-    
+Roo.rtf.Group = function(parent)
+{
+    // we dont want to acutally store parent - it will make debug a nightmare..
+    this.content = [];
+    this.cn  = [];
+     
+       
     
-    this.addEvents({
-        /**
-         * @event initialize
-         * Fires when the editor is fully initialized (including the iframe)
-         * @param {Roo.HtmlEditorCore} this
-         */
-        initialize: true,
-        /**
-         * @event activate
-         * Fires when the editor is first receives the focus. Any insertion must wait
-         * until after this event.
-         * @param {Roo.HtmlEditorCore} this
-         */
-        activate: true,
-         /**
-         * @event beforesync
-         * Fires before the textarea is updated with content from the editor iframe. Return false
-         * to cancel the sync.
-         * @param {Roo.HtmlEditorCore} this
-         * @param {String} html
-         */
-        beforesync: true,
-         /**
-         * @event beforepush
-         * Fires before the iframe editor is updated with content from the textarea. Return false
-         * to cancel the push.
-         * @param {Roo.HtmlEditorCore} this
-         * @param {String} html
-         */
-        beforepush: true,
-         /**
-         * @event sync
-         * Fires when the textarea is updated with content from the editor iframe.
-         * @param {Roo.HtmlEditorCore} this
-         * @param {String} html
-         */
-        sync: true,
-         /**
-         * @event push
-         * Fires when the iframe editor is updated with content from the textarea.
-         * @param {Roo.HtmlEditorCore} this
-         * @param {String} html
-         */
-        push: true,
+};
+
+Roo.rtf.Group.prototype = {
+    ignorable : false,
+    content: false,
+    cn: false,
+    addContent : function(node) {
+        // could set styles...
+        this.content.push(node);
+    },
+    addChild : function(cn)
+    {
+        this.cn.push(cn);
+    },
+    // only for images really...
+    toDataURL : function()
+    {
+        var mimetype = false;
+        switch(true) {
+            case this.content.filter(function(a) { return a.value == 'pngblip' } ).length > 0: 
+                mimetype = "image/png";
+                break;
+             case this.content.filter(function(a) { return a.value == 'jpegblip' } ).length > 0:
+                mimetype = "image/jpeg";
+                break;
+            default :
+                return 'about:blank'; // ?? error?
+        }
         
-        /**
-         * @event editorevent
-         * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
-         * @param {Roo.HtmlEditorCore} this
-         */
-        editorevent: true
         
-    });
-    
-    // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
+        var hexstring = this.content[this.content.length-1].value;
+        
+        return 'data:' + mimetype + ';base64,' + btoa(hexstring.match(/\w{2}/g).map(function(a) {
+            return String.fromCharCode(parseInt(a, 16));
+        }).join(""));
+    }
     
-    // defaults : white / black...
-    this.applyBlacklists();
+};
+// this looks like it's normally the {rtf{ .... }}
+Roo.rtf.Document = function()
+{
+    // we dont want to acutally store parent - it will make debug a nightmare..
+    this.rtlch  = [];
+    this.content = [];
+    this.cn = [];
     
+};
+Roo.extend(Roo.rtf.Document, Roo.rtf.Group, { 
+    addChild : function(cn)
+    {
+        this.cn.push(cn);
+        switch(cn.type) {
+            case 'rtlch': // most content seems to be inside this??
+            case 'listtext':
+            case 'shpinst':
+                this.rtlch.push(cn);
+                return;
+            default:
+                this[cn.type] = cn;
+        }
+        
+    },
     
+    getElementsByType : function(type)
+    {
+        var ret =  [];
+        this._getElementsByType(type, ret, this.cn, 'rtf');
+        return ret;
+    },
+    _getElementsByType : function (type, ret, search_array, path)
+    {
+        search_array.forEach(function(n,i) {
+            if (n.type == type) {
+                n.path = path + '/' + n.type + ':' + i;
+                ret.push(n);
+            }
+            if (n.cn.length > 0) {
+                this._getElementsByType(type, ret, n.cn, path + '/' + n.type+':'+i);
+            }
+        },this);
+    }
     
+});
+Roo.rtf.Ctrl = function(opts)
+{
+    this.value = opts.value;
+    this.param = opts.param;
 };
+/**
+ *
+ *
+ * based on this https://github.com/iarna/rtf-parser
+ * it's really only designed to extract pict from pasted RTF 
+ *
+ * usage:
+ *
+ *  var images = new Roo.rtf.Parser().parse(a_string).filter(function(g) { return g.type == 'pict'; });
+ *  
+ *
+ */
 
 
-Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
 
 
-     /**
-     * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
-     */
+Roo.rtf.Parser = function(text) {
+    //super({objectMode: true})
+    this.text = '';
+    this.parserState = this.parseText;
     
-    owner : false,
+    // these are for interpeter...
+    this.doc = {};
+    ///this.parserState = this.parseTop
+    this.groupStack = [];
+    this.hexStore = [];
+    this.doc = false;
     
-     /**
-     * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
-     *                        Roo.resizable.
-     */
-    resizable : false,
-     /**
-     * @cfg {Number} height (in pixels)
-     */   
-    height: 300,
-   /**
-     * @cfg {Number} width (in pixels)
-     */   
-    width: 500,
+    this.groups = []; // where we put the return.
     
-    /**
-     * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
-     * 
-     */
-    stylesheets: false,
+    for (var ii = 0; ii < text.length; ++ii) {
+        ++this.cpos;
+        
+        if (text[ii] === '\n') {
+            ++this.row;
+            this.col = 1;
+        } else {
+            ++this.col;
+        }
+        this.parserState(text[ii]);
+    }
     
-    // id of frame..
-    frameId: false,
     
-    // private properties
-    validationEvent : false,
-    deferHeight: true,
-    initialized : false,
-    activated : false,
-    sourceEditMode : false,
-    onFocus : Roo.emptyFn,
-    iframePad:3,
-    hideMode:'offsets',
     
-    clearUp: true,
+};
+Roo.rtf.Parser.prototype = {
+    text : '', // string being parsed..
+    controlWord : '',
+    controlWordParam :  '',
+    hexChar : '',
+    doc : false,
+    group: false,
+    groupStack : false,
+    hexStore : false,
     
-    // blacklist + whitelisted elements..
-    black: false,
-    white: false,
-     
-    bodyCls : '',
+    
+    cpos : 0, 
+    row : 1, // reportin?
+    col : 1, //
 
-    /**
-     * 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
-     * want to change the initialization markup of the iframe (e.g. to add stylesheets).
-     */
-    getDocMarkup : function(){
-        // body styles..
-        var st = '';
-        
-        // inherit styels from page...?? 
-        if (this.stylesheets === false) {
-            
-            Roo.get(document.head).select('style').each(function(node) {
-                st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
-            });
-            
-            Roo.get(document.head).select('link').each(function(node) { 
-                st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
-            });
-            
-        } else if (!this.stylesheets.length) {
-                // simple..
-                st = '<style type="text/css">' +
-                    'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
-                   '</style>';
-        } else { 
-            st = '<style type="text/css">' +
-                    this.stylesheets +
-                '</style>';
+     
+    push : function (el)
+    {
+        var m = 'cmd'+ el.type;
+        if (typeof(this[m]) == 'undefined') {
+            Roo.log('invalid cmd:' + el.type);
+            return;
+        }
+        this[m](el);
+        //Roo.log(el);
+    },
+    flushHexStore : function()
+    {
+        if (this.hexStore.length < 1) {
+            return;
         }
+        var hexstr = this.hexStore.map(
+            function(cmd) {
+                return cmd.value;
+        }).join('');
         
-        st +=  '<style type="text/css">' +
-            'IMG { cursor: pointer } ' +
-        '</style>';
-
-        var cls = 'roo-htmleditor-body';
+        this.group.addContent( new Roo.rtf.Hex( hexstr ));
+              
+            
+        this.hexStore.splice(0)
         
-        if(this.bodyCls.length){
-            cls += ' ' + this.bodyCls;
+    },
+    
+    cmdgroupstart : function()
+    {
+        this.flushHexStore();
+        if (this.group) {
+            this.groupStack.push(this.group);
         }
-        
-        return '<html><head>' + st  +
-            //<style type="text/css">' +
-            //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
-            //'</style>' +
-            ' </head><body class="' +  cls + '"></body></html>';
+         // parent..
+        if (this.doc === false) {
+            this.group = this.doc = new Roo.rtf.Document();
+            return;
+            
+        }
+        this.group = new Roo.rtf.Group(this.group);
     },
-
-    // private
-    onRender : function(ct, position)
+    cmdignorable : function()
     {
-        var _t = this;
-        //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
-        this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
-        
-        
-        this.el.dom.style.border = '0 none';
-        this.el.dom.setAttribute('tabIndex', -1);
-        this.el.addClass('x-hidden hide');
-        
+        this.flushHexStore();
+        this.group.ignorable = true;
+    },
+    cmdendparagraph : function()
+    {
+        this.flushHexStore();
+        this.group.addContent(new Roo.rtf.Paragraph());
+    },
+    cmdgroupend : function ()
+    {
+        this.flushHexStore();
+        var endingGroup = this.group;
         
         
-        if(Roo.isIE){ // fix IE 1px bogus margin
-            this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
+        this.group = this.groupStack.pop();
+        if (this.group) {
+            this.group.addChild(endingGroup);
         }
-       
-        
-        this.frameId = Roo.id();
-        
-         
-        
-        var iframe = this.owner.wrap.createChild({
-            tag: 'iframe',
-            cls: 'form-control', // bootstrap..
-            id: this.frameId,
-            name: this.frameId,
-            frameBorder : 'no',
-            'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
-        }, this.el
-        );
         
         
-        this.iframe = iframe.dom;
-
-         this.assignDocWin();
-        
-        this.doc.designMode = 'on';
-       
-        this.doc.open();
-        this.doc.write(this.getDocMarkup());
-        this.doc.close();
-
         
-        var task = { // must defer to wait for browser to be ready
-            run : function(){
-                //console.log("run task?" + this.doc.readyState);
-                this.assignDocWin();
-                if(this.doc.body || this.doc.readyState == 'complete'){
-                    try {
-                        this.doc.designMode="on";
-                    } catch (e) {
-                        return;
-                    }
-                    Roo.TaskMgr.stop(task);
-                    this.initEditor.defer(10, this);
-                }
-            },
-            interval : 10,
-            duration: 10000,
-            scope: this
-        };
-        Roo.TaskMgr.start(task);
-
+        var doc = this.group || this.doc;
+        //if (endingGroup instanceof FontTable) {
+        //  doc.fonts = endingGroup.table
+        //} else if (endingGroup instanceof ColorTable) {
+        //  doc.colors = endingGroup.table
+        //} else if (endingGroup !== this.doc && !endingGroup.get('ignorable')) {
+        if (endingGroup.ignorable === false) {
+            //code
+            this.groups.push(endingGroup);
+           // Roo.log( endingGroup );
+        }
+            //Roo.each(endingGroup.content, function(item)) {
+            //    doc.addContent(item);
+            //}
+            //process.emit('debug', 'GROUP END', endingGroup.type, endingGroup.get('ignorable'))
+        //}
     },
-
-    // private
-    onResize : function(w, h)
+    cmdtext : function (cmd)
     {
-         Roo.log('resize: ' +w + ',' + h );
-        //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
-        if(!this.iframe){
-            return;
+        this.flushHexStore();
+        if (!this.group) { // an RTF fragment, missing the {\rtf1 header
+            //this.group = this.doc
+            return;  // we really don't care about stray text...
         }
-        if(typeof w == 'number'){
-            
-            this.iframe.style.width = w + 'px';
+        this.group.addContent(new Roo.rtf.Span(cmd));
+    },
+    cmdcontrolword : function (cmd)
+    {
+        this.flushHexStore();
+        if (!this.group.type) {
+            this.group.type = cmd.value;
+            return;
         }
-        if(typeof h == 'number'){
-            
-            this.iframe.style.height = h + 'px';
-            if(this.doc){
-                (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
-            }
+        this.group.addContent(new Roo.rtf.Ctrl(cmd));
+        // we actually don't care about ctrl words...
+        return ;
+        /*
+        var method = 'ctrl$' + cmd.value.replace(/-(.)/g, (_, char) => char.toUpperCase())
+        if (this[method]) {
+            this[method](cmd.param)
+        } else {
+            if (!this.group.get('ignorable')) process.emit('debug', method, cmd.param)
         }
-        
+        */
     },
-
-    /**
-     * Toggles the editor between standard and source edit mode.
-     * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
-     */
-    toggleSourceEdit : function(sourceEditMode){
-        
-        this.sourceEditMode = sourceEditMode === true;
-        
-        if(this.sourceEditMode){
-            Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
-            
-        }else{
-            Roo.get(this.iframe).removeClass(['x-hidden','hide']);
-            //this.iframe.className = '';
-            this.deferFocus();
-        }
-        //this.setSize(this.owner.wrap.getSize());
-        //this.fireEvent('editmodechange', this, this.sourceEditMode);
+    cmdhexchar : function(cmd) {
+        this.hexStore.push(cmd);
+    },
+    cmderror : function(cmd) {
+        throw cmd.value;
     },
-
     
-  
-
-    /**
-     * Protected method that will not generally be called directly. If you need/want
-     * custom HTML cleanup, this is the method you should override.
-     * @param {String} html The HTML to be cleaned
-     * return {String} The cleaned HTML
-     */
-    cleanHtml : function(html){
-        html = String(html);
-        if(html.length > 5){
-            if(Roo.isSafari){ // strip safari nonsense
-                html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
-            }
+    /*
+      _flush (done) {
+        if (this.text !== '\u0000') this.emitText()
+        done()
+      }
+      */
+      
+      
+    parseText : function(c)
+    {
+        if (c === '\\') {
+            this.parserState = this.parseEscapes;
+        } else if (c === '{') {
+            this.emitStartGroup();
+        } else if (c === '}') {
+            this.emitEndGroup();
+        } else if (c === '\x0A' || c === '\x0D') {
+            // cr/lf are noise chars
+        } else {
+            this.text += c;
         }
-        if(html == '&nbsp;'){
-            html = '';
+    },
+    
+    parseEscapes: function (c)
+    {
+        if (c === '\\' || c === '{' || c === '}') {
+            this.text += c;
+            this.parserState = this.parseText;
+        } else {
+            this.parserState = this.parseControlSymbol;
+            this.parseControlSymbol(c);
         }
-        return html;
     },
-
-    /**
-     * HTML Editor -> Textarea
-     * Protected method that will not generally be called directly. Syncs the contents
-     * of the editor iframe with the textarea.
-     */
-    syncValue : function(){
-        if(this.initialized){
-            var bd = (this.doc.body || this.doc.documentElement);
-            //this.cleanUpPaste(); -- this is done else where and causes havoc..
-            var html = bd.innerHTML;
-            if(Roo.isSafari){
-                var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
-                var m = bs ? bs.match(/text-align:(.*?);/i) : false;
-                if(m && m[1]){
-                    html = '<div style="'+m[0]+'">' + html + '</div>';
-                }
-            }
-            html = this.cleanHtml(html);
-            // fix up the special chars.. normaly like back quotes in word...
-            // however we do not want to do this with chinese..
-            html = html.replace(/([\x80-\uffff])/g, function (a, b) {
-                var cc = b.charCodeAt();
-                if (
-                    (cc >= 0x4E00 && cc < 0xA000 ) ||
-                    (cc >= 0x3400 && cc < 0x4E00 ) ||
-                    (cc >= 0xf900 && cc < 0xfb00 )
-                ) {
-                        return b;
-                }
-                return "&#"+cc+";" 
-            });
-            if(this.owner.fireEvent('beforesync', this, html) !== false){
-                this.el.dom.value = html;
-                this.owner.fireEvent('sync', this, html);
-            }
+    parseControlSymbol: function(c)
+    {
+        if (c === '~') {
+            this.text += '\u00a0'; // nbsp
+            this.parserState = this.parseText
+        } else if (c === '-') {
+             this.text += '\u00ad'; // soft hyphen
+        } else if (c === '_') {
+            this.text += '\u2011'; // non-breaking hyphen
+        } else if (c === '*') {
+            this.emitIgnorable();
+            this.parserState = this.parseText;
+        } else if (c === "'") {
+            this.parserState = this.parseHexChar;
+        } else if (c === '|') { // formula cacter
+            this.emitFormula();
+            this.parserState = this.parseText;
+        } else if (c === ':') { // subentry in an index entry
+            this.emitIndexSubEntry();
+            this.parserState = this.parseText;
+        } else if (c === '\x0a') {
+            this.emitEndParagraph();
+            this.parserState = this.parseText;
+        } else if (c === '\x0d') {
+            this.emitEndParagraph();
+            this.parserState = this.parseText;
+        } else {
+            this.parserState = this.parseControlWord;
+            this.parseControlWord(c);
         }
     },
-
-    /**
-     * Protected method that will not generally be called directly. Pushes the value of the textarea
-     * into the iframe editor.
-     */
-    pushValue : function(){
-        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);
+    parseHexChar: function (c)
+    {
+        if (/^[A-Fa-f0-9]$/.test(c)) {
+            this.hexChar += c;
+            if (this.hexChar.length >= 2) {
+              this.emitHexChar();
+              this.parserState = this.parseText;
             }
+            return;
         }
+        this.emitError("Invalid character \"" + c + "\" in hex literal.");
+        this.parserState = this.parseText;
+        
     },
-
-    // private
-    deferFocus : function(){
-        this.focus.defer(10, this);
+    parseControlWord : function(c)
+    {
+        if (c === ' ') {
+            this.emitControlWord();
+            this.parserState = this.parseText;
+        } else if (/^[-\d]$/.test(c)) {
+            this.parserState = this.parseControlWordParam;
+            this.controlWordParam += c;
+        } else if (/^[A-Za-z]$/.test(c)) {
+          this.controlWord += c;
+        } else {
+          this.emitControlWord();
+          this.parserState = this.parseText;
+          this.parseText(c);
+        }
     },
-
-    // doc'ed in Field
-    focus : function(){
-        if(this.win && !this.sourceEditMode){
-            this.win.focus();
-        }else{
-            this.el.focus();
+    parseControlWordParam : function (c) {
+        if (/^\d$/.test(c)) {
+          this.controlWordParam += c;
+        } else if (c === ' ') {
+          this.emitControlWord();
+          this.parserState = this.parseText;
+        } else {
+          this.emitControlWord();
+          this.parserState = this.parseText;
+          this.parseText(c);
         }
     },
     
-    assignDocWin: function()
+    
+    
+    
+    emitText : function () {
+        if (this.text === '') {
+            return;
+        }
+        this.push({
+            type: 'text',
+            value: this.text,
+            pos: this.cpos,
+            row: this.row,
+            col: this.col
+        });
+        this.text = ''
+    },
+    emitControlWord : function ()
     {
-        var iframe = this.iframe;
-        
-         if(Roo.isIE){
-            this.doc = iframe.contentWindow.document;
-            this.win = iframe.contentWindow;
+        this.emitText();
+        if (this.controlWord === '') {
+            // do we want to track this - it seems just to cause problems.
+            //this.emitError('empty control word');
         } else {
-//            if (!Roo.get(this.frameId)) {
-//                return;
-//            }
-//            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
-//            this.win = Roo.get(this.frameId).dom.contentWindow;
-            
-            if (!Roo.get(this.frameId) && !iframe.contentDocument) {
-                return;
-            }
-            
-            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
-            this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
+            this.push({
+                  type: 'controlword',
+                  value: this.controlWord,
+                  param: this.controlWordParam !== '' && Number(this.controlWordParam),
+                  pos: this.cpos,
+                  row: this.row,
+                  col: this.col
+            });
         }
+        this.controlWord = '';
+        this.controlWordParam = '';
+    },
+    emitStartGroup : function ()
+    {
+        this.emitText();
+        this.push({
+            type: 'groupstart',
+            pos: this.cpos,
+            row: this.row,
+            col: this.col
+        });
+    },
+    emitEndGroup : function ()
+    {
+        this.emitText();
+        this.push({
+            type: 'groupend',
+            pos: this.cpos,
+            row: this.row,
+            col: this.col
+        });
+    },
+    emitIgnorable : function ()
+    {
+        this.emitText();
+        this.push({
+            type: 'ignorable',
+            pos: this.cpos,
+            row: this.row,
+            col: this.col
+        });
+    },
+    emitHexChar : function ()
+    {
+        this.emitText();
+        this.push({
+            type: 'hexchar',
+            value: this.hexChar,
+            pos: this.cpos,
+            row: this.row,
+            col: this.col
+        });
+        this.hexChar = ''
+    },
+    emitError : function (message)
+    {
+      this.emitText();
+      this.push({
+            type: 'error',
+            value: message,
+            row: this.row,
+            col: this.col,
+            char: this.cpos //,
+            //stack: new Error().stack
+        });
     },
+    emitEndParagraph : function () {
+        this.emitText();
+        this.push({
+            type: 'endparagraph',
+            pos: this.cpos,
+            row: this.row,
+            col: this.col
+        });
+    }
+     
+} ;
+Roo.htmleditor = {};
+/**
+ * @class Roo.htmleditor.Filter
+ * Base Class for filtering htmleditor stuff. - do not use this directly - extend it.
+ * @cfg {DomElement} node The node to iterate and filter
+ * @cfg {boolean|String|Array} tag Tags to replace 
+ * @constructor
+ * Create a new Filter.
+ * @param {Object} config Configuration options
+ */
+
+
+
+Roo.htmleditor.Filter = function(cfg) {
+    Roo.apply(this.cfg);
+    // this does not actually call walk as it's really just a abstract class
+}
+
+
+Roo.htmleditor.Filter.prototype = {
     
-    // private
-    initEditor : function(){
-        //console.log("INIT EDITOR");
-        this.assignDocWin();
-        
-        
-        
-        this.doc.designMode="on";
-        this.doc.open();
-        this.doc.write(this.getDocMarkup());
-        this.doc.close();
-        
-        var dbody = (this.doc.body || this.doc.documentElement);
-        //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
-        // this copies styles from the containing element into thsi one..
-        // not sure why we need all of this..
-        //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
+    node: false,
+    
+    tag: false,
+
+    // overrride to do replace comments.
+    replaceComment : false,
+    
+    // overrride to do replace or do stuff with tags..
+    replaceTag : false,
+    
+    walk : function(dom)
+    {
+        Roo.each( Array.from(dom.childNodes), function( e ) {
+            switch(true) {
+                
+                case e.nodeType == 8 &&  this.replaceComment  !== false: // comment
+                    this.replaceComment(e);
+                    return;
+                
+                case e.nodeType != 1: //not a node.
+                    return;
+                
+                case this.tag === true: // everything
+                case e.tagName.indexOf(":") > -1 && typeof(this.tag) == 'object' && this.tag.indexOf(":") > -1:
+                case e.tagName.indexOf(":") > -1 && typeof(this.tag) == 'string' && this.tag == ":":
+                case typeof(this.tag) == 'object' && this.tag.indexOf(e.tagName) > -1: // array and it matches.
+                case typeof(this.tag) == 'string' && this.tag == e.tagName: // array and it matches.
+                    if (this.replaceTag && false === this.replaceTag(e)) {
+                        return;
+                    }
+                    if (e.hasChildNodes()) {
+                        this.walk(e);
+                    }
+                    return;
+                
+                default:    // tags .. that do not match.
+                    if (e.hasChildNodes()) {
+                        this.walk(e);
+                    }
+            }
+            
+        }, this);
         
-        //var ss = this.el.getStyles( 'background-image', 'background-repeat');
-        //ss['background-attachment'] = 'fixed'; // w3c
-        dbody.bgProperties = 'fixed'; // ie
-        //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
-        });
-        if(Roo.isGecko){
-            Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
-        }
-        if(Roo.isIE || Roo.isSafari || Roo.isOpera){
-            Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
+    },
+    
+    
+    removeNodeKeepChildren : function( node)
+    {
+    
+        ar = Array.from(node.childNodes);
+        for (var i = 0; i < ar.length; i++) {
+         
+            node.removeChild(ar[i]);
+            // what if we need to walk these???
+            node.parentNode.insertBefore(ar[i], node);
+           
         }
-        this.initialized = true;
+        node.parentNode.removeChild(node);
+    }
+}; 
 
-        this.owner.fireEvent('initialize', this);
-        this.pushValue();
-    },
+/**
+ * @class Roo.htmleditor.FilterAttributes
+ * clean attributes and  styles including http:// etc.. in attribute
+ * @constructor
+* Run a new Attribute Filter
+* @param {Object} config Configuration options
+ */
+Roo.htmleditor.FilterAttributes = function(cfg)
+{
+    Roo.apply(this, cfg);
+    this.attrib_black = this.attrib_black || [];
+    this.attrib_white = this.attrib_white || [];
 
-    // private
-    onDestroy : function(){
-        
-        
+    this.attrib_clean = this.attrib_clean || [];
+    this.style_white = this.style_white || [];
+    this.style_black = this.style_black || [];
+    this.walk(cfg.node);
+}
+
+Roo.extend(Roo.htmleditor.FilterAttributes, Roo.htmleditor.Filter,
+{
+    tag: true, // all tags
+    
+    attrib_black : false, // array
+    attrib_clean : false,
+    attrib_white : false,
+
+    style_white : false,
+    style_black : false,
+     
+     
+    replaceTag : function(node)
+    {
+        if (!node.attributes || !node.attributes.length) {
+            return true;
+        }
         
-        if(this.rendered){
+        for (var i = node.attributes.length-1; i > -1 ; i--) {
+            var a = node.attributes[i];
+            //console.log(a);
+            if (this.attrib_white.length && this.attrib_white.indexOf(a.name.toLowerCase()) < 0) {
+                node.removeAttribute(a.name);
+                continue;
+            }
             
-            //for (var i =0; i < this.toolbars.length;i++) {
-            //    // fixme - ask toolbars for heights?
-            //    this.toolbars[i].onDestroy();
-           // }
             
-            //this.wrap.dom.innerHTML = '';
-            //this.wrap.remove();
+            
+            if (a.name.toLowerCase().substr(0,2)=='on')  {
+                node.removeAttribute(a.name);
+                continue;
+            }
+            
+            
+            if (this.attrib_black.indexOf(a.name.toLowerCase()) > -1) {
+                node.removeAttribute(a.name);
+                continue;
+            }
+            if (this.attrib_clean.indexOf(a.name.toLowerCase()) > -1) {
+                this.cleanAttr(node,a.name,a.value); // fixme..
+                continue;
+            }
+            if (a.name == 'style') {
+                this.cleanStyle(node,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?
+            
         }
+        return true; // clean children
     },
-
-    // private
-    onFirstFocus : function(){
-        
-        this.assignDocWin();
         
+    cleanAttr: function(node, n,v)
+    {
         
-        this.activated = true;
-         
-    
-        if(Roo.isGecko){ // prevent silly gecko errors
-            this.win.focus();
-            var s = this.win.getSelection();
-            if(!s.focusNode || s.focusNode.nodeType != 3){
-                var r = s.getRangeAt(0);
-                r.selectNodeContents((this.doc.body || this.doc.documentElement));
-                r.collapse(true);
-                this.deferFocus();
-            }
-            try{
-                this.execCmd('useCSS', true);
-                this.execCmd('styleWithCSS', false);
-            }catch(e){}
+        if (v.match(/^\./) || v.match(/^\//)) {
+            return;
         }
-        this.owner.fireEvent('activate', this);
-    },
-
-    // private
-    adjustFont: function(btn){
-        var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
-        //if(Roo.isSafari){ // safari
-        //    adjust *= 2;
-       // }
-        var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
-        if(Roo.isSafari){ // safari
-            var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
-            v =  (v < 10) ? 10 : v;
-            v =  (v > 48) ? 48 : v;
-            v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
-            
+        if (v.match(/^(http|https):\/\//)
+            || v.match(/^mailto:/) 
+            || v.match(/^ftp:/)
+            || v.match(/^data:/)
+            ) {
+            return;
         }
+        if (v.match(/^#/)) {
+            return;
+        }
+        if (v.match(/^\{/)) { // allow template editing.
+            return;
+        }
+//            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
+        node.removeAttribute(n);
         
-        
-        v = Math.max(1, v+adjust);
-        
-        this.execCmd('FontSize', v  );
-    },
-
-    onEditorEvent : function(e)
-    {
-        this.owner.fireEvent('editorevent', this, e);
-      //  this.updateToolbar();
-        this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
     },
-
-    insertTag : function(tg)
+    cleanStyle : function(node,  n,v)
     {
-        // could be a bit smarter... -> wrap the current selected tRoo..
-        if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
-            
-            range = this.createRange(this.getSelection());
-            var wrappingNode = this.doc.createElement(tg.toLowerCase());
-            wrappingNode.appendChild(range.extractContents());
-            range.insertNode(wrappingNode);
-
+        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 ( this.style_black.length && (this.style_black.indexOf(l) > -1 || this.style_black.indexOf(l.toLowerCase()) > -1)) {
+                return true;
+            }
+            //Roo.log()
+            // only allow 'c whitelisted system attributes'
+            if ( this.style_white.length &&  style_white.indexOf(l) < 0 && style_white.indexOf(l.toLowerCase()) < 0 ) {
+                return true;
+            }
             
             
+            clean.push(p);
+            return true;
+        },this);
+        if (clean.length) { 
+            node.setAttribute(n, clean.join(';'));
+        } else {
+            node.removeAttribute(n);
         }
-        this.execCmd("formatblock",   tg);
         
-    },
-    
-    insertText : function(txt)
-    {
+    }
+        
         
         
-        var range = this.createRange();
-        range.deleteContents();
-               //alert(Sender.getAttribute('label'));
-               
-        range.insertNode(this.doc.createTextNode(txt));
-    } ,
     
-     
+});/**
+ * @class Roo.htmleditor.FilterBlack
+ * remove blacklisted elements.
+ * @constructor
+ * Run a new Blacklisted Filter
+ * @param {Object} config Configuration options
+ */
 
-    /**
-     * Executes a Midas editor command on the editor document and performs necessary focus and
-     * toolbar updates. <b>This should only be called after the editor is initialized.</b>
-     * @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){
-        this.win.focus();
-        this.execCmd(cmd, value);
-        this.owner.fireEvent('editorevent', this);
-        //this.updateToolbar();
-        this.owner.deferFocus();
-    },
+Roo.htmleditor.FilterBlack = function(cfg)
+{
+    Roo.apply(this, cfg);
+    this.walk(cfg.node);
+}
 
-    /**
-     * Executes a Midas editor command directly on the editor document.
-     * For visual commands, you should use {@link #relayCmd} instead.
-     * <b>This should only be called after the editor is initialized.</b>
-     * @param {String} cmd The Midas command
-     * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
-     */
-    execCmd : function(cmd, value){
-        this.doc.execCommand(cmd, false, value === undefined ? null : value);
-        this.syncValue();
-    },
+Roo.extend(Roo.htmleditor.FilterBlack, Roo.htmleditor.Filter,
+{
+    tag : true, // all elements.
    
-    /**
-     * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
-     * to insert tRoo.
-     * @param {String} text | dom node.. 
-     */
-    insertAtCursor : function(text)
+    replaceTag : function(n)
+    {
+        n.parentNode.removeChild(n);
+    }
+});
+/**
+ * @class Roo.htmleditor.FilterComment
+ * remove comments.
+ * @constructor
+* Run a new Comments Filter
+* @param {Object} config Configuration options
+ */
+Roo.htmleditor.FilterComment = function(cfg)
+{
+    this.walk(cfg.node);
+}
+
+Roo.extend(Roo.htmleditor.FilterComment, Roo.htmleditor.Filter,
+{
+  
+    replaceComment : function(n)
     {
+        n.parentNode.removeChild(n);
+    }
+});/**
+ * @class Roo.htmleditor.FilterKeepChildren
+ * remove tags but keep children
+ * @constructor
+ * Run a new Keep Children Filter
+ * @param {Object} config Configuration options
+ */
+
+Roo.htmleditor.FilterKeepChildren = function(cfg)
+{
+    Roo.apply(this, cfg);
+    if (this.tag === false) {
+        return; // dont walk.. (you can use this to use this just to do a child removal on a single tag )
+    }
+    // hacky?
+    if ((typeof(this.tag) == 'object' && this.tag.indexOf(":") > -1)) {
+        this.cleanNamespace = true;
+    }
         
-        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();
-            
-            
-            // from jquery ui (MIT licenced)
-            var range, node;
-            var win = this.win;
-            
-            if (win.getSelection && win.getSelection().getRangeAt) {
-                range = win.getSelection().getRangeAt(0);
-                node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
-                range.insertNode(node);
-            } else if (win.document.selection && win.document.selection.createRange) {
-                // no firefox support
-                var txt = typeof(text) == 'string' ? text : text.outerHTML;
-                win.document.selection.createRange().pasteHTML(txt);
-            } else {
-                // no firefox support
-                var txt = typeof(text) == 'string' ? text : text.outerHTML;
-                this.execCmd('InsertHTML', txt);
-            } 
-            
-            this.syncValue();
-            
-            this.deferFocus();
-        }
-    },
- // private
-    mozKeyPress : function(e){
-        if(e.ctrlKey){
-            var c = e.getCharCode(), cmd;
-          
-            if(c > 0){
-                c = String.fromCharCode(c).toLowerCase();
-                switch(c){
-                    case 'b':
-                        cmd = 'bold';
-                        break;
-                    case 'i':
-                        cmd = 'italic';
-                        break;
-                    
-                    case 'u':
-                        cmd = 'underline';
-                        break;
-                    
-                    case 'v':
-                        this.cleanUpPaste.defer(100, this);
-                        return;
-                        
-                }
-                if(cmd){
-                    this.win.focus();
-                    this.execCmd(cmd);
-                    this.deferFocus();
-                    e.preventDefault();
+    this.walk(cfg.node);
+}
+
+Roo.extend(Roo.htmleditor.FilterKeepChildren, Roo.htmleditor.FilterBlack,
+{
+    cleanNamespace : false, // should really be an option, rather than using ':' inside of this tag.
+  
+    replaceTag : function(node)
+    {
+        // walk children...
+        //Roo.log(node.tagName);
+        var ar = Array.from(node.childNodes);
+        //remove first..
+        
+        for (var i = 0; i < ar.length; i++) {
+            var e = ar[i];
+            if (e.nodeType == 1) {
+                if (
+                    (typeof(this.tag) == 'object' && this.tag.indexOf(e.tagName) > -1)
+                    || // array and it matches
+                    (typeof(this.tag) == 'string' && this.tag == e.tagName)
+                    ||
+                    (e.tagName.indexOf(":") > -1 && typeof(this.tag) == 'object' && this.tag.indexOf(":") > -1)
+                    ||
+                    (e.tagName.indexOf(":") > -1 && typeof(this.tag) == 'string' && this.tag == ":")
+                ) {
+                    this.replaceTag(ar[i]); // child is blacklisted as well...
+                    continue;
                 }
+            }
+        }  
+        ar = Array.from(node.childNodes);
+        for (var i = 0; i < ar.length; i++) {
+         
+            node.removeChild(ar[i]);
+            // what if we need to walk these???
+            node.parentNode.insertBefore(ar[i], node);
+            if (this.tag !== false) {
+                this.walk(ar[i]);
                 
             }
         }
-    },
+        //Roo.log("REMOVE:" + node.tagName);
+        node.parentNode.removeChild(node);
+        return false; // don't walk children
+        
+        
+    }
+});/**
+ * @class Roo.htmleditor.FilterParagraph
+ * paragraphs cause a nightmare for shared content - this filter is designed to be called ? at various points when editing
+ * like on 'push' to remove the <p> tags and replace them with line breaks.
+ * @constructor
+ * Run a new Paragraph Filter
+ * @param {Object} config Configuration options
+ */
 
-    // private
-    fixKeys : function(){ // load time branching for fastest keydown performance
-        if(Roo.isIE){
-            return function(e){
-                var k = e.getKey(), r;
-                if(k == e.TAB){
-                    e.stopEvent();
-                    r = this.doc.selection.createRange();
-                    if(r){
-                        r.collapse(true);
-                        r.pasteHTML('&#160;&#160;&#160;&#160;');
-                        this.deferFocus();
-                    }
-                    return;
-                }
-                
-                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.collapse(false);
-                            r.select();
-                        }
-                    }
-                }
-                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
-                    this.cleanUpPaste.defer(100, this);
-                    return;
-                }
-                
-                
-            };
-        }else if(Roo.isOpera){
-            return function(e){
-                var k = e.getKey();
-                if(k == e.TAB){
-                    e.stopEvent();
-                    this.win.focus();
-                    this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
-                    this.deferFocus();
-                }
-                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
-                    this.cleanUpPaste.defer(100, this);
-                    return;
-                }
-                
-            };
-        }else if(Roo.isSafari){
-            return function(e){
-                var k = e.getKey();
-                
-                if(k == e.TAB){
-                    e.stopEvent();
-                    this.execCmd('InsertText','\t');
-                    this.deferFocus();
-                    return;
-                }
-               if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
-                    this.cleanUpPaste.defer(100, this);
-                    return;
-                }
-                
-             };
-        }
-    }(),
+Roo.htmleditor.FilterParagraph = function(cfg)
+{
+    // no need to apply config.
+    this.walk(cfg.node);
+}
+
+Roo.extend(Roo.htmleditor.FilterParagraph, Roo.htmleditor.Filter,
+{
     
-    getAllAncestors: function()
+     
+    tag : 'P',
+    
+     
+    replaceTag : function(node)
     {
-        var p = this.getSelectedNode();
-        var a = [];
-        if (!p) {
-            a.push(p); // push blank onto stack..
-            p = this.getParentElement();
+        
+        if (node.childNodes.length == 1 &&
+            node.childNodes[0].nodeType == 3 &&
+            node.childNodes[0].textContent.trim().length < 1
+            ) {
+            // remove and replace with '<BR>';
+            node.parentNode.replaceChild(node.ownerDocument.createElement('BR'),node);
+            return false; // no need to walk..
         }
+        var ar = Array.from(node.childNodes);
+        for (var i = 0; i < ar.length; i++) {
+            node.removeChild(ar[i]);
+            // what if we need to walk these???
+            node.parentNode.insertBefore(ar[i], node);
+        }
+        // now what about this?
+        // <p> &nbsp; </p>
         
+        // double BR.
+        node.parentNode.insertBefore(node.ownerDocument.createElement('BR'), node);
+        node.parentNode.insertBefore(node.ownerDocument.createElement('BR'), node);
+        node.parentNode.removeChild(node);
         
-        while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
-            a.push(p);
-            p = p.parentNode;
-        }
-        a.push(this.doc.body);
-        return a;
-    },
-    lastSel : false,
-    lastSelNode : false,
-    
+        return false;
+
+    }
     
-    getSelection : function() 
+});/**
+ * @class Roo.htmleditor.FilterSpan
+ * filter span's with no attributes out..
+ * @constructor
+ * Run a new Span Filter
+ * @param {Object} config Configuration options
+ */
+
+Roo.htmleditor.FilterSpan = function(cfg)
+{
+    // no need to apply config.
+    this.walk(cfg.node);
+}
+
+Roo.extend(Roo.htmleditor.FilterSpan, Roo.htmleditor.FilterKeepChildren,
+{
+     
+    tag : 'SPAN',
+     
+    replaceTag : function(node)
     {
-        this.assignDocWin();
-        return Roo.isIE ? this.doc.selection : this.win.getSelection();
-    },
+        if (node.attributes && node.attributes.length > 0) {
+            return true; // walk if there are any.
+        }
+        Roo.htmleditor.FilterKeepChildren.prototype.replaceTag.call(this, node);
+        return false;
+     
+    }
     
-    getSelectedNode: function() 
-    {
-        // this may only work on Gecko!!!
-        
-        // should we cache this!!!!
+});/**
+ * @class Roo.htmleditor.FilterTableWidth
+  try and remove table width data - as that frequently messes up other stuff.
+ * 
+ *      was 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..
+ *
+ * @constructor
+ * Run a new Table Filter
+ * @param {Object} config Configuration options
+ */
+
+Roo.htmleditor.FilterTableWidth = function(cfg)
+{
+    // no need to apply config.
+    this.tag = ['TABLE', 'TD', 'TR', 'TH', 'THEAD', 'TBODY' ];
+    this.walk(cfg.node);
+}
+
+Roo.extend(Roo.htmleditor.FilterTableWidth, Roo.htmleditor.Filter,
+{
+     
+     
+    
+    replaceTag: function(node) {
         
         
+      
+        if (node.hasAttribute('width')) {
+            node.removeAttribute('width');
+        }
         
          
-        var range = this.createRange(this.getSelection()).cloneRange();
-        
-        if (Roo.isIE) {
-            var parent = range.parentElement();
-            while (true) {
-                var testRange = range.duplicate();
-                testRange.moveToElementText(parent);
-                if (testRange.inRange(range)) {
-                    break;
-                }
-                if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
-                    break;
-                }
-                parent = parent.parentElement;
-            }
-            return parent;
-        }
-        
-        // is ancestor a text element.
-        var ac =  range.commonAncestorContainer;
-        if (ac.nodeType == 3) {
-            ac = ac.parentNode;
-        }
-        
-        var ar = ac.childNodes;
-         
-        var nodes = [];
-        var other_nodes = [];
-        var has_other_nodes = false;
-        for (var i=0;i<ar.length;i++) {
-            if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
-                continue;
-            }
-            // fullly contained node.
-            
-            if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
-                nodes.push(ar[i]);
-                continue;
-            }
-            
-            // probably selected..
-            if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
-                other_nodes.push(ar[i]);
-                continue;
-            }
-            // outer..
-            if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
-                continue;
-            }
-            
-            
-            has_other_nodes = true;
-        }
-        if (!nodes.length && other_nodes.length) {
-            nodes= other_nodes;
-        }
-        if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
-            return false;
-        }
-        
-        return nodes[0];
-    },
-    createRange: function(sel)
-    {
-        // this has strange effects when using with 
-        // top toolbar - not sure if it's a great idea.
-        //this.editor.contentWindow.focus();
-        if (typeof sel != "undefined") {
-            try {
-                return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
-            } catch(e) {
-                return this.doc.createRange();
-            }
-        } else {
-            return this.doc.createRange();
-        }
-    },
-    getParentElement: function()
-    {
-        
-        this.assignDocWin();
-        var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
-        
-        var range = this.createRange(sel);
-         
-        try {
-            var p = range.commonAncestorContainer;
-            while (p.nodeType == 3) { // text node
-                p = p.parentNode;
-            }
-            return p;
-        } catch (e) {
-            return null;
-        }
-    
-    },
-    /***
-     *
-     * Range intersection.. the hard stuff...
-     *  '-1' = before
-     *  '0' = hits..
-     *  '1' = after.
-     *         [ -- selected range --- ]
-     *   [fail]                        [fail]
-     *
-     *    basically..
-     *      if end is before start or  hits it. fail.
-     *      if start is after end or hits it fail.
-     *
-     *   if either hits (but other is outside. - then it's not 
-     *   
-     *    
-     **/
-    
-    
-    // @see http://www.thismuchiknow.co.uk/?p=64.
-    rangeIntersectsNode : function(range, node)
-    {
-        var nodeRange = node.ownerDocument.createRange();
-        try {
-            nodeRange.selectNode(node);
-        } catch (e) {
-            nodeRange.selectNodeContents(node);
-        }
-    
-        var rangeStartRange = range.cloneRange();
-        rangeStartRange.collapse(true);
-    
-        var rangeEndRange = range.cloneRange();
-        rangeEndRange.collapse(false);
-    
-        var nodeStartRange = nodeRange.cloneRange();
-        nodeStartRange.collapse(true);
-    
-        var nodeEndRange = nodeRange.cloneRange();
-        nodeEndRange.collapse(false);
-    
-        return rangeStartRange.compareBoundaryPoints(
-                 Range.START_TO_START, nodeEndRange) == -1 &&
-               rangeEndRange.compareBoundaryPoints(
-                 Range.START_TO_START, nodeStartRange) == 1;
-        
-         
-    },
-    rangeCompareNode : function(range, node)
-    {
-        var nodeRange = node.ownerDocument.createRange();
-        try {
-            nodeRange.selectNode(node);
-        } catch (e) {
-            nodeRange.selectNodeContents(node);
-        }
-        
-        
-        range.collapse(true);
-    
-        nodeRange.collapse(true);
-     
-        var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
-        var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
-         
-        //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
-        
-        var nodeIsBefore   =  ss == 1;
-        var nodeIsAfter    = ee == -1;
-        
-        if (nodeIsBefore && nodeIsAfter) {
-            return 0; // outer
-        }
-        if (!nodeIsBefore && nodeIsAfter) {
-            return 1; //right trailed.
-        }
-        
-        if (nodeIsBefore && !nodeIsAfter) {
-            return 2;  // left trailed.
-        }
-        // 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 output = input;
-        Roo.each(he.swapCodes, function(sw) { 
-            var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
-            
-            output = output.replace(swapper, sw[1]);
-        });
-        
-        return output;
-    },
-    
-    
-    cleanUpChildren : function (n)
-    {
-        if (!n.childNodes.length) {
-            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;
-        
-        // 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;
-            }
-//            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 = [];
+        if (node.hasAttribute("style")) {
+            // pretty basic...
             
-            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;
+            var styles = node.getAttribute("style").split(";");
+            var nstyle = [];
+            Roo.each(styles, function(s) {
+                if (!s.match(/:/)) {
+                    return;
                 }
-                //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;
+                var kv = s.split(":");
+                if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
+                    return;
                 }
-                
-                
-                 
-                
-                clean.push(p);
-                return true;
+                // what ever is left... we allow.
+                nstyle.push(s);
             });
-            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.className = '';
-                }
-                
-                if (a.value.match(/^body$/)) {
-                    node.className = '';
-                }
-                continue;
+            node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
+            if (!nstyle.length) {
+                node.removeAttribute('style');
             }
-            
-            // style cleanup!?
-            // class cleanup?
-            
         }
         
-        
-        this.cleanUpChildren(node);
-        
-        
-    },
+        return true; // continue doing children..
+    }
+});/**
+ * @class Roo.htmleditor.FilterWord
+ * try and clean up all the mess that Word generates.
+ * 
+ * This is the 'nice version' - see 'Heavy' that white lists a very short list of elements, and multi-filters 
+ * @constructor
+ * Run a new Span Filter
+ * @param {Object} config Configuration options
+ */
+
+Roo.htmleditor.FilterWord = function(cfg)
+{
+    // no need to apply config.
+    this.replaceDocBullets(cfg.node);
+    
+    this.replaceAname(cfg.node);
+    // this is disabled as the removal is done by other filters;
+   // this.walk(cfg.node);
+    this.replaceImageTable(cfg.node);
+    
+}
+
+Roo.extend(Roo.htmleditor.FilterWord, Roo.htmleditor.Filter,
+{
+    tag: true,
+     
     
     /**
      * Clean up MS wordisms...
      */
-    cleanWord : function(node)
+    replaceTag : function(node)
     {
-        if (!node) {
-            this.cleanWord(this.doc.body);
-            return;
-        }
-        
+         
+        // no idea what this does - span with text, replaceds with just text.
         if(
                 node.nodeName == 'SPAN' &&
                 !node.hasAttributes() &&
                 node.childNodes.length == 1 &&
-                node.firstChild.nodeName == "#text"
+                node.firstChild.nodeName == "#text"  
         ) {
             var textNode = node.firstChild;
             node.removeChild(textNode);
-            
-            node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
+            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);
-            node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , 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);
+            return false; // dont do chidren - we have remove our node - so no need to do chdhilren?
         }
         
-        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;
+            return false; // dont do chidlren
         }
-        
+        //Roo.log(node.tagName);
         // remove - but keep children..
-        if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
+        if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
+            //Roo.log('-- removed');
             while (node.childNodes.length) {
                 var cn = node.childNodes[0];
                 node.removeChild(cn);
                 node.parentNode.insertBefore(cn, node);
+                // move node to parent - and clean it..
+                if (cn.nodeType == 1) {
+                    this.replaceTag(cn);
+                }
+                
             }
             node.parentNode.removeChild(node);
-            this.iterateChildren(node, this.cleanWord);
-            return;
+            /// no need to iterate chidlren = it's got none..
+            //this.iterateChildren(node, this.cleanWord);
+            return false; // no need to iterate children.
         }
         // clean styles
         if (node.className.length) {
@@ -44148,5667 +46265,7669 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                 node.removeAttribute('style');
             }
         }
-        this.iterateChildren(node, this.cleanWord);
+        return true; // do children
         
         
         
     },
-    /**
-     * 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)
+    
+    styleToObject: function(node)
     {
-        if (!node.childNodes.length) {
+        var styles = (node.getAttribute("style") || '').split(";");
+        var ret = {};
+        Roo.each(styles, function(s) {
+            if (!s.match(/:/)) {
                 return;
+            }
+            var kv = s.split(":");
+             
+            // what ever is left... we allow.
+            ret[kv[0].trim()] = kv[1];
+        });
+        return ret;
+    },
+    
+    
+    replaceAname : function (doc)
+    {
+        // replace all the a/name without..
+        var aa = Array.from(doc.getElementsByTagName('a'));
+        for (var i = 0; i  < aa.length; i++) {
+            var a = aa[i];
+            if (a.hasAttribute("name")) {
+                a.removeAttribute("name");
+            }
+            if (a.hasAttribute("href")) {
+                continue;
+            }
+            // reparent children.
+            this.removeNodeKeepChildren(a);
+            
         }
-        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..
-     *
-     */
-    cleanTableWidths : function(node)
+    replaceDocBullets : function(doc)
     {
-         
-         
-        if (!node) {
-            this.cleanTableWidths(this.doc.body);
-            return;
+        // this is a bit odd - but it appears some indents use ql-indent-1
+         //Roo.log(doc.innerHTML);
+        
+        var listpara = Array.from(doc.getElementsByClassName('MsoListParagraphCxSpFirst'));
+        for( var i = 0; i < listpara.length; i ++) {
+            listpara[i].className = "MsoListParagraph";
         }
         
-        // ignore list...
-        if (node.nodeName == "#text" || node.nodeName == "#comment") {
-            return; 
+        listpara =  Array.from(doc.getElementsByClassName('MsoListParagraphCxSpMiddle'));
+        for( var i = 0; i < listpara.length; i ++) {
+            listpara[i].className = "MsoListParagraph";
         }
-        Roo.log(node.tagName);
-        if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
-            this.iterateChildren(node, this.cleanTableWidths);
-            return;
+        listpara =  Array.from(doc.getElementsByClassName('MsoListParagraphCxSpLast'));
+        for( var i = 0; i < listpara.length; i ++) {
+            listpara[i].className = "MsoListParagraph";
         }
-        if (node.hasAttribute('width')) {
-            node.removeAttribute('width');
+        listpara =  Array.from(doc.getElementsByClassName('ql-indent-1'));
+        for( var i = 0; i < listpara.length; i ++) {
+            listpara[i].className = "MsoListParagraph";
         }
         
-         
-        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 is a bit hacky - we had one word document where h2 had a miso-list attribute.
+        var htwo =  Array.from(doc.getElementsByTagName('h2'));
+        for( var i = 0; i < htwo.length; i ++) {
+            if (htwo[i].hasAttribute('style') && htwo[i].getAttribute('style').match(/mso-list:/)) {
+                htwo[i].className = "MsoListParagraph";
             }
         }
+        listpara =  Array.from(doc.getElementsByClassName('MsoNormal'));
+        for( var i = 0; i < listpara.length; i ++) {
+            if (listpara[i].hasAttribute('style') && listpara[i].getAttribute('style').match(/mso-list:/)) {
+                listpara[i].className = "MsoListParagraph";
+            } else {
+                listpara[i].className = "MsoNormalx";
+            }
+        }
+       
+        listpara = doc.getElementsByClassName('MsoListParagraph');
+        // Roo.log(doc.innerHTML);
         
-        this.iterateChildren(node, this.cleanTableWidths);
         
         
+        while(listpara.length) {
+            
+            this.replaceDocBullet(listpara.item(0));
+        }
+      
     },
     
+     
     
-    
-    
-    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') {
+    replaceDocBullet : function(p)
+    {
+        // gather all the siblings.
+        var ns = p,
+            parent = p.parentNode,
+            doc = parent.ownerDocument,
+            items = [];
+         
+        //Roo.log("Parsing: " + p.innerText)    ;
+        var listtype = 'ul';   
+        while (ns) {
+            if (ns.nodeType != 1) {
+                ns = ns.nextSibling;
+                continue;
+            }
+            if (!ns.className.match(/(MsoListParagraph|ql-indent-1)/i)) {
+                //Roo.log("Missing para r q1indent - got:" + ns.className);
+                break;
+            }
+            var spans = ns.getElementsByTagName('span');
             
-            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;
+            if (ns.hasAttribute('style') && ns.getAttribute('style').match(/mso-list/)) {
+                items.push(ns);
+                ns = ns.nextSibling;
+                has_list = true;
+                if (!spans.length) {
+                    continue;
+                }
+                var ff = '';
+                var se = spans[0];
+                for (var i = 0; i < spans.length;i++) {
+                    se = spans[i];
+                    if (se.hasAttribute('style')  && se.hasAttribute('style') && se.style.fontFamily != '') {
+                        ff = se.style.fontFamily;
+                        break;
                     }
-                    attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
+                }
+                 
+                    
+                //Roo.log("got font family: " + ff);
+                if (typeof(ff) != 'undefined' && !ff.match(/(Symbol|Wingdings)/) && "·o".indexOf(se.innerText.trim()) < 0) {
+                    listtype = 'ol';
                 }
                 
-                ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
-            } 
-            else {
-                
-                // eack
+                continue;
             }
-        } else {
-            tagName = false;
-        }
-        if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
-            return ret;
+            //Roo.log("no mso-list?");
+            
+            var spans = ns.getElementsByTagName('span');
+            if (!spans.length) {
+                break;
+            }
+            var has_list  = false;
+            for(var i = 0; i < spans.length; i++) {
+                if (spans[i].hasAttribute('style') && spans[i].getAttribute('style').match(/mso-list/)) {
+                    has_list = true;
+                    break;
+                }
+            }
+            if (!has_list) {
+                break;
+            }
+            items.push(ns);
+            ns = ns.nextSibling;
+            
+            
         }
-        if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
-            nopadtext = true;
+        if (!items.length) {
+            ns.className = "";
+            return;
         }
         
+        var ul = parent.ownerDocument.createElement(listtype); // what about number lists...
+        parent.insertBefore(ul, p);
+        var lvl = 0;
+        var stack = [ ul ];
+        var last_li = false;
         
-        // 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;
+        var margin_to_depth = {};
+        max_margins = -1;
+        
+        items.forEach(function(n, ipos) {
+            //Roo.log("got innertHMLT=" + n.innerHTML);
+            
+            var spans = n.getElementsByTagName('span');
+            if (!spans.length) {
+                //Roo.log("No spans found");
+                 
+                parent.removeChild(n);
+                
+                
+                return; // skip it...
             }
-            // 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;
+            var num = 1;
+            var style = {};
+            for(var i = 0; i < spans.length; i++) {
+            
+                style = this.styleToObject(spans[i]);
+                if (typeof(style['mso-list']) == 'undefined') {
+                    continue;
+                }
+                if (listtype == 'ol') {
+                   num = spans[i].innerText.replace(/[^0-9]+]/g,'')  * 1;
+                }
+                spans[i].parentNode.removeChild(spans[i]); // remove the fake bullet.
+                break;
+            }
+            //Roo.log("NOW GOT innertHMLT=" + n.innerHTML);
+            style = this.styleToObject(n); // mo-list is from the parent node.
+            if (typeof(style['mso-list']) == 'undefined') {
+                //Roo.log("parent is missing level");
+                  
+                parent.removeChild(n);
+                 
+                return;
             }
-            allText = false;
             
-            innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
+            var margin = style['margin-left'];
+            if (typeof(margin_to_depth[margin]) == 'undefined') {
+                max_margins++;
+                margin_to_depth[margin] = max_margins;
+            }
+            nlvl = margin_to_depth[margin] ;
+             
+            if (nlvl > lvl) {
+                //new indent
+                var nul = doc.createElement(listtype); // what about number lists...
+                if (!last_li) {
+                    last_li = doc.createElement('li');
+                    stack[lvl].appendChild(last_li);
+                }
+                last_li.appendChild(nul);
+                stack[nlvl] = nul;
                 
-            // 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;
+            }
+            lvl = nlvl;
+            
+            // not starting at 1..
+            if (!stack[nlvl].hasAttribute("start") && listtype == "ol") {
+                stack[nlvl].setAttribute("start", num);
+            }
+            
+            var nli = stack[nlvl].appendChild(doc.createElement('li'));
+            last_li = nli;
+            nli.innerHTML = n.innerHTML;
+            //Roo.log("innerHTML = " + n.innerHTML);
+            parent.removeChild(n);
+            
+             
+             
+            
+        },this);
         
-        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()
+    
+    replaceImageTable : function(doc)
     {
-        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.white = [];
-        this.black = [];
-        Roo.each(Roo.HtmlEditorCore.white, function(tag) {
-            if (b.indexOf(tag) > -1) {
+         /*
+          <table cellpadding=0 cellspacing=0 align=left>
+  <tr>
+   <td width=423 height=0></td>
+  </tr>
+  <tr>
+   <td></td>
+   <td><img width=601 height=401
+   src="file:///C:/Users/Alan/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg"
+   v:shapes="Picture_x0020_2"></td>
+  </tr>
+ </table>
+ */
+        var imgs = Array.from(doc.getElementsByTagName('img'));
+        Roo.each(imgs, function(img) {
+            var td = img.parentNode;
+            if (td.nodeName !=  'TD') {
                 return;
             }
-            this.white.push(tag);
-            
-        }, this);
-        
-        Roo.each(w, function(tag) {
-            if (b.indexOf(tag) > -1) {
+            var tr = td.parentNode;
+            if (tr.nodeName !=  'TR') {
                 return;
             }
-            if (this.white.indexOf(tag) > -1) {
+            var tbody = tr.parentNode;
+            if (tbody.nodeName !=  'TBODY') {
                 return;
             }
-            this.white.push(tag);
-            
-        }, this);
-        
-        
-        Roo.each(Roo.HtmlEditorCore.black, function(tag) {
-            if (w.indexOf(tag) > -1) {
+            var table = tbody.parentNode;
+            if (table.nodeName !=  'TABLE') {
                 return;
             }
-            this.black.push(tag);
+            // first row..
             
-        }, this);
-        
-        Roo.each(b, function(tag) {
-            if (w.indexOf(tag) > -1) {
+            if (table.getElementsByTagName('tr').length != 2) {
                 return;
             }
-            if (this.black.indexOf(tag) > -1) {
+            if (table.getElementsByTagName('td').length != 3) {
                 return;
             }
-            this.black.push(tag);
+            if (table.innerText.trim() != '') {
+                return;
+            }
+            var p = table.parentNode;
+            img.parentNode.removeChild(img);
+            p.insertBefore(img, table);
+            p.removeChild(table);
             
-        }, this);
-        
-        
-        w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
-        b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
-        
-        this.cwhite = [];
-        this.cblack = [];
-        Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
-            if (b.indexOf(tag) > -1) {
-                return;
-            }
-            this.cwhite.push(tag);
             
-        }, this);
-        
-        Roo.each(w, function(tag) {
-            if (b.indexOf(tag) > -1) {
-                return;
-            }
-            if (this.cwhite.indexOf(tag) > -1) {
-                return;
-            }
-            this.cwhite.push(tag);
             
-        }, this);
+        });
+        
+      
+    }
+    
+});
+/**
+ * @class Roo.htmleditor.FilterStyleToTag
+ * part of the word stuff... - certain 'styles' should be converted to tags.
+ * eg.
+ *   font-weight: bold -> bold
+ *   ?? super / subscrit etc..
+ * 
+ * @constructor
+* Run a new style to tag filter.
+* @param {Object} config Configuration options
+ */
+Roo.htmleditor.FilterStyleToTag = function(cfg)
+{
+    
+    this.tags = {
+        B  : [ 'fontWeight' , 'bold'],
+        I :  [ 'fontStyle' , 'italic'],
+        //pre :  [ 'font-style' , 'italic'],
+        // h1.. h6 ?? font-size?
+        SUP : [ 'verticalAlign' , 'super' ],
+        SUB : [ 'verticalAlign' , 'sub' ]
         
         
-        Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
-            if (w.indexOf(tag) > -1) {
-                return;
-            }
-            this.cblack.push(tag);
-            
-        }, this);
+    };
+    
+    Roo.apply(this, cfg);
+     
+    
+    this.walk(cfg.node);
+    
+    
+    
+}
+
+
+Roo.extend(Roo.htmleditor.FilterStyleToTag, Roo.htmleditor.Filter,
+{
+    tag: true, // all tags
+    
+    tags : false,
+    
+    
+    replaceTag : function(node)
+    {
         
-        Roo.each(b, function(tag) {
-            if (w.indexOf(tag) > -1) {
-                return;
+        
+        if (node.getAttribute("style") === null) {
+            return true;
+        }
+        var inject = [];
+        for (var k in this.tags) {
+            if (node.style[this.tags[k][0]] == this.tags[k][1]) {
+                inject.push(k);
+                node.style.removeProperty(this.tags[k][0]);
             }
-            if (this.cblack.indexOf(tag) > -1) {
-                return;
+        }
+        if (!inject.length) {
+            return true; 
+        }
+        var cn = Array.from(node.childNodes);
+        var nn = node;
+        Roo.each(inject, function(t) {
+            var nc = node.ownerDocument.createElement(t);
+            nn.appendChild(nc);
+            nn = nc;
+        });
+        for(var i = 0;i < cn.length;cn++) {
+            node.removeChild(cn[i]);
+            nn.appendChild(cn[i]);
+        }
+        return true /// iterate thru
+    }
+    
+})/**
+ * @class Roo.htmleditor.FilterLongBr
+ * BR/BR/BR - keep a maximum of 2...
+ * @constructor
+ * Run a new Long BR Filter
+ * @param {Object} config Configuration options
+ */
+
+Roo.htmleditor.FilterLongBr = function(cfg)
+{
+    // no need to apply config.
+    this.walk(cfg.node);
+}
+
+Roo.extend(Roo.htmleditor.FilterLongBr, Roo.htmleditor.Filter,
+{
+    
+     
+    tag : 'BR',
+    
+     
+    replaceTag : function(node)
+    {
+        
+        var ps = node.nextSibling;
+        while (ps && ps.nodeType == 3 && ps.nodeValue.trim().length < 1) {
+            ps = ps.nextSibling;
+        }
+        
+        if (!ps &&  [ 'TD', 'TH', 'LI', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ].indexOf(node.parentNode.tagName) > -1) { 
+            node.parentNode.removeChild(node); // remove last BR inside one fo these tags
+            return false;
+        }
+        
+        if (!ps || ps.nodeType != 1) {
+            return false;
+        }
+        
+        if (!ps || ps.tagName != 'BR') {
+           
+            return false;
+        }
+        
+        
+        
+        
+        
+        if (!node.previousSibling) {
+            return false;
+        }
+        var ps = node.previousSibling;
+        
+        while (ps && ps.nodeType == 3 && ps.nodeValue.trim().length < 1) {
+            ps = ps.previousSibling;
+        }
+        if (!ps || ps.nodeType != 1) {
+            return false;
+        }
+        // if header or BR before.. then it's a candidate for removal.. - as we only want '2' of these..
+        if (!ps || [ 'BR', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ].indexOf(ps.tagName) < 0) {
+            return false;
+        }
+        
+        node.parentNode.removeChild(node); // remove me...
+        
+        return false; // no need to do children
+
+    }
+    
+}); 
+
+/**
+ * @class Roo.htmleditor.FilterBlock
+ * removes id / data-block and contenteditable that are associated with blocks
+ * usage should be done on a cloned copy of the dom
+ * @constructor
+* Run a new Attribute Filter { node : xxxx }}
+* @param {Object} config Configuration options
+ */
+Roo.htmleditor.FilterBlock = function(cfg)
+{
+    Roo.apply(this, cfg);
+    var qa = cfg.node.querySelectorAll;
+    this.removeAttributes('data-block');
+    this.removeAttributes('contenteditable');
+    this.removeAttributes('id');
+    
+}
+
+Roo.apply(Roo.htmleditor.FilterBlock.prototype,
+{
+    node: true, // all tags
+     
+     
+    removeAttributes : function(attr)
+    {
+        var ar = this.node.querySelectorAll('*[' + attr + ']');
+        for (var i =0;i<ar.length;i++) {
+            ar[i].removeAttribute(attr);
+        }
+    }
+        
+        
+        
+    
+});
+/***
+ * This is based loosely on tinymce 
+ * @class Roo.htmleditor.TidySerializer
+ * https://github.com/thorn0/tinymce.html/blob/master/tinymce.html.js
+ * @constructor
+ * @method Serializer
+ * @param {Object} settings Name/value settings object.
+ */
+
+
+Roo.htmleditor.TidySerializer = function(settings)
+{
+    Roo.apply(this, settings);
+    
+    this.writer = new Roo.htmleditor.TidyWriter(settings);
+    
+    
+
+};
+Roo.htmleditor.TidySerializer.prototype = {
+    
+    /**
+     * @param {boolean} inner do the inner of the node.
+     */
+    inner : false,
+    
+    writer : false,
+    
+    /**
+    * Serializes the specified node into a string.
+    *
+    * @example
+    * new tinymce.html.Serializer().serialize(new tinymce.html.DomParser().parse('<p>text</p>'));
+    * @method serialize
+    * @param {DomElement} node Node instance to serialize.
+    * @return {String} String with HTML based on DOM tree.
+    */
+    serialize : function(node) {
+        
+        // = settings.validate;
+        var writer = this.writer;
+        var self  = this;
+        this.handlers = {
+            // #text
+            3: function(node) {
+                
+                writer.text(node.nodeValue, node);
+            },
+            // #comment
+            8: function(node) {
+                writer.comment(node.nodeValue);
+            },
+            // Processing instruction
+            7: function(node) {
+                writer.pi(node.name, node.nodeValue);
+            },
+            // Doctype
+            10: function(node) {
+                writer.doctype(node.nodeValue);
+            },
+            // CDATA
+            4: function(node) {
+                writer.cdata(node.nodeValue);
+            },
+            // Document fragment
+            11: function(node) {
+                node = node.firstChild;
+                if (!node) {
+                    return;
+                }
+                while(node) {
+                    self.walk(node);
+                    node = node.nextSibling
+                }
             }
-            this.cblack.push(tag);
-            
-        }, this);
+        };
+        writer.reset();
+        1 != node.nodeType || this.inner ? this.handlers[11](node) : this.walk(node);
+        return writer.getContent();
     },
-    
-    setStylesheets : function(stylesheets)
+
+    walk: function(node)
     {
-        if(typeof(stylesheets) == 'string'){
-            Roo.get(this.iframe.contentDocument.head).createChild({
-                tag : 'link',
-                rel : 'stylesheet',
-                type : 'text/css',
-                href : stylesheets
-            });
+        var attrName, attrValue, sortedAttrs, i, l, elementRule,
+            handler = this.handlers[node.nodeType];
             
+        if (handler) {
+            handler(node);
             return;
         }
-        var _this = this;
+    
+        var name = node.nodeName;
+        var isEmpty = node.childNodes.length < 1;
+      
+        var writer = this.writer;
+        var attrs = node.attributes;
+        // Sort attributes
+        
+        writer.start(node.nodeName, attrs, isEmpty, node);
+        if (isEmpty) {
+            return;
+        }
+        node = node.firstChild;
+        if (!node) {
+            writer.end(name);
+            return;
+        }
+        while (node) {
+            this.walk(node);
+            node = node.nextSibling;
+        }
+        writer.end(name);
+        
+    
+    }
+    // Serialize element and treat all non elements as fragments
+   
+}; 
+
+/***
+ * This is based loosely on tinymce 
+ * @class Roo.htmleditor.TidyWriter
+ * https://github.com/thorn0/tinymce.html/blob/master/tinymce.html.js
+ *
+ * Known issues?
+ * - not tested much with 'PRE' formated elements.
+ * 
+ *
+ *
+ */
+
+Roo.htmleditor.TidyWriter = function(settings)
+{
+    
+    // indent, indentBefore, indentAfter, encode, htmlOutput, html = [];
+    Roo.apply(this, settings);
+    this.html = [];
+    this.state = [];
      
-        Roo.each(stylesheets, function(s) {
-            if(!s.length){
-                return;
+    this.encode = Roo.htmleditor.TidyEntities.getEncodeFunc(settings.entity_encoding || 'raw', settings.entities);
+  
+}
+Roo.htmleditor.TidyWriter.prototype = {
+
+    state : false,
+    
+    indent :  '  ',
+    
+    // part of state...
+    indentstr : '',
+    in_pre: false,
+    in_inline : false,
+    last_inline : false,
+    encode : false,
+     
+    
+            /**
+    * Writes the a start element such as <p id="a">.
+    *
+    * @method start
+    * @param {String} name Name of the element.
+    * @param {Array} attrs Optional attribute array or undefined if it hasn't any.
+    * @param {Boolean} empty Optional empty state if the tag should end like <br />.
+    */
+    start: function(name, attrs, empty, node)
+    {
+        var i, l, attr, value;
+        
+        // there are some situations where adding line break && indentation will not work. will not work.
+        // <span / b / i ... formating?
+        
+        var in_inline = this.in_inline || Roo.htmleditor.TidyWriter.inline_elements.indexOf(name) > -1;
+        var in_pre    = this.in_pre    || Roo.htmleditor.TidyWriter.whitespace_elements.indexOf(name) > -1;
+        
+        var is_short   = empty ? Roo.htmleditor.TidyWriter.shortend_elements.indexOf(name) > -1 : false;
+        
+        var add_lb = name == 'BR' ? false : in_inline;
+        
+        if (!add_lb && !this.in_pre && this.lastElementEndsWS()) {
+            i_inline = false;
+        }
+
+        var indentstr =  this.indentstr;
+        
+        // e_inline = elements that can be inline, but still allow \n before and after?
+        // only 'BR' ??? any others?
+        
+        // ADD LINE BEFORE tage
+        if (!this.in_pre) {
+            if (in_inline) {
+                //code
+                if (name == 'BR') {
+                    this.addLine();
+                } else if (this.lastElementEndsWS()) {
+                    this.addLine();
+                } else{
+                    // otherwise - no new line. (and dont indent.)
+                    indentstr = '';
+                }
+                
+            } else {
+                this.addLine();
+            }
+        } else {
+            indentstr = '';
+        }
+        
+        this.html.push(indentstr + '<', name.toLowerCase());
+        
+        if (attrs) {
+            for (i = 0, l = attrs.length; i < l; i++) {
+                attr = attrs[i];
+                this.html.push(' ', attr.name, '="', this.encode(attr.value, true), '"');
+            }
+        }
+     
+        if (empty) {
+            if (is_short) {
+                this.html[this.html.length] = '/>';
+            } else {
+                this.html[this.html.length] = '></' + name.toLowerCase() + '>';
             }
+            var e_inline = name == 'BR' ? false : this.in_inline;
             
-            Roo.get(_this.iframe.contentDocument.head).createChild({
-                tag : 'link',
-                rel : 'stylesheet',
-                type : 'text/css',
-                href : s
-            });
+            if (!e_inline && !this.in_pre) {
+                this.addLine();
+            }
+            return;
+        
+        }
+        // not empty..
+        this.html[this.html.length] = '>';
+        
+        // there is a special situation, where we need to turn on in_inline - if any of the imediate chidlren are one of these.
+        /*
+        if (!in_inline && !in_pre) {
+            var cn = node.firstChild;
+            while(cn) {
+                if (Roo.htmleditor.TidyWriter.inline_elements.indexOf(cn.nodeName) > -1) {
+                    in_inline = true
+                    break;
+                }
+                cn = cn.nextSibling;
+            }
+             
+        }
+        */
+        
+        
+        this.pushState({
+            indentstr : in_pre   ? '' : (this.indentstr + this.indent),
+            in_pre : in_pre,
+            in_inline :  in_inline
         });
-
+        // add a line after if we are not in a
+        
+        if (!in_inline && !in_pre) {
+            this.addLine();
+        }
+        
+            
+         
         
     },
     
-    removeStylesheets : function()
+    lastElementEndsWS : function()
     {
-        var _this = this;
+        var value = this.html.length > 0 ? this.html[this.html.length-1] : false;
+        if (value === false) {
+            return true;
+        }
+        return value.match(/\s+$/);
         
-        Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
-            s.remove();
-        });
     },
     
-    setStyle : function(style)
-    {
-        Roo.get(this.iframe.contentDocument.head).createChild({
-            tag : 'style',
-            type : 'text/css',
-            html : style
-        });
-
-        return;
-    }
-    
-    // hide stuff that is not compatible
     /**
-     * @event blur
-     * @hide
+     * Writes the a end element such as </p>.
+     *
+     * @method end
+     * @param {String} name Name of the element.
      */
+    end: function(name) {
+        var value;
+        this.popState();
+        var indentstr = '';
+        var in_inline = this.in_inline || Roo.htmleditor.TidyWriter.inline_elements.indexOf(name) > -1;
+        
+        if (!this.in_pre && !in_inline) {
+            this.addLine();
+            indentstr  = this.indentstr;
+        }
+        this.html.push(indentstr + '</', name.toLowerCase(), '>');
+        this.last_inline = in_inline;
+        
+        // pop the indent state..
+    },
     /**
-     * @event change
-     * @hide
+     * Writes a text node.
+     *
+     * In pre - we should not mess with the contents.
+     * 
+     *
+     * @method text
+     * @param {String} text String to write out.
+     * @param {Boolean} raw Optional raw state if true the contents wont get encoded.
      */
+    text: function(in_text, node)
+    {
+        // if not in whitespace critical
+        if (in_text.length < 1) {
+            return;
+        }
+        var text = new XMLSerializer().serializeToString(document.createTextNode(in_text)); // escape it properly?
+        
+        if (this.in_pre) {
+            this.html[this.html.length] =  text;
+            return;   
+        }
+        
+        if (this.in_inline) {
+            text = text.replace(/\s+/g,' '); // all white space inc line breaks to a slingle' '
+            if (text != ' ') {
+                text = text.replace(/\s+/,' ');  // all white space to single white space
+                
+                    
+                // if next tag is '<BR>', then we can trim right..
+                if (node.nextSibling &&
+                    node.nextSibling.nodeType == 1 &&
+                    node.nextSibling.nodeName == 'BR' )
+                {
+                    text = text.replace(/\s+$/g,'');
+                }
+                // if previous tag was a BR, we can also trim..
+                if (node.previousSibling &&
+                    node.previousSibling.nodeType == 1 &&
+                    node.previousSibling.nodeName == 'BR' )
+                {
+                    text = this.indentstr +  text.replace(/^\s+/g,'');
+                }
+                if (text.match(/\n/)) {
+                    text = text.replace(
+                        /(?![^\n]{1,64}$)([^\n]{1,64})\s/g, '$1\n' + this.indentstr
+                    );
+                    // remoeve the last whitespace / line break.
+                    text = text.replace(/\n\s+$/,'');
+                }
+                // repace long lines
+                
+            }
+             
+            this.html[this.html.length] =  text;
+            return;   
+        }
+        // see if previous element was a inline element.
+        var indentstr = this.indentstr;
+   
+        text = text.replace(/\s+/g," "); // all whitespace into single white space.
+        
+        // should trim left?
+        if (node.previousSibling &&
+            node.previousSibling.nodeType == 1 &&
+            Roo.htmleditor.TidyWriter.inline_elements.indexOf(node.previousSibling.nodeName) > -1)
+        {
+            indentstr = '';
+            
+        } else {
+            this.addLine();
+            text = text.replace(/^\s+/,''); // trim left
+          
+        }
+        // should trim right?
+        if (node.nextSibling &&
+            node.nextSibling.nodeType == 1 &&
+            Roo.htmleditor.TidyWriter.inline_elements.indexOf(node.nextSibling.nodeName) > -1)
+        {
+          // noop
+            
+        }  else {
+            text = text.replace(/\s+$/,''); // trim right
+        }
+         
+              
+        
+        
+        
+        if (text.length < 1) {
+            return;
+        }
+        if (!text.match(/\n/)) {
+            this.html.push(indentstr + text);
+            return;
+        }
+        
+        text = this.indentstr + text.replace(
+            /(?![^\n]{1,64}$)([^\n]{1,64})\s/g, '$1\n' + this.indentstr
+        );
+        // remoeve the last whitespace / line break.
+        text = text.replace(/\s+$/,''); 
+        
+        this.html.push(text);
+        
+        // split and indent..
+        
+        
+    },
     /**
-     * @event focus
-     * @hide
+     * Writes a cdata node such as <![CDATA[data]]>.
+     *
+     * @method cdata
+     * @param {String} text String to write out inside the cdata.
      */
+    cdata: function(text) {
+        this.html.push('<![CDATA[', text, ']]>');
+    },
     /**
-     * @event specialkey
-     * @hide
+    * Writes a comment node such as <!-- Comment -->.
+    *
+    * @method cdata
+    * @param {String} text String to write out inside the comment.
+    */
+   comment: function(text) {
+       this.html.push('<!--', text, '-->');
+   },
+    /**
+     * Writes a PI node such as <?xml attr="value" ?>.
+     *
+     * @method pi
+     * @param {String} name Name of the pi.
+     * @param {String} text String to write out inside the pi.
      */
+    pi: function(name, text) {
+        text ? this.html.push('<?', name, ' ', this.encode(text), '?>') : this.html.push('<?', name, '?>');
+        this.indent != '' && this.html.push('\n');
+    },
     /**
-     * @cfg {String} fieldClass @hide
+     * Writes a doctype node such as <!DOCTYPE data>.
+     *
+     * @method doctype
+     * @param {String} text String to write out inside the doctype.
      */
+    doctype: function(text) {
+        this.html.push('<!DOCTYPE', text, '>', this.indent != '' ? '\n' : '');
+    },
     /**
-     * @cfg {String} focusClass @hide
+     * Resets the internal buffer if one wants to reuse the writer.
+     *
+     * @method reset
+     */
+    reset: function() {
+        this.html.length = 0;
+        this.state = [];
+        this.pushState({
+            indentstr : '',
+            in_pre : false, 
+            in_inline : false
+        })
+    },
+    /**
+     * Returns the contents that got serialized.
+     *
+     * @method getContent
+     * @return {String} HTML contents that got written down.
      */
+    getContent: function() {
+        return this.html.join('').replace(/\n$/, '');
+    },
+    
+    pushState : function(cfg)
+    {
+        this.state.push(cfg);
+        Roo.apply(this, cfg);
+    },
+    
+    popState : function()
+    {
+        if (this.state.length < 1) {
+            return; // nothing to push
+        }
+        var cfg = {
+            in_pre: false,
+            indentstr : ''
+        };
+        this.state.pop();
+        if (this.state.length > 0) {
+            cfg = this.state[this.state.length-1]; 
+        }
+        Roo.apply(this, cfg);
+    },
+    
+    addLine: function()
+    {
+        if (this.html.length < 1) {
+            return;
+        }
+        
+        
+        var value = this.html[this.html.length - 1];
+        if (value.length > 0 && '\n' !== value) {
+            this.html.push('\n');
+        }
+    }
+    
+    
+//'pre script noscript style textarea video audio iframe object code'
+// shortended... 'area base basefont br col frame hr img input isindex link  meta param embed source wbr track');
+// inline 
+};
+
+Roo.htmleditor.TidyWriter.inline_elements = [
+        'SPAN','STRONG','B','EM','I','FONT','STRIKE','U','VAR',
+        'CITE','DFN','CODE','MARK','Q','SUP','SUB','SAMP', 'A'
+];
+Roo.htmleditor.TidyWriter.shortend_elements = [
+    'AREA','BASE','BASEFONT','BR','COL','FRAME','HR','IMG','INPUT',
+    'ISINDEX','LINK','','META','PARAM','EMBED','SOURCE','WBR','TRACK'
+];
+
+Roo.htmleditor.TidyWriter.whitespace_elements = [
+    'PRE','SCRIPT','NOSCRIPT','STYLE','TEXTAREA','VIDEO','AUDIO','IFRAME','OBJECT','CODE'
+];/***
+ * This is based loosely on tinymce 
+ * @class Roo.htmleditor.TidyEntities
+ * @static
+ * https://github.com/thorn0/tinymce.html/blob/master/tinymce.html.js
+ *
+ * Not 100% sure this is actually used or needed.
+ */
+
+Roo.htmleditor.TidyEntities = {
+    
     /**
-     * @cfg {String} autoCreate @hide
+     * initialize data..
      */
+    init : function (){
+     
+        this.namedEntities = this.buildEntitiesLookup(this.namedEntitiesData, 32);
+       
+    },
+
+
+    buildEntitiesLookup: function(items, radix) {
+        var i, chr, entity, lookup = {};
+        if (!items) {
+            return {};
+        }
+        items = typeof(items) == 'string' ? items.split(',') : items;
+        radix = radix || 10;
+        // Build entities lookup table
+        for (i = 0; i < items.length; i += 2) {
+            chr = String.fromCharCode(parseInt(items[i], radix));
+            // Only add non base entities
+            if (!this.baseEntities[chr]) {
+                entity = '&' + items[i + 1] + ';';
+                lookup[chr] = entity;
+                lookup[entity] = chr;
+            }
+        }
+        return lookup;
+        
+    },
+    
+    asciiMap : {
+            128: '€',
+            130: '‚',
+            131: 'ƒ',
+            132: '„',
+            133: '…',
+            134: '†',
+            135: '‡',
+            136: 'ˆ',
+            137: '‰',
+            138: 'Š',
+            139: '‹',
+            140: 'Œ',
+            142: 'Ž',
+            145: '‘',
+            146: '’',
+            147: '“',
+            148: '”',
+            149: '•',
+            150: '–',
+            151: '—',
+            152: '˜',
+            153: '™',
+            154: 'š',
+            155: '›',
+            156: 'œ',
+            158: 'ž',
+            159: 'Ÿ'
+    },
+    // Raw entities
+    baseEntities : {
+        '"': '&quot;',
+        // Needs to be escaped since the YUI compressor would otherwise break the code
+        '\'': '&#39;',
+        '<': '&lt;',
+        '>': '&gt;',
+        '&': '&amp;',
+        '`': '&#96;'
+    },
+    // Reverse lookup table for raw entities
+    reverseEntities : {
+        '&lt;': '<',
+        '&gt;': '>',
+        '&amp;': '&',
+        '&quot;': '"',
+        '&apos;': '\''
+    },
+    
+    attrsCharsRegExp : /[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
+    textCharsRegExp : /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
+    rawCharsRegExp : /[<>&\"\']/g,
+    entityRegExp : /&#([a-z0-9]+);?|&([a-z0-9]+);/gi,
+    namedEntities  : false,
+    namedEntitiesData : [ 
+        '50',
+        'nbsp',
+        '51',
+        'iexcl',
+        '52',
+        'cent',
+        '53',
+        'pound',
+        '54',
+        'curren',
+        '55',
+        'yen',
+        '56',
+        'brvbar',
+        '57',
+        'sect',
+        '58',
+        'uml',
+        '59',
+        'copy',
+        '5a',
+        'ordf',
+        '5b',
+        'laquo',
+        '5c',
+        'not',
+        '5d',
+        'shy',
+        '5e',
+        'reg',
+        '5f',
+        'macr',
+        '5g',
+        'deg',
+        '5h',
+        'plusmn',
+        '5i',
+        'sup2',
+        '5j',
+        'sup3',
+        '5k',
+        'acute',
+        '5l',
+        'micro',
+        '5m',
+        'para',
+        '5n',
+        'middot',
+        '5o',
+        'cedil',
+        '5p',
+        'sup1',
+        '5q',
+        'ordm',
+        '5r',
+        'raquo',
+        '5s',
+        'frac14',
+        '5t',
+        'frac12',
+        '5u',
+        'frac34',
+        '5v',
+        'iquest',
+        '60',
+        'Agrave',
+        '61',
+        'Aacute',
+        '62',
+        'Acirc',
+        '63',
+        'Atilde',
+        '64',
+        'Auml',
+        '65',
+        'Aring',
+        '66',
+        'AElig',
+        '67',
+        'Ccedil',
+        '68',
+        'Egrave',
+        '69',
+        'Eacute',
+        '6a',
+        'Ecirc',
+        '6b',
+        'Euml',
+        '6c',
+        'Igrave',
+        '6d',
+        'Iacute',
+        '6e',
+        'Icirc',
+        '6f',
+        'Iuml',
+        '6g',
+        'ETH',
+        '6h',
+        'Ntilde',
+        '6i',
+        'Ograve',
+        '6j',
+        'Oacute',
+        '6k',
+        'Ocirc',
+        '6l',
+        'Otilde',
+        '6m',
+        'Ouml',
+        '6n',
+        'times',
+        '6o',
+        'Oslash',
+        '6p',
+        'Ugrave',
+        '6q',
+        'Uacute',
+        '6r',
+        'Ucirc',
+        '6s',
+        'Uuml',
+        '6t',
+        'Yacute',
+        '6u',
+        'THORN',
+        '6v',
+        'szlig',
+        '70',
+        'agrave',
+        '71',
+        'aacute',
+        '72',
+        'acirc',
+        '73',
+        'atilde',
+        '74',
+        'auml',
+        '75',
+        'aring',
+        '76',
+        'aelig',
+        '77',
+        'ccedil',
+        '78',
+        'egrave',
+        '79',
+        'eacute',
+        '7a',
+        'ecirc',
+        '7b',
+        'euml',
+        '7c',
+        'igrave',
+        '7d',
+        'iacute',
+        '7e',
+        'icirc',
+        '7f',
+        'iuml',
+        '7g',
+        'eth',
+        '7h',
+        'ntilde',
+        '7i',
+        'ograve',
+        '7j',
+        'oacute',
+        '7k',
+        'ocirc',
+        '7l',
+        'otilde',
+        '7m',
+        'ouml',
+        '7n',
+        'divide',
+        '7o',
+        'oslash',
+        '7p',
+        'ugrave',
+        '7q',
+        'uacute',
+        '7r',
+        'ucirc',
+        '7s',
+        'uuml',
+        '7t',
+        'yacute',
+        '7u',
+        'thorn',
+        '7v',
+        'yuml',
+        'ci',
+        'fnof',
+        'sh',
+        'Alpha',
+        'si',
+        'Beta',
+        'sj',
+        'Gamma',
+        'sk',
+        'Delta',
+        'sl',
+        'Epsilon',
+        'sm',
+        'Zeta',
+        'sn',
+        'Eta',
+        'so',
+        'Theta',
+        'sp',
+        'Iota',
+        'sq',
+        'Kappa',
+        'sr',
+        'Lambda',
+        'ss',
+        'Mu',
+        'st',
+        'Nu',
+        'su',
+        'Xi',
+        'sv',
+        'Omicron',
+        't0',
+        'Pi',
+        't1',
+        'Rho',
+        't3',
+        'Sigma',
+        't4',
+        'Tau',
+        't5',
+        'Upsilon',
+        't6',
+        'Phi',
+        't7',
+        'Chi',
+        't8',
+        'Psi',
+        't9',
+        'Omega',
+        'th',
+        'alpha',
+        'ti',
+        'beta',
+        'tj',
+        'gamma',
+        'tk',
+        'delta',
+        'tl',
+        'epsilon',
+        'tm',
+        'zeta',
+        'tn',
+        'eta',
+        'to',
+        'theta',
+        'tp',
+        'iota',
+        'tq',
+        'kappa',
+        'tr',
+        'lambda',
+        'ts',
+        'mu',
+        'tt',
+        'nu',
+        'tu',
+        'xi',
+        'tv',
+        'omicron',
+        'u0',
+        'pi',
+        'u1',
+        'rho',
+        'u2',
+        'sigmaf',
+        'u3',
+        'sigma',
+        'u4',
+        'tau',
+        'u5',
+        'upsilon',
+        'u6',
+        'phi',
+        'u7',
+        'chi',
+        'u8',
+        'psi',
+        'u9',
+        'omega',
+        'uh',
+        'thetasym',
+        'ui',
+        'upsih',
+        'um',
+        'piv',
+        '812',
+        'bull',
+        '816',
+        'hellip',
+        '81i',
+        'prime',
+        '81j',
+        'Prime',
+        '81u',
+        'oline',
+        '824',
+        'frasl',
+        '88o',
+        'weierp',
+        '88h',
+        'image',
+        '88s',
+        'real',
+        '892',
+        'trade',
+        '89l',
+        'alefsym',
+        '8cg',
+        'larr',
+        '8ch',
+        'uarr',
+        '8ci',
+        'rarr',
+        '8cj',
+        'darr',
+        '8ck',
+        'harr',
+        '8dl',
+        'crarr',
+        '8eg',
+        'lArr',
+        '8eh',
+        'uArr',
+        '8ei',
+        'rArr',
+        '8ej',
+        'dArr',
+        '8ek',
+        'hArr',
+        '8g0',
+        'forall',
+        '8g2',
+        'part',
+        '8g3',
+        'exist',
+        '8g5',
+        'empty',
+        '8g7',
+        'nabla',
+        '8g8',
+        'isin',
+        '8g9',
+        'notin',
+        '8gb',
+        'ni',
+        '8gf',
+        'prod',
+        '8gh',
+        'sum',
+        '8gi',
+        'minus',
+        '8gn',
+        'lowast',
+        '8gq',
+        'radic',
+        '8gt',
+        'prop',
+        '8gu',
+        'infin',
+        '8h0',
+        'ang',
+        '8h7',
+        'and',
+        '8h8',
+        'or',
+        '8h9',
+        'cap',
+        '8ha',
+        'cup',
+        '8hb',
+        'int',
+        '8hk',
+        'there4',
+        '8hs',
+        'sim',
+        '8i5',
+        'cong',
+        '8i8',
+        'asymp',
+        '8j0',
+        'ne',
+        '8j1',
+        'equiv',
+        '8j4',
+        'le',
+        '8j5',
+        'ge',
+        '8k2',
+        'sub',
+        '8k3',
+        'sup',
+        '8k4',
+        'nsub',
+        '8k6',
+        'sube',
+        '8k7',
+        'supe',
+        '8kl',
+        'oplus',
+        '8kn',
+        'otimes',
+        '8l5',
+        'perp',
+        '8m5',
+        'sdot',
+        '8o8',
+        'lceil',
+        '8o9',
+        'rceil',
+        '8oa',
+        'lfloor',
+        '8ob',
+        'rfloor',
+        '8p9',
+        'lang',
+        '8pa',
+        'rang',
+        '9ea',
+        'loz',
+        '9j0',
+        'spades',
+        '9j3',
+        'clubs',
+        '9j5',
+        'hearts',
+        '9j6',
+        'diams',
+        'ai',
+        'OElig',
+        'aj',
+        'oelig',
+        'b0',
+        'Scaron',
+        'b1',
+        'scaron',
+        'bo',
+        'Yuml',
+        'm6',
+        'circ',
+        'ms',
+        'tilde',
+        '802',
+        'ensp',
+        '803',
+        'emsp',
+        '809',
+        'thinsp',
+        '80c',
+        'zwnj',
+        '80d',
+        'zwj',
+        '80e',
+        'lrm',
+        '80f',
+        'rlm',
+        '80j',
+        'ndash',
+        '80k',
+        'mdash',
+        '80o',
+        'lsquo',
+        '80p',
+        'rsquo',
+        '80q',
+        'sbquo',
+        '80s',
+        'ldquo',
+        '80t',
+        'rdquo',
+        '80u',
+        'bdquo',
+        '810',
+        'dagger',
+        '811',
+        'Dagger',
+        '81g',
+        'permil',
+        '81p',
+        'lsaquo',
+        '81q',
+        'rsaquo',
+        '85c',
+        'euro'
+    ],
+
+         
     /**
-     * @cfg {String} inputType @hide
+     * Encodes the specified string using raw entities. This means only the required XML base entities will be encoded.
+     *
+     * @method encodeRaw
+     * @param {String} text Text to encode.
+     * @param {Boolean} attr Optional flag to specify if the text is attribute contents.
+     * @return {String} Entity encoded text.
      */
+    encodeRaw: function(text, attr)
+    {
+        var t = this;
+        return text.replace(attr ? this.attrsCharsRegExp : this.textCharsRegExp, function(chr) {
+            return t.baseEntities[chr] || chr;
+        });
+    },
     /**
-     * @cfg {String} invalidClass @hide
+     * Encoded the specified text with both the attributes and text entities. This function will produce larger text contents
+     * since it doesn't know if the context is within a attribute or text node. This was added for compatibility
+     * and is exposed as the DOMUtils.encode function.
+     *
+     * @method encodeAllRaw
+     * @param {String} text Text to encode.
+     * @return {String} Entity encoded text.
      */
+    encodeAllRaw: function(text) {
+        var t = this;
+        return ('' + text).replace(this.rawCharsRegExp, function(chr) {
+            return t.baseEntities[chr] || chr;
+        });
+    },
     /**
-     * @cfg {String} invalidText @hide
+     * Encodes the specified string using numeric entities. The core entities will be
+     * encoded as named ones but all non lower ascii characters will be encoded into numeric entities.
+     *
+     * @method encodeNumeric
+     * @param {String} text Text to encode.
+     * @param {Boolean} attr Optional flag to specify if the text is attribute contents.
+     * @return {String} Entity encoded text.
      */
+    encodeNumeric: function(text, attr) {
+        var t = this;
+        return text.replace(attr ? this.attrsCharsRegExp : this.textCharsRegExp, function(chr) {
+            // Multi byte sequence convert it to a single entity
+            if (chr.length > 1) {
+                return '&#' + (1024 * (chr.charCodeAt(0) - 55296) + (chr.charCodeAt(1) - 56320) + 65536) + ';';
+            }
+            return t.baseEntities[chr] || '&#' + chr.charCodeAt(0) + ';';
+        });
+    },
     /**
-     * @cfg {String} msgFx @hide
+     * Encodes the specified string using named entities. The core entities will be encoded
+     * as named ones but all non lower ascii characters will be encoded into named entities.
+     *
+     * @method encodeNamed
+     * @param {String} text Text to encode.
+     * @param {Boolean} attr Optional flag to specify if the text is attribute contents.
+     * @param {Object} entities Optional parameter with entities to use.
+     * @return {String} Entity encoded text.
      */
+    encodeNamed: function(text, attr, entities) {
+        var t = this;
+        entities = entities || this.namedEntities;
+        return text.replace(attr ? this.attrsCharsRegExp : this.textCharsRegExp, function(chr) {
+            return t.baseEntities[chr] || entities[chr] || chr;
+        });
+    },
     /**
-     * @cfg {String} validateOnBlur @hide
+     * Returns an encode function based on the name(s) and it's optional entities.
+     *
+     * @method getEncodeFunc
+     * @param {String} name Comma separated list of encoders for example named,numeric.
+     * @param {String} entities Optional parameter with entities to use instead of the built in set.
+     * @return {function} Encode function to be used.
      */
-});
-
-Roo.HtmlEditorCore.white = [
-        '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', 
-       
-       'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
-      'thead',   'tr', 
-     
-      'dir', 'menu', 'ol', 'ul', 'dl',
-       
-      '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..
-];
-Roo.HtmlEditorCore.clean = [
-    'script', 'style', 'title', 'xml'
-];
-Roo.HtmlEditorCore.remove = [
-    'font'
-];
-// attributes..
+    getEncodeFunc: function(name, entities) {
+        entities = this.buildEntitiesLookup(entities) || this.namedEntities;
+        var t = this;
+        function encodeNamedAndNumeric(text, attr) {
+            return text.replace(attr ? t.attrsCharsRegExp : t.textCharsRegExp, function(chr) {
+                return t.baseEntities[chr] || entities[chr] || '&#' + chr.charCodeAt(0) + ';' || chr;
+            });
+        }
 
-Roo.HtmlEditorCore.ablack = [
-    'on'
-];
+        function encodeCustomNamed(text, attr) {
+            return t.encodeNamed(text, attr, entities);
+        }
+        // Replace + with , to be compatible with previous TinyMCE versions
+        name = this.makeMap(name.replace(/\+/g, ','));
+        // Named and numeric encoder
+        if (name.named && name.numeric) {
+            return this.encodeNamedAndNumeric;
+        }
+        // Named encoder
+        if (name.named) {
+            // Custom names
+            if (entities) {
+                return encodeCustomNamed;
+            }
+            return this.encodeNamed;
+        }
+        // Numeric
+        if (name.numeric) {
+            return this.encodeNumeric;
+        }
+        // Raw encoder
+        return this.encodeRaw;
+    },
+    /**
+     * Decodes the specified string, this will replace entities with raw UTF characters.
+     *
+     * @method decode
+     * @param {String} text Text to entity decode.
+     * @return {String} Entity decoded string.
+     */
+    decode: function(text)
+    {
+        var  t = this;
+        return text.replace(this.entityRegExp, function(all, numeric) {
+            if (numeric) {
+                numeric = 'x' === numeric.charAt(0).toLowerCase() ? parseInt(numeric.substr(1), 16) : parseInt(numeric, 10);
+                // Support upper UTF
+                if (numeric > 65535) {
+                    numeric -= 65536;
+                    return String.fromCharCode(55296 + (numeric >> 10), 56320 + (1023 & numeric));
+                }
+                return t.asciiMap[numeric] || String.fromCharCode(numeric);
+            }
+            return t.reverseEntities[all] || t.namedEntities[all] || t.nativeDecode(all);
+        });
+    },
+    nativeDecode : function (text) {
+        return text;
+    },
+    makeMap : function (items, delim, map) {
+               var i;
+               items = items || [];
+               delim = delim || ',';
+               if (typeof items == "string") {
+                       items = items.split(delim);
+               }
+               map = map || {};
+               i = items.length;
+               while (i--) {
+                       map[items[i]] = {};
+               }
+               return map;
+       }
+};
     
-Roo.HtmlEditorCore.aclean = [ 
-    'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
-];
+    
+    
+Roo.htmleditor.TidyEntities.init();
+/**
+ * @class Roo.htmleditor.KeyEnter
+ * Handle Enter press..
+ * @cfg {Roo.HtmlEditorCore} core the editor.
+ * @constructor
+ * Create a new Filter.
+ * @param {Object} config Configuration options
+ */
 
-// protocols..
-Roo.HtmlEditorCore.pwhite= [
-        'http',  'https',  'mailto'
-];
 
-// white listed style attributes.
-Roo.HtmlEditorCore.cwhite= [
-      //  'text-align', /// default is to allow most things..
-      
-         
-//        'font-size'//??
-];
 
-// black listed style attributes.
-Roo.HtmlEditorCore.cblack= [
-      //  'font-size' -- this can be set by the project 
-];
 
 
-Roo.HtmlEditorCore.swapCodes   =[ 
-    [    8211, "--" ], 
-    [    8212, "--" ], 
-    [    8216,  "'" ],  
-    [    8217, "'" ],  
-    [    8220, '"' ],  
-    [    8221, '"' ],  
-    [    8226, "*" ],  
-    [    8230, "..." ]
-]; 
+Roo.htmleditor.KeyEnter = function(cfg) {
+    Roo.apply(this, cfg);
+    // this does not actually call walk as it's really just a abstract class
+    Roo.get(this.core.doc.body).on('keypress', this.keypress, this);
+}
 
-    //<script type="text/javascript">
+//Roo.htmleditor.KeyEnter.i = 0;
 
-/*
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- * Licence LGPL
- * 
- */
-Roo.form.HtmlEditor = function(config){
-    
-    
-    
-    Roo.form.HtmlEditor.superclass.constructor.call(this, config);
+
+Roo.htmleditor.KeyEnter.prototype = {
     
-    if (!this.toolbars) {
-        this.toolbars = [];
-    }
-    this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
+    core : false,
     
+    keypress : function(e)
+    {
+        if (e.charCode != 13 && e.charCode != 10) {
+            Roo.log([e.charCode,e]);
+            return true;
+        }
+        e.preventDefault();
+        // https://stackoverflow.com/questions/18552336/prevent-contenteditable-adding-div-on-enter-chrome
+        var doc = this.core.doc;
+          //add a new line
+       
     
+        var sel = this.core.getSelection();
+        var range = sel.getRangeAt(0);
+        var n = range.commonAncestorContainer;
+        var pc = range.closest([ 'ol', 'ul']);
+        var pli = range.closest('li');
+        if (!pc || e.ctrlKey) {
+            // on it list, or ctrl pressed.
+            if (!e.ctrlKey) {
+                sel.insertNode('br', 'after'); 
+            } else {
+                // only do this if we have ctrl key..
+                var br = doc.createElement('br');
+                br.className = 'clear';
+                br.setAttribute('style', 'clear: both');
+                sel.insertNode(br, 'after'); 
+            }
+            
+         
+            this.core.undoManager.addEvent();
+            this.core.fireEditorEvent(e);
+            return false;
+        }
+        
+        // deal with <li> insetion
+        if (pli.innerText.trim() == '' &&
+            pli.previousSibling &&
+            pli.previousSibling.nodeName == 'LI' &&
+            pli.previousSibling.innerText.trim() ==  '') {
+            pli.parentNode.removeChild(pli.previousSibling);
+            sel.cursorAfter(pc);
+            this.core.undoManager.addEvent();
+            this.core.fireEditorEvent(e);
+            return false;
+        }
+    
+        var li = doc.createElement('LI');
+        li.innerHTML = '&nbsp;';
+        if (!pli || !pli.firstSibling) {
+            pc.appendChild(li);
+        } else {
+            pli.parentNode.insertBefore(li, pli.firstSibling);
+        }
+        sel.cursorText (li.firstChild);
+      
+        this.core.undoManager.addEvent();
+        this.core.fireEditorEvent(e);
+
+        return false;
+        
+    
+        
+        
+         
+    }
 };
+     
+/**
+ * @class Roo.htmleditor.Block
+ * Base class for html editor blocks - do not use it directly .. extend it..
+ * @cfg {DomElement} node The node to apply stuff to.
+ * @cfg {String} friendly_name the name that appears in the context bar about this block
+ * @cfg {Object} Context menu - see Roo.form.HtmlEditor.ToolbarContext
+ * @constructor
+ * Create a new Filter.
+ * @param {Object} config Configuration options
+ */
 
+Roo.htmleditor.Block  = function(cfg)
+{
+    // do nothing .. should not be called really.
+}
 /**
- * @class Roo.form.HtmlEditor
- * @extends Roo.form.Field
- * Provides a lightweight HTML Editor component.
- *
- * This has been tested on Fireforx / Chrome.. IE may not be so great..
- * 
- * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
- * supported by this editor.</b><br/><br/>
- * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
- * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
+ * factory method to get the block from an element (using cache if necessary)
+ * @static
+ * @param {HtmlElement} the dom element
  */
-Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
-    /**
-     * @cfg {Boolean} clearUp
-     */
-    clearUp : true,
-      /**
-     * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
-     */
-    toolbars : false,
-   
-     /**
-     * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
-     *                        Roo.resizable.
-     */
-    resizable : false,
-     /**
-     * @cfg {Number} height (in pixels)
-     */   
-    height: 300,
-   /**
-     * @cfg {Number} width (in pixels)
-     */   
-    width: 500,
+Roo.htmleditor.Block.factory = function(node)
+{
+    var cc = Roo.htmleditor.Block.cache;
+    var id = Roo.get(node).id;
+    if (typeof(cc[id]) != 'undefined' && (!cc[id].node || cc[id].node.closest('body'))) {
+        Roo.htmleditor.Block.cache[id].readElement(node);
+        return Roo.htmleditor.Block.cache[id];
+    }
+    var db  = node.getAttribute('data-block');
+    if (!db) {
+        db = node.nodeName.toLowerCase().toUpperCaseFirst();
+    }
+    var cls = Roo.htmleditor['Block' + db];
+    if (typeof(cls) == 'undefined') {
+        //Roo.log(node.getAttribute('data-block'));
+        Roo.log("OOps missing block : " + 'Block' + db);
+        return false;
+    }
+    Roo.htmleditor.Block.cache[id] = new cls({ node: node });
+    return Roo.htmleditor.Block.cache[id];  /// should trigger update element
+};
+
+/**
+ * initalize all Elements from content that are 'blockable'
+ * @static
+ * @param the body element
+ */
+Roo.htmleditor.Block.initAll = function(body, type)
+{
+    if (typeof(type) == 'undefined') {
+        var ia = Roo.htmleditor.Block.initAll;
+        ia(body,'table');
+        ia(body,'td');
+        ia(body,'figure');
+        return;
+    }
+    Roo.each(Roo.get(body).query(type), function(e) {
+        Roo.htmleditor.Block.factory(e);    
+    },this);
+};
+// question goes here... do we need to clear out this cache sometimes?
+// or show we make it relivant to the htmleditor.
+Roo.htmleditor.Block.cache = {};
+
+Roo.htmleditor.Block.prototype = {
     
-    /**
-     * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
-     * 
-     */
-    stylesheets: false,
+    node : false,
     
+     // used by context menu
+    friendly_name : 'Based Block',
     
-     /**
-     * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
-     * 
-     */
-    cblack: false,
+    // text for button to delete this element
+    deleteTitle : false,
+    
+    context : false,
     /**
-     * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
-     * 
+     * Update a node with values from this object
+     * @param {DomElement} node
      */
-    cwhite: false,
-    
+    updateElement : function(node)
+    {
+        Roo.DomHelper.update(node === undefined ? this.node : node, this.toObject());
+    },
      /**
-     * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
-     * 
+     * convert to plain HTML for calling insertAtCursor..
      */
-    black: false,
+    toHTML : function()
+    {
+        return Roo.DomHelper.markup(this.toObject());
+    },
     /**
-     * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
-     * 
+     * used by readEleemnt to extract data from a node
+     * may need improving as it's pretty basic
+     
+     * @param {DomElement} node
+     * @param {String} tag - tag to find, eg. IMG ?? might be better to use DomQuery ?
+     * @param {String} attribute (use html - for contents, style for using next param as style, or false to return the node)
+     * @param {String} style the style property - eg. text-align
      */
-    white: false,
+    getVal : function(node, tag, attr, style)
+    {
+        var n = node;
+        if (tag !== true && n.tagName != tag.toUpperCase()) {
+            // in theory we could do figure[3] << 3rd figure? or some more complex search..?
+            // but kiss for now.
+            n = node.getElementsByTagName(tag).item(0);
+        }
+        if (!n) {
+            return '';
+        }
+        if (attr === false) {
+            return n;
+        }
+        if (attr == 'html') {
+            return n.innerHTML;
+        }
+        if (attr == 'style') {
+            return n.style[style]; 
+        }
+        
+        return n.hasAttribute(attr) ? n.getAttribute(attr) : '';
+            
+    },
+    /**
+     * create a DomHelper friendly object - for use with 
+     * Roo.DomHelper.markup / overwrite / etc..
+     * (override this)
+     */
+    toObject : function()
+    {
+        return {};
+    },
+      /**
+     * Read a node that has a 'data-block' property - and extract the values from it.
+     * @param {DomElement} node - the node
+     */
+    readElement : function(node)
+    {
+        
+    } 
     
-    // id of frame..
-    frameId: false,
     
-    // private properties
-    validationEvent : false,
-    deferHeight: true,
-    initialized : false,
-    activated : false,
+};
+
+
+/**
+ * @class Roo.htmleditor.BlockFigure
+ * Block that has an image and a figcaption
+ * @cfg {String} image_src the url for the image
+ * @cfg {String} align (left|right) alignment for the block default left
+ * @cfg {String} caption the text to appear below  (and in the alt tag)
+ * @cfg {String} caption_display (block|none) display or not the caption
+ * @cfg {String|number} image_width the width of the image number or %?
+ * @cfg {String|number} image_height the height of the image number or %?
+ * 
+ * @constructor
+ * Create a new Filter.
+ * @param {Object} config Configuration options
+ */
+
+Roo.htmleditor.BlockFigure = function(cfg)
+{
+    if (cfg.node) {
+        this.readElement(cfg.node);
+        this.updateElement(cfg.node);
+    }
+    Roo.apply(this, cfg);
+}
+Roo.extend(Roo.htmleditor.BlockFigure, Roo.htmleditor.Block, {
     
-    onFocus : Roo.emptyFn,
-    iframePad:3,
-    hideMode:'offsets',
+    // setable values.
+    image_src: '',
+    align: 'center',
+    caption : '',
+    caption_display : 'block',
+    width : '100%',
+    cls : '',
+    href: '',
+    video_url : '',
     
-    actionMode : 'container', // defaults to hiding it...
+    // margin: '2%', not used
     
-    defaultAutoCreate : { // modified by initCompnoent..
-        tag: "textarea",
-        style:"width:500px;height:300px;",
-        autocomplete: "new-password"
-    },
+    text_align: 'left', //   (left|right) alignment for the text caption default left. - not used at present
 
-    // private
-    initComponent : function(){
-        this.addEvents({
-            /**
-             * @event initialize
-             * Fires when the editor is fully initialized (including the iframe)
-             * @param {HtmlEditor} this
-             */
-            initialize: true,
-            /**
-             * @event activate
-             * Fires when the editor is first receives the focus. Any insertion must wait
-             * until after this event.
-             * @param {HtmlEditor} this
-             */
-            activate: true,
-             /**
-             * @event beforesync
-             * Fires before the textarea is updated with content from the editor iframe. Return false
-             * to cancel the sync.
-             * @param {HtmlEditor} this
-             * @param {String} html
-             */
-            beforesync: true,
-             /**
-             * @event beforepush
-             * Fires before the iframe editor is updated with content from the textarea. Return false
-             * to cancel the push.
-             * @param {HtmlEditor} this
-             * @param {String} html
-             */
-            beforepush: true,
-             /**
-             * @event sync
-             * Fires when the textarea is updated with content from the editor iframe.
-             * @param {HtmlEditor} this
-             * @param {String} html
-             */
-            sync: true,
-             /**
-             * @event push
-             * Fires when the iframe editor is updated with content from the textarea.
-             * @param {HtmlEditor} this
-             * @param {String} html
-             */
-            push: true,
-             /**
-             * @event editmodechange
-             * Fires when the editor switches edit modes
-             * @param {HtmlEditor} this
-             * @param {Boolean} sourceEdit True if source edit, false if standard editing.
-             */
-            editmodechange: true,
-            /**
-             * @event editorevent
-             * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
-             * @param {HtmlEditor} this
-             */
-            editorevent: true,
-            /**
-             * @event firstfocus
-             * Fires when on first focus - needed by toolbars..
-             * @param {HtmlEditor} this
-             */
-            firstfocus: true,
-            /**
-             * @event autosave
-             * Auto save the htmlEditor value as a file into Events
-             * @param {HtmlEditor} this
-             */
-            autosave: true,
-            /**
-             * @event savedpreview
-             * preview the saved version of htmlEditor
-             * @param {HtmlEditor} this
-             */
-            savedpreview: true,
-            
-            /**
-            * @event stylesheetsclick
-            * Fires when press the Sytlesheets button
-            * @param {Roo.HtmlEditorCore} this
-            */
-            stylesheetsclick: true
-        });
-        this.defaultAutoCreate =  {
-            tag: "textarea",
-            style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
-            autocomplete: "new-password"
+    
+    // used by context menu
+    friendly_name : 'Image with caption',
+    deleteTitle : "Delete Image and Caption",
+    
+    contextMenu : function(toolbar)
+    {
+        
+        var block = function() {
+            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode);
         };
-    },
-
-    /**
-     * Protected method that will not generally be called directly. It
-     * is called when the editor creates its toolbar. Override this method if you need to
-     * add custom toolbar buttons.
-     * @param {HtmlEditor} editor
-     */
-    createToolbar : function(editor){
-        Roo.log("create toolbars");
-        if (!editor.toolbars || !editor.toolbars.length) {
-            editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
-        }
         
-        for (var i =0 ; i < editor.toolbars.length;i++) {
-            editor.toolbars[i] = Roo.factory(
-                    typeof(editor.toolbars[i]) == 'string' ?
-                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
-                Roo.form.HtmlEditor);
-            editor.toolbars[i].init(editor);
-        }
-         
         
-    },
-
-     
-    // private
-    onRender : function(ct, position)
-    {
-        var _t = this;
-        Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
+        var rooui =  typeof(Roo.bootstrap) == 'undefined' ? Roo : Roo.bootstrap;
         
-        this.wrap = this.el.wrap({
-            cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
-        });
+        var syncValue = toolbar.editorcore.syncValue;
         
-        this.editorcore.onRender(ct, position);
+        var fields = {};
+        
+        return [
+             {
+                xtype : 'TextItem',
+                text : "Source: ",
+                xns : rooui.Toolbar  //Boostrap?
+            },
+            {
+                xtype : 'Button',
+                text: 'Change Image URL',
+                 
+                listeners : {
+                    click: function (btn, state)
+                    {
+                        var b = block();
+                        
+                        Roo.MessageBox.show({
+                            title : "Image Source URL",
+                            msg : "Enter the url for the image",
+                            buttons: Roo.MessageBox.OKCANCEL,
+                            fn: function(btn, val){
+                                if (btn != 'ok') {
+                                    return;
+                                }
+                                b.image_src = val;
+                                b.updateElement();
+                                syncValue();
+                                toolbar.editorcore.onEditorEvent();
+                            },
+                            minWidth:250,
+                            prompt:true,
+                            //multiline: multiline,
+                            modal : true,
+                            value : b.image_src
+                        });
+                    }
+                },
+                xns : rooui.Toolbar
+            },
          
-        if (this.resizable) {
-            this.resizeEl = new Roo.Resizable(this.wrap, {
-                pinned : true,
-                wrap: true,
-                dynamic : true,
-                minHeight : this.height,
-                height: this.height,
-                handles : this.resizable,
-                width: this.width,
+            {
+                xtype : 'Button',
+                text: 'Change Link URL',
+                 
                 listeners : {
-                    resize : function(r, w, h) {
-                        _t.onResize(w,h); // -something
+                    click: function (btn, state)
+                    {
+                        var b = block();
+                        
+                        Roo.MessageBox.show({
+                            title : "Link URL",
+                            msg : "Enter the url for the link - leave blank to have no link",
+                            buttons: Roo.MessageBox.OKCANCEL,
+                            fn: function(btn, val){
+                                if (btn != 'ok') {
+                                    return;
+                                }
+                                b.href = val;
+                                b.updateElement();
+                                syncValue();
+                                toolbar.editorcore.onEditorEvent();
+                            },
+                            minWidth:250,
+                            prompt:true,
+                            //multiline: multiline,
+                            modal : true,
+                            value : b.href
+                        });
                     }
-                }
-            });
+                },
+                xns : rooui.Toolbar
+            },
+            {
+                xtype : 'Button',
+                text: 'Show Video URL',
+                 
+                listeners : {
+                    click: function (btn, state)
+                    {
+                        Roo.MessageBox.alert("Video URL",
+                            block().video_url == '' ? 'This image is not linked ot a video' :
+                                'The image is linked to: <a target="_new" href="' + block().video_url + '">' + block().video_url + '</a>');
+                    }
+                },
+                xns : rooui.Toolbar
+            },
             
-        }
-        this.createToolbar(this);
-       
-        
-        if(!this.width){
-            this.setSize(this.wrap.getSize());
-        }
-        if (this.resizeEl) {
-            this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
-            // should trigger onReize..
-        }
-        
-        this.keyNav = new Roo.KeyNav(this.el, {
             
-            "tab" : function(e){
-                e.preventDefault();
-                
-                var value = this.getValue();
-                
-                var start = this.el.dom.selectionStart;
-                var end = this.el.dom.selectionEnd;
-                
-                if(!e.shiftKey){
-                    
-                    this.setValue(value.substring(0, start) + "\t" + value.substring(end));
-                    this.el.dom.setSelectionRange(end + 1, end + 1);
-                    return;
-                }
-                
-                var f = value.substring(0, start).split("\t");
-                
-                if(f.pop().length != 0){
-                    return;
-                }
-                
-                this.setValue(f.join("\t") + value.substring(end));
-                this.el.dom.setSelectionRange(start - 1, start - 1);
-                
+            {
+                xtype : 'TextItem',
+                text : "Width: ",
+                xns : rooui.Toolbar  //Boostrap?
             },
-            
-            "home" : function(e){
-                e.preventDefault();
-                
-                var curr = this.el.dom.selectionStart;
-                var lines = this.getValue().split("\n");
-                
-                if(!lines.length){
-                    return;
-                }
-                
-                if(e.ctrlKey){
-                    this.el.dom.setSelectionRange(0, 0);
-                    return;
-                }
-                
-                var pos = 0;
-                
-                for (var i = 0; i < lines.length;i++) {
-                    pos += lines[i].length;
-                    
-                    if(i != 0){
-                        pos += 1;
-                    }
-                    
-                    if(pos < curr){
-                        continue;
+            {
+                xtype : 'ComboBox',
+                allowBlank : false,
+                displayField : 'val',
+                editable : true,
+                listWidth : 100,
+                triggerAction : 'all',
+                typeAhead : true,
+                valueField : 'val',
+                width : 70,
+                name : 'width',
+                listeners : {
+                    select : function (combo, r, index)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        var b = block();
+                        b.width = r.get('val');
+                        b.updateElement();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
                     }
-                    
-                    pos -= lines[i].length;
-                    
-                    break;
+                },
+                xns : rooui.form,
+                store : {
+                    xtype : 'SimpleStore',
+                    data : [
+                        ['100%'],
+                        ['80%'],
+                        ['50%'],
+                        ['20%'],
+                        ['10%']
+                    ],
+                    fields : [ 'val'],
+                    xns : Roo.data
                 }
-                
-                if(!e.shiftKey){
-                    this.el.dom.setSelectionRange(pos, pos);
-                    return;
+            },
+            {
+                xtype : 'TextItem',
+                text : "Align: ",
+                xns : rooui.Toolbar  //Boostrap?
+            },
+            {
+                xtype : 'ComboBox',
+                allowBlank : false,
+                displayField : 'val',
+                editable : true,
+                listWidth : 100,
+                triggerAction : 'all',
+                typeAhead : true,
+                valueField : 'val',
+                width : 70,
+                name : 'align',
+                listeners : {
+                    select : function (combo, r, index)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        var b = block();
+                        b.align = r.get('val');
+                        b.updateElement();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.form,
+                store : {
+                    xtype : 'SimpleStore',
+                    data : [
+                        ['left'],
+                        ['right'],
+                        ['center']
+                    ],
+                    fields : [ 'val'],
+                    xns : Roo.data
                 }
-                
-                this.el.dom.selectionStart = pos;
-                this.el.dom.selectionEnd = curr;
             },
             
-            "end" : function(e){
-                e.preventDefault();
-                
-                var curr = this.el.dom.selectionStart;
-                var lines = this.getValue().split("\n");
-                
-                if(!lines.length){
-                    return;
-                }
+             
+            {
+                xtype : 'Button',
+                text: 'Hide Caption',
+                name : 'caption_display',
+                pressed : false,
+                enableToggle : true,
+                setValue : function(v) {
+                    // this trigger toggle.
+                     
+                    this.setText(v ? "Hide Caption" : "Show Caption");
+                    this.setPressed(v != 'block');
+                },
+                listeners : {
+                    toggle: function (btn, state)
+                    {
+                        var b  = block();
+                        b.caption_display = b.caption_display == 'block' ? 'none' : 'block';
+                        this.setText(b.caption_display == 'block' ? "Hide Caption" : "Show Caption");
+                        b.updateElement();
+                        syncValue();
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.Toolbar
+            }
+        ];
+        
+    },
+    /**
+     * create a DomHelper friendly object - for use with
+     * Roo.DomHelper.markup / overwrite / etc..
+     */
+    toObject : function()
+    {
+        var d = document.createElement('div');
+        d.innerHTML = this.caption;
+        
+        var m = this.width != '100%' && this.align == 'center' ? '0 auto' : 0; 
+        
+        var iw = this.align == 'center' ? this.width : '100%';
+        var img =   {
+            tag : 'img',
+            contenteditable : 'false',
+            src : this.image_src,
+            alt : d.innerText.replace(/\n/g, " ").replace(/\s+/g, ' ').trim(), // removeHTML and reduce spaces..
+            style: {
+                width : iw,
+                maxWidth : iw + ' !important', // this is not getting rendered?
+                margin : m  
                 
-                if(e.ctrlKey){
-                    this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
-                    return;
-                }
+            }
+        };
+        /*
+        '<div class="{0}" width="420" height="315" src="{1}" frameborder="0" allowfullscreen>' +
+                    '<a href="{2}">' + 
+                        '<img class="{0}-thumbnail" src="{3}/Images/{4}/{5}#image-{4}" />' + 
+                    '</a>' + 
+                '</div>',
+        */
                 
-                var pos = 0;
+        if (this.href.length > 0) {
+            img = {
+                tag : 'a',
+                href: this.href,
+                contenteditable : 'true',
+                cn : [
+                    img
+                ]
+            };
+        }
+        
+        
+        if (this.video_url.length > 0) {
+            img = {
+                tag : 'div',
+                cls : this.cls,
+                frameborder : 0,
+                allowfullscreen : true,
+                width : 420,  // these are for video tricks - that we replace the outer
+                height : 315,
+                src : this.video_url,
+                cn : [
+                    img
+                ]
+            };
+        }
+        // we remove caption totally if its hidden... - will delete data.. but otherwise we end up with fake caption
+        var captionhtml = this.caption_display == 'none' ? '' : (this.caption.length ? this.caption : "Caption");
+        
+  
+        var ret =   {
+            tag: 'figure',
+            'data-block' : 'Figure',
+            'data-width' : this.width, 
+            contenteditable : 'false',
+            
+            style : {
+                display: 'block',
+                float :  this.align ,
+                maxWidth :  this.align == 'center' ? '100% !important' : (this.width + ' !important'),
+                width : this.align == 'center' ? '100%' : this.width,
+                margin:  '0px',
+                padding: this.align == 'center' ? '0' : '0 10px' ,
+                textAlign : this.align   // seems to work for email..
                 
-                for (var i = 0; i < lines.length;i++) {
-                    
-                    pos += lines[i].length;
-                    
-                    if(i != 0){
-                        pos += 1;
-                    }
+            },
+           
+            
+            align : this.align,
+            cn : [
+                img,
+              
+                {
+                    tag: 'figcaption',
+                    'data-display' : this.caption_display,
+                    style : {
+                        textAlign : 'left',
+                        fontSize : '16px',
+                        lineHeight : '24px',
+                        display : this.caption_display,
+                        maxWidth : (this.align == 'center' ?  this.width : '100%' ) + ' !important',
+                        margin: m,
+                        width: this.align == 'center' ?  this.width : '100%' 
                     
-                    if(pos < curr){
-                        continue;
-                    }
+                         
+                    },
+                    cls : this.cls.length > 0 ? (this.cls  + '-thumbnail' ) : '',
+                    cn : [
+                        {
+                            tag: 'div',
+                            style  : {
+                                marginTop : '16px',
+                                textAlign : 'left'
+                            },
+                            align: 'left',
+                            cn : [
+                                {
+                                    // we can not rely on yahoo syndication to use CSS elements - so have to use  '<i>' to encase stuff.
+                                    tag : 'i',
+                                    contenteditable : true,
+                                    html : captionhtml
+                                }
+                                
+                            ]
+                        }
+                        
+                    ]
                     
-                    break;
                 }
-                
-                if(!e.shiftKey){
-                    this.el.dom.setSelectionRange(pos, pos);
-                    return;
-                }
-                
-                this.el.dom.selectionStart = curr;
-                this.el.dom.selectionEnd = pos;
-            },
-
-            scope : this,
-
-            doRelay : function(foo, bar, hname){
-                return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
-            },
+            ]
+        };
+        return ret;
+         
+    },
+    
+    readElement : function(node)
+    {
+        // this should not really come from the link...
+        this.video_url = this.getVal(node, 'div', 'src');
+        this.cls = this.getVal(node, 'div', 'class');
+        this.href = this.getVal(node, 'a', 'href');
+        
+        
+        this.image_src = this.getVal(node, 'img', 'src');
+         
+        this.align = this.getVal(node, 'figure', 'align');
+        var figcaption = this.getVal(node, 'figcaption', false);
+        if (figcaption !== '') {
+            this.caption = this.getVal(figcaption, 'i', 'html');
+        }
+        
 
-            forceKeyDown: true
-        });
+        this.caption_display = this.getVal(node, 'figcaption', 'data-display');
+        //this.text_align = this.getVal(node, 'figcaption', 'style','text-align');
+        this.width = this.getVal(node, true, 'data-width');
+        //this.margin = this.getVal(node, 'figure', 'style', 'margin');
         
-//        if(this.autosave && this.w){
-//            this.autoSaveFn = setInterval(this.autosave, 1000);
-//        }
     },
+    removeNode : function()
+    {
+        return this.node;
+    }
+    
+  
+   
+     
+    
+    
+    
+    
+})
 
-    // private
-    onResize : function(w, h)
+
+/**
+ * @class Roo.htmleditor.BlockTable
+ * Block that manages a table
+ * 
+ * @constructor
+ * Create a new Filter.
+ * @param {Object} config Configuration options
+ */
+
+Roo.htmleditor.BlockTable = function(cfg)
+{
+    if (cfg.node) {
+        this.readElement(cfg.node);
+        this.updateElement(cfg.node);
+    }
+    Roo.apply(this, cfg);
+    if (!cfg.node) {
+        this.rows = [];
+        for(var r = 0; r < this.no_row; r++) {
+            this.rows[r] = [];
+            for(var c = 0; c < this.no_col; c++) {
+                this.rows[r][c] = this.emptyCell();
+            }
+        }
+    }
+    
+    
+}
+Roo.extend(Roo.htmleditor.BlockTable, Roo.htmleditor.Block, {
+    rows : false,
+    no_col : 1,
+    no_row : 1,
+    
+    
+    width: '100%',
+    
+    // used by context menu
+    friendly_name : 'Table',
+    deleteTitle : 'Delete Table',
+    // context menu is drawn once..
+    
+    contextMenu : function(toolbar)
     {
-        Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
-        var ew = false;
-        var eh = false;
         
-        if(this.el ){
-            if(typeof w == 'number'){
-                var aw = w - this.wrap.getFrameWidth('lr');
-                this.el.setWidth(this.adjustWidth('textarea', aw));
-                ew = aw;
-            }
-            if(typeof h == 'number'){
-                var tbh = 0;
-                for (var i =0; i < this.toolbars.length;i++) {
-                    // fixme - ask toolbars for heights?
-                    tbh += this.toolbars[i].tb.el.getHeight();
-                    if (this.toolbars[i].footer) {
-                        tbh += this.toolbars[i].footer.el.getHeight();
+        var block = function() {
+            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode);
+        };
+        
+        
+        var rooui =  typeof(Roo.bootstrap) == 'undefined' ? Roo : Roo.bootstrap;
+        
+        var syncValue = toolbar.editorcore.syncValue;
+        
+        var fields = {};
+        
+        return [
+            {
+                xtype : 'TextItem',
+                text : "Width: ",
+                xns : rooui.Toolbar  //Boostrap?
+            },
+            {
+                xtype : 'ComboBox',
+                allowBlank : false,
+                displayField : 'val',
+                editable : true,
+                listWidth : 100,
+                triggerAction : 'all',
+                typeAhead : true,
+                valueField : 'val',
+                width : 100,
+                name : 'width',
+                listeners : {
+                    select : function (combo, r, index)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        var b = block();
+                        b.width = r.get('val');
+                        b.updateElement();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
                     }
+                },
+                xns : rooui.form,
+                store : {
+                    xtype : 'SimpleStore',
+                    data : [
+                        ['100%'],
+                        ['auto']
+                    ],
+                    fields : [ 'val'],
+                    xns : Roo.data
                 }
-                
-                
-                
-                
-                var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
-                ah -= 5; // knock a few pixes off for look..
-//                Roo.log(ah);
-                this.el.setHeight(this.adjustWidth('textarea', ah));
-                var eh = ah;
-            }
-        }
-        Roo.log('onResize:' + [w,h,ew,eh].join(',') );
-        this.editorcore.onResize(ew,eh);
+            },
+            // -------- Cols
+            
+            {
+                xtype : 'TextItem',
+                text : "Columns: ",
+                xns : rooui.Toolbar  //Boostrap?
+            },
+         
+            {
+                xtype : 'Button',
+                text: '-',
+                listeners : {
+                    click : function (_self, e)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        block().removeColumn();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.Toolbar
+            },
+            {
+                xtype : 'Button',
+                text: '+',
+                listeners : {
+                    click : function (_self, e)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        block().addColumn();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.Toolbar
+            },
+            // -------- ROWS
+            {
+                xtype : 'TextItem',
+                text : "Rows: ",
+                xns : rooui.Toolbar  //Boostrap?
+            },
+         
+            {
+                xtype : 'Button',
+                text: '-',
+                listeners : {
+                    click : function (_self, e)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        block().removeRow();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.Toolbar
+            },
+            {
+                xtype : 'Button',
+                text: '+',
+                listeners : {
+                    click : function (_self, e)
+                    {
+                        block().addRow();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.Toolbar
+            },
+            // -------- ROWS
+            {
+                xtype : 'Button',
+                text: 'Reset Column Widths',
+                listeners : {
+                    
+                    click : function (_self, e)
+                    {
+                        block().resetWidths();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.Toolbar
+            } 
+            
+            
+            
+        ];
         
     },
-
-    /**
-     * Toggles the editor between standard and source edit mode.
-     * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
+    
+    
+  /**
+     * create a DomHelper friendly object - for use with
+     * Roo.DomHelper.markup / overwrite / etc..
+     * ?? should it be called with option to hide all editing features?
      */
-    toggleSourceEdit : function(sourceEditMode)
+    toObject : function()
     {
-        this.editorcore.toggleSourceEdit(sourceEditMode);
         
-        if(this.editorcore.sourceEditMode){
-            Roo.log('editor - showing textarea');
-            
-//            Roo.log('in');
-//            Roo.log(this.syncValue());
-            this.editorcore.syncValue();
-            this.el.removeClass('x-hidden');
-            this.el.dom.removeAttribute('tabIndex');
-            this.el.focus();
+        var ret = {
+            tag : 'table',
+            contenteditable : 'false', // this stops cell selection from picking the table.
+            'data-block' : 'Table',
+            style : {
+                width:  this.width,
+                border : 'solid 1px #000', // ??? hard coded?
+                'border-collapse' : 'collapse' 
+            },
+            cn : [
+                { tag : 'tbody' , cn : [] }
+            ]
+        };
+        
+        // do we have a head = not really 
+        var ncols = 0;
+        Roo.each(this.rows, function( row ) {
+            var tr = {
+                tag: 'tr',
+                style : {
+                    margin: '6px',
+                    border : 'solid 1px #000',
+                    textAlign : 'left' 
+                },
+                cn : [ ]
+            };
             
-            for (var i = 0; i < this.toolbars.length; i++) {
-                if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
-                    this.toolbars[i].tb.hide();
-                    this.toolbars[i].footer.hide();
+            ret.cn[0].cn.push(tr);
+            // does the row have any properties? ?? height?
+            var nc = 0;
+            Roo.each(row, function( cell ) {
+                
+                var td = {
+                    tag : 'td',
+                    contenteditable :  'true',
+                    'data-block' : 'Td',
+                    html : cell.html,
+                    style : cell.style
+                };
+                if (cell.colspan > 1) {
+                    td.colspan = cell.colspan ;
+                    nc += cell.colspan;
+                } else {
+                    nc++;
                 }
-            }
+                if (cell.rowspan > 1) {
+                    td.rowspan = cell.rowspan ;
+                }
+                
+                
+                // widths ?
+                tr.cn.push(td);
+                    
+                
+            }, this);
+            ncols = Math.max(nc, ncols);
             
-        }else{
-            Roo.log('editor - hiding textarea');
-//            Roo.log('out')
-//            Roo.log(this.pushValue()); 
-            this.editorcore.pushValue();
             
-            this.el.addClass('x-hidden');
-            this.el.dom.setAttribute('tabIndex', -1);
+        }, this);
+        // add the header row..
+        
+        ncols++;
+         
+        
+        return ret;
+         
+    },
+    
+    readElement : function(node)
+    {
+        node  = node ? node : this.node ;
+        this.width = this.getVal(node, true, 'style', 'width') || '100%';
+        
+        this.rows = [];
+        this.no_row = 0;
+        var trs = Array.from(node.rows);
+        trs.forEach(function(tr) {
+            var row =  [];
+            this.rows.push(row);
             
-            for (var i = 0; i < this.toolbars.length; i++) {
-                if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
-                    this.toolbars[i].tb.show();
-                    this.toolbars[i].footer.show();
-                }
-            }
+            this.no_row++;
+            var no_column = 0;
+            Array.from(tr.cells).forEach(function(td) {
+                
+                var add = {
+                    colspan : td.hasAttribute('colspan') ? td.getAttribute('colspan')*1 : 1,
+                    rowspan : td.hasAttribute('rowspan') ? td.getAttribute('rowspan')*1 : 1,
+                    style : td.hasAttribute('style') ? td.getAttribute('style') : '',
+                    html : td.innerHTML
+                };
+                no_column += add.colspan;
+                     
+                
+                row.push(add);
+                
+                
+            },this);
+            this.no_col = Math.max(this.no_col, no_column);
             
-            //this.deferFocus();
-        }
+            
+        },this);
         
-        this.setSize(this.wrap.getSize());
-        this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
         
-        this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
     },
-    // private (for BoxComponent)
-    adjustSize : Roo.BoxComponent.prototype.adjustSize,
-
-    // private (for BoxComponent)
-    getResizeEl : function(){
-        return this.wrap;
+    normalizeRows: function()
+    {
+        var ret= [];
+        var rid = -1;
+        this.rows.forEach(function(row) {
+            rid++;
+            ret[rid] = [];
+            row = this.normalizeRow(row);
+            var cid = 0;
+            row.forEach(function(c) {
+                while (typeof(ret[rid][cid]) != 'undefined') {
+                    cid++;
+                }
+                if (typeof(ret[rid]) == 'undefined') {
+                    ret[rid] = [];
+                }
+                ret[rid][cid] = c;
+                c.row = rid;
+                c.col = cid;
+                if (c.rowspan < 2) {
+                    return;
+                }
+                
+                for(var i = 1 ;i < c.rowspan; i++) {
+                    if (typeof(ret[rid+i]) == 'undefined') {
+                        ret[rid+i] = [];
+                    }
+                    ret[rid+i][cid] = c;
+                }
+            });
+        }, this);
+        return ret;
+    
     },
-
-    // private (for BoxComponent)
-    getPositionEl : function(){
-        return this.wrap;
+    
+    normalizeRow: function(row)
+    {
+        var ret= [];
+        row.forEach(function(c) {
+            if (c.colspan < 2) {
+                ret.push(c);
+                return;
+            }
+            for(var i =0 ;i < c.colspan; i++) {
+                ret.push(c);
+            }
+        });
+        return ret;
+    
     },
-
-    // private
-    initEvents : function(){
-        this.originalValue = this.getValue();
+    
+    deleteColumn : function(sel)
+    {
+        if (!sel || sel.type != 'col') {
+            return;
+        }
+        if (this.no_col < 2) {
+            return;
+        }
+        
+        this.rows.forEach(function(row) {
+            var cols = this.normalizeRow(row);
+            var col = cols[sel.col];
+            if (col.colspan > 1) {
+                col.colspan --;
+            } else {
+                row.remove(col);
+            }
+            
+        }, this);
+        this.no_col--;
+        
     },
-
-    /**
-     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
-     * @method
-     */
-    markInvalid : Roo.emptyFn,
-    /**
-     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
-     * @method
-     */
-    clearInvalid : Roo.emptyFn,
-
-    setValue : function(v){
-        Roo.form.HtmlEditor.superclass.setValue.call(this, v);
-        this.editorcore.pushValue();
+    removeColumn : function()
+    {
+        this.deleteColumn({
+            type: 'col',
+            col : this.no_col-1
+        });
+        this.updateElement();
     },
-
+    
      
-    // private
-    deferFocus : function(){
-        this.focus.defer(10, this);
-    },
-
-    // doc'ed in Field
-    focus : function(){
-        this.editorcore.focus();
+    addColumn : function()
+    {
         
+        this.rows.forEach(function(row) {
+            row.push(this.emptyCell());
+           
+        }, this);
+        this.updateElement();
     },
-      
-
-    // private
-    onDestroy : function(){
+    
+    deleteRow : function(sel)
+    {
+        if (!sel || sel.type != 'row') {
+            return;
+        }
         
+        if (this.no_row < 2) {
+            return;
+        }
         
+        var rows = this.normalizeRows();
         
-        if(this.rendered){
-            
-            for (var i =0; i < this.toolbars.length;i++) {
-                // fixme - ask toolbars for heights?
-                this.toolbars[i].onDestroy();
+        
+        rows[sel.row].forEach(function(col) {
+            if (col.rowspan > 1) {
+                col.rowspan--;
+            } else {
+                col.remove = 1; // flage it as removed.
             }
             
-            this.wrap.dom.innerHTML = '';
-            this.wrap.remove();
-        }
-    },
-
-    // private
-    onFirstFocus : function(){
-        //Roo.log("onFirstFocus");
-        this.editorcore.onFirstFocus();
-         for (var i =0; i < this.toolbars.length;i++) {
-            this.toolbars[i].onFirstFocus();
-        }
+        }, this);
+        var newrows = [];
+        this.rows.forEach(function(row) {
+            newrow = [];
+            row.forEach(function(c) {
+                if (typeof(c.remove) == 'undefined') {
+                    newrow.push(c);
+                }
+                
+            });
+            if (newrow.length > 0) {
+                newrows.push(row);
+            }
+        });
+        this.rows =  newrows;
+        
+        
+        
+        this.no_row--;
+        this.updateElement();
         
     },
-    
-    // private
-    syncValue : function()
+    removeRow : function()
     {
-        this.editorcore.syncValue();
+        this.deleteRow({
+            type: 'row',
+            row : this.no_row-1
+        });
+        
     },
     
-    pushValue : function()
+     
+    addRow : function()
     {
-        this.editorcore.pushValue();
+        
+        var row = [];
+        for (var i = 0; i < this.no_col; i++ ) {
+            
+            row.push(this.emptyCell());
+           
+        }
+        this.rows.push(row);
+        this.updateElement();
+        
+    },
+     
+    // the default cell object... at present...
+    emptyCell : function() {
+        return (new Roo.htmleditor.BlockTd({})).toObject();
+        
+     
     },
     
-    setStylesheets : function(stylesheets)
+    removeNode : function()
     {
-        this.editorcore.setStylesheets(stylesheets);
+        return this.node;
     },
     
-    removeStylesheets : function()
+    
+    
+    resetWidths : function()
     {
-        this.editorcore.removeStylesheets();
+        Array.from(this.node.getElementsByTagName('td')).forEach(function(n) {
+            var nn = Roo.htmleditor.Block.factory(n);
+            nn.width = '';
+            nn.updateElement(n);
+        });
     }
-     
     
-    // hide stuff that is not compatible
-    /**
-     * @event blur
-     * @hide
-     */
-    /**
-     * @event change
-     * @hide
-     */
-    /**
-     * @event focus
-     * @hide
-     */
-    /**
-     * @event specialkey
-     * @hide
-     */
-    /**
-     * @cfg {String} fieldClass @hide
-     */
-    /**
-     * @cfg {String} focusClass @hide
-     */
-    /**
-     * @cfg {String} autoCreate @hide
-     */
-    /**
-     * @cfg {String} inputType @hide
-     */
-    /**
-     * @cfg {String} invalidClass @hide
-     */
-    /**
-     * @cfg {String} invalidText @hide
-     */
-    /**
-     * @cfg {String} msgFx @hide
-     */
-    /**
-     * @cfg {String} validateOnBlur @hide
-     */
-});
-    // <script type="text/javascript">
-/*
- * Based on
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *  
- */
+    
+    
+    
+})
 
 /**
- * @class Roo.form.HtmlEditorToolbar1
- * Basic Toolbar
- * 
- * Usage:
  *
- new Roo.form.HtmlEditor({
-    ....
-    toolbars : [
-        new Roo.form.HtmlEditorToolbar1({
-            disable : { fonts: 1 , format: 1, ..., ... , ...],
-            btns : [ .... ]
-        })
-    }
-     
- * 
- * @cfg {Object} disable List of elements to disable..
- * @cfg {Array} btns List of additional buttons.
- * 
- * 
- * NEEDS Extra CSS? 
- * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
+ * editing a TD?
+ *
+ * since selections really work on the table cell, then editing really should work from there
+ *
+ * The original plan was to support merging etc... - but that may not be needed yet..
+ *
+ * So this simple version will support:
+ *   add/remove cols
+ *   adjust the width +/-
+ *   reset the width...
+ *   
+ *
  */
+
+
  
-Roo.form.HtmlEditor.ToolbarStandard = function(config)
+
+/**
+ * @class Roo.htmleditor.BlockTable
+ * Block that manages a table
+ * 
+ * @constructor
+ * Create a new Filter.
+ * @param {Object} config Configuration options
+ */
+
+Roo.htmleditor.BlockTd = function(cfg)
 {
-    
-    Roo.apply(this, config);
-    
-    // default disabled, based on 'good practice'..
-    this.disable = this.disable || {};
-    Roo.applyIf(this.disable, {
-        fontSize : true,
-        colors : true,
-        specialElements : true
-    });
+    if (cfg.node) {
+        this.readElement(cfg.node);
+        this.updateElement(cfg.node);
+    }
+    Roo.apply(this, cfg);
+     
     
     
-    //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
-    // dont call parent... till later.
 }
-
-Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
-    
-    tb: false,
-    
-    rendered: false,
+Roo.extend(Roo.htmleditor.BlockTd, Roo.htmleditor.Block, {
+    node : false,
     
-    editor : false,
-    editorcore : false,
-    /**
-     * @cfg {Object} disable  List of toolbar elements to disable
-         
-     */
-    disable : false,
+    width: '',
+    textAlign : 'left',
+    valign : 'top',
     
+    colspan : 1,
+    rowspan : 1,
     
-     /**
-     * @cfg {String} createLinkText The default text for the create link prompt
-     */
-    createLinkText : 'Please enter the URL for the link:',
-    /**
-     * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
-     */
-    defaultLinkValue : 'http:/'+'/',
-   
     
-      /**
-     * @cfg {Array} fontFamilies An array of available font families
-     */
-    fontFamilies : [
-        'Arial',
-        'Courier New',
-        'Tahoma',
-        'Times New Roman',
-        'Verdana'
-    ],
+    // used by context menu
+    friendly_name : 'Table Cell',
+    deleteTitle : false, // use our customer delete
     
-    specialChars : [
-           "&#169;",
-          "&#174;",     
-          "&#8482;",    
-          "&#163;" ,    
-         // "&#8212;",    
-          "&#8230;",    
-          "&#247;" ,    
-        //  "&#225;" ,     ?? a acute?
-           "&#8364;"    , //Euro
-       //   "&#8220;"    ,
-        //  "&#8221;"    ,
-        //  "&#8226;"    ,
-          "&#176;"  //   , // degrees
-
-         // "&#233;"     , // e ecute
-         // "&#250;"     , // u ecute?
-    ],
+    // context menu is drawn once..
     
-    specialElements : [
+    contextMenu : function(toolbar)
+    {
+        
+        var cell = function() {
+            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode);
+        };
+        
+        var table = function() {
+            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode.closest('table'));
+        };
+        
+        var lr = false;
+        var saveSel = function()
         {
-            text: "Insert Table",
-            xtype: 'MenuItem',
-            xns : Roo.Menu,
-            ihtml :  '<table><tr><td>Cell</td></tr></table>' 
+            lr = toolbar.editorcore.getSelection().getRangeAt(0);
+        }
+        var restoreSel = function()
+        {
+            if (lr) {
+                (function() {
+                    toolbar.editorcore.focus();
+                    var cr = toolbar.editorcore.getSelection();
+                    cr.removeAllRanges();
+                    cr.addRange(lr);
+                    toolbar.editorcore.onEditorEvent();
+                }).defer(10, this);
                 
-        },
-        {    
-            text: "Insert Image",
-            xtype: 'MenuItem',
-            xns : Roo.Menu,
-            ihtml : '<img src="about:blank"/>'
-            
+                
+            }
         }
         
-         
-    ],
-    
-    
-    inputElements : [ 
-            "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password", 
-            "input:submit", "input:button", "select", "textarea", "label" ],
-    formats : [
-        ["p"] ,  
-        ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"], 
-        ["pre"],[ "code"], 
-        ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
-        ['div'],['span']
-    ],
-    
-    cleanStyles : [
-        "font-size"
-    ],
-     /**
-     * @cfg {String} defaultFont default font to use.
-     */
-    defaultFont: 'tahoma',
-   
-    fontSelect : false,
-    
-    
-    formatCombo : false,
-    
-    init : function(editor)
-    {
-        this.editor = editor;
-        this.editorcore = editor.editorcore ? editor.editorcore : editor;
-        var editorcore = this.editorcore;
-        
-        var _t = this;
-        
-        var fid = editorcore.frameId;
-        var etb = this;
-        function btn(id, toggle, handler){
-            var xid = fid + '-'+ id ;
-            return {
-                id : xid,
-                cmd : id,
-                cls : 'x-btn-icon x-edit-'+id,
-                enableToggle:toggle !== false,
-                scope: _t, // was editor...
-                handler:handler||_t.relayBtnCmd,
-                clickEvent:'mousedown',
-                tooltip: etb.buttonTips[id] || undefined, ///tips ???
-                tabIndex:-1
-            };
-        }
+        var rooui =  typeof(Roo.bootstrap) == 'undefined' ? Roo : Roo.bootstrap;
         
+        var syncValue = toolbar.editorcore.syncValue;
         
+        var fields = {};
         
-        var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
-        this.tb = tb;
-         // stop form submits
-        tb.el.on('click', function(e){
-            e.preventDefault(); // what does this do?
-        });
-
-        if(!this.disable.font) { // && !Roo.isSafari){
-            /* why no safari for fonts 
-            editor.fontSelect = tb.el.createChild({
-                tag:'select',
-                tabIndex: -1,
-                cls:'x-font-select',
-                html: this.createFontOptions()
-            });
-            
-            editor.fontSelect.on('change', function(){
-                var font = editor.fontSelect.dom.value;
-                editor.relayCmd('fontname', font);
-                editor.deferFocus();
-            }, editor);
-            
-            tb.add(
-                editor.fontSelect.dom,
-                '-'
-            );
-            */
-            
-        };
-        if(!this.disable.formats){
-            this.formatCombo = new Roo.form.ComboBox({
-                store: new Roo.data.SimpleStore({
-                    id : 'tag',
-                    fields: ['tag'],
-                    data : this.formats // from states.js
-                }),
-                blockFocus : true,
-                name : '',
-                //autoCreate : {tag: "div",  size: "20"},
-                displayField:'tag',
-                typeAhead: false,
-                mode: 'local',
-                editable : false,
-                triggerAction: 'all',
-                emptyText:'Add tag',
-                selectOnFocus:true,
-                width:135,
+        return [
+            {
+                xtype : 'Button',
+                text : 'Edit Table',
                 listeners : {
-                    'select': function(c, r, i) {
-                        editorcore.insertTag(r.get('tag'));
-                        editor.focus();
+                    click : function() {
+                        var t = toolbar.tb.selectedNode.closest('table');
+                        toolbar.editorcore.selectNode(t);
+                        toolbar.editorcore.onEditorEvent();                        
                     }
                 }
-
-            });
-            tb.addField(this.formatCombo);
-            
-        }
-        
-        if(!this.disable.format){
-            tb.add(
-                btn('bold'),
-                btn('italic'),
-                btn('underline'),
-                btn('strikethrough')
-            );
-        };
-        if(!this.disable.fontSize){
-            tb.add(
-                '-',
-                
-                
-                btn('increasefontsize', false, editorcore.adjustFont),
-                btn('decreasefontsize', false, editorcore.adjustFont)
-            );
-        };
-        
-        
-        if(!this.disable.colors){
-            tb.add(
-                '-', {
-                    id:editorcore.frameId +'-forecolor',
-                    cls:'x-btn-icon x-edit-forecolor',
-                    clickEvent:'mousedown',
-                    tooltip: this.buttonTips['forecolor'] || undefined,
-                    tabIndex:-1,
-                    menu : new Roo.menu.ColorMenu({
-                        allowReselect: true,
-                        focus: Roo.emptyFn,
-                        value:'000000',
-                        plain:true,
-                        selectHandler: function(cp, color){
-                            editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
-                            editor.deferFocus();
-                        },
-                        scope: editorcore,
-                        clickEvent:'mousedown'
-                    })
-                }, {
-                    id:editorcore.frameId +'backcolor',
-                    cls:'x-btn-icon x-edit-backcolor',
-                    clickEvent:'mousedown',
-                    tooltip: this.buttonTips['backcolor'] || undefined,
-                    tabIndex:-1,
-                    menu : new Roo.menu.ColorMenu({
-                        focus: Roo.emptyFn,
-                        value:'FFFFFF',
-                        plain:true,
-                        allowReselect: true,
-                        selectHandler: function(cp, color){
-                            if(Roo.isGecko){
-                                editorcore.execCmd('useCSS', false);
-                                editorcore.execCmd('hilitecolor', color);
-                                editorcore.execCmd('useCSS', true);
-                                editor.deferFocus();
-                            }else{
-                                editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor', 
-                                    Roo.isSafari || Roo.isIE ? '#'+color : color);
-                                editor.deferFocus();
-                            }
-                        },
-                        scope:editorcore,
-                        clickEvent:'mousedown'
-                    })
-                }
-            );
-        };
-        // now add all the items...
-        
-
-        if(!this.disable.alignments){
-            tb.add(
-                '-',
-                btn('justifyleft'),
-                btn('justifycenter'),
-                btn('justifyright')
-            );
-        };
-
-        //if(!Roo.isSafari){
-            if(!this.disable.links){
-                tb.add(
-                    '-',
-                    btn('createlink', false, this.createLink)    /// MOVE TO HERE?!!?!?!?!
-                );
-            };
-
-            if(!this.disable.lists){
-                tb.add(
-                    '-',
-                    btn('insertorderedlist'),
-                    btn('insertunorderedlist')
-                );
-            }
-            if(!this.disable.sourceEdit){
-                tb.add(
-                    '-',
-                    btn('sourceedit', true, function(btn){
-                        this.toggleSourceEdit(btn.pressed);
-                    })
-                );
-            }
-        //}
-        
-        var smenu = { };
-        // special menu.. - needs to be tidied up..
-        if (!this.disable.special) {
-            smenu = {
-                text: "&#169;",
-                cls: 'x-edit-none',
-                
-                menu : {
-                    items : []
-                }
-            };
-            for (var i =0; i < this.specialChars.length; i++) {
-                smenu.menu.items.push({
-                    
-                    html: this.specialChars[i],
-                    handler: function(a,b) {
-                        editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
-                        //editor.insertAtCursor(a.html);
-                        
-                    },
-                    tabIndex:-1
-                });
-            }
-            
-            
-            tb.add(smenu);
-            
-            
-        }
-        
-        var cmenu = { };
-        if (!this.disable.cleanStyles) {
-            cmenu = {
-                cls: 'x-btn-icon x-btn-clear',
                 
-                menu : {
-                    items : []
-                }
-            };
-            for (var i =0; i < this.cleanStyles.length; i++) {
-                cmenu.menu.items.push({
-                    actiontype : this.cleanStyles[i],
-                    html: 'Remove ' + this.cleanStyles[i],
-                    handler: function(a,b) {
-//                        Roo.log(a);
-//                        Roo.log(b);
-                        var c = Roo.get(editorcore.doc.body);
-                        c.select('[style]').each(function(s) {
-                            s.dom.style.removeProperty(a.actiontype);
-                        });
-                        editorcore.syncValue();
-                    },
-                    tabIndex:-1
-                });
-            }
-             cmenu.menu.items.push({
-                actiontype : 'tablewidths',
-                html: 'Remove Table Widths',
-                handler: function(a,b) {
-                    editorcore.cleanTableWidths();
-                    editorcore.syncValue();
+            },
+              
+           
+             
+            {
+                xtype : 'TextItem',
+                text : "Column Width: ",
+                 xns : rooui.Toolbar 
+               
+            },
+            {
+                xtype : 'Button',
+                text: '-',
+                listeners : {
+                    click : function (_self, e)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        cell().shrinkColumn();
+                        syncValue();
+                         toolbar.editorcore.onEditorEvent();
+                    }
                 },
-                tabIndex:-1
-            });
-            cmenu.menu.items.push({
-                actiontype : 'word',
-                html: 'Remove MS Word Formating',
-                handler: function(a,b) {
-                    editorcore.cleanWord();
-                    editorcore.syncValue();
+                xns : rooui.Toolbar
+            },
+            {
+                xtype : 'Button',
+                text: '+',
+                listeners : {
+                    click : function (_self, e)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        cell().growColumn();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
                 },
-                tabIndex:-1
-            });
+                xns : rooui.Toolbar
+            },
             
-            cmenu.menu.items.push({
-                actiontype : 'all',
-                html: 'Remove All Styles',
-                handler: function(a,b) {
-                    
-                    var c = Roo.get(editorcore.doc.body);
-                    c.select('[style]').each(function(s) {
-                        s.dom.removeAttribute('style');
-                    });
-                    editorcore.syncValue();
+            {
+                xtype : 'TextItem',
+                text : "Vertical Align: ",
+                xns : rooui.Toolbar  //Boostrap?
+            },
+            {
+                xtype : 'ComboBox',
+                allowBlank : false,
+                displayField : 'val',
+                editable : true,
+                listWidth : 100,
+                triggerAction : 'all',
+                typeAhead : true,
+                valueField : 'val',
+                width : 100,
+                name : 'valign',
+                listeners : {
+                    select : function (combo, r, index)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        var b = cell();
+                        b.valign = r.get('val');
+                        b.updateElement();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
                 },
-                tabIndex:-1
-            });
+                xns : rooui.form,
+                store : {
+                    xtype : 'SimpleStore',
+                    data : [
+                        ['top'],
+                        ['middle'],
+                        ['bottom'] // there are afew more... 
+                    ],
+                    fields : [ 'val'],
+                    xns : Roo.data
+                }
+            },
             
-            cmenu.menu.items.push({
-                actiontype : 'all',
-                html: 'Remove All CSS Classes',
-                handler: function(a,b) {
-                    
-                    var c = Roo.get(editorcore.doc.body);
-                    c.select('[class]').each(function(s) {
-                        s.dom.className = '';
-                    });
-                    editorcore.syncValue();
-                },
-                tabIndex:-1
-            });
+            {
+                xtype : 'TextItem',
+                text : "Merge Cells: ",
+                 xns : rooui.Toolbar 
+               
+            },
             
-             cmenu.menu.items.push({
-                actiontype : 'tidy',
-                html: 'Tidy HTML Source',
-                handler: function(a,b) {
-                    editorcore.doc.body.innerHTML = editorcore.domToHTML();
-                    editorcore.syncValue();
-                },
-                tabIndex:-1
-            });
             
+            {
+                xtype : 'Button',
+                text: 'Right',
+                listeners : {
+                    click : function (_self, e)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        cell().mergeRight();
+                        //block().growColumn();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.Toolbar
+            },
+             
+            {
+                xtype : 'Button',
+                text: 'Below',
+                listeners : {
+                    click : function (_self, e)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        cell().mergeBelow();
+                        //block().growColumn();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.Toolbar
+            },
+            {
+                xtype : 'TextItem',
+                text : "| ",
+                 xns : rooui.Toolbar 
+               
+            },
             
-            tb.add(cmenu);
-        }
-         
-        if (!this.disable.specialElements) {
-            var semenu = {
-                text: "Other;",
-                cls: 'x-edit-none',
+            {
+                xtype : 'Button',
+                text: 'Split',
+                listeners : {
+                    click : function (_self, e)
+                    {
+                        //toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        cell().split();
+                        syncValue();
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        toolbar.editorcore.onEditorEvent();
+                                             
+                    }
+                },
+                xns : rooui.Toolbar
+            },
+            {
+                xtype : 'Fill',
+                xns : rooui.Toolbar 
+               
+            },
+        
+          
+            {
+                xtype : 'Button',
+                text: 'Delete',
+                 
+                xns : rooui.Toolbar,
                 menu : {
-                    items : []
-                }
-            };
-            for (var i =0; i < this.specialElements.length; i++) {
-                semenu.menu.items.push(
-                    Roo.apply({ 
-                        handler: function(a,b) {
-                            editor.insertAtCursor(this.ihtml);
+                    xtype : 'Menu',
+                    xns : rooui.menu,
+                    items : [
+                        {
+                            xtype : 'Item',
+                            html: 'Column',
+                            listeners : {
+                                click : function (_self, e)
+                                {
+                                    var t = table();
+                                    
+                                    cell().deleteColumn();
+                                    syncValue();
+                                    toolbar.editorcore.selectNode(t.node);
+                                    toolbar.editorcore.onEditorEvent();   
+                                }
+                            },
+                            xns : rooui.menu
+                        },
+                        {
+                            xtype : 'Item',
+                            html: 'Row',
+                            listeners : {
+                                click : function (_self, e)
+                                {
+                                    var t = table();
+                                    cell().deleteRow();
+                                    syncValue();
+                                    
+                                    toolbar.editorcore.selectNode(t.node);
+                                    toolbar.editorcore.onEditorEvent();   
+                                                         
+                                }
+                            },
+                            xns : rooui.menu
+                        },
+                       {
+                            xtype : 'Separator',
+                            xns : rooui.menu
+                        },
+                        {
+                            xtype : 'Item',
+                            html: 'Table',
+                            listeners : {
+                                click : function (_self, e)
+                                {
+                                    var t = table();
+                                    var nn = t.node.nextSibling || t.node.previousSibling;
+                                    t.node.parentNode.removeChild(t.node);
+                                    if (nn) { 
+                                        toolbar.editorcore.selectNode(nn, true);
+                                    }
+                                    toolbar.editorcore.onEditorEvent();   
+                                                         
+                                }
+                            },
+                            xns : rooui.menu
                         }
-                    }, this.specialElements[i])
-                );
-                    
+                    ]
+                }
             }
             
-            tb.add(semenu);
-            
+            // align... << fixme
             
+        ];
+        
+    },
+    
+    
+  /**
+     * create a DomHelper friendly object - for use with
+     * Roo.DomHelper.markup / overwrite / etc..
+     * ?? should it be called with option to hide all editing features?
+     */
+ /**
+     * create a DomHelper friendly object - for use with
+     * Roo.DomHelper.markup / overwrite / etc..
+     * ?? should it be called with option to hide all editing features?
+     */
+    toObject : function()
+    {
+        var ret = {
+            tag : 'td',
+            contenteditable : 'true', // this stops cell selection from picking the table.
+            'data-block' : 'Td',
+            valign : this.valign,
+            style : {  
+                'text-align' :  this.textAlign,
+                border : 'solid 1px rgb(0, 0, 0)', // ??? hard coded?
+                'border-collapse' : 'collapse',
+                padding : '6px', // 8 for desktop / 4 for mobile
+                'vertical-align': this.valign
+            },
+            html : this.html
+        };
+        if (this.width != '') {
+            ret.width = this.width;
+            ret.style.width = this.width;
         }
-         
         
-        if (this.btns) {
-            for(var i =0; i< this.btns.length;i++) {
-                var b = Roo.factory(this.btns[i],Roo.form);
-                b.cls =  'x-edit-none';
-                
-                if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
-                    b.cls += ' x-init-enable';
-                }
-                
-                b.scope = editorcore;
-                tb.add(b);
-            }
         
+        if (this.colspan > 1) {
+            ret.colspan = this.colspan ;
+        } 
+        if (this.rowspan > 1) {
+            ret.rowspan = this.rowspan ;
         }
         
+           
         
+        return ret;
+         
+    },
+    
+    readElement : function(node)
+    {
+        node  = node ? node : this.node ;
+        this.width = node.style.width;
+        this.colspan = Math.max(1,1*node.getAttribute('colspan'));
+        this.rowspan = Math.max(1,1*node.getAttribute('rowspan'));
+        this.html = node.innerHTML;
+        if (node.style.textAlign != '') {
+            this.textAlign = node.style.textAlign;
+        }
         
-        // disable everything...
         
-        this.tb.items.each(function(item){
+    },
+     
+    // the default cell object... at present...
+    emptyCell : function() {
+        return {
+            colspan :  1,
+            rowspan :  1,
+            textAlign : 'left',
+            html : "&nbsp;" // is this going to be editable now?
+        };
+     
+    },
+    
+    removeNode : function()
+    {
+        return this.node.closest('table');
+         
+    },
+    
+    cellData : false,
+    
+    colWidths : false,
+    
+    toTableArray  : function()
+    {
+        var ret = [];
+        var tab = this.node.closest('tr').closest('table');
+        Array.from(tab.rows).forEach(function(r, ri){
+            ret[ri] = [];
+        });
+        var rn = 0;
+        this.colWidths = [];
+        var all_auto = true;
+        Array.from(tab.rows).forEach(function(r, ri){
             
-           if(
-                item.id != editorcore.frameId+ '-sourceedit' && 
-                (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
-            ){
+            var cn = 0;
+            Array.from(r.cells).forEach(function(ce, ci){
+                var c =  {
+                    cell : ce,
+                    row : rn,
+                    col: cn,
+                    colspan : ce.colSpan,
+                    rowspan : ce.rowSpan
+                };
+                if (ce.isEqualNode(this.node)) {
+                    this.cellData = c;
+                }
+                // if we have been filled up by a row?
+                if (typeof(ret[rn][cn]) != 'undefined') {
+                    while(typeof(ret[rn][cn]) != 'undefined') {
+                        cn++;
+                    }
+                    c.col = cn;
+                }
                 
-                item.disable();
-            }
-        });
-        this.rendered = true;
+                if (typeof(this.colWidths[cn]) == 'undefined' && c.colspan < 2) {
+                    this.colWidths[cn] =   ce.style.width;
+                    if (this.colWidths[cn] != '') {
+                        all_auto = false;
+                    }
+                }
+                
+                
+                if (c.colspan < 2 && c.rowspan < 2 ) {
+                    ret[rn][cn] = c;
+                    cn++;
+                    return;
+                }
+                for(var j = 0; j < c.rowspan; j++) {
+                    if (typeof(ret[rn+j]) == 'undefined') {
+                        continue; // we have a problem..
+                    }
+                    ret[rn+j][cn] = c;
+                    for(var i = 0; i < c.colspan; i++) {
+                        ret[rn+j][cn+i] = c;
+                    }
+                }
+                
+                cn += c.colspan;
+            }, this);
+            rn++;
+        }, this);
+        
+        // initalize widths.?
+        // either all widths or no widths..
+        if (all_auto) {
+            this.colWidths[0] = false; // no widths flag.
+        }
+        
+        
+        return ret;
         
-        // the all the btns;
-        editor.on('editorevent', this.updateToolbar, this);
-        // other toolbars need to implement this..
-        //editor.on('editmodechange', this.updateToolbar, this);
     },
     
     
-    relayBtnCmd : function(btn) {
-        this.editorcore.relayCmd(btn.cmd);
-    },
-    // 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);
+    
+    
+    mergeRight: function()
+    {
+         
+        // get the contents of the next cell along..
+        var tr = this.node.closest('tr');
+        var i = Array.prototype.indexOf.call(tr.childNodes, this.node);
+        if (i >= tr.childNodes.length - 1) {
+            return; // no cells on right to merge with.
         }
-    },
+        var table = this.toTableArray();
+        
+        if (typeof(table[this.cellData.row][this.cellData.col+this.cellData.colspan]) == 'undefined') {
+            return; // nothing right?
+        }
+        var rc = table[this.cellData.row][this.cellData.col+this.cellData.colspan];
+        // right cell - must be same rowspan and on the same row.
+        if (rc.rowspan != this.cellData.rowspan || rc.row != this.cellData.row) {
+            return; // right hand side is not same rowspan.
+        }
+        
+        
+        
+        this.node.innerHTML += ' ' + rc.cell.innerHTML;
+        tr.removeChild(rc.cell);
+        this.colspan += rc.colspan;
+        this.node.setAttribute('colspan', this.colspan);
 
+        var table = this.toTableArray();
+        this.normalizeWidths(table);
+        this.updateWidths(table);
+    },
     
-    /**
-     * Protected method that will not generally be called directly. It triggers
-     * a toolbar update by reading the markup state of the current selection in the editor.
-     */
-    updateToolbar: function(){
-
-        if(!this.editorcore.activated){
-            this.editor.onFirstFocus();
-            return;
-        }
-
-        var btns = this.tb.items.map, 
-            doc = this.editorcore.doc,
-            frameId = this.editorcore.frameId;
-
-        if(!this.disable.font && !Roo.isSafari){
-            /*
-            var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
-            if(name != this.fontSelect.dom.value){
-                this.fontSelect.dom.value = name;
-            }
-            */
+    
+    mergeBelow : function()
+    {
+        var table = this.toTableArray();
+        if (typeof(table[this.cellData.row+this.cellData.rowspan]) == 'undefined') {
+            return; // no row below
         }
-        if(!this.disable.format){
-            btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
-            btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
-            btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
-            btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
+        if (typeof(table[this.cellData.row+this.cellData.rowspan][this.cellData.col]) == 'undefined') {
+            return; // nothing right?
         }
-        if(!this.disable.alignments){
-            btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
-            btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
-            btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
+        var rc = table[this.cellData.row+this.cellData.rowspan][this.cellData.col];
+        
+        if (rc.colspan != this.cellData.colspan || rc.col != this.cellData.col) {
+            return; // right hand side is not same rowspan.
         }
-        if(!Roo.isSafari && !this.disable.lists){
-            btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
-            btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
+        this.node.innerHTML =  this.node.innerHTML + rc.cell.innerHTML ;
+        rc.cell.parentNode.removeChild(rc.cell);
+        this.rowspan += rc.rowspan;
+        this.node.setAttribute('rowspan', this.rowspan);
+    },
+    
+    split: function()
+    {
+        if (this.node.rowSpan < 2 && this.node.colSpan < 2) {
+            return;
         }
+        var table = this.toTableArray();
+        var cd = this.cellData;
+        this.rowspan = 1;
+        this.colspan = 1;
         
-        var ans = this.editorcore.getAllAncestors();
-        if (this.formatCombo) {
-            
+        for(var r = cd.row; r < cd.row + cd.rowspan; r++) {
+             
             
-            var store = this.formatCombo.store;
-            this.formatCombo.setValue("");
-            for (var i =0; i < ans.length;i++) {
-                if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
-                    // select it..
-                    this.formatCombo.setValue(ans[i].tagName.toLowerCase());
-                    break;
+            for(var c = cd.col; c < cd.col + cd.colspan; c++) {
+                if (r == cd.row && c == cd.col) {
+                    this.node.removeAttribute('rowspan');
+                    this.node.removeAttribute('colspan');
                 }
+                 
+                var ntd = this.node.cloneNode(); // which col/row should be 0..
+                ntd.removeAttribute('id'); 
+                ntd.style.width  = this.colWidths[c];
+                ntd.innerHTML = '';
+                table[r][c] = { cell : ntd, col : c, row: r , colspan : 1 , rowspan : 1   };
             }
+            
         }
+        this.redrawAllCells(table);
         
-        
-        
-        // hides menus... - so this cant be on a menu...
-        Roo.menu.MenuMgr.hideAll();
-
-        //this.editorsyncValue();
     },
-   
     
-    createFontOptions : function(){
-        var buf = [], fs = this.fontFamilies, ff, lc;
-        
-        
+    
+    
+    redrawAllCells: function(table)
+    {
         
-        for(var i = 0, len = fs.length; i< len; i++){
-            ff = fs[i];
-            lc = ff.toLowerCase();
-            buf.push(
-                '<option value="',lc,'" style="font-family:',ff,';"',
-                    (this.defaultFont == lc ? ' selected="true">' : '>'),
-                    ff,
-                '</option>'
-            );
+         
+        var tab = this.node.closest('tr').closest('table');
+        var ctr = tab.rows[0].parentNode;
+        Array.from(tab.rows).forEach(function(r, ri){
+            
+            Array.from(r.cells).forEach(function(ce, ci){
+                ce.parentNode.removeChild(ce);
+            });
+            r.parentNode.removeChild(r);
+        });
+        for(var r = 0 ; r < table.length; r++) {
+            var re = tab.rows[r];
+            
+            var re = tab.ownerDocument.createElement('tr');
+            ctr.appendChild(re);
+            for(var c = 0 ; c < table[r].length; c++) {
+                if (table[r][c].cell === false) {
+                    continue;
+                }
+                
+                re.appendChild(table[r][c].cell);
+                 
+                table[r][c].cell = false;
+            }
         }
-        return buf.join('');
-    },
-    
-    toggleSourceEdit : function(sourceEditMode){
         
-        Roo.log("toolbar toogle");
-        if(sourceEditMode === undefined){
-            sourceEditMode = !this.sourceEditMode;
+    },
+    updateWidths : function(table)
+    {
+        for(var r = 0 ; r < table.length; r++) {
+           
+            for(var c = 0 ; c < table[r].length; c++) {
+                if (table[r][c].cell === false) {
+                    continue;
+                }
+                
+                if (this.colWidths[0] != false && table[r][c].colspan < 2) {
+                    var el = Roo.htmleditor.Block.factory(table[r][c].cell);
+                    el.width = Math.floor(this.colWidths[c])  +'%';
+                    el.updateElement(el.node);
+                }
+                if (this.colWidths[0] != false && table[r][c].colspan > 1) {
+                    var el = Roo.htmleditor.Block.factory(table[r][c].cell);
+                    var width = 0;
+                    for(var i = 0; i < table[r][c].colspan; i ++) {
+                        width += Math.floor(this.colWidths[c + i]);
+                    }
+                    el.width = width  +'%';
+                    el.updateElement(el.node);
+                }
+                table[r][c].cell = false; // done
+            }
         }
-        this.sourceEditMode = sourceEditMode === true;
-        var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
-        // just toggle the button?
-        if(btn.pressed !== this.sourceEditMode){
-            btn.toggle(this.sourceEditMode);
+    },
+    normalizeWidths : function(table)
+    {
+        if (this.colWidths[0] === false) {
+            var nw = 100.0 / this.colWidths.length;
+            this.colWidths.forEach(function(w,i) {
+                this.colWidths[i] = nw;
+            },this);
             return;
         }
+    
+        var t = 0, missing = [];
         
-        if(sourceEditMode){
-            Roo.log("disabling buttons");
-            this.tb.items.each(function(item){
-                if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
-                    item.disable();
-                }
-            });
-          
-        }else{
-            Roo.log("enabling buttons");
-            if(this.editorcore.initialized){
-                this.tb.items.each(function(item){
-                    item.enable();
-                });
+        this.colWidths.forEach(function(w,i) {
+            //if you mix % and
+            this.colWidths[i] = this.colWidths[i] == '' ? 0 : (this.colWidths[i]+'').replace(/[^0-9]+/g,'')*1;
+            var add =  this.colWidths[i];
+            if (add > 0) {
+                t+=add;
+                return;
             }
+            missing.push(i);
+            
             
+        },this);
+        var nc = this.colWidths.length;
+        if (missing.length) {
+            var mult = (nc - missing.length) / (1.0 * nc);
+            var t = mult * t;
+            var ew = (100 -t) / (1.0 * missing.length);
+            this.colWidths.forEach(function(w,i) {
+                if (w > 0) {
+                    this.colWidths[i] = w * mult;
+                    return;
+                }
+                
+                this.colWidths[i] = ew;
+            }, this);
+            // have to make up numbers..
+             
         }
-        Roo.log("calling toggole on editor");
-        // tell the editor that it's been pressed..
-        this.editor.toggleSourceEdit(sourceEditMode);
-       
-    },
-     /**
-     * Object collection of toolbar tooltips for the buttons in the editor. The key
-     * is the command id associated with that button and the value is a valid QuickTips object.
-     * For example:
-<pre><code>
-{
-    bold : {
-        title: 'Bold (Ctrl+B)',
-        text: 'Make the selected text bold.',
-        cls: 'x-html-editor-tip'
+        // now we should have all the widths..
+        
+    
     },
-    italic : {
-        title: 'Italic (Ctrl+I)',
-        text: 'Make the selected text italic.',
-        cls: 'x-html-editor-tip'
+    
+    shrinkColumn : function()
+    {
+        var table = this.toTableArray();
+        this.normalizeWidths(table);
+        var col = this.cellData.col;
+        var nw = this.colWidths[col] * 0.8;
+        if (nw < 5) {
+            return;
+        }
+        var otherAdd = (this.colWidths[col]  * 0.2) / (this.colWidths.length -1);
+        this.colWidths.forEach(function(w,i) {
+            if (i == col) {
+                 this.colWidths[i] = nw;
+                return;
+            }
+            this.colWidths[i] += otherAdd
+        }, this);
+        this.updateWidths(table);
+         
     },
-    ...
-</code></pre>
-    * @type Object
-     */
-    buttonTips : {
-        bold : {
-            title: 'Bold (Ctrl+B)',
-            text: 'Make the selected text bold.',
-            cls: 'x-html-editor-tip'
-        },
-        italic : {
-            title: 'Italic (Ctrl+I)',
-            text: 'Make the selected text italic.',
-            cls: 'x-html-editor-tip'
-        },
-        underline : {
-            title: 'Underline (Ctrl+U)',
-            text: 'Underline the selected text.',
-            cls: 'x-html-editor-tip'
-        },
-        strikethrough : {
-            title: 'Strikethrough',
-            text: 'Strikethrough the selected text.',
-            cls: 'x-html-editor-tip'
-        },
-        increasefontsize : {
-            title: 'Grow Text',
-            text: 'Increase the font size.',
-            cls: 'x-html-editor-tip'
-        },
-        decreasefontsize : {
-            title: 'Shrink Text',
-            text: 'Decrease the font size.',
-            cls: 'x-html-editor-tip'
-        },
-        backcolor : {
-            title: 'Text Highlight Color',
-            text: 'Change the background color of the selected text.',
-            cls: 'x-html-editor-tip'
-        },
-        forecolor : {
-            title: 'Font Color',
-            text: 'Change the color of the selected text.',
-            cls: 'x-html-editor-tip'
-        },
-        justifyleft : {
-            title: 'Align Text Left',
-            text: 'Align text to the left.',
-            cls: 'x-html-editor-tip'
-        },
-        justifycenter : {
-            title: 'Center Text',
-            text: 'Center text in the editor.',
-            cls: 'x-html-editor-tip'
-        },
-        justifyright : {
-            title: 'Align Text Right',
-            text: 'Align text to the right.',
-            cls: 'x-html-editor-tip'
-        },
-        insertunorderedlist : {
-            title: 'Bullet List',
-            text: 'Start a bulleted list.',
-            cls: 'x-html-editor-tip'
-        },
-        insertorderedlist : {
-            title: 'Numbered List',
-            text: 'Start a numbered list.',
-            cls: 'x-html-editor-tip'
-        },
-        createlink : {
-            title: 'Hyperlink',
-            text: 'Make the selected text a hyperlink.',
-            cls: 'x-html-editor-tip'
-        },
-        sourceedit : {
-            title: 'Source Edit',
-            text: 'Switch to source editing mode.',
-            cls: 'x-html-editor-tip'
+    growColumn : function()
+    {
+        var table = this.toTableArray();
+        this.normalizeWidths(table);
+        var col = this.cellData.col;
+        var nw = this.colWidths[col] * 1.2;
+        if (nw > 90) {
+            return;
         }
+        var otherSub = (this.colWidths[col]  * 0.2) / (this.colWidths.length -1);
+        this.colWidths.forEach(function(w,i) {
+            if (i == col) {
+                this.colWidths[i] = nw;
+                return;
+            }
+            this.colWidths[i] -= otherSub
+        }, this);
+        this.updateWidths(table);
+         
     },
-    // private
-    onDestroy : function(){
-        if(this.rendered){
-            
-            this.tb.items.each(function(item){
-                if(item.menu){
-                    item.menu.removeAll();
-                    if(item.menu.el){
-                        item.menu.el.destroy();
-                    }
-                }
-                item.destroy();
-            });
-             
+    deleteRow : function()
+    {
+        // delete this rows 'tr'
+        // if any of the cells in this row have a rowspan > 1 && row!= this row..
+        // then reduce the rowspan.
+        var table = this.toTableArray();
+        // this.cellData.row;
+        for (var i =0;i< table[this.cellData.row].length ; i++) {
+            var c = table[this.cellData.row][i];
+            if (c.row != this.cellData.row) {
+                
+                c.rowspan--;
+                c.cell.setAttribute('rowspan', c.rowspan);
+                continue;
+            }
+            if (c.rowspan > 1) {
+                c.rowspan--;
+                c.cell.setAttribute('rowspan', c.rowspan);
+            }
         }
+        table.splice(this.cellData.row,1);
+        this.redrawAllCells(table);
+        
     },
-    onFirstFocus: function() {
-        this.tb.items.each(function(item){
-           item.enable();
-        });
+    deleteColumn : function()
+    {
+        var table = this.toTableArray();
+        
+        for (var i =0;i< table.length ; i++) {
+            var c = table[i][this.cellData.col];
+            if (c.col != this.cellData.col) {
+                table[i][this.cellData.col].colspan--;
+            } else if (c.colspan > 1) {
+                c.colspan--;
+                c.cell.setAttribute('colspan', c.colspan);
+            }
+            table[i].splice(this.cellData.col,1);
+        }
+        
+        this.redrawAllCells(table);
     }
-});
-
-
+    
+    
+    
+    
+})
 
+//<script type="text/javascript">
 
-// <script type="text/javascript">
 /*
- * Based on
- * Ext JS Library 1.1.1
+ * Based  Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
- *  
+ * LGPL
+ *
  */
-
  
 /**
- * @class Roo.form.HtmlEditor.ToolbarContext
- * Context Toolbar
- * 
- * Usage:
+ * @class Roo.HtmlEditorCore
+ * @extends Roo.Component
+ * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
  *
- new Roo.form.HtmlEditor({
-    ....
-    toolbars : [
-        { xtype: 'ToolbarStandard', styles : {} }
-        { xtype: 'ToolbarContext', disable : {} }
-    ]
-})
-
-     
- * 
- * @config : {Object} disable List of elements to disable.. (not done yet.)
- * @config : {Object} styles  Map of styles available.
- * 
+ * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
  */
 
-Roo.form.HtmlEditor.ToolbarContext = function(config)
-{
+Roo.HtmlEditorCore = function(config){
     
-    Roo.apply(this, config);
-    //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
-    // dont call parent... till later.
-    this.styles = this.styles || {};
-}
-
-
-Roo.form.HtmlEditor.ToolbarContext.types = {
-    'IMG' : {
-        width : {
-            title: "Width",
-            width: 40
-        },
-        height:  {
-            title: "Height",
-            width: 40
-        },
-        align: {
-            title: "Align",
-            opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
-            width : 80
-            
-        },
-        border: {
-            title: "Border",
-            width: 40
-        },
-        alt: {
-            title: "Alt",
-            width: 120
-        },
-        src : {
-            title: "Src",
-            width: 220
-        }
+    
+    Roo.HtmlEditorCore.superclass.constructor.call(this, config);
+    
+    
+    this.addEvents({
+        /**
+         * @event initialize
+         * Fires when the editor is fully initialized (including the iframe)
+         * @param {Roo.HtmlEditorCore} this
+         */
+        initialize: true,
+        /**
+         * @event activate
+         * Fires when the editor is first receives the focus. Any insertion must wait
+         * until after this event.
+         * @param {Roo.HtmlEditorCore} this
+         */
+        activate: true,
+         /**
+         * @event beforesync
+         * Fires before the textarea is updated with content from the editor iframe. Return false
+         * to cancel the sync.
+         * @param {Roo.HtmlEditorCore} this
+         * @param {String} html
+         */
+        beforesync: true,
+         /**
+         * @event beforepush
+         * Fires before the iframe editor is updated with content from the textarea. Return false
+         * to cancel the push.
+         * @param {Roo.HtmlEditorCore} this
+         * @param {String} html
+         */
+        beforepush: true,
+         /**
+         * @event sync
+         * Fires when the textarea is updated with content from the editor iframe.
+         * @param {Roo.HtmlEditorCore} this
+         * @param {String} html
+         */
+        sync: true,
+         /**
+         * @event push
+         * Fires when the iframe editor is updated with content from the textarea.
+         * @param {Roo.HtmlEditorCore} this
+         * @param {String} html
+         */
+        push: true,
         
-    },
-    'A' : {
-        name : {
-            title: "Name",
-            width: 50
-        },
-        target:  {
-            title: "Target",
-            width: 120
-        },
-        href:  {
-            title: "Href",
-            width: 220
-        } // border?
+        /**
+         * @event editorevent
+         * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
+         * @param {Roo.HtmlEditorCore} this
+         */
+        editorevent: true 
+         
         
-    },
-    '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 : {
-            title: "name",
-            width: 120
-        },
-        value : {
-            title: "Value",
-            width: 120
-        },
-        width : {
-            title: "Width",
-            width: 40
-        }
-    },
-    'LABEL' : {
-        'for' : {
-            title: "For",
-            width: 120
-        }
-    },
-    'TEXTAREA' : {
-          name : {
-            title: "name",
-            width: 120
-        },
-        rows : {
-            title: "Rows",
-            width: 20
-        },
-        cols : {
-            title: "Cols",
-            width: 20
-        }
-    },
-    'SELECT' : {
-        name : {
-            title: "name",
-            width: 120
-        },
-        selectoptions : {
-            title: "Options",
-            width: 200
-        }
-    },
+    });
+    
+    // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
+    
+    // defaults : white / black...
+    this.applyBlacklists();
+    
     
-    // should we really allow this??
-    // should this just be 
-    'BODY' : {
-        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..
-    }
-
-};
-
-// this should be configurable.. - you can either set it up using stores, or modify options somehwere..
-Roo.form.HtmlEditor.ToolbarContext.stores = false;
-
-Roo.form.HtmlEditor.ToolbarContext.options = {
-        'font-family'  : [ 
-                [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
-                [ 'Courier New', 'Courier New'],
-                [ 'Tahoma', 'Tahoma'],
-                [ 'Times New Roman,serif', 'Times'],
-                [ 'Verdana','Verdana' ]
-        ]
 };
 
-// fixme - these need to be configurable..
 
-//Roo.form.HtmlEditor.ToolbarContext.types
+Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
 
 
-Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
+     /**
+     * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
+     */
     
-    tb: false,
+    owner : false,
     
-    rendered: false,
+     /**
+     * @cfg {String} css styling for resizing. (used on bootstrap only)
+     */
+    resize : false,
+     /**
+     * @cfg {Number} height (in pixels)
+     */   
+    height: 300,
+   /**
+     * @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,
     
-    editor : false,
-    editorcore : false,
     /**
-     * @cfg {Object} disable  List of toolbar elements to disable
-         
+     * @cfg {boolean} enableBlocks - default true - if the block editor (table and figure should be enabled)
      */
-    disable : false,
+    enableBlocks : true,
     /**
-     * @cfg {Object} styles List of styles 
-     *    eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] } 
-     *
-     * These must be defined in the page, so they get rendered correctly..
-     * .headline { }
-     * TD.underline { }
+     * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
      * 
      */
-    styles : false,
+    stylesheets: false,
+     /**
+     * @cfg {String} language default en - language of text (usefull for rtl languages)
+     * 
+     */
+    language: 'en',
     
-    options: 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,
+    // id of frame..
+    frameId: false,
     
-    toolbars : false,
+    // private properties
+    validationEvent : false,
+    deferHeight: true,
+    initialized : false,
+    activated : false,
+    sourceEditMode : false,
+    onFocus : Roo.emptyFn,
+    iframePad:3,
+    hideMode:'offsets',
     
-    init : function(editor)
-    {
-        this.editor = editor;
-        this.editorcore = editor.editorcore ? editor.editorcore : editor;
-        var editorcore = this.editorcore;
+    clearUp: true,
+    
+    // blacklist + whitelisted elements..
+    black: false,
+    white: false,
+     
+    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
+     * want to change the initialization markup of the iframe (e.g. to add stylesheets).
+     */
+    getDocMarkup : function(){
+        // body styles..
+        var st = '';
         
-        var fid = editorcore.frameId;
-        var etb = this;
-        function btn(id, toggle, handler){
-            var xid = fid + '-'+ id ;
-            return {
-                id : xid,
-                cmd : id,
-                cls : 'x-btn-icon x-edit-'+id,
-                enableToggle:toggle !== false,
-                scope: editorcore, // was editor...
-                handler:handler||editorcore.relayBtnCmd,
-                clickEvent:'mousedown',
-                tooltip: etb.buttonTips[id] || undefined, ///tips ???
-                tabIndex:-1
-            };
+        // inherit styels from page...?? 
+        if (this.stylesheets === false) {
+            
+            Roo.get(document.head).select('style').each(function(node) {
+                st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
+            });
+            
+            Roo.get(document.head).select('link').each(function(node) { 
+                st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
+            });
+            
+        } else if (!this.stylesheets.length) {
+                // simple..
+                st = '<style type="text/css">' +
+                    'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
+                   '</style>';
+        } else {
+            for (var i in this.stylesheets) {
+                if (typeof(this.stylesheets[i]) != 'string') {
+                    continue;
+                }
+                st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
+            }
+            
         }
-        // create a new element.
-        var wdiv = editor.wrap.createChild({
-                tag: 'div'
-            }, editor.wrap.dom.firstChild.nextSibling, true);
         
-        // can we do this more than once??
+        st +=  '<style type="text/css">' +
+            'IMG { cursor: pointer } ' +
+        '</style>';
         
-         // stop form submits
-      
-        // disable everything...
-        var ty= Roo.form.HtmlEditor.ToolbarContext.types;
-        this.toolbars = {};
-           
-        for (var i in  ty) {
-          
-            this.toolbars[i] = this.buildToolbar(ty[i],i);
-        }
-        this.tb = this.toolbars.BODY;
-        this.tb.el.show();
-        this.buildFooter();
-        this.footer.show();
-        editor.on('hide', function( ) { this.footer.hide() }, this);
-        editor.on('show', function( ) { this.footer.show() }, this);
+        st += '<meta name="google" content="notranslate">';
         
-         
-        this.rendered = true;
+        var cls = 'notranslate roo-htmleditor-body';
         
-        // the all the btns;
-        editor.on('editorevent', this.updateToolbar, this);
-        // other toolbars need to implement this..
-        //editor.on('editmodechange', this.updateToolbar, this);
-    },
-    
-    
-    
-    /**
-     * Protected method that will not generally be called directly. It triggers
-     * a toolbar update by reading the markup state of the current selection in the editor.
-     *
-     * Note you can force an update by calling on('editorevent', scope, false)
-     */
-    updateToolbar: function(editor,ev,sel){
-
-        //Roo.log(ev);
-        // capture mouse up - this is handy for selecting images..
-        // perhaps should go somewhere else...
-        if(!this.editorcore.activated){
-             this.editor.onFirstFocus();
-            return;
+        if(this.bodyCls.length){
+            cls += ' ' + this.bodyCls;
         }
         
+        return '<html  class="notranslate" translate="no"><head>' + st  +
+            //<style type="text/css">' +
+            //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
+            //'</style>' +
+            ' </head><body contenteditable="true" data-enable-grammerly="true" class="' +  cls + '"></body></html>';
+    },
+
+    // private
+    onRender : function(ct, position)
+    {
+        var _t = this;
+        //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
+        this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
         
         
-        // http://developer.yahoo.com/yui/docs/simple-editor.js.html
-        // selectNode - might want to handle IE?
-        if (ev &&
-            (ev.type == 'mouseup' || ev.type == 'click' ) &&
-            ev.target && ev.target.tagName == 'IMG') {
-            // they have click on an image...
-            // let's see if we can change the selection...
-            sel = ev.target;
-         
-              var nodeRange = sel.ownerDocument.createRange();
-            try {
-                nodeRange.selectNode(sel);
-            } catch (e) {
-                nodeRange.selectNodeContents(sel);
-            }
-            //nodeRange.collapse(true);
-            var s = this.editorcore.win.getSelection();
-            s.removeAllRanges();
-            s.addRange(nodeRange);
-        }  
+        this.el.dom.style.border = '0 none';
+        this.el.dom.setAttribute('tabIndex', -1);
+        this.el.addClass('x-hidden hide');
         
-      
-        var updateFooter = sel ? false : true;
         
         
-        var ans = this.editorcore.getAllAncestors();
+        if(Roo.isIE){ // fix IE 1px bogus margin
+            this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
+        }
+       
         
-        // pick
-        var ty= Roo.form.HtmlEditor.ToolbarContext.types;
+        this.frameId = Roo.id();
         
-        if (!sel) { 
-            sel = ans.length ? (ans[0] ?  ans[0]  : ans[1]) : this.editorcore.doc.body;
-            sel = sel ? sel : this.editorcore.doc.body;
-            sel = sel.tagName.length ? sel : this.editorcore.doc.body;
-            
+        var ifcfg = {
+            tag: 'iframe',
+            cls: 'form-control', // bootstrap..
+            id: this.frameId,
+            name: this.frameId,
+            frameBorder : 'no',
+            'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
+        };
+        if (this.resize) {
+            ifcfg.style = { resize : this.resize };
         }
-        // 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 iframe = this.owner.wrap.createChild(ifcfg, this.el); 
         
-        var lastSel = this.tb.selectedNode;
         
-        this.tb.selectedNode = sel;
+        this.iframe = iframe.dom;
+
+        this.assignDocWin();
         
-        // if current menu does not match..
+        this.doc.designMode = 'on';
+       
+        this.doc.open();
+        this.doc.write(this.getDocMarkup());
+        this.doc.close();
+
         
-        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]);
+        var task = { // must defer to wait for browser to be ready
+            run : function(){
+                //console.log("run task?" + this.doc.readyState);
+                this.assignDocWin();
+                if(this.doc.body || this.doc.readyState == 'complete'){
+                    try {
+                        this.doc.designMode="on";
+                        
+                    } catch (e) {
                         return;
-                    } 
-                   e.setValue(sel.getAttribute(e.attrname));
-                });
-            }
-            
-            var hasStyles = false;
-            for(var i in this.styles) {
-                hasStyles = true;
-                break;
-            }
-            
-            // update styles
-            if (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 ] );         
-                    });
+                    }
+                    Roo.TaskMgr.stop(task);
+                    this.initEditor.defer(10, this);
                 }
-                
-                st.store.loadData(avs);
-                st.collapse();
-                st.setValue(cn);
-            }
-            // flag our selected Node.
-            this.tb.selectedNode = sel;
-           
-           
-            Roo.menu.MenuMgr.hideAll();
+            },
+            interval : 10,
+            duration: 10000,
+            scope: this
+        };
+        Roo.TaskMgr.start(task);
 
-        }
-        
-        if (!updateFooter) {
-            //this.footDisp.dom.innerHTML = ''; 
+    },
+
+    // private
+    onResize : function(w, h)
+    {
+         Roo.log('resize: ' +w + ',' + h );
+        //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
+        if(!this.iframe){
             return;
         }
-        // update the footer
-        //
-        var html = '';
-        
-        this.footerEls = ans.reverse();
-        Roo.each(this.footerEls, function(a,i) {
-            if (!a) { return; }
-            html += html.length ? ' &gt; '  :  '';
+        if(typeof w == 'number'){
             
-            html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
+            this.iframe.style.width = w + 'px';
+        }
+        if(typeof h == 'number'){
             
-        });
-       
-        // 
-        var sz = this.footDisp.up('td').getSize();
-        this.footDisp.dom.style.width = (sz.width -10) + 'px';
-        this.footDisp.dom.style.marginLeft = '5px';
+            this.iframe.style.height = h + 'px';
+            if(this.doc){
+                (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
+            }
+        }
         
-        this.footDisp.dom.style.overflow = 'hidden';
+    },
+
+    /**
+     * Toggles the editor between standard and source edit mode.
+     * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
+     */
+    toggleSourceEdit : function(sourceEditMode){
         
-        this.footDisp.dom.innerHTML = html;
+        this.sourceEditMode = sourceEditMode === true;
+        
+        if(this.sourceEditMode){
+            Roo.get(this.iframe).addClass(['x-hidden','hide', 'd-none']);     //FIXME - what's the BS styles for these
             
-        //this.editorsyncValue();
+        }else{
+            Roo.get(this.iframe).removeClass(['x-hidden','hide', 'd-none']);
+            //this.iframe.className = '';
+            this.deferFocus();
+        }
+        //this.setSize(this.owner.wrap.getSize());
+        //this.fireEvent('editmodechange', this, this.sourceEditMode);
     },
-     
+
     
-   
-       
-    // private
-    onDestroy : function(){
-        if(this.rendered){
-            
-            this.tb.items.each(function(item){
-                if(item.menu){
-                    item.menu.removeAll();
-                    if(item.menu.el){
-                        item.menu.el.destroy();
-                    }
-                }
-                item.destroy();
-            });
-             
+  
+
+    /**
+     * Protected method that will not generally be called directly. If you need/want
+     * custom HTML cleanup, this is the method you should override.
+     * @param {String} html The HTML to be cleaned
+     * return {String} The cleaned HTML
+     */
+    cleanHtml : function(html)
+    {
+        html = String(html);
+        if(html.length > 5){
+            if(Roo.isSafari){ // strip safari nonsense
+                html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
+            }
         }
+        if(html == '&nbsp;'){
+            html = '';
+        }
+        return html;
     },
-    onFirstFocus: function() {
-        // need to do this for all the toolbars..
-        this.tb.items.each(function(item){
-           item.enable();
-        });
-    },
-    buildToolbar: function(tlist, nm)
+
+    /**
+     * HTML Editor -> Textarea
+     * Protected method that will not generally be called directly. Syncs the contents
+     * of the editor iframe with the textarea.
+     */
+    syncValue : function()
     {
-        var editor = this.editor;
-        var editorcore = this.editorcore;
-         // create a new element.
-        var wdiv = editor.wrap.createChild({
-                tag: 'div'
-            }, editor.wrap.dom.firstChild.nextSibling, true);
-        
-       
-        var tb = new Roo.Toolbar(wdiv);
-        // add the name..
-        
-        tb.add(nm+ ":&nbsp;");
-        
-        var styles = [];
-        for(var i in this.styles) {
-            styles.push(i);
-        }
-        
-        // styles...
-        if (styles && styles.length) {
+        //Roo.log("HtmlEditorCore:syncValue (EDITOR->TEXT)");
+        if(this.initialized){
             
-            // this needs a multi-select checkbox...
-            tb.addField( new Roo.form.ComboBox({
-                store: new Roo.data.SimpleStore({
-                    id : 'val',
-                    fields: ['val', 'selected'],
-                    data : [] 
-                }),
-                name : '-roo-edit-className',
-                attrname : 'className',
-                displayField: 'val',
-                typeAhead: false,
-                mode: 'local',
-                editable : false,
-                triggerAction: 'all',
-                emptyText:'Select Style',
-                selectOnFocus:true,
-                width: 130,
-                listeners : {
-                    'select': function(c, r, i) {
-                        // initial support only for on class per el..
-                        tb.selectedNode.className =  r ? r.get('val') : '';
-                        editorcore.syncValue();
-                    }
-                }
-    
-            }));
-        }
-        
-        var tbc = Roo.form.HtmlEditor.ToolbarContext;
-        var tbops = tbc.options;
-        
-        for (var i in tlist) {
+            if (this.undoManager) {
+                this.undoManager.addEvent();
+            }
+
             
-            var item = tlist[i];
-            tb.add(item.title + ":&nbsp;");
+            var bd = (this.doc.body || this.doc.documentElement);
+           
             
+            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);
+            }
             
-            //optname == used so you can configure the options available..
-            var opts = item.opts ? item.opts : false;
-            if (item.optname) {
-                opts = tbops[item.optname];
            
+            if (this.enableBlocks) {
+                new Roo.htmleditor.FilterBlock({ node : div });
             }
             
-            if (opts) {
-                // opts == pulldown..
-                tb.addField( new Roo.form.ComboBox({
-                    store:   typeof(tbc.stores[i]) != 'undefined' ?  Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
-                        id : 'val',
-                        fields: ['val', 'display'],
-                        data : opts  
-                    }),
-                    name : '-roo-edit-' + i,
-                    attrname : i,
-                    stylename : item.style ? item.style : false,
-                    displayField: item.displayField ? item.displayField : 'val',
-                    valueField :  'val',
-                    typeAhead: false,
-                    mode: typeof(tbc.stores[i]) != 'undefined'  ? 'remote' : 'local',
-                    editable : false,
-                    triggerAction: 'all',
-                    emptyText:'Select',
-                    selectOnFocus:true,
-                    width: item.width ? item.width  : 130,
-                    listeners : {
-                        'select': function(c, r, i) {
-                            if (c.stylename) {
-                                tb.selectedNode.style[c.stylename] =  r.get('val');
-                                return;
-                            }
-                            tb.selectedNode.setAttribute(c.attrname, r.get('val'));
-                        }
-                    }
-
-                }));
-                continue;
-                    
-                 
+            var html = div.innerHTML;
+            
+            //?? tidy?
+            if (this.autoClean) {
                 
-                tb.addField( new Roo.form.TextField({
-                    name: i,
-                    width: 100,
-                    //allowBlank:false,
-                    value: ''
-                }));
-                continue;
-            }
-            tb.addField( new Roo.form.TextField({
-                name: '-roo-edit-' + i,
-                attrname : i,
+                new Roo.htmleditor.FilterAttributes({
+                    node : div,
+                    attrib_white : [
+                            'href',
+                            'src',
+                            'name',
+                            'align',
+                            'colspan',
+                            'rowspan',
+                            'data-display',
+                            'data-width',
+                            'start' ,
+                            'style',
+                            // youtube embed.
+                            'class',
+                            'allowfullscreen',
+                            'frameborder',
+                            'width',
+                            'height',
+                            'alt'
+                            ],
+                    attrib_clean : ['href', 'src' ] 
+                });
                 
-                width: item.width,
-                //allowBlank:true,
-                value: '',
-                listeners: {
-                    'change' : function(f, nv, ov) {
-                        tb.selectedNode.setAttribute(f.attrname, nv);
-                        editorcore.syncValue();
-                    }
+                var tidy = new Roo.htmleditor.TidySerializer({
+                    inner:  true
+                });
+                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;
+                if(m && m[1]){
+                    html = '<div style="'+m[0]+'">' + html + '</div>';
                 }
-            }));
+            }
+            html = this.cleanHtml(html);
+            // fix up the special chars.. normaly like back quotes in word...
+            // however we do not want to do this with chinese..
+            html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
+                
+                var cc = match.charCodeAt();
+
+                // Get the character value, handling surrogate pairs
+                if (match.length == 2) {
+                    // It's a surrogate pair, calculate the Unicode code point
+                    var high = match.charCodeAt(0) - 0xD800;
+                    var low  = match.charCodeAt(1) - 0xDC00;
+                    cc = (high * 0x400) + low + 0x10000;
+                }  else if (
+                    (cc >= 0x4E00 && cc < 0xA000 ) ||
+                    (cc >= 0x3400 && cc < 0x4E00 ) ||
+                    (cc >= 0xf900 && cc < 0xfb00 )
+                ) {
+                        return match;
+                }  
+         
+                // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
+                return "&#" + cc + ";";
+                
+                
+            });
+            
+            
              
+            if(this.owner.fireEvent('beforesync', this, html) !== false){
+                this.el.dom.value = html;
+                this.owner.fireEvent('sync', this, html);
+            }
         }
-        
-        var _this = this;
-        
-        if(nm == 'BODY'){
-            tb.addSeparator();
-        
-            tb.addButton( {
-                text: 'Stylesheets',
+    },
 
-                listeners : {
-                    click : function ()
-                    {
-                        _this.editor.fireEvent('stylesheetsclick', _this.editor);
-                    }
-                }
-            });
-        }
-        
-        tb.addFill();
-        tb.addButton( {
-            text: 'Remove Tag',
+    /**
+     * TEXTAREA -> EDITABLE
+     * Protected method that will not generally be called directly. Pushes the value of the textarea
+     * into the iframe editor.
+     */
+    pushValue : function()
+    {
+        //Roo.log("HtmlEditorCore:pushValue (TEXT->EDITOR)");
+        if(this.initialized){
+            var v = this.el.dom.value.trim();
+            
+            
+            if(this.owner.fireEvent('beforepush', this, v) !== false){
+                var d = (this.doc.body || this.doc.documentElement);
+                d.innerHTML = v;
+                 
+                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'));
+            }
+            
+            
+        }
+    },
+
+    // private
+    deferFocus : function(){
+        this.focus.defer(10, this);
+    },
+
+    // doc'ed in Field
+    focus : function(){
+        if(this.win && !this.sourceEditMode){
+            this.win.focus();
+        }else{
+            this.el.focus();
+        }
+    },
     
-            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);
-                        
-                    }
-                    pn.removeChild(sn);
-                    var range = editorcore.createRange();
+    assignDocWin: function()
+    {
+        var iframe = this.iframe;
         
-                    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 = ''; 
-                }
+         if(Roo.isIE){
+            this.doc = iframe.contentWindow.document;
+            this.win = iframe.contentWindow;
+        } else {
+//            if (!Roo.get(this.frameId)) {
+//                return;
+//            }
+//            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
+//            this.win = Roo.get(this.frameId).dom.contentWindow;
+            
+            if (!Roo.get(this.frameId) && !iframe.contentDocument) {
+                return;
             }
             
-                    
-                
+            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
+            this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
+        }
+    },
+    
+    // private
+    initEditor : function(){
+        //console.log("INIT EDITOR");
+        this.assignDocWin();
+        
+        
+        
+        this.doc.designMode="on";
+        this.doc.open();
+        this.doc.write(this.getDocMarkup());
+        this.doc.close();
+        
+        var dbody = (this.doc.body || this.doc.documentElement);
+        //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
+        // this copies styles from the containing element into thsi one..
+        // not sure why we need all of this..
+        //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
+        
+        //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, {
+             
+            '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});
         
-        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;
          
         
+        this.owner.fireEvent('initialize', this);
+        this.pushValue();
     },
-    buildFooter : function()
+    // 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..
         
-        var fel = this.editor.wrap.createChild();
-        this.footer = new Roo.Toolbar(fel);
-        // toolbar has scrolly on left / right?
-        var footDisp= new Roo.Toolbar.Fill();
-        var _t = this;
-        this.footer.add(
-            {
-                text : '&lt;',
-                xtype: 'Button',
-                handler : function() {
-                    _t.footDisp.scrollTo('left',0,true)
-                }
-            }
-        );
-        this.footer.add( footDisp );
-        this.footer.add( 
+        // 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 && cd.files.length > 0) {
+            // pasting images?
+            var urlAPI = (window.createObjectURL && window) || 
+                (window.URL && URL.revokeObjectURL && URL) || 
+                (window.webkitURL && webkitURL);
+            
+            var r = new FileReader();
+            var t = this;
+            r.addEventListener('load',function()
             {
-                text : '&gt;',
-                xtype: 'Button',
-                handler : function() {
-                    // no animation..
-                    _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
+                
+                var d = (new DOMParser().parseFromString('<img src="' + r.result+ '">', 'text/html')).body;
+                // is insert asycn?
+                if (t.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..
+                        
+                    });
                 }
-            }
-        );
-        var fel = Roo.get(footDisp.el);
-        fel.addClass('x-editor-context');
-        this.footDispWrap = fel; 
-        this.footDispWrap.overflow  = 'hidden';
+                t.insertAtCursor(d.innerHTML.replace(/&nbsp;/g,' '));
+                t.owner.fireEvent('paste', this);
+            });
+            r.readAsDataURL(cd.files[0]);
+            
+            e.preventDefault();
+            
+            return false;
+        }
+        if (cd.types.indexOf('text/html') < 0 ) {
+            return false;
+        }
+        var images = [];
+        var html = cd.getData('text/html'); // clipboard event
+        if (cd.types.indexOf('text/rtf') > -1) {
+            var parser = new Roo.rtf.Parser(cd.getData('text/rtf'));
+            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|footerf)/); }) // ignore headers/footers etc.
+                       .map(function(g) { return g.toDataURL(); })
+                       .filter(function(g) { return g != 'about:blank'; });
         
-        this.footDisp = fel.createChild();
-        this.footDispWrap.on('click', this.onContextClick, this)
+        //Roo.log(html);
+        html = this.cleanWordChars(html);
         
+        var d = (new DOMParser().parseFromString(html, 'text/html')).body;
         
-    },
-    onContextClick : function (ev,dom)
-    {
-        ev.preventDefault();
-        var  cn = dom.className;
-        //Roo.log(cn);
-        if (!cn.match(/x-ed-loc-/)) {
-            return;
+        
+        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;
         }
-        var n = cn.split('-').pop();
-        var ans = this.footerEls;
-        var sel = ans[n];
         
-         // pick
-        var range = this.editorcore.createRange();
         
-        range.selectNodeContents(sel);
-        //range.selectNode(sel);
         
+        if (images.length > 0) {
+            // replace all v:imagedata - with img.
+            var ar = Array.from(d.getElementsByTagName('v:imagedata'));
+            Roo.each(ar, function(node) {
+                node.parentNode.insertBefore(d.ownerDocument.createElement('img'), node );
+                node.parentNode.removeChild(node);
+            });
+            
+            
+            Roo.each(d.getElementsByTagName('img'), function(img, i) {
+                img.setAttribute('src', images[i]);
+            });
+        }
+        if (this.autoClean) {
+            new Roo.htmleditor.FilterWord({ node : d });
+            
+            new Roo.htmleditor.FilterStyleToTag({ node : d });
+            new Roo.htmleditor.FilterAttributes({
+                node : d,
+                attrib_white : ['href', 'src', 'name', 'align', 'colspan', 'rowspan', 'data-display', 'data-width', 'start'],
+                attrib_clean : ['href', 'src' ] 
+            });
+            new Roo.htmleditor.FilterBlack({ node : d, tag : this.black});
+            // should be fonts..
+            new Roo.htmleditor.FilterKeepChildren({node : d, tag : [ 'FONT', ':' ]} );
+            new Roo.htmleditor.FilterParagraph({ node : d });
+            new Roo.htmleditor.FilterSpan({ node : d });
+            new Roo.htmleditor.FilterLongBr({ node : d });
+            new Roo.htmleditor.FilterComment({ 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..
+                
+            });
+        }
         
-        var selection = this.editorcore.getSelection();
-        selection.removeAllRanges();
-        selection.addRange(range);
         
+        this.insertAtCursor(d.innerHTML.replace(/&nbsp;/g,' '));
+        if (this.enableBlocks) {
+            Roo.htmleditor.Block.initAll(this.doc.body);
+        }
+         
         
+        e.preventDefault();
+        this.owner.fireEvent('paste', this);
+        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(){
         
-        this.updateToolbar(null, null, sel);
         
         
-    }
-    
-    
-    
-    
-    
-});
-
-
-
-
+        if(this.rendered){
+            
+            //for (var i =0; i < this.toolbars.length;i++) {
+            //    // fixme - ask toolbars for heights?
+            //    this.toolbars[i].onDestroy();
+           // }
+            
+            //this.wrap.dom.innerHTML = '';
+            //this.wrap.remove();
+        }
+    },
 
-/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-/**
- * @class Roo.form.BasicForm
- * @extends Roo.util.Observable
- * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
- * @constructor
- * @param {String/HTMLElement/Roo.Element} el The form element or its id
- * @param {Object} config Configuration options
- */
-Roo.form.BasicForm = function(el, config){
-    this.allItems = [];
-    this.childForms = [];
-    Roo.apply(this, config);
-    /*
-     * The Roo.form.Field items in this form.
-     * @type MixedCollection
-     */
-     
-     
-    this.items = new Roo.util.MixedCollection(false, function(o){
-        return o.id || (o.id = Roo.id());
-    });
-    this.addEvents({
-        /**
-         * @event beforeaction
-         * Fires before any action is performed. Return false to cancel the action.
-         * @param {Form} this
-         * @param {Action} action The action to be performed
-         */
-        beforeaction: true,
-        /**
-         * @event actionfailed
-         * Fires when an action fails.
-         * @param {Form} this
-         * @param {Action} action The action that failed
-         */
-        actionfailed : true,
-        /**
-         * @event actioncomplete
-         * Fires when an action is completed.
-         * @param {Form} this
-         * @param {Action} action The action that completed
-         */
-        actioncomplete : true
-    });
-    if(el){
-        this.initEl(el);
-    }
-    Roo.form.BasicForm.superclass.constructor.call(this);
+    // private
+    onFirstFocus : function(){
+        
+        this.assignDocWin();
+        this.undoManager = new Roo.lib.UndoManager(100,(this.doc.body || this.doc.documentElement));
+        
+        this.activated = true;
+         
     
-    Roo.form.BasicForm.popover.apply();
-};
-
-Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
-    /**
-     * @cfg {String} method
-     * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
-     */
-    /**
-     * @cfg {DataReader} reader
-     * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
-     * This is optional as there is built-in support for processing JSON.
-     */
-    /**
-     * @cfg {DataReader} errorReader
-     * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
-     * This is completely optional as there is built-in support for processing JSON.
-     */
-    /**
-     * @cfg {String} url
-     * The URL to use for form actions if one isn't supplied in the action options.
-     */
-    /**
-     * @cfg {Boolean} fileUpload
-     * Set to true if this form is a file upload.
-     */
-     
-    /**
-     * @cfg {Object} baseParams
-     * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
-     */
-     /**
-     
-    /**
-     * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
-     */
-    timeout: 30,
+        if(Roo.isGecko){ // prevent silly gecko errors
+            this.win.focus();
+            var s = this.win.getSelection();
+            if(!s.focusNode || s.focusNode.nodeType != 3){
+                var r = s.getRangeAt(0);
+                r.selectNodeContents((this.doc.body || this.doc.documentElement));
+                r.collapse(true);
+                this.deferFocus();
+            }
+            try{
+                this.execCmd('useCSS', true);
+                this.execCmd('styleWithCSS', false);
+            }catch(e){}
+        }
+        this.owner.fireEvent('activate', this);
+    },
 
     // private
-    activeAction : null,
+    adjustFont: function(btn){
+        var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
+        //if(Roo.isSafari){ // safari
+        //    adjust *= 2;
+       // }
+        var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
+        if(Roo.isSafari){ // safari
+            var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
+            v =  (v < 10) ? 10 : v;
+            v =  (v > 48) ? 48 : v;
+            v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
+            
+        }
+        
+        
+        v = Math.max(1, v+adjust);
+        
+        this.execCmd('FontSize', v  );
+    },
 
-    /**
-     * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
-     * or setValues() data instead of when the form was first created.
-     */
-    trackResetOnLoad : false,
-    
-    
-    /**
-     * childForms - used for multi-tab forms
-     * @type {Array}
-     */
-    childForms : false,
-    
-    /**
-     * allItems - full list of fields.
-     * @type {Array}
-     */
-    allItems : false,
-    
-    /**
-     * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
-     * element by passing it or its id or mask the form itself by passing in true.
-     * @type Mixed
-     */
-    waitMsgTarget : false,
-    
-    /**
-     * @type Boolean
-     */
-    disableMask : false,
-    
-    /**
-     * @cfg {Boolean} errorMask (true|false) default false
-     */
-    errorMask : false,
+    onEditorEvent : function(e)
+    {
+         
+        
+        if (e && (e.ctrlKey || e.metaKey) && e.keyCode === 90) {
+            return; // we do not handle this.. (undo manager does..)
+        }
+        // clicking a 'block'?
+        
+        // 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
+    },
     
-    /**
-     * @cfg {Number} maskOffset Default 100
-     */
-    maskOffset : 100,
-
-    // private
-    initEl : function(el){
-        this.el = Roo.get(el);
-        this.id = this.el.id || Roo.id();
-        this.el.on('submit', this.onSubmit, this);
-        this.el.addClass('x-form');
+    fireEditorEvent: function(e)
+    {
+        this.owner.fireEvent('editorevent', this, e);
     },
 
-    // private
-    onSubmit : function(e){
-        e.stopEvent();
+    insertTag : function(tg)
+    {
+        // could be a bit smarter... -> wrap the current selected tRoo..
+        if (tg.toLowerCase() == 'span' ||
+            tg.toLowerCase() == 'code' ||
+            tg.toLowerCase() == 'sup' ||
+            tg.toLowerCase() == 'sub' 
+            ) {
+            
+            range = this.createRange(this.getSelection());
+            var wrappingNode = this.doc.createElement(tg.toLowerCase());
+            wrappingNode.appendChild(range.extractContents());
+            range.insertNode(wrappingNode);
+
+            return;
+            
+            
+            
+        }
+        this.execCmd("formatblock",   tg);
+        this.undoManager.addEvent(); 
     },
+    
+    insertText : function(txt)
+    {
+        
+        
+        var range = this.createRange();
+        range.deleteContents();
+               //alert(Sender.getAttribute('label'));
+               
+        range.insertNode(this.doc.createTextNode(txt));
+        this.undoManager.addEvent();
+    } ,
+    
+     
 
     /**
-     * Returns true if client-side validation on the form is successful.
-     * @return Boolean
+     * Executes a Midas editor command on the editor document and performs necessary focus and
+     * toolbar updates. <b>This should only be called after the editor is initialized.</b>
+     * @param {String} cmd The Midas command
+     * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
      */
-    isValid : function(){
-        var valid = true;
-        var target = false;
-        this.items.each(function(f){
-            if(f.validate()){
-                return;
-            }
-            
-            valid = false;
+    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':
+            case 'underline':                
+                // if there is no selection, then we insert, and set the curson inside it..
+                this.execCmd('styleWithCSS', false); 
+                break;
                 
-            if(!target && f.el.isVisible(true)){
-                target = f;
-            }
-        });
         
-        if(this.errorMask && !valid){
-            Roo.form.BasicForm.popover.mask(this, target);
+            default:
+                break;
         }
         
-        return valid;
+        
+        this.win.focus();
+        this.execCmd(cmd, value);
+        this.owner.fireEvent('editorevent', this);
+        //this.updateToolbar();
+        this.owner.deferFocus();
     },
 
     /**
-     * DEPRICATED Returns true if any fields in this form have changed since their original load. 
-     * @return Boolean
+     * Executes a Midas editor command directly on the editor document.
+     * For visual commands, you should use {@link #relayCmd} instead.
+     * <b>This should only be called after the editor is initialized.</b>
+     * @param {String} cmd The Midas command
+     * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
      */
-    isDirty : function(){
-        var dirty = false;
-        this.items.each(function(f){
-           if(f.isDirty()){
-               dirty = true;
-               return false;
-           }
-        });
-        return dirty;
-    },
-    
-    /**
-     * Returns true if any fields in this form have changed since their original load. (New version)
-     * @return Boolean
-     */
-    
-    hasChanged : function()
-    {
-        var dirty = false;
-        this.items.each(function(f){
-           if(f.hasChanged()){
-               dirty = true;
-               return false;
-           }
-        });
-        return dirty;
-        
+    execCmd : function(cmd, value){
+        this.doc.execCommand(cmd, false, value === undefined ? null : value);
+        this.syncValue();
     },
+   
     /**
-     * Resets all hasChanged to 'false' -
-     * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
-     * So hasChanged storage is only to be used for this purpose
-     * @return Boolean
+     * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
+     * to insert tRoo.
+     * @param {String} text | dom node.. 
      */
-    resetHasChanged : function()
+    insertAtCursor : function(text)
     {
-        this.items.each(function(f){
-           f.resetHasChanged();
-        });
-        
-    },
-    
-    
-    /**
-     * Performs a predefined action (submit or load) or custom actions you define on this form.
-     * @param {String} actionName The name of the action type
-     * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
-     * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
-     * accept other config options):
-     * <pre>
-Property          Type             Description
-----------------  ---------------  ----------------------------------------------------------------------------------
-url               String           The url for the action (defaults to the form's url)
-method            String           The form method to use (defaults to the form's method, or POST if not defined)
-params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
-clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
-                                   validate the form on the client (defaults to false)
-     * </pre>
-     * @return {BasicForm} this
-     */
-    doAction : function(action, options){
-        if(typeof action == 'string'){
-            action = new Roo.form.Action.ACTION_TYPES[action](this, options);
-        }
-        if(this.fireEvent('beforeaction', this, action) !== false){
-            this.beforeAction(action);
-            action.run.defer(100, action);
-        }
-        return this;
-    },
-
-    /**
-     * Shortcut to do a submit action.
-     * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
-     * @return {BasicForm} this
-     */
-    submit : function(options){
-        this.doAction('submit', options);
-        return this;
-    },
-
-    /**
-     * Shortcut to do a load action.
-     * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
-     * @return {BasicForm} this
-     */
-    load : function(options){
-        this.doAction('load', options);
-        return this;
-    },
-
-    /**
-     * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
-     * @param {Record} record The record to edit
-     * @return {BasicForm} this
-     */
-    updateRecord : function(record){
-        record.beginEdit();
-        var fs = record.fields;
-        fs.each(function(f){
-            var field = this.findField(f.name);
-            if(field){
-                record.set(f.name, field.getValue());
-            }
-        }, this);
-        record.endEdit();
-        return this;
-    },
-
-    /**
-     * Loads an Roo.data.Record into this form.
-     * @param {Record} record The record to load
-     * @return {BasicForm} this
-     */
-    loadRecord : function(record){
-        this.setValues(record.data);
-        return this;
-    },
-
-    // private
-    beforeAction : function(action){
-        var o = action.options;
         
-        if(!this.disableMask) {
-            if(this.waitMsgTarget === true){
-                this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
-            }else if(this.waitMsgTarget){
-                this.waitMsgTarget = Roo.get(this.waitMsgTarget);
-                this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
-            }else {
-                Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
-            }
+        if(!this.activated){
+            return;
         }
-        
          
-    },
-
-    // private
-    afterAction : function(action, success){
-        this.activeAction = null;
-        var o = action.options;
-        
-        if(!this.disableMask) {
-            if(this.waitMsgTarget === true){
-                this.el.unmask();
-            }else if(this.waitMsgTarget){
-                this.waitMsgTarget.unmask();
-            }else{
-                Roo.MessageBox.updateProgress(1);
-                Roo.MessageBox.hide();
-            }
-        }
-        
-        if(success){
-            if(o.reset){
-                this.reset();
-            }
-            Roo.callback(o.success, o.scope, [this, action]);
-            this.fireEvent('actioncomplete', this, action);
+        if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
+            this.win.focus();
             
-        }else{
             
-            // failure condition..
-            // we have a scenario where updates need confirming.
-            // eg. if a locking scenario exists..
-            // we look for { errors : { needs_confirm : true }} in the response.
-            if (
-                (typeof(action.result) != 'undefined')  &&
-                (typeof(action.result.errors) != 'undefined')  &&
-                (typeof(action.result.errors.needs_confirm) != 'undefined')
-           ){
-                var _t = this;
-                Roo.MessageBox.confirm(
-                    "Change requires confirmation",
-                    action.result.errorMsg,
-                    function(r) {
-                        if (r != 'yes') {
-                            return;
-                        }
-                        _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
-                    }
-                    
-                );
+            // from jquery ui (MIT licenced)
+            var range, node;
+            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);
                 
                 
-                return;
-            }
+                
+            } 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);
             
-            Roo.callback(o.failure, o.scope, [this, action]);
-            // show an error message if no failed handler is set..
-            if (!this.hasListener('actionfailed')) {
-                Roo.MessageBox.alert("Error",
-                    (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
-                        action.result.errorMsg :
-                        "Saving Failed, please check your entries or try again"
-                );
-            }
+            } else {
+                // no firefox support
+                var txt = typeof(text) == 'string' ? text : text.outerHTML;
+                this.execCmd('InsertHTML', txt);
+            } 
+            this.syncValue();
             
-            this.fireEvent('actionfailed', this, action);
-        }
-        
-    },
-
-    /**
-     * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
-     * @param {String} id The value to search for
-     * @return Field
-     */
-    findField : function(id){
-        var field = this.items.get(id);
-        if(!field){
-            this.items.each(function(f){
-                if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
-                    field = f;
-                    return false;
-                }
-            });
-        }
-        return field || null;
-    },
-
-    /**
-     * Add a secondary form to this one, 
-     * Used to provide tabbed forms. One form is primary, with hidden values 
-     * which mirror the elements from the other forms.
-     * 
-     * @param {Roo.form.Form} form to add.
-     * 
-     */
-    addForm : function(form)
-    {
-       
-        if (this.childForms.indexOf(form) > -1) {
-            // already added..
-            return;
+            this.deferFocus();
         }
-        this.childForms.push(form);
-        var n = '';
-        Roo.each(form.allItems, function (fe) {
-            
-            n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
-            if (this.findField(n)) { // already added..
-                return;
-            }
-            var add = new Roo.form.Hidden({
-                name : n
-            });
-            add.render(this.el);
-            
-            this.add( add );
-        }, this);
-        
     },
-    /**
-     * Mark fields in this form invalid in bulk.
-     * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
-     * @return {BasicForm} this
-     */
-    markInvalid : function(errors){
-        if(errors instanceof Array){
-            for(var i = 0, len = errors.length; i < len; i++){
-                var fieldError = errors[i];
-                var f = this.findField(fieldError.id);
-                if(f){
-                    f.markInvalid(fieldError.msg);
+ // private
+    mozKeyPress : function(e){
+        if(e.ctrlKey){
+            var c = e.getCharCode(), cmd;
+          
+            if(c > 0){
+                c = String.fromCharCode(c).toLowerCase();
+                switch(c){
+                    case 'b':
+                        cmd = 'bold';
+                        break;
+                    case 'i':
+                        cmd = 'italic';
+                        break;
+                    
+                    case 'u':
+                        cmd = 'underline';
+                        break;
+                    
+                    //case 'v':
+                      //  this.cleanUpPaste.defer(100, this);
+                      //  return;
+                        
                 }
-            }
-        }else{
-            var field, id;
-            for(id in errors){
-                if(typeof errors[id] != 'function' && (field = this.findField(id))){
-                    field.markInvalid(errors[id]);
+                if(cmd){
+                    
+                    this.relayCmd(cmd);
+                    //this.win.focus();
+                    //this.execCmd(cmd);
+                    //this.deferFocus();
+                    e.preventDefault();
                 }
+                
             }
         }
-        Roo.each(this.childForms || [], function (f) {
-            f.markInvalid(errors);
-        });
-        
-        return this;
     },
 
-    /**
-     * Set values for fields in this form in bulk.
-     * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
-     * @return {BasicForm} this
-     */
-    setValues : function(values){
-        if(values instanceof Array){ // array of objects
-            for(var i = 0, len = values.length; i < len; i++){
-                var v = values[i];
-                var f = this.findField(v.id);
-                if(f){
-                    f.setValue(v.value);
-                    if(this.trackResetOnLoad){
-                        f.originalValue = f.getValue();
+    // private
+    fixKeys : function(){ // load time branching for fastest keydown performance
+        
+        
+        if(Roo.isIE){
+            return function(e){
+                var k = e.getKey(), r;
+                if(k == e.TAB){
+                    e.stopEvent();
+                    r = this.doc.selection.createRange();
+                    if(r){
+                        r.collapse(true);
+                        r.pasteHTML('&#160;&#160;&#160;&#160;');
+                        this.deferFocus();
                     }
+                    return;
                 }
-            }
-        }else{ // object hash
-            var field, id;
-            for(id in values){
-                if(typeof values[id] != 'function' && (field = this.findField(id))){
-                    
-                    if (field.setFromData && 
-                        field.valueField && 
-                        field.displayField &&
-                        // combos' with local stores can 
-                        // be queried via setValue()
-                        // to set their value..
-                        (field.store && !field.store.isLocal)
-                        ) {
-                        // it's a combo
-                        var sd = { };
-                        sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
-                        sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
-                        field.setFromData(sd);
-                        
-                    } else {
-                        field.setValue(values[id]);
-                    }
-                    
-                    
-                    if(this.trackResetOnLoad){
-                        field.originalValue = field.getValue();
+                /// 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.collapse(false);
+                            r.select();
+                        }
                     }
                 }
-            }
-        }
-        this.resetHasChanged();
-        
-        
-        Roo.each(this.childForms || [], function (f) {
-            f.setValues(values);
-            f.resetHasChanged();
-        });
+                */
+                //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
+                //    this.cleanUpPaste.defer(100, this);
+                //    return;
+                //}
                 
-        return this;
-    },
-
-    /**
-     * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
-     * they are returned as an array.
-     * @param {Boolean} asString
-     * @return {Object}
-     */
-    getValues : function(asString){
-        if (this.childForms) {
-            // copy values from the child forms
-            Roo.each(this.childForms, function (f) {
-                this.setValues(f.getValues());
-            }, this);
+                
+            };
+        }else if(Roo.isOpera){
+            return function(e){
+                var k = e.getKey();
+                if(k == e.TAB){
+                    e.stopEvent();
+                    this.win.focus();
+                    this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
+                    this.deferFocus();
+                }
+               
+                //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
+                //    this.cleanUpPaste.defer(100, this);
+                 //   return;
+                //}
+                
+            };
+        }else if(Roo.isSafari){
+            return function(e){
+                var k = e.getKey();
+                
+                if(k == e.TAB){
+                    e.stopEvent();
+                    this.execCmd('InsertText','\t');
+                    this.deferFocus();
+                    return;
+                }
+                 this.mozKeyPress(e);
+                
+               //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
+                 //   this.cleanUpPaste.defer(100, this);
+                 //   return;
+               // }
+                
+             };
+        }
+    }(),
+    
+    getAllAncestors: function()
+    {
+        var p = this.getSelectedNode();
+        var a = [];
+        if (!p) {
+            a.push(p); // push blank onto stack..
+            p = this.getParentElement();
         }
         
         
-        
-        var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
-        if(asString === true){
-            return fs;
+        while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
+            a.push(p);
+            p = p.parentNode;
         }
-        return Roo.urlDecode(fs);
+        a.push(this.doc.body);
+        return a;
     },
+    lastSel : false,
+    lastSelNode : false,
     
+    
+    getSelection : function() 
+    {
+        this.assignDocWin();
+        return Roo.lib.Selection.wrap(Roo.isIE ? this.doc.selection : this.win.getSelection(), this.doc);
+    },
     /**
-     * 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.
-     * @return {Object}
+     * Select a dom node
+     * @param {DomElement} node the node to select
      */
-    getFieldValues : function(with_hidden)
+    selectNode : function(node, collapse)
     {
-        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);
+        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() 
+    {
+        // this may only work on Gecko!!!
         
-        var ret = {};
-        this.items.each(function(f){
-            if (!f.getName()) {
-                return;
-            }
-            var v = f.getValue();
-            if (f.inputType =='radio') {
-                if (typeof(ret[f.getName()]) == 'undefined') {
-                    ret[f.getName()] = ''; // empty..
+        // should we cache this!!!!
+        
+         
+         
+        var range = this.createRange(this.getSelection()).cloneRange();
+        
+        if (Roo.isIE) {
+            var parent = range.parentElement();
+            while (true) {
+                var testRange = range.duplicate();
+                testRange.moveToElementText(parent);
+                if (testRange.inRange(range)) {
+                    break;
                 }
-                
-                if (!f.el.dom.checked) {
-                    return;
-                    
+                if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
+                    break;
                 }
-                v = f.el.dom.value;
-                
+                parent = parent.parentElement;
+            }
+            return parent;
+        }
+        
+        // is ancestor a text element.
+        var ac =  range.commonAncestorContainer;
+        if (ac.nodeType == 3) {
+            ac = ac.parentNode;
+        }
+        
+        var ar = ac.childNodes;
+         
+        var nodes = [];
+        var other_nodes = [];
+        var has_other_nodes = false;
+        for (var i=0;i<ar.length;i++) {
+            if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
+                continue;
             }
+            // fullly contained node.
             
-            // not sure if this supported any more..
-            if ((typeof(v) == 'object') && f.getRawValue) {
-                v = f.getRawValue() ; // dates..
+            if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
+                nodes.push(ar[i]);
+                continue;
             }
-            // combo boxes where name != hiddenName...
-            if (f.name != f.getName()) {
-                ret[f.name] = f.getRawValue();
+            
+            // probably selected..
+            if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
+                other_nodes.push(ar[i]);
+                continue;
             }
-            ret[f.getName()] = v;
-        });
+            // outer..
+            if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
+                continue;
+            }
+            
+            
+            has_other_nodes = true;
+        }
+        if (!nodes.length && other_nodes.length) {
+            nodes= other_nodes;
+        }
+        if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
+            return false;
+        }
         
-        return ret;
+        return nodes[0];
     },
-
-    /**
-     * Clears all invalid messages in this form.
-     * @return {BasicForm} this
-     */
-    clearInvalid : function(){
-        this.items.each(function(f){
-           f.clearInvalid();
-        });
+    
+    
+    createRange: function(sel)
+    {
+        // this has strange effects when using with 
+        // top toolbar - not sure if it's a great idea.
+        //this.editor.contentWindow.focus();
+        if (typeof sel != "undefined") {
+            try {
+                return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
+            } catch(e) {
+                return this.doc.createRange();
+            }
+        } else {
+            return this.doc.createRange();
+        }
+    },
+    getParentElement: function()
+    {
         
-        Roo.each(this.childForms || [], function (f) {
-            f.clearInvalid();
-        });
+        this.assignDocWin();
+        var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
+        
+        var range = this.createRange(sel);
+         
+        try {
+            var p = range.commonAncestorContainer;
+            while (p.nodeType == 3) { // text node
+                p = p.parentNode;
+            }
+            return p;
+        } catch (e) {
+            return null;
+        }
+    
+    },
+    /***
+     *
+     * Range intersection.. the hard stuff...
+     *  '-1' = before
+     *  '0' = hits..
+     *  '1' = after.
+     *         [ -- selected range --- ]
+     *   [fail]                        [fail]
+     *
+     *    basically..
+     *      if end is before start or  hits it. fail.
+     *      if start is after end or hits it fail.
+     *
+     *   if either hits (but other is outside. - then it's not 
+     *   
+     *    
+     **/
+    
+    
+    // @see http://www.thismuchiknow.co.uk/?p=64.
+    rangeIntersectsNode : function(range, node)
+    {
+        var nodeRange = node.ownerDocument.createRange();
+        try {
+            nodeRange.selectNode(node);
+        } catch (e) {
+            nodeRange.selectNodeContents(node);
+        }
+    
+        var rangeStartRange = range.cloneRange();
+        rangeStartRange.collapse(true);
+    
+        var rangeEndRange = range.cloneRange();
+        rangeEndRange.collapse(false);
+    
+        var nodeStartRange = nodeRange.cloneRange();
+        nodeStartRange.collapse(true);
+    
+        var nodeEndRange = nodeRange.cloneRange();
+        nodeEndRange.collapse(false);
+    
+        return rangeStartRange.compareBoundaryPoints(
+                 Range.START_TO_START, nodeEndRange) == -1 &&
+               rangeEndRange.compareBoundaryPoints(
+                 Range.START_TO_START, nodeStartRange) == 1;
         
+         
+    },
+    rangeCompareNode : function(range, node)
+    {
+        var nodeRange = node.ownerDocument.createRange();
+        try {
+            nodeRange.selectNode(node);
+        } catch (e) {
+            nodeRange.selectNodeContents(node);
+        }
         
-        return this;
+        
+        range.collapse(true);
+    
+        nodeRange.collapse(true);
+     
+        var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
+        var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
+         
+        //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
+        
+        var nodeIsBefore   =  ss == 1;
+        var nodeIsAfter    = ee == -1;
+        
+        if (nodeIsBefore && nodeIsAfter) {
+            return 0; // outer
+        }
+        if (!nodeIsBefore && nodeIsAfter) {
+            return 1; //right trailed.
+        }
+        
+        if (nodeIsBefore && !nodeIsAfter) {
+            return 2;  // left trailed.
+        }
+        // fully contined.
+        return 3;
     },
-
-    /**
-     * Resets this form.
-     * @return {BasicForm} this
-     */
-    reset : function(){
-        this.items.each(function(f){
-            f.reset();
-        });
+    cleanWordChars : function(input) {// change the chars to hex code
         
-        Roo.each(this.childForms || [], function (f) {
-            f.reset();
+       var swapCodes  = [ 
+            [    8211, "&#8211;" ], 
+            [    8212, "&#8212;" ], 
+            [    8216,  "'" ],  
+            [    8217, "'" ],  
+            [    8220, '"' ],  
+            [    8221, '"' ],  
+            [    8226, "*" ],  
+            [    8230, "..." ]
+        ]; 
+        var output = input;
+        Roo.each(swapCodes, function(sw) { 
+            var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
+            
+            output = output.replace(swapper, sw[1]);
         });
-        this.resetHasChanged();
         
-        return this;
+        return output;
     },
-
-    /**
-     * Add Roo.form components to this form.
-     * @param {Field} field1
-     * @param {Field} field2 (optional)
-     * @param {Field} etc (optional)
-     * @return {BasicForm} this
-     */
-    add : function(){
-        this.items.addAll(Array.prototype.slice.call(arguments, 0));
-        return this;
+    
+     
+    
+        
+    
+    cleanUpChild : function (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} );
+         
+        
     },
-
-
+    
     /**
-     * Removes a field from the items collection (does NOT remove its markup).
-     * @param {Field} field
-     * @return {BasicForm} this
+     * Clean up MS wordisms...
+     * @deprecated - use filter directly
      */
-    remove : function(field){
-        this.items.remove(field);
-        return this;
+    cleanWord : function(node)
+    {
+        new Roo.htmleditor.FilterWord({ node : node ? node : this.doc.body });
+        new Roo.htmleditor.FilterKeepChildren({node : node ? node : this.doc.body, tag : [ 'FONT', ':' ]} );
+        
     },
-
+   
+    
     /**
-     * Looks at the fields in this form, checks them for an id attribute,
-     * and calls applyTo on the existing dom element with that id.
-     * @return {BasicForm} this
-     */
-    render : function(){
-        this.items.each(function(f){
-            if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
-                f.applyTo(f.id);
-            }
-        });
-        return this;
-    },
 
-    /**
-     * Calls {@link Ext#apply} for all fields in this form with the passed object.
-     * @param {Object} values
-     * @return {BasicForm} this
+     * @deprecated - use filters
      */
-    applyToFields : function(o){
-        this.items.each(function(f){
-           Roo.apply(f, o);
-        });
-        return this;
+    cleanTableWidths : function(node)
+    {
+        new Roo.htmleditor.FilterTableWidth({ node : node ? node : this.doc.body});
+        
     },
-
-    /**
-     * Calls {@link Ext#applyIf} for all field in this form with the passed object.
-     * @param {Object} values
-     * @return {BasicForm} this
-     */
-    applyIfToFields : function(o){
-        this.items.each(function(f){
-           Roo.applyIf(f, o);
-        });
-        return this;
-    }
-});
-
-// back compat
-Roo.BasicForm = Roo.form.BasicForm;
-
-Roo.apply(Roo.form.BasicForm, {
     
-    popover : {
-        
-        padding : 5,
-        
-        isApplied : false,
+     
         
-        isMasked : false,
+    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 :  [];
         
-        form : false,
+        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;
         
-        target : false,
+        this.white = [];
+        this.black = [];
+        Roo.each(Roo.HtmlEditorCore.white, function(tag) {
+            if (b.indexOf(tag) > -1) {
+                return;
+            }
+            this.white.push(tag);
+            
+        }, this);
         
-        intervalID : false,
+        Roo.each(w, function(tag) {
+            if (b.indexOf(tag) > -1) {
+                return;
+            }
+            if (this.white.indexOf(tag) > -1) {
+                return;
+            }
+            this.white.push(tag);
+            
+        }, this);
         
-        maskEl : false,
         
-        apply : function()
-        {
-            if(this.isApplied){
+        Roo.each(Roo.HtmlEditorCore.black, function(tag) {
+            if (w.indexOf(tag) > -1) {
                 return;
             }
+            this.black.push(tag);
             
-            this.maskEl = {
-                top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
-                left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
-                bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
-                right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
-            };
-            
-            this.maskEl.top.enableDisplayMode("block");
-            this.maskEl.left.enableDisplayMode("block");
-            this.maskEl.bottom.enableDisplayMode("block");
-            this.maskEl.right.enableDisplayMode("block");
-            
-            Roo.get(document.body).on('click', function(){
-                this.unmask();
-            }, this);
-            
-            Roo.get(document.body).on('touchstart', function(){
-                this.unmask();
-            }, this);
-            
-            this.isApplied = true
-        },
+        }, this);
         
-        mask : function(form, target)
-        {
-            this.form = form;
-            
-            this.target = target;
-            
-            if(!this.form.errorMask || !target.el){
+        Roo.each(b, function(tag) {
+            if (w.indexOf(tag) > -1) {
                 return;
             }
+            if (this.black.indexOf(tag) > -1) {
+                return;
+            }
+            this.black.push(tag);
             
-            var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
-            
-            var ot = this.target.el.calcOffsetsTo(scrollable);
-            
-            var scrollTo = ot[1] - this.form.maskOffset;
-            
-            scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
-            
-            scrollable.scrollTo('top', scrollTo);
-            
-            var el = this.target.wrap || this.target.el;
-            
-            var box = el.getBox();
-            
-            this.maskEl.top.setStyle('position', 'absolute');
-            this.maskEl.top.setStyle('z-index', 10000);
-            this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
-            this.maskEl.top.setLeft(0);
-            this.maskEl.top.setTop(0);
-            this.maskEl.top.show();
-            
-            this.maskEl.left.setStyle('position', 'absolute');
-            this.maskEl.left.setStyle('z-index', 10000);
-            this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
-            this.maskEl.left.setLeft(0);
-            this.maskEl.left.setTop(box.y - this.padding);
-            this.maskEl.left.show();
-
-            this.maskEl.bottom.setStyle('position', 'absolute');
-            this.maskEl.bottom.setStyle('z-index', 10000);
-            this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
-            this.maskEl.bottom.setLeft(0);
-            this.maskEl.bottom.setTop(box.bottom + this.padding);
-            this.maskEl.bottom.show();
-
-            this.maskEl.right.setStyle('position', 'absolute');
-            this.maskEl.right.setStyle('z-index', 10000);
-            this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
-            this.maskEl.right.setLeft(box.right + this.padding);
-            this.maskEl.right.setTop(box.y - this.padding);
-            this.maskEl.right.show();
-
-            this.intervalID = window.setInterval(function() {
-                Roo.form.BasicForm.popover.unmask();
-            }, 10000);
-
-            window.onwheel = function(){ return false;};
+        }, this);
+        
+        
+        w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
+        b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
+        
+        this.cwhite = [];
+        this.cblack = [];
+        Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
+            if (b.indexOf(tag) > -1) {
+                return;
+            }
+            this.cwhite.push(tag);
             
-            (function(){ this.isMasked = true; }).defer(500, this);
+        }, this);
+        
+        Roo.each(w, function(tag) {
+            if (b.indexOf(tag) > -1) {
+                return;
+            }
+            if (this.cwhite.indexOf(tag) > -1) {
+                return;
+            }
+            this.cwhite.push(tag);
             
-        },
+        }, this);
         
-        unmask : function()
-        {
-            if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
+        
+        Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
+            if (w.indexOf(tag) > -1) {
                 return;
             }
+            this.cblack.push(tag);
             
-            this.maskEl.top.setStyle('position', 'absolute');
-            this.maskEl.top.setSize(0, 0).setXY([0, 0]);
-            this.maskEl.top.hide();
-
-            this.maskEl.left.setStyle('position', 'absolute');
-            this.maskEl.left.setSize(0, 0).setXY([0, 0]);
-            this.maskEl.left.hide();
-
-            this.maskEl.bottom.setStyle('position', 'absolute');
-            this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
-            this.maskEl.bottom.hide();
-
-            this.maskEl.right.setStyle('position', 'absolute');
-            this.maskEl.right.setSize(0, 0).setXY([0, 0]);
-            this.maskEl.right.hide();
+        }, this);
+        
+        Roo.each(b, function(tag) {
+            if (w.indexOf(tag) > -1) {
+                return;
+            }
+            if (this.cblack.indexOf(tag) > -1) {
+                return;
+            }
+            this.cblack.push(tag);
             
-            window.onwheel = function(){ return true;};
+        }, this);
+    },
+    
+    setStylesheets : function(stylesheets)
+    {
+        if(typeof(stylesheets) == 'string'){
+            Roo.get(this.iframe.contentDocument.head).createChild({
+                tag : 'link',
+                rel : 'stylesheet',
+                type : 'text/css',
+                href : stylesheets
+            });
             
-            if(this.intervalID){
-                window.clearInterval(this.intervalID);
-                this.intervalID = false;
+            return;
+        }
+        var _this = this;
+     
+        Roo.each(stylesheets, function(s) {
+            if(!s.length){
+                return;
             }
             
-            this.isMasked = false;
-            
+            Roo.get(_this.iframe.contentDocument.head).createChild({
+                tag : 'link',
+                rel : 'stylesheet',
+                type : 'text/css',
+                href : s
+            });
+        });
+
+        
+    },
+    
+    
+    updateLanguage : function()
+    {
+        if (!this.iframe || !this.iframe.contentDocument) {
+            return;
         }
+        Roo.get(this.iframe.contentDocument.body).attr("lang", this.language);
+    },
+    
+    
+    removeStylesheets : function()
+    {
+        var _this = this;
         
-    }
+        Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
+            s.remove();
+        });
+    },
     
-});/*
- * 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">
- */
+    setStyle : function(style)
+    {
+        Roo.get(this.iframe.contentDocument.head).createChild({
+            tag : 'style',
+            type : 'text/css',
+            html : style
+        });
 
-/**
- * @class Roo.form.Form
- * @extends Roo.form.BasicForm
- * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
- * @constructor
- * @param {Object} config Configuration options
- */
-Roo.form.Form = function(config){
-    var xitems =  [];
-    if (config.items) {
-        xitems = config.items;
-        delete config.items;
+        return;
     }
-   
     
-    Roo.form.Form.superclass.constructor.call(this, null, config);
-    this.url = this.url || this.action;
-    if(!this.root){
-        this.root = new Roo.form.Layout(Roo.applyIf({
-            id: Roo.id()
-        }, config));
-    }
-    this.active = this.root;
+    // hide stuff that is not compatible
     /**
-     * Array of all the buttons that have been added to this form via {@link addButton}
-     * @type Array
+     * @event blur
+     * @hide
      */
-    this.buttons = [];
-    this.allItems = [];
-    this.addEvents({
-        /**
-         * @event clientvalidation
-         * If the monitorValid config option is true, this event fires repetitively to notify of valid state
-         * @param {Form} this
-         * @param {Boolean} valid true if the form has passed client-side validation
-         */
-        clientvalidation: true,
-        /**
-         * @event rendered
-         * Fires when the form is rendered
-         * @param {Roo.form.Form} form
-         */
-        rendered : true
-    });
-    
-    if (this.progressUrl) {
-            // push a hidden field onto the list of fields..
-            this.addxtype( {
-                    xns: Roo.form, 
-                    xtype : 'Hidden', 
-                    name : 'UPLOAD_IDENTIFIER' 
-            });
-        }
-        
-    
-    Roo.each(xitems, this.addxtype, this);
-    
-};
-
-Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
     /**
-     * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
+     * @event change
+     * @hide
      */
     /**
-     * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
+     * @event focus
+     * @hide
      */
     /**
-     * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
+     * @event specialkey
+     * @hide
      */
-    buttonAlign:'center',
-
     /**
-     * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
+     * @cfg {String} fieldClass @hide
      */
-    minButtonWidth:75,
-
     /**
-     * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
-     * This property cascades to child containers if not set.
+     * @cfg {String} focusClass @hide
      */
-    labelAlign:'left',
-
     /**
-     * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
-     * fires a looping event with that state. This is required to bind buttons to the valid
-     * state using the config value formBind:true on the button.
+     * @cfg {String} autoCreate @hide
      */
-    monitorValid : false,
-
     /**
-     * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
+     * @cfg {String} inputType @hide
      */
-    monitorPoll : 200,
-    
     /**
-     * @cfg {String} progressUrl - Url to return progress data 
+     * @cfg {String} invalidClass @hide
      */
-    
-    progressUrl : false,
     /**
-     * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
-     * sending a formdata with extra parameters - eg uploaded elements.
+     * @cfg {String} invalidText @hide
      */
-    
-    formData : false,
-    
     /**
-     * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
-     * fields are added and the column is closed. If no fields are passed the column remains open
-     * until end() is called.
-     * @param {Object} config The config to pass to the column
-     * @param {Field} field1 (optional)
-     * @param {Field} field2 (optional)
-     * @param {Field} etc (optional)
-     * @return Column The column container object
+     * @cfg {String} msgFx @hide
      */
-    column : function(c){
-        var col = new Roo.form.Column(c);
-        this.start(col);
-        if(arguments.length > 1){ // duplicate code required because of Opera
-            this.add.apply(this, Array.prototype.slice.call(arguments, 1));
-            this.end();
-        }
-        return col;
-    },
-
     /**
-     * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
-     * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
-     * until end() is called.
-     * @param {Object} config The config to pass to the fieldset
-     * @param {Field} field1 (optional)
-     * @param {Field} field2 (optional)
-     * @param {Field} etc (optional)
-     * @return FieldSet The fieldset container object
+     * @cfg {String} validateOnBlur @hide
      */
-    fieldset : function(c){
-        var fs = new Roo.form.FieldSet(c);
-        this.start(fs);
-        if(arguments.length > 1){ // duplicate code required because of Opera
-            this.add.apply(this, Array.prototype.slice.call(arguments, 1));
-            this.end();
-        }
-        return fs;
-    },
+});
 
-    /**
-     * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
-     * fields are added and the container is closed. If no fields are passed the container remains open
-     * until end() is called.
-     * @param {Object} config The config to pass to the Layout
-     * @param {Field} field1 (optional)
-     * @param {Field} field2 (optional)
-     * @param {Field} etc (optional)
-     * @return Layout The container object
-     */
-    container : function(c){
-        var l = new Roo.form.Layout(c);
-        this.start(l);
-        if(arguments.length > 1){ // duplicate code required because of Opera
-            this.add.apply(this, Array.prototype.slice.call(arguments, 1));
-            this.end();
-        }
-        return l;
-    },
+Roo.HtmlEditorCore.white = [
+        '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', 
+       
+       'CAPTION', 'COL', 'COLGROUP', 'TBODY', 'TD', 'TFOOT', 'TH', 
+      'THEAD',   'TR', 
+     
+      'DIR', 'MENU', 'OL', 'UL', 'DL',
+       
+      'EMBED',  'OBJECT'
+];
 
-    /**
-     * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
-     * @param {Object} container A Roo.form.Layout or subclass of Layout
-     * @return {Form} this
-     */
-    start : function(c){
-        // cascade label info
-        Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
-        this.active.stack.push(c);
-        c.ownerCt = this.active;
-        this.active = c;
-        return this;
-    },
 
-    /**
-     * Closes the current open container
-     * @return {Form} this
-     */
-    end : function(){
-        if(this.active == this.root){
-            return this;
-        }
-        this.active = this.active.ownerCt;
-        return this;
-    },
+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',
+        //'FONT' // CLEAN LATER..
+        'COLGROUP', 'COL'   // messy tables.
+        
+        
+];
+Roo.HtmlEditorCore.clean = [ // ?? needed???
+     'SCRIPT', 'STYLE', 'TITLE', 'XML'
+];
+Roo.HtmlEditorCore.tag_remove = [
+    'FONT', 'TBODY'  
+];
+// attributes..
 
-    /**
-     * Add Roo.form components to the current open container (e.g. column, fieldset, etc.).  Fields added via this method
-     * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
-     * as the label of the field.
-     * @param {Field} field1
-     * @param {Field} field2 (optional)
-     * @param {Field} etc. (optional)
-     * @return {Form} this
-     */
-    add : function(){
-        this.active.stack.push.apply(this.active.stack, arguments);
-        this.allItems.push.apply(this.allItems,arguments);
-        var r = [];
-        for(var i = 0, a = arguments, len = a.length; i < len; i++) {
-            if(a[i].isFormField){
-                r.push(a[i]);
-            }
-        }
-        if(r.length > 0){
-            Roo.form.Form.superclass.add.apply(this, r);
-        }
-        return this;
-    },
+Roo.HtmlEditorCore.ablack = [
+    'on'
+];
     
+Roo.HtmlEditorCore.aclean = [ 
+    'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
+];
+
+// protocols..
+Roo.HtmlEditorCore.pwhite= [
+        'http',  'https',  'mailto'
+];
+
+// white listed style attributes.
+Roo.HtmlEditorCore.cwhite= [
+      //  'text-align', /// default is to allow most things..
+      
+         
+//        'font-size'//??
+];
+
+// black listed style attributes.
+Roo.HtmlEditorCore.cblack= [
+      //  'font-size' -- this can be set by the project 
+];
+
+
+
 
+    //<script type="text/javascript">
+
+/*
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ * Licence LGPL
+ * 
+ */
+Roo.form.HtmlEditor = function(config){
     
     
     
-     /**
-     * Find any element that has been added to a form, using it's ID or name
-     * This can include framesets, columns etc. along with regular fields..
-     * @param {String} id - id or name to find.
-     
-     * @return {Element} e - or false if nothing found.
-     */
-    findbyId : function(id)
-    {
-        var ret = false;
-        if (!id) {
-            return ret;
-        }
-        Roo.each(this.allItems, function(f){
-            if (f.id == id || f.name == id ){
-                ret = f;
-                return false;
-            }
-        });
-        return ret;
-    },
-
+    Roo.form.HtmlEditor.superclass.constructor.call(this, config);
+    
+    if (!this.toolbars) {
+        this.toolbars = [];
+    }
+    this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
     
     
+};
+
+/**
+ * @class Roo.form.HtmlEditor
+ * @extends Roo.form.Field
+ * Provides a lightweight HTML Editor component.
+ *
+ * This has been tested on Fireforx / Chrome.. IE may not be so great..
+ * 
+ * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
+ * supported by this editor.</b><br/><br/>
+ * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
+ * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
+ */
+Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
     /**
-     * Render this form into the passed container. This should only be called once!
-     * @param {String/HTMLElement/Element} container The element this component should be rendered into
-     * @return {Form} this
+     * @cfg {Boolean} clearUp
      */
-    render : function(ct)
-    {
-        
-        
-        
-        ct = Roo.get(ct);
-        var o = this.autoCreate || {
-            tag: 'form',
-            method : this.method || 'POST',
-            id : this.id || Roo.id()
-        };
-        this.initEl(ct.createChild(o));
-
-        this.root.render(this.el);
-        
-       
-             
-        this.items.each(function(f){
-            f.render('x-form-el-'+f.id);
-        });
-
-        if(this.buttons.length > 0){
-            // tables are required to maintain order and for correct IE layout
-            var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
-                cls:"x-form-btns x-form-btns-"+this.buttonAlign,
-                html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
-            }}, null, true);
-            var tr = tb.getElementsByTagName('tr')[0];
-            for(var i = 0, len = this.buttons.length; i < len; i++) {
-                var b = this.buttons[i];
-                var td = document.createElement('td');
-                td.className = 'x-form-btn-td';
-                b.render(tr.appendChild(td));
-            }
-        }
-        if(this.monitorValid){ // initialize after render
-            this.startMonitoring();
-        }
-        this.fireEvent('rendered', this);
-        return this;
-    },
-
+    clearUp : true,
+      /**
+     * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
+     */
+    toolbars : false,
+   
+     /**
+     * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
+     *                        Roo.resizable.
+     */
+    resizable : false,
+     /**
+     * @cfg {Number} height (in pixels)
+     */   
+    height: 300,
+   /**
+     * @cfg {Number} width (in pixels)
+     */   
+    width: 500,
+    
     /**
-     * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
-     * @param {String/Object} config A string becomes the button text, an object can either be a Button config
-     * object or a valid Roo.DomHelper element config
-     * @param {Function} handler The function called when the button is clicked
-     * @param {Object} scope (optional) The scope of the handler function
-     * @return {Roo.Button}
+     * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets - this is usally a good idea  rootURL + '/roojs1/css/undoreset.css',   .
+     * 
      */
-    addButton : function(config, handler, scope){
-        var bc = {
-            handler: handler,
-            scope: scope,
-            minWidth: this.minButtonWidth,
-            hideParent:true
-        };
-        if(typeof config == "string"){
-            bc.text = config;
-        }else{
-            Roo.apply(bc, config);
-        }
-        var btn = new Roo.Button(null, bc);
-        this.buttons.push(btn);
-        return btn;
-    },
-
+    stylesheets: false,
+    
+    
      /**
-     * Adds a series of form elements (using the xtype property as the factory method.
-     * Valid xtypes are:  TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
-     * @param {Object} config 
+     * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
+     * 
+     */
+    cblack: false,
+    /**
+     * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
+     * 
      */
+    cwhite: false,
     
-    addxtype : function()
-    {
-        var ar = Array.prototype.slice.call(arguments, 0);
-        var ret = false;
-        for(var i = 0; i < ar.length; i++) {
-            if (!ar[i]) {
-                continue; // skip -- if this happends something invalid got sent, we 
-                // should ignore it, as basically that interface element will not show up
-                // and that should be pretty obvious!!
-            }
-            
-            if (Roo.form[ar[i].xtype]) {
-                ar[i].form = this;
-                var fe = Roo.factory(ar[i], Roo.form);
-                if (!ret) {
-                    ret = fe;
-                }
-                fe.form = this;
-                if (fe.store) {
-                    fe.store.form = this;
-                }
-                if (fe.isLayout) {  
-                         
-                    this.start(fe);
-                    this.allItems.push(fe);
-                    if (fe.items && fe.addxtype) {
-                        fe.addxtype.apply(fe, fe.items);
-                        delete fe.items;
-                    }
-                     this.end();
-                    continue;
-                }
-                
-                
-                 
-                this.add(fe);
-              //  console.log('adding ' + ar[i].xtype);
-            }
-            if (ar[i].xtype == 'Button') {  
-                //console.log('adding button');
-                //console.log(ar[i]);
-                this.addButton(ar[i]);
-                this.allItems.push(fe);
-                continue;
-            }
-            
-            if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
-                alert('end is not supported on xtype any more, use items');
-            //    this.end();
-            //    //console.log('adding end');
-            }
-            
-        }
-        return ret;
-    },
+     /**
+     * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
+     * 
+     */
+    black: false,
+    /**
+     * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
+     * 
+     */
+    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,
     
     /**
-     * Starts monitoring of the valid state of this form. Usually this is done by passing the config
-     * option "monitorValid"
+     * @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
      */
-    startMonitoring : function(){
-        if(!this.bound){
-            this.bound = true;
-            Roo.TaskMgr.start({
-                run : this.bindHandler,
-                interval : this.monitorPoll || 200,
-                scope: this
-            });
-        }
-    },
-
+    autoClean: true,
     /**
-     * Stops monitoring of the valid state of this form
+     * @cfg {string} bodyCls default '' default classes to add to body of editable area - usually undoreset is a good start..
      */
-    stopMonitoring : function(){
-        this.bound = false;
-    },
-
-    // private
-    bindHandler : function(){
-        if(!this.bound){
-            return false; // stops binding
-        }
-        var valid = true;
-        this.items.each(function(f){
-            if(!f.isValid(true)){
-                valid = false;
-                return false;
-            }
-        });
-        for(var i = 0, len = this.buttons.length; i < len; i++){
-            var btn = this.buttons[i];
-            if(btn.formBind === true && btn.disabled === valid){
-                btn.setDisabled(!valid);
-            }
-        }
-        this.fireEvent('clientvalidation', this, valid);
-    }
-    
-    
-    
+    bodyCls : '',
+    /**
+     * @cfg {String} language default en - language of text (usefull for rtl languages)
+     * 
+     */
+    language: 'en',
     
+     
+    // id of frame..
+    frameId: false,
     
+    // private properties
+    validationEvent : false,
+    deferHeight: true,
+    initialized : false,
+    activated : false,
     
+    onFocus : Roo.emptyFn,
+    iframePad:3,
+    hideMode:'offsets',
     
+    actionMode : 'container', // defaults to hiding it...
     
-});
-
-
-// back compat
-Roo.Form = Roo.form.Form;
-/*
- * 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">
- */
-
-// as we use this in bootstrap.
-Roo.namespace('Roo.form');
- /**
- * @class Roo.form.Action
- * Internal Class used to handle form actions
- * @constructor
- * @param {Roo.form.BasicForm} el The form element or its id
- * @param {Object} config Configuration options
- */
-
-// define the action interface
-Roo.form.Action = function(form, options){
-    this.form = form;
-    this.options = options || {};
-};
-/**
- * Client Validation Failed
- * @const 
- */
-Roo.form.Action.CLIENT_INVALID = 'client';
-/**
- * Server Validation Failed
- * @const 
- */
-Roo.form.Action.SERVER_INVALID = 'server';
- /**
- * Connect to Server Failed
- * @const 
- */
-Roo.form.Action.CONNECT_FAILURE = 'connect';
-/**
- * Reading Data from Server Failed
- * @const 
- */
-Roo.form.Action.LOAD_FAILURE = 'load';
-
-Roo.form.Action.prototype = {
-    type : 'default',
-    failureType : undefined,
-    response : undefined,
-    result : undefined,
-
-    // interface method
-    run : function(options){
-
-    },
-
-    // interface method
-    success : function(response){
-
-    },
-
-    // interface method
-    handleResponse : function(response){
-
+    defaultAutoCreate : { // modified by initCompnoent..
+        tag: "textarea",
+        style:"width:500px;height:300px;",
+        autocomplete: "new-password"
     },
 
-    // default connection failure
-    failure : function(response){
-        
-        this.response = response;
-        this.failureType = Roo.form.Action.CONNECT_FAILURE;
-        this.form.afterAction(this, false);
+    // private
+    initComponent : function(){
+        this.addEvents({
+            /**
+             * @event initialize
+             * Fires when the editor is fully initialized (including the iframe)
+             * @param {HtmlEditor} this
+             */
+            initialize: true,
+            /**
+             * @event activate
+             * Fires when the editor is first receives the focus. Any insertion must wait
+             * until after this event.
+             * @param {HtmlEditor} this
+             */
+            activate: true,
+             /**
+             * @event beforesync
+             * Fires before the textarea is updated with content from the editor iframe. Return false
+             * to cancel the sync.
+             * @param {HtmlEditor} this
+             * @param {String} html
+             */
+            beforesync: true,
+             /**
+             * @event beforepush
+             * Fires before the iframe editor is updated with content from the textarea. Return false
+             * to cancel the push.
+             * @param {HtmlEditor} this
+             * @param {String} html
+             */
+            beforepush: true,
+             /**
+             * @event sync
+             * Fires when the textarea is updated with content from the editor iframe.
+             * @param {HtmlEditor} this
+             * @param {String} html
+             */
+            sync: true,
+             /**
+             * @event push
+             * Fires when the iframe editor is updated with content from the textarea.
+             * @param {HtmlEditor} this
+             * @param {String} html
+             */
+            push: true,
+             /**
+             * @event editmodechange
+             * Fires when the editor switches edit modes
+             * @param {HtmlEditor} this
+             * @param {Boolean} sourceEdit True if source edit, false if standard editing.
+             */
+            editmodechange: true,
+            /**
+             * @event editorevent
+             * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
+             * @param {HtmlEditor} this
+             */
+            editorevent: true,
+            /**
+             * @event firstfocus
+             * Fires when on first focus - needed by toolbars..
+             * @param {HtmlEditor} this
+             */
+            firstfocus: true,
+            /**
+             * @event autosave
+             * Auto save the htmlEditor value as a file into Events
+             * @param {HtmlEditor} this
+             */
+            autosave: true,
+            /**
+             * @event savedpreview
+             * preview the saved version of htmlEditor
+             * @param {HtmlEditor} this
+             */
+            savedpreview: true,
+            
+            /**
+            * @event stylesheetsclick
+            * Fires when press the Sytlesheets button
+            * @param {Roo.HtmlEditorCore} this
+            */
+            stylesheetsclick: true,
+            /**
+            * @event paste
+            * Fires when press user pastes into the editor
+            * @param {Roo.HtmlEditorCore} this
+            */
+            paste: true 
+        });
+        this.defaultAutoCreate =  {
+            tag: "textarea",
+            style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
+            autocomplete: "new-password"
+        };
     },
 
-    processResponse : function(response){
-        this.response = response;
-        if(!response.responseText){
-            return true;
+    /**
+     * Protected method that will not generally be called directly. It
+     * is called when the editor creates its toolbar. Override this method if you need to
+     * add custom toolbar buttons.
+     * @param {HtmlEditor} editor
+     */
+    createToolbar : function(editor){
+        Roo.log("create toolbars");
+        if (!editor.toolbars || !editor.toolbars.length) {
+            editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
         }
-        this.result = this.handleResponse(response);
-        return this.result;
-    },
-
-    // utility functions used internally
-    getUrl : function(appendParams){
-        var url = this.options.url || this.form.url || this.form.el.dom.action;
-        if(appendParams){
-            var p = this.getParams();
-            if(p){
-                url += (url.indexOf('?') != -1 ? '&' : '?') + p;
-            }
+        
+        for (var i =0 ; i < editor.toolbars.length;i++) {
+            editor.toolbars[i] = Roo.factory(
+                    typeof(editor.toolbars[i]) == 'string' ?
+                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
+                Roo.form.HtmlEditor);
+            editor.toolbars[i].init(editor);
         }
-        return url;
-    },
-
-    getMethod : function(){
-        return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
+         
+        
     },
-
-    getParams : function(){
-        var bp = this.form.baseParams;
-        var p = this.options.params;
-        if(p){
-            if(typeof p == "object"){
-                p = Roo.urlEncode(Roo.applyIf(p, bp));
-            }else if(typeof p == 'string' && bp){
-                p += '&' + Roo.urlEncode(bp);
-            }
-        }else if(bp){
-            p = Roo.urlEncode(bp);
+    /**
+     * 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 p;
-    },
-
-    createCallback : function(){
-        return {
-            success: this.success,
-            failure: this.failure,
-            scope: this,
-            timeout: (this.form.timeout*1000),
-            upload: this.form.fileUpload ? this.success : undefined
-        };
-    }
-};
-
-Roo.form.Action.Submit = function(form, options){
-    Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
-};
-
-Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
-    type : 'submit',
-
-    haveProgress : false,
-    uploadComplete : false,
+        return this.toolbars[1].tb.selectedNode;
     
-    // uploadProgress indicator.
-    uploadProgress : function()
+    },
+    // private
+    onRender : function(ct, position)
     {
-        if (!this.form.progressUrl) {
-            return;
+        var _t = this;
+        Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
+        
+        this.wrap = this.el.wrap({
+            cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
+        });
+        
+        this.editorcore.onRender(ct, position);
+         
+        if (this.resizable) {
+            this.resizeEl = new Roo.Resizable(this.wrap, {
+                pinned : true,
+                wrap: true,
+                dynamic : true,
+                minHeight : this.height,
+                height: this.height,
+                handles : this.resizable,
+                width: this.width,
+                listeners : {
+                    resize : function(r, w, h) {
+                        _t.onResize(w,h); // -something
+                    }
+                }
+            });
+            
         }
+        this.createToolbar(this);
+       
         
-        if (!this.haveProgress) {
-            Roo.MessageBox.progress("Uploading", "Uploading");
+        if(!this.width){
+            this.setSize(this.wrap.getSize());
         }
-        if (this.uploadComplete) {
-           Roo.MessageBox.hide();
-           return;
+        if (this.resizeEl) {
+            this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
+            // should trigger onReize..
         }
         
-        this.haveProgress = true;
-   
-        var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
-        
-        var c = new Roo.data.Connection();
-        c.request({
-            url : this.form.progressUrl,
-            params: {
-                id : uid
+        this.keyNav = new Roo.KeyNav(this.el, {
+            
+            "tab" : function(e){
+                e.preventDefault();
+                
+                var value = this.getValue();
+                
+                var start = this.el.dom.selectionStart;
+                var end = this.el.dom.selectionEnd;
+                
+                if(!e.shiftKey){
+                    
+                    this.setValue(value.substring(0, start) + "\t" + value.substring(end));
+                    this.el.dom.setSelectionRange(end + 1, end + 1);
+                    return;
+                }
+                
+                var f = value.substring(0, start).split("\t");
+                
+                if(f.pop().length != 0){
+                    return;
+                }
+                
+                this.setValue(f.join("\t") + value.substring(end));
+                this.el.dom.setSelectionRange(start - 1, start - 1);
+                
             },
-            method: 'GET',
-            success : function(req){
-               //console.log(data);
-                var rdata = false;
-                var edata;
-                try  {
-                   rdata = Roo.decode(req.responseText)
-                } catch (e) {
-                    Roo.log("Invalid data from server..");
-                    Roo.log(edata);
+            
+            "home" : function(e){
+                e.preventDefault();
+                
+                var curr = this.el.dom.selectionStart;
+                var lines = this.getValue().split("\n");
+                
+                if(!lines.length){
                     return;
                 }
-                if (!rdata || !rdata.success) {
-                    Roo.log(rdata);
-                    Roo.MessageBox.alert(Roo.encode(rdata));
+                
+                if(e.ctrlKey){
+                    this.el.dom.setSelectionRange(0, 0);
                     return;
                 }
-                var data = rdata.data;
                 
-                if (this.uploadComplete) {
-                   Roo.MessageBox.hide();
-                   return;
+                var pos = 0;
+                
+                for (var i = 0; i < lines.length;i++) {
+                    pos += lines[i].length;
+                    
+                    if(i != 0){
+                        pos += 1;
+                    }
+                    
+                    if(pos < curr){
+                        continue;
+                    }
+                    
+                    pos -= lines[i].length;
+                    
+                    break;
                 }
-                   
-                if (data){
-                    Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
-                       Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
-                    );
+                
+                if(!e.shiftKey){
+                    this.el.dom.setSelectionRange(pos, pos);
+                    return;
                 }
-                this.uploadProgress.defer(2000,this);
+                
+                this.el.dom.selectionStart = pos;
+                this.el.dom.selectionEnd = curr;
             },
-       
-            failure: function(data) {
-                Roo.log('progress url failed ');
-                Roo.log(data);
+            
+            "end" : function(e){
+                e.preventDefault();
+                
+                var curr = this.el.dom.selectionStart;
+                var lines = this.getValue().split("\n");
+                
+                if(!lines.length){
+                    return;
+                }
+                
+                if(e.ctrlKey){
+                    this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
+                    return;
+                }
+                
+                var pos = 0;
+                
+                for (var i = 0; i < lines.length;i++) {
+                    
+                    pos += lines[i].length;
+                    
+                    if(i != 0){
+                        pos += 1;
+                    }
+                    
+                    if(pos < curr){
+                        continue;
+                    }
+                    
+                    break;
+                }
+                
+                if(!e.shiftKey){
+                    this.el.dom.setSelectionRange(pos, pos);
+                    return;
+                }
+                
+                this.el.dom.selectionStart = curr;
+                this.el.dom.selectionEnd = pos;
             },
-            scope : this
+
+            scope : this,
+
+            doRelay : function(foo, bar, hname){
+                return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
+            },
+
+            forceKeyDown: true
         });
-           
+        
+//        if(this.autosave && this.w){
+//            this.autoSaveFn = setInterval(this.autosave, 1000);
+//        }
     },
-    
-    
-    run : function()
+
+    // private
+    onResize : function(w, h)
     {
-        // run get Values on the form, so it syncs any secondary forms.
-        this.form.getValues();
+        Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
+        var ew = false;
+        var eh = false;
         
-        var o = this.options;
-        var method = this.getMethod();
-        var isPost = method == 'POST';
-        if(o.clientValidation === false || this.form.isValid()){
-            
-            if (this.form.progressUrl) {
-                this.form.findField('UPLOAD_IDENTIFIER').setValue(
-                    (new Date() * 1) + '' + Math.random());
-                    
-            } 
-            
-            
-            Roo.Ajax.request(Roo.apply(this.createCallback(), {
-                form:this.form.el.dom,
-                url:this.getUrl(!isPost),
-                method: method,
-                params:isPost ? this.getParams() : null,
-                isUpload: this.form.fileUpload,
-                formData : this.form.formData
-            }));
-            
-            this.uploadProgress();
-
-        }else if (o.clientValidation !== false){ // client validation failed
-            this.failureType = Roo.form.Action.CLIENT_INVALID;
-            this.form.afterAction(this, false);
-        }
-    },
-
-    success : function(response)
-    {
-        this.uploadComplete= true;
-        if (this.haveProgress) {
-            Roo.MessageBox.hide();
+        if(this.el ){
+            if(typeof w == 'number'){
+                var aw = w - this.wrap.getFrameWidth('lr');
+                this.el.setWidth(this.adjustWidth('textarea', aw));
+                ew = aw;
+            }
+            if(typeof h == 'number'){
+                var tbh = 0;
+                for (var i =0; i < this.toolbars.length;i++) {
+                    // fixme - ask toolbars for heights?
+                    tbh += this.toolbars[i].tb.el.getHeight();
+                    if (this.toolbars[i].footer) {
+                        tbh += this.toolbars[i].footer.el.getHeight();
+                    }
+                }
+                
+                
+                
+                
+                var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
+                ah -= 5; // knock a few pixes off for look..
+//                Roo.log(ah);
+                this.el.setHeight(this.adjustWidth('textarea', ah));
+                var eh = ah;
+            }
         }
+        Roo.log('onResize:' + [w,h,ew,eh].join(',') );
+        this.editorcore.onResize(ew,eh);
         
-        
-        var result = this.processResponse(response);
-        if(result === true || result.success){
-            this.form.afterAction(this, true);
-            return;
-        }
-        if(result.errors){
-            this.form.markInvalid(result.errors);
-            this.failureType = Roo.form.Action.SERVER_INVALID;
-        }
-        this.form.afterAction(this, false);
     },
-    failure : function(response)
+
+    /**
+     * Toggles the editor between standard and source edit mode.
+     * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
+     */
+    toggleSourceEdit : function(sourceEditMode)
     {
-        this.uploadComplete= true;
-        if (this.haveProgress) {
-            Roo.MessageBox.hide();
-        }
+        this.editorcore.toggleSourceEdit(sourceEditMode);
         
-        this.response = response;
-        this.failureType = Roo.form.Action.CONNECT_FAILURE;
-        this.form.afterAction(this, false);
-    },
-    
-    handleResponse : function(response){
-        if(this.form.errorReader){
-            var rs = this.form.errorReader.read(response);
-            var errors = [];
-            if(rs.records){
-                for(var i = 0, len = rs.records.length; i < len; i++) {
-                    var r = rs.records[i];
-                    errors[i] = r.data;
+        if(this.editorcore.sourceEditMode){
+            Roo.log('editor - showing textarea');
+            
+//            Roo.log('in');
+//            Roo.log(this.syncValue());
+            this.editorcore.syncValue();
+            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){
+                    this.toolbars[i].tb.hide();
+                    this.toolbars[i].footer.hide();
                 }
             }
-            if(errors.length < 1){
-                errors = null;
+            
+        }else{
+            Roo.log('editor - hiding textarea');
+//            Roo.log('out')
+//            Roo.log(this.pushValue()); 
+            this.editorcore.pushValue();
+            
+            this.el.addClass('x-hidden');
+            this.el.dom.setAttribute('tabIndex', -1);
+            
+            for (var i = 0; i < this.toolbars.length; i++) {
+                if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
+                    this.toolbars[i].tb.show();
+                    this.toolbars[i].footer.show();
+                }
             }
-            return {
-                success : rs.success,
-                errors : errors
-            };
-        }
-        var ret = false;
-        try {
-            ret = Roo.decode(response.responseText);
-        } catch (e) {
-            ret = {
-                success: false,
-                errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
-                errors : []
-            };
+            
+            //this.deferFocus();
         }
-        return ret;
         
-    }
-});
+        this.setSize(this.wrap.getSize());
+        this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
+        
+        this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
+    },
+    // private (for BoxComponent)
+    adjustSize : Roo.BoxComponent.prototype.adjustSize,
 
+    // private (for BoxComponent)
+    getResizeEl : function(){
+        return this.wrap;
+    },
 
-Roo.form.Action.Load = function(form, options){
-    Roo.form.Action.Load.superclass.constructor.call(this, form, options);
-    this.reader = this.form.reader;
-};
+    // private (for BoxComponent)
+    getPositionEl : function(){
+        return this.wrap;
+    },
 
-Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
-    type : 'load',
+    // private
+    initEvents : function(){
+        this.originalValue = this.getValue();
+    },
 
-    run : function(){
+    /**
+     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
+     * @method
+     */
+    markInvalid : Roo.emptyFn,
+    /**
+     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
+     * @method
+     */
+    clearInvalid : Roo.emptyFn,
+
+    setValue : function(v){
+        Roo.form.HtmlEditor.superclass.setValue.call(this, v);
+        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);
+    },
+
+    // doc'ed in Field
+    focus : function(){
+        this.editorcore.focus();
         
-        Roo.Ajax.request(Roo.apply(
-                this.createCallback(), {
-                    method:this.getMethod(),
-                    url:this.getUrl(false),
-                    params:this.getParams()
-        }));
     },
+      
 
-    success : function(response){
+    // private
+    onDestroy : function(){
         
-        var result = this.processResponse(response);
-        if(result === true || !result.success || !result.data){
-            this.failureType = Roo.form.Action.LOAD_FAILURE;
-            this.form.afterAction(this, false);
-            return;
+        
+        
+        if(this.rendered){
+            
+            for (var i =0; i < this.toolbars.length;i++) {
+                // fixme - ask toolbars for heights?
+                this.toolbars[i].onDestroy();
+            }
+            
+            this.wrap.dom.innerHTML = '';
+            this.wrap.remove();
         }
-        this.form.clearInvalid();
-        this.form.setValues(result.data);
-        this.form.afterAction(this, true);
     },
 
-    handleResponse : function(response){
-        if(this.form.reader){
-            var rs = this.form.reader.read(response);
-            var data = rs.records && rs.records[0] ? rs.records[0].data : null;
-            return {
-                success : rs.success,
-                data : data
-            };
+    // private
+    onFirstFocus : function(){
+        //Roo.log("onFirstFocus");
+        this.editorcore.onFirstFocus();
+         for (var i =0; i < this.toolbars.length;i++) {
+            this.toolbars[i].onFirstFocus();
         }
-        return Roo.decode(response.responseText);
-    }
-});
-
-Roo.form.Action.ACTION_TYPES = {
-    'load' : Roo.form.Action.Load,
-    'submit' : Roo.form.Action.Submit
-};/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-/**
- * @class Roo.form.Layout
- * @extends Roo.Component
- * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
- * @constructor
- * @param {Object} config Configuration options
- */
-Roo.form.Layout = function(config){
-    var xitems = [];
-    if (config.items) {
-        xitems = config.items;
-        delete config.items;
+        
+    },
+    
+    // private
+    syncValue : function()
+    {
+        this.editorcore.syncValue();
+    },
+    
+    pushValue : function()
+    {
+        this.editorcore.pushValue();
+    },
+    
+    setStylesheets : function(stylesheets)
+    {
+        this.editorcore.setStylesheets(stylesheets);
+    },
+    
+    removeStylesheets : function()
+    {
+        this.editorcore.removeStylesheets();
     }
-    Roo.form.Layout.superclass.constructor.call(this, config);
-    this.stack = [];
-    Roo.each(xitems, this.addxtype, this);
      
-};
-
-Roo.extend(Roo.form.Layout, Roo.Component, {
+    
+    // hide stuff that is not compatible
     /**
-     * @cfg {String/Object} autoCreate
-     * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
+     * @event blur
+     * @hide
      */
     /**
-     * @cfg {String/Object/Function} style
-     * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
-     * a function which returns such a specification.
+     * @event change
+     * @hide
      */
     /**
-     * @cfg {String} labelAlign
-     * Valid values are "left," "top" and "right" (defaults to "left")
+     * @event focus
+     * @hide
      */
     /**
-     * @cfg {Number} labelWidth
-     * Fixed width in pixels of all field labels (defaults to undefined)
+     * @event specialkey
+     * @hide
      */
     /**
-     * @cfg {Boolean} clear
-     * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
+     * @cfg {String} fieldClass @hide
      */
-    clear : true,
     /**
-     * @cfg {String} labelSeparator
-     * The separator to use after field labels (defaults to ':')
+     * @cfg {String} focusClass @hide
      */
-    labelSeparator : ':',
     /**
-     * @cfg {Boolean} hideLabels
-     * True to suppress the display of field labels in this layout (defaults to false)
+     * @cfg {String} autoCreate @hide
      */
-    hideLabels : false,
-
-    // private
-    defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
-    
-    isLayout : true,
-    
-    // private
-    onRender : function(ct, position){
-        if(this.el){ // from markup
-            this.el = Roo.get(this.el);
-        }else {  // generate
-            var cfg = this.getAutoCreate();
-            this.el = ct.createChild(cfg, position);
-        }
-        if(this.style){
-            this.el.applyStyles(this.style);
-        }
-        if(this.labelAlign){
-            this.el.addClass('x-form-label-'+this.labelAlign);
-        }
-        if(this.hideLabels){
-            this.labelStyle = "display:none";
-            this.elementStyle = "padding-left:0;";
-        }else{
-            if(typeof this.labelWidth == 'number'){
-                this.labelStyle = "width:"+this.labelWidth+"px;";
-                this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
-            }
-            if(this.labelAlign == 'top'){
-                this.labelStyle = "width:auto;";
-                this.elementStyle = "padding-left:0;";
-            }
-        }
-        var stack = this.stack;
-        var slen = stack.length;
-        if(slen > 0){
-            if(!this.fieldTpl){
-                var t = new Roo.Template(
-                    '<div class="x-form-item {5}">',
-                        '<label for="{0}" style="{2}">{1}{4}</label>',
-                        '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
-                        '</div>',
-                    '</div><div class="x-form-clear-left"></div>'
-                );
-                t.disableFormats = true;
-                t.compile();
-                Roo.form.Layout.prototype.fieldTpl = t;
-            }
-            for(var i = 0; i < slen; i++) {
-                if(stack[i].isFormField){
-                    this.renderField(stack[i]);
-                }else{
-                    this.renderComponent(stack[i]);
-                }
-            }
-        }
-        if(this.clear){
-            this.el.createChild({cls:'x-form-clear'});
-        }
-    },
-
-    // private
-    renderField : function(f){
-        f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
-               f.id, //0
-               f.fieldLabel, //1
-               f.labelStyle||this.labelStyle||'', //2
-               this.elementStyle||'', //3
-               typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
-               f.itemCls||this.itemCls||''  //5
-       ], true).getPrevSibling());
-    },
-
-    // private
-    renderComponent : function(c){
-        c.render(c.isLayout ? this.el : this.el.createChild());    
-    },
     /**
-     * Adds a object form elements (using the xtype property as the factory method.)
-     * Valid xtypes are:  TextField, TextArea .... Button, Layout, FieldSet, Column
-     * @param {Object} config 
+     * @cfg {String} inputType @hide
      */
-    addxtype : function(o)
-    {
-        // create the lement.
-        o.form = this.form;
-        var fe = Roo.factory(o, Roo.form);
-        this.form.allItems.push(fe);
-        this.stack.push(fe);
-        
-        if (fe.isFormField) {
-            this.form.items.add(fe);
-        }
-         
-        return fe;
-    }
-});
-
-/**
- * @class Roo.form.Column
- * @extends Roo.form.Layout
- * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
- * @constructor
- * @param {Object} config Configuration options
- */
-Roo.form.Column = function(config){
-    Roo.form.Column.superclass.constructor.call(this, config);
-};
-
-Roo.extend(Roo.form.Column, Roo.form.Layout, {
     /**
-     * @cfg {Number/String} width
-     * The fixed width of the column in pixels or CSS value (defaults to "auto")
+     * @cfg {String} invalidClass @hide
      */
     /**
-     * @cfg {String/Object} autoCreate
-     * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
+     * @cfg {String} invalidText @hide
+     */
+    /**
+     * @cfg {String} msgFx @hide
+     */
+    /**
+     * @cfg {String} validateOnBlur @hide
      */
-
-    // private
-    defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
-
-    // private
-    onRender : function(ct, position){
-        Roo.form.Column.superclass.onRender.call(this, ct, position);
-        if(this.width){
-            this.el.setWidth(this.width);
-        }
-    }
 });
-
+    /*
+ * Based on
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *  
+ */
 
 /**
- * @class Roo.form.Row
- * @extends Roo.form.Layout
- * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
- * @constructor
- * @param {Object} config Configuration options
- */
+ * @class Roo.form.HtmlEditor.ToolbarStandard
+ * Basic Toolbar
 
+ * Usage:
+ *
+ new Roo.form.HtmlEditor({
+    ....
+    toolbars : [
+        new Roo.form.HtmlEditorToolbar1({
+            disable : { fonts: 1 , format: 1, ..., ... , ...],
+            btns : [ .... ]
+        })
+    }
+     
+ * 
+ * @cfg {Object} disable List of elements to disable..
+ * @cfg {Roo.Toolbar.Item|Roo.Toolbar.Button|Roo.Toolbar.SplitButton|Roo.form.Field} btns[] List of additional buttons.
+ * 
+ * 
+ * NEEDS Extra CSS? 
+ * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
+ */
  
-Roo.form.Row = function(config){
-    Roo.form.Row.superclass.constructor.call(this, config);
-};
-Roo.extend(Roo.form.Row, Roo.form.Layout, {
-      /**
-     * @cfg {Number/String} width
-     * The fixed width of the column in pixels or CSS value (defaults to "auto")
-     */
-    /**
-     * @cfg {Number/String} height
-     * The fixed height of the column in pixels or CSS value (defaults to "auto")
-     */
-    defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
+Roo.form.HtmlEditor.ToolbarStandard = function(config)
+{
     
-    padWidth : 20,
-    // private
-    onRender : function(ct, position){
-        //console.log('row render');
-        if(!this.rowTpl){
-            var t = new Roo.Template(
-                '<div class="x-form-item {5}" style="float:left;width:{6}px">',
-                    '<label for="{0}" style="{2}">{1}{4}</label>',
-                    '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
-                    '</div>',
-                '</div>'
-            );
-            t.disableFormats = true;
-            t.compile();
-            Roo.form.Layout.prototype.rowTpl = t;
-        }
-        this.fieldTpl = this.rowTpl;
-        
-        //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
-        var labelWidth = 100;
-        
-        if ((this.labelAlign != 'top')) {
-            if (typeof this.labelWidth == 'number') {
-                labelWidth = this.labelWidth
-            }
-            this.padWidth =  20 + labelWidth;
-            
-        }
-        
-        Roo.form.Column.superclass.onRender.call(this, ct, position);
-        if(this.width){
-            this.el.setWidth(this.width);
-        }
-        if(this.height){
-            this.el.setHeight(this.height);
-        }
-    },
+    Roo.apply(this, config);
     
-    // private
-    renderField : function(f){
-        f.fieldEl = this.fieldTpl.append(this.el, [
-               f.id, f.fieldLabel,
-               f.labelStyle||this.labelStyle||'',
-               this.elementStyle||'',
-               typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
-               f.itemCls||this.itemCls||'',
-               f.width ? f.width + this.padWidth : 160 + this.padWidth
-       ],true);
-    }
-});
-
-/**
- * @class Roo.form.FieldSet
- * @extends Roo.form.Layout
- * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
- * @constructor
- * @param {Object} config Configuration options
- */
-Roo.form.FieldSet = function(config){
-    Roo.form.FieldSet.superclass.constructor.call(this, config);
-};
-
-Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
-    /**
-     * @cfg {String} legend
-     * The text to display as the legend for the FieldSet (defaults to '')
-     */
-    /**
-     * @cfg {String/Object} autoCreate
-     * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
-     */
-
-    // private
-    defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
-
-    // private
-    onRender : function(ct, position){
-        Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
-        if(this.legend){
-            this.setLegend(this.legend);
-        }
-    },
-
-    // private
-    setLegend : function(text){
-        if(this.rendered){
-            this.el.child('legend').update(text);
-        }
-    }
-});/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-/**
- * @class Roo.form.VTypes
- * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
- * @singleton
- */
-Roo.form.VTypes = function(){
-    // closure these in so they are only created once.
-    var alpha = /^[a-zA-Z_]+$/;
-    var alphanum = /^[a-zA-Z0-9_]+$/;
-    var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
-    var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
-
-    // All these messages and functions are configurable
-    return {
-        /**
-         * The function used to validate email addresses
-         * @param {String} value The email address
-         */
-        'email' : function(v){
-            return email.test(v);
-        },
-        /**
-         * The error text to display when the email validation function returns false
-         * @type String
-         */
-        'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
-        /**
-         * The keystroke filter mask to be applied on email input
-         * @type RegExp
-         */
-        'emailMask' : /[a-z0-9_\.\-@]/i,
-
-        /**
-         * The function used to validate URLs
-         * @param {String} value The URL
-         */
-        'url' : function(v){
-            return url.test(v);
-        },
-        /**
-         * The error text to display when the url validation function returns false
-         * @type String
-         */
-        'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
-        
-        /**
-         * The function used to validate alpha values
-         * @param {String} value The value
-         */
-        'alpha' : function(v){
-            return alpha.test(v);
-        },
-        /**
-         * The error text to display when the alpha validation function returns false
-         * @type String
-         */
-        'alphaText' : 'This field should only contain letters and _',
-        /**
-         * The keystroke filter mask to be applied on alpha input
-         * @type RegExp
-         */
-        'alphaMask' : /[a-z_]/i,
-
-        /**
-         * The function used to validate alphanumeric values
-         * @param {String} value The value
-         */
-        'alphanum' : function(v){
-            return alphanum.test(v);
-        },
-        /**
-         * The error text to display when the alphanumeric validation function returns false
-         * @type String
-         */
-        'alphanumText' : 'This field should only contain letters, numbers and _',
-        /**
-         * The keystroke filter mask to be applied on alphanumeric input
-         * @type RegExp
-         */
-        'alphanumMask' : /[a-z0-9_]/i
-    };
-}();//<script type="text/javascript">
-
-/**
- * @class Roo.form.FCKeditor
- * @extends Roo.form.TextArea
- * Wrapper around the FCKEditor http://www.fckeditor.net
- * @constructor
- * Creates a new FCKeditor
- * @param {Object} config Configuration options
- */
-Roo.form.FCKeditor = function(config){
-    Roo.form.FCKeditor.superclass.constructor.call(this, config);
-    this.addEvents({
-         /**
-         * @event editorinit
-         * Fired when the editor is initialized - you can add extra handlers here..
-         * @param {FCKeditor} this
-         * @param {Object} the FCK object.
-         */
-        editorinit : true
+    // default disabled, based on 'good practice'..
+    this.disable = this.disable || {};
+    Roo.applyIf(this.disable, {
+        fontSize : true,
+        colors : true,
+        specialElements : true
     });
     
     
-};
-Roo.form.FCKeditor.editors = { };
-Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
-{
-    //defaultAutoCreate : {
-    //    tag : "textarea",style   : "width:100px;height:60px;" ,autocomplete    : "off"
-    //},
-    // private
+    //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
+    // dont call parent... till later.
+}
+
+Roo.form.HtmlEditor.ToolbarStandard.prototype = {
+    
+    tb: false,
+    
+    rendered: false,
+    
+    editor : false,
+    editorcore : false,
     /**
-     * @cfg {Object} fck options - see fck manual for details.
+     * @cfg {Object} disable  List of toolbar elements to disable
+         
      */
-    fckconfig : false,
+    disable : false,
     
-    /**
-     * @cfg {Object} fck toolbar set (Basic or Default)
+    
+     /**
+     * @cfg {String} createLinkText The default text for the create link prompt
      */
-    toolbarSet : 'Basic',
+    createLinkText : 'Please enter the URL for the link:',
     /**
-     * @cfg {Object} fck BasePath
-     */ 
-    basePath : '/fckeditor/',
-    
+     * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
+     */
+    defaultLinkValue : 'http:/'+'/',
+   
     
-    frame : false,
+      /**
+     * @cfg {Array} fontFamilies An array of available font families
+     */
+    fontFamilies : [
+        'Arial',
+        'Courier New',
+        'Tahoma',
+        'Times New Roman',
+        'Verdana'
+    ],
     
-    value : '',
+    specialChars : [
+           "&#169;",
+          "&#174;",     
+          "&#8482;",    
+          "&#163;" ,    
+         // "&#8212;",    
+          "&#8230;",    
+          "&#247;" ,    
+        //  "&#225;" ,     ?? a acute?
+           "&#8364;"    , //Euro
+       //   "&#8220;"    ,
+        //  "&#8221;"    ,
+        //  "&#8226;"    ,
+          "&#176;"  //   , // degrees
+
+         // "&#233;"     , // e ecute
+         // "&#250;"     , // u ecute?
+    ],
     
-   
-    onRender : function(ct, position)
-    {
-        if(!this.el){
-            this.defaultAutoCreate = {
-                tag: "textarea",
-                style:"width:300px;height:60px;",
-                autocomplete: "new-password"
-            };
-        }
-        Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
-        /*
-        if(this.grow){
-            this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
-            if(this.preventScrollbars){
-                this.el.setStyle("overflow", "hidden");
-            }
-            this.el.setHeight(this.growMin);
+    specialElements : [
+        {
+            text: "Insert Table",
+            xtype: 'MenuItem',
+            xns : Roo.Menu,
+            ihtml :  '<table><tr><td>Cell</td></tr></table>' 
+                
+        },
+        {    
+            text: "Insert Image",
+            xtype: 'MenuItem',
+            xns : Roo.Menu,
+            ihtml : '<img src="about:blank"/>'
+            
         }
-        */
-        //console.log('onrender' + this.getId() );
-        Roo.form.FCKeditor.editors[this.getId()] = this;
-         
-
-        this.replaceTextarea() ;
         
-    },
+         
+    ],
     
-    getEditor : function() {
-        return this.fckEditor;
-    },
-    /**
-     * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
-     * @param {Mixed} value The value to set
+    
+    inputElements : [ 
+            "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password", 
+            "input:submit", "input:button", "select", "textarea", "label" ],
+    formats : [
+        ["p"] ,  
+        ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"], 
+        ["pre"],[ "code"], 
+        ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
+        ['div'],['span'],
+        ['sup'],['sub']
+    ],
+    
+    cleanStyles : [
+        "font-size"
+    ],
+     /**
+     * @cfg {String} defaultFont default font to use.
      */
+    defaultFont: 'tahoma',
+   
+    fontSelect : false,
     
     
-    setValue : function(value)
+    formatCombo : false,
+    
+    init : function(editor)
     {
-        //console.log('setValue: ' + value);
-        
-        if(typeof(value) == 'undefined') { // not sure why this is happending...
-            return;
-        }
-        Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
-        
-        //if(!this.el || !this.getEditor()) {
-        //    this.value = value;
-            //this.setValue.defer(100,this,[value]);    
-        //    return;
-        //} 
-        
-        if(!this.getEditor()) {
-            return;
-        }
-        
-        this.getEditor().SetData(value);
+        this.editor = editor;
+        this.editorcore = editor.editorcore ? editor.editorcore : editor;
+        var editorcore = this.editorcore;
         
-        //
-
-    },
-
-    /**
-     * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
-     * @return {Mixed} value The field value
-     */
-    getValue : function()
-    {
+        var _t = this;
         
-        if (this.frame && this.frame.dom.style.display == 'none') {
-            return Roo.form.FCKeditor.superclass.getValue.call(this);
+        var fid = editorcore.frameId;
+        var etb = this;
+        function btn(id, toggle, handler){
+            var xid = fid + '-'+ id ;
+            return {
+                id : xid,
+                cmd : id,
+                cls : 'x-btn-icon x-edit-'+id,
+                enableToggle:toggle !== false,
+                scope: _t, // was editor...
+                handler:handler||_t.relayBtnCmd,
+                clickEvent:'mousedown',
+                tooltip: etb.buttonTips[id] || undefined, ///tips ???
+                tabIndex:-1
+            };
         }
         
-        if(!this.el || !this.getEditor()) {
-           
-           // this.getValue.defer(100,this); 
-            return this.value;
-        }
-       
         
-        var value=this.getEditor().GetData();
-        Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
-        return Roo.form.FCKeditor.superclass.getValue.call(this);
         
+        var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
+        this.tb = tb;
+         // stop form submits
+        tb.el.on('click', function(e){
+            e.preventDefault(); // what does this do?
+        });
 
-    },
+        if(!this.disable.font) { // && !Roo.isSafari){
+            /* why no safari for fonts 
+            editor.fontSelect = tb.el.createChild({
+                tag:'select',
+                tabIndex: -1,
+                cls:'x-font-select',
+                html: this.createFontOptions()
+            });
+            
+            editor.fontSelect.on('change', function(){
+                var font = editor.fontSelect.dom.value;
+                editor.relayCmd('fontname', font);
+                editor.deferFocus();
+            }, editor);
+            
+            tb.add(
+                editor.fontSelect.dom,
+                '-'
+            );
+            */
+            
+        };
+        if(!this.disable.formats){
+            this.formatCombo = new Roo.form.ComboBox({
+                store: new Roo.data.SimpleStore({
+                    id : 'tag',
+                    fields: ['tag'],
+                    data : this.formats // from states.js
+                }),
+                blockFocus : true,
+                name : '',
+                //autoCreate : {tag: "div",  size: "20"},
+                displayField:'tag',
+                typeAhead: false,
+                mode: 'local',
+                editable : false,
+                triggerAction: 'all',
+                emptyText:'Add tag',
+                selectOnFocus:true,
+                width:135,
+                listeners : {
+                    'select': function(c, r, i) {
+                        editorcore.insertTag(r.get('tag'));
+                        editor.focus();
+                    }
+                }
 
-    /**
-     * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
-     * @return {Mixed} value The field value
-     */
-    getRawValue : function()
-    {
-        if (this.frame && this.frame.dom.style.display == 'none') {
-            return Roo.form.FCKeditor.superclass.getRawValue.call(this);
+            });
+            tb.addField(this.formatCombo);
+            
         }
         
-        if(!this.el || !this.getEditor()) {
-            //this.getRawValue.defer(100,this); 
-            return this.value;
-            return;
-        }
+        if(!this.disable.format){
+            tb.add(
+                btn('bold'),
+                btn('italic'),
+                btn('underline'),
+                btn('strikethrough')
+            );
+        };
+        if(!this.disable.fontSize){
+            tb.add(
+                '-',
+                
+                
+                btn('increasefontsize', false, editorcore.adjustFont),
+                btn('decreasefontsize', false, editorcore.adjustFont)
+            );
+        };
         
         
+        if(!this.disable.colors){
+            tb.add(
+                '-', {
+                    id:editorcore.frameId +'-forecolor',
+                    cls:'x-btn-icon x-edit-forecolor',
+                    clickEvent:'mousedown',
+                    tooltip: this.buttonTips['forecolor'] || undefined,
+                    tabIndex:-1,
+                    menu : new Roo.menu.ColorMenu({
+                        allowReselect: true,
+                        focus: Roo.emptyFn,
+                        value:'000000',
+                        plain:true,
+                        selectHandler: function(cp, color){
+                            editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
+                            editor.deferFocus();
+                        },
+                        scope: editorcore,
+                        clickEvent:'mousedown'
+                    })
+                }, {
+                    id:editorcore.frameId +'backcolor',
+                    cls:'x-btn-icon x-edit-backcolor',
+                    clickEvent:'mousedown',
+                    tooltip: this.buttonTips['backcolor'] || undefined,
+                    tabIndex:-1,
+                    menu : new Roo.menu.ColorMenu({
+                        focus: Roo.emptyFn,
+                        value:'FFFFFF',
+                        plain:true,
+                        allowReselect: true,
+                        selectHandler: function(cp, color){
+                            if(Roo.isGecko){
+                                editorcore.execCmd('useCSS', false);
+                                editorcore.execCmd('hilitecolor', color);
+                                editorcore.execCmd('useCSS', true);
+                                editor.deferFocus();
+                            }else{
+                                editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor', 
+                                    Roo.isSafari || Roo.isIE ? '#'+color : color);
+                                editor.deferFocus();
+                            }
+                        },
+                        scope:editorcore,
+                        clickEvent:'mousedown'
+                    })
+                }
+            );
+        };
+        // now add all the items...
         
-        var value=this.getEditor().GetData();
-        Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
-        return Roo.form.FCKeditor.superclass.getRawValue.call(this);
-         
-    },
-    
-    setSize : function(w,h) {
-        
-        
-        
-        //if (this.frame && this.frame.dom.style.display == 'none') {
-        //    Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
-        //    return;
-        //}
-        //if(!this.el || !this.getEditor()) {
-        //    this.setSize.defer(100,this, [w,h]); 
-        //    return;
+
+        if(!this.disable.alignments){
+            tb.add(
+                '-',
+                btn('justifyleft'),
+                btn('justifycenter'),
+                btn('justifyright')
+            );
+        };
+
+        //if(!Roo.isSafari){
+            if(!this.disable.links){
+                tb.add(
+                    '-',
+                    btn('createlink', false, this.createLink)    /// MOVE TO HERE?!!?!?!?!
+                );
+            };
+
+            if(!this.disable.lists){
+                tb.add(
+                    '-',
+                    btn('insertorderedlist'),
+                    btn('insertunorderedlist')
+                );
+            }
+            if(!this.disable.sourceEdit){
+                tb.add(
+                    '-',
+                    btn('sourceedit', true, function(btn){
+                        this.toggleSourceEdit(btn.pressed);
+                    })
+                );
+            }
         //}
         
+        var smenu = { };
+        // special menu.. - needs to be tidied up..
+        if (!this.disable.special) {
+            smenu = {
+                text: "&#169;",
+                cls: 'x-edit-none',
+                
+                menu : {
+                    items : []
+                }
+            };
+            for (var i =0; i < this.specialChars.length; i++) {
+                smenu.menu.items.push({
+                    
+                    html: this.specialChars[i],
+                    handler: function(a,b) {
+                        editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
+                        //editor.insertAtCursor(a.html);
+                        
+                    },
+                    tabIndex:-1
+                });
+            }
+            
+            
+            tb.add(smenu);
+            
+            
+        }
         
-        
-        Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
-        
-        this.frame.dom.setAttribute('width', w);
-        this.frame.dom.setAttribute('height', h);
-        this.frame.setSize(w,h);
-        
-    },
-    
-    toggleSourceEdit : function(value) {
-        
-      
+        var cmenu = { };
+        if (!this.disable.cleanStyles) {
+            cmenu = {
+                cls: 'x-btn-icon x-btn-clear',
+                
+                menu : {
+                    items : []
+                }
+            };
+            for (var i =0; i < this.cleanStyles.length; i++) {
+                cmenu.menu.items.push({
+                    actiontype : this.cleanStyles[i],
+                    html: 'Remove ' + this.cleanStyles[i],
+                    handler: function(a,b) {
+//                        Roo.log(a);
+//                        Roo.log(b);
+                        var c = Roo.get(editorcore.doc.body);
+                        c.select('[style]').each(function(s) {
+                            s.dom.style.removeProperty(a.actiontype);
+                        });
+                        editorcore.syncValue();
+                    },
+                    tabIndex:-1
+                });
+            }
+            cmenu.menu.items.push({
+                actiontype : 'tablewidths',
+                html: 'Remove Table Widths',
+                handler: function(a,b) {
+                    editorcore.cleanTableWidths();
+                    editorcore.syncValue();
+                },
+                tabIndex:-1
+            });
+            cmenu.menu.items.push({
+                actiontype : 'word',
+                html: 'Remove MS Word Formating',
+                handler: function(a,b) {
+                    editorcore.cleanWord();
+                    editorcore.syncValue();
+                },
+                tabIndex:-1
+            });
+            
+            cmenu.menu.items.push({
+                actiontype : 'all',
+                html: 'Remove All Styles',
+                handler: function(a,b) {
+                    
+                    var c = Roo.get(editorcore.doc.body);
+                    c.select('[style]').each(function(s) {
+                        s.dom.removeAttribute('style');
+                    });
+                    editorcore.syncValue();
+                },
+                tabIndex:-1
+            });
+            
+            cmenu.menu.items.push({
+                actiontype : 'all',
+                html: 'Remove All CSS Classes',
+                handler: function(a,b) {
+                    
+                    var c = Roo.get(editorcore.doc.body);
+                    c.select('[class]').each(function(s) {
+                        s.dom.removeAttribute('class');
+                    });
+                    editorcore.cleanWord();
+                    editorcore.syncValue();
+                },
+                tabIndex:-1
+            });
+            
+             cmenu.menu.items.push({
+                actiontype : 'tidy',
+                html: 'Tidy HTML Source',
+                handler: function(a,b) {
+                    new Roo.htmleditor.Tidy(editorcore.doc.body);
+                    editorcore.syncValue();
+                },
+                tabIndex:-1
+            });
+            
+            
+            tb.add(cmenu);
+        }
          
-        this.el.dom.style.display = value ? '' : 'none';
-        this.frame.dom.style.display = value ?  'none' : '';
-        
-    },
-    
-    
-    focus: function(tag)
-    {
-        if (this.frame.dom.style.display == 'none') {
-            return Roo.form.FCKeditor.superclass.focus.call(this);
+        if (!this.disable.specialElements) {
+            var semenu = {
+                text: "Other;",
+                cls: 'x-edit-none',
+                menu : {
+                    items : []
+                }
+            };
+            for (var i =0; i < this.specialElements.length; i++) {
+                semenu.menu.items.push(
+                    Roo.apply({ 
+                        handler: function(a,b) {
+                            editor.insertAtCursor(this.ihtml);
+                        }
+                    }, this.specialElements[i])
+                );
+                    
+            }
+            
+            tb.add(semenu);
+            
+            
         }
-        if(!this.el || !this.getEditor()) {
-            this.focus.defer(100,this, [tag]); 
-            return;
+         
+        
+        if (this.btns) {
+            for(var i =0; i< this.btns.length;i++) {
+                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){
+                    b.cls += ' x-init-enable';
+                }
+                
+                b.scope = editorcore;
+                tb.add(b);
+            }
+        
         }
         
         
         
+        // disable everything...
         
-        var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
-        this.getEditor().Focus();
-        if (tgs.length) {
-            if (!this.getEditor().Selection.GetSelection()) {
-                this.focus.defer(100,this, [tag]); 
-                return;
-            }
-            
+        this.tb.items.each(function(item){
             
-            var r = this.getEditor().EditorDocument.createRange();
-            r.setStart(tgs[0],0);
-            r.setEnd(tgs[0],0);
-            this.getEditor().Selection.GetSelection().removeAllRanges();
-            this.getEditor().Selection.GetSelection().addRange(r);
-            this.getEditor().Focus();
-        }
+           if(
+                item.id != editorcore.frameId+ '-sourceedit' && 
+                (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
+            ){
+                
+                item.disable();
+            }
+        });
+        this.rendered = true;
         
+        // the all the btns;
+        editor.on('editorevent', this.updateToolbar, this);
+        // other toolbars need to implement this..
+        //editor.on('editmodechange', this.updateToolbar, this);
     },
     
     
-    
-    replaceTextarea : function()
-    {
-        if ( document.getElementById( this.getId() + '___Frame' ) ) {
-            return ;
-        }
-        //if ( !this.checkBrowser || this._isCompatibleBrowser() )
-        //{
-            // We must check the elements firstly using the Id and then the name.
-        var oTextarea = document.getElementById( this.getId() );
-        
-        var colElementsByName = document.getElementsByName( this.getId() ) ;
-         
-        oTextarea.style.display = 'none' ;
-
-        if ( oTextarea.tabIndex ) {            
-            this.TabIndex = oTextarea.tabIndex ;
-        }
-        
-        this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
-        this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
-        this.frame = Roo.get(this.getId() + '___Frame')
-    },
-    
-    _getConfigHtml : function()
-    {
-        var sConfig = '' ;
-
-        for ( var o in this.fckconfig ) {
-            sConfig += sConfig.length > 0  ? '&amp;' : '';
-            sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
-        }
-
-        return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
+    relayBtnCmd : function(btn) {
+        this.editorcore.relayCmd(btn.cmd);
     },
-    
-    
-    _getIFrameHtml : function()
-    {
-        var sFile = 'fckeditor.html' ;
-        /* no idea what this is about..
-        try
-        {
-            if ( (/fcksource=true/i).test( window.top.location.search ) )
-                sFile = 'fckeditor.original.html' ;
+    // private used internally
+    createLink : function(){
+        //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;
+            }
         }
-        catch (e) { 
-        */
-
-        var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
-        sLink += this.toolbarSet ? ( '&amp;Toolbar=' + this.toolbarSet)  : '';
         
+        (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.
         
-        var html = '<iframe id="' + this.getId() +
-            '___Frame" src="' + sLink +
-            '" width="' + this.width +
-            '" height="' + this.height + '"' +
-            (this.tabIndex ?  ' tabindex="' + this.tabIndex + '"' :'' ) +
-            ' frameborder="0" scrolling="no"></iframe>' ;
-
-        return html ;
     },
-    
-    _insertHtmlBefore : function( html, element )
-    {
-        if ( element.insertAdjacentHTML )      {
-            // IE
-            element.insertAdjacentHTML( 'beforeBegin', html ) ;
-        } else { // Gecko
-            var oRange = document.createRange() ;
-            oRange.setStartBefore( element ) ;
-            var oFragment = oRange.createContextualFragment( html );
-            element.parentNode.insertBefore( oFragment, element ) ;
-        }
-    }
-    
-    
-  
-    
-    
-    
-    
-
-});
-
-//Roo.reg('fckeditor', Roo.form.FCKeditor);
-
-function FCKeditor_OnComplete(editorInstance){
-    var f = Roo.form.FCKeditor.editors[editorInstance.Name];
-    f.fckEditor = editorInstance;
-    //console.log("loaded");
-    f.fireEvent('editorinit', f, editorInstance);
-} 
-  
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-//<script type="text/javascript">
-/**
- * @class Roo.form.GridField
- * @extends Roo.form.Field
- * Embed a grid (or editable grid into a form)
- * STATUS ALPHA
- * 
- * This embeds a grid in a form, the value of the field should be the json encoded array of rows
- * it needs 
- * xgrid.store = Roo.data.Store
- * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
- * xgrid.store.reader = Roo.data.JsonReader 
- * 
- * 
- * @constructor
- * Creates a new GridField
- * @param {Object} config Configuration options
- */
-Roo.form.GridField = function(config){
-    Roo.form.GridField.superclass.constructor.call(this, config);
-     
-};
 
-Roo.extend(Roo.form.GridField, Roo.form.Field,  {
-    /**
-     * @cfg {Number} width  - used to restrict width of grid..
-     */
-    width : 100,
-    /**
-     * @cfg {Number} height - used to restrict height of grid..
-     */
-    height : 50,
-     /**
-     * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
-         * 
-         *}
-     */
-    xgrid : false, 
-    /**
-     * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
-     * {tag: "input", type: "checkbox", autocomplete: "off"})
-     */
-   // defaultAutoCreate : { tag: 'div' },
-    defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
+    
     /**
-     * @cfg {String} addTitle Text to include for adding a title.
+     * Protected method that will not generally be called directly. It triggers
+     * a toolbar update by reading the markup state of the current selection in the editor.
      */
-    addTitle : false,
-    //
-    onResize : function(){
-        Roo.form.Field.superclass.onResize.apply(this, arguments);
-    },
-
-    initEvents : function(){
-        // Roo.form.Checkbox.superclass.initEvents.call(this);
-        // has no events...
-       
-    },
-
+    updateToolbar: function(){
 
-    getResizeEl : function(){
-        return this.wrap;
-    },
+        if(!this.editorcore.activated){
+            this.editor.onFirstFocus();
+            return;
+        }
 
-    getPositionEl : function(){
-        return this.wrap;
-    },
+        var btns = this.tb.items.map, 
+            doc = this.editorcore.doc,
+            frameId = this.editorcore.frameId;
 
-    // private
-    onRender : function(ct, position){
-        
-        this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
-        var style = this.style;
-        delete this.style;
-        
-        Roo.form.GridField.superclass.onRender.call(this, ct, position);
-        this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
-        this.viewEl = this.wrap.createChild({ tag: 'div' });
-        if (style) {
-            this.viewEl.applyStyles(style);
+        if(!this.disable.font && !Roo.isSafari){
+            /*
+            var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
+            if(name != this.fontSelect.dom.value){
+                this.fontSelect.dom.value = name;
+            }
+            */
         }
-        if (this.width) {
-            this.viewEl.setWidth(this.width);
+        if(!this.disable.format){
+            btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
+            btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
+            btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
+            btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
         }
-        if (this.height) {
-            this.viewEl.setHeight(this.height);
+        if(!this.disable.alignments){
+            btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
+            btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
+            btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
+        }
+        if(!Roo.isSafari && !this.disable.lists){
+            btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
+            btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
         }
-        //if(this.inputValue !== undefined){
-        //this.setValue(this.value);
         
+        var ans = this.editorcore.getAllAncestors();
+        if (this.formatCombo) {
+            
+            
+            var store = this.formatCombo.store;
+            this.formatCombo.setValue("");
+            for (var i =0; i < ans.length;i++) {
+                if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
+                    // select it..
+                    this.formatCombo.setValue(ans[i].tagName.toLowerCase());
+                    break;
+                }
+            }
+        }
         
-        this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
         
         
-        this.grid.render();
-        this.grid.getDataSource().on('remove', this.refreshValue, this);
-        this.grid.getDataSource().on('update', this.refreshValue, this);
-        this.grid.on('afteredit', this.refreshValue, this);
-    },
-     
+        // hides menus... - so this cant be on a menu...
+        Roo.menu.MenuMgr.hideAll();
+
+        //this.editorsyncValue();
+    },
+   
     
-    /**
-     * Sets the value of the item. 
-     * @param {String} either an object  or a string..
-     */
-    setValue : function(v){
-        //this.value = v;
-        v = v || []; // empty set..
-        // this does not seem smart - it really only affects memoryproxy grids..
-        if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
-            var ds = this.grid.getDataSource();
-            // assumes a json reader..
-            var data = {}
-            data[ds.reader.meta.root ] =  typeof(v) == 'string' ? Roo.decode(v) : v;
-            ds.loadData( data);
+    createFontOptions : function(){
+        var buf = [], fs = this.fontFamilies, ff, lc;
+        
+        
+        
+        for(var i = 0, len = fs.length; i< len; i++){
+            ff = fs[i];
+            lc = ff.toLowerCase();
+            buf.push(
+                '<option value="',lc,'" style="font-family:',ff,';"',
+                    (this.defaultFont == lc ? ' selected="true">' : '>'),
+                    ff,
+                '</option>'
+            );
         }
-        // clear selection so it does not get stale.
-        if (this.grid.sm) { 
-            this.grid.sm.clearSelections();
+        return buf.join('');
+    },
+    
+    toggleSourceEdit : function(sourceEditMode){
+        
+        Roo.log("toolbar toogle");
+        if(sourceEditMode === undefined){
+            sourceEditMode = !this.sourceEditMode;
+        }
+        this.sourceEditMode = sourceEditMode === true;
+        var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
+        // just toggle the button?
+        if(btn.pressed !== this.sourceEditMode){
+            btn.toggle(this.sourceEditMode);
+            return;
         }
         
-        Roo.form.GridField.superclass.setValue.call(this, v);
-        this.refreshValue();
-        // should load data in the grid really....
+        if(sourceEditMode){
+            Roo.log("disabling buttons");
+            this.tb.items.each(function(item){
+                if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
+                    item.disable();
+                }
+            });
+          
+        }else{
+            Roo.log("enabling buttons");
+            if(this.editorcore.initialized){
+                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);
+            
+            }
+            
+        }
+        Roo.log("calling toggole on editor");
+        // tell the editor that it's been pressed..
+        this.editor.toggleSourceEdit(sourceEditMode);
+       
+    },
+     /**
+     * Object collection of toolbar tooltips for the buttons in the editor. The key
+     * is the command id associated with that button and the value is a valid QuickTips object.
+     * For example:
+<pre><code>
+{
+    bold : {
+        title: 'Bold (Ctrl+B)',
+        text: 'Make the selected text bold.',
+        cls: 'x-html-editor-tip'
+    },
+    italic : {
+        title: 'Italic (Ctrl+I)',
+        text: 'Make the selected text italic.',
+        cls: 'x-html-editor-tip'
+    },
+    ...
+</code></pre>
+    * @type Object
+     */
+    buttonTips : {
+        bold : {
+            title: 'Bold (Ctrl+B)',
+            text: 'Make the selected text bold.',
+            cls: 'x-html-editor-tip'
+        },
+        italic : {
+            title: 'Italic (Ctrl+I)',
+            text: 'Make the selected text italic.',
+            cls: 'x-html-editor-tip'
+        },
+        underline : {
+            title: 'Underline (Ctrl+U)',
+            text: 'Underline the selected text.',
+            cls: 'x-html-editor-tip'
+        },
+        strikethrough : {
+            title: 'Strikethrough',
+            text: 'Strikethrough the selected text.',
+            cls: 'x-html-editor-tip'
+        },
+        increasefontsize : {
+            title: 'Grow Text',
+            text: 'Increase the font size.',
+            cls: 'x-html-editor-tip'
+        },
+        decreasefontsize : {
+            title: 'Shrink Text',
+            text: 'Decrease the font size.',
+            cls: 'x-html-editor-tip'
+        },
+        backcolor : {
+            title: 'Text Highlight Color',
+            text: 'Change the background color of the selected text.',
+            cls: 'x-html-editor-tip'
+        },
+        forecolor : {
+            title: 'Font Color',
+            text: 'Change the color of the selected text.',
+            cls: 'x-html-editor-tip'
+        },
+        justifyleft : {
+            title: 'Align Text Left',
+            text: 'Align text to the left.',
+            cls: 'x-html-editor-tip'
+        },
+        justifycenter : {
+            title: 'Center Text',
+            text: 'Center text in the editor.',
+            cls: 'x-html-editor-tip'
+        },
+        justifyright : {
+            title: 'Align Text Right',
+            text: 'Align text to the right.',
+            cls: 'x-html-editor-tip'
+        },
+        insertunorderedlist : {
+            title: 'Bullet List',
+            text: 'Start a bulleted list.',
+            cls: 'x-html-editor-tip'
+        },
+        insertorderedlist : {
+            title: 'Numbered List',
+            text: 'Start a numbered list.',
+            cls: 'x-html-editor-tip'
+        },
+        createlink : {
+            title: 'Hyperlink',
+            text: 'Make the selected text a hyperlink.',
+            cls: 'x-html-editor-tip'
+        },
+        sourceedit : {
+            title: 'Source Edit',
+            text: 'Switch to source editing mode.',
+            cls: 'x-html-editor-tip'
+        }
     },
-    
     // private
-    refreshValue: function() {
-         var val = [];
-        this.grid.getDataSource().each(function(r) {
-            val.push(r.data);
+    onDestroy : function(){
+        if(this.rendered){
+            
+            this.tb.items.each(function(item){
+                if(item.menu){
+                    item.menu.removeAll();
+                    if(item.menu.el){
+                        item.menu.el.destroy();
+                    }
+                }
+                item.destroy();
+            });
+             
+        }
+    },
+    onFirstFocus: function() {
+        this.tb.items.each(function(item){
+           item.enable();
         });
-        this.el.dom.value = Roo.encode(val);
     }
-    
-     
-    
-    
-});/*
- * Based on:
+};
+
+
+
+
+// <script type="text/javascript">
+/*
+ * Based on
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
+ *  
  */
+
 /**
- * @class Roo.form.DisplayField
- * @extends Roo.form.Field
- * A generic Field to display non-editable data.
- * @cfg {Boolean} closable (true|false) default false
- * @constructor
- * Creates a new Display Field item.
- * @param {Object} config Configuration options
+ * @class Roo.form.HtmlEditor.ToolbarContext
+ * Context Toolbar
+ * 
+ * Usage:
+ *
+ new Roo.form.HtmlEditor({
+    ....
+    toolbars : [
+        { xtype: 'ToolbarStandard', styles : {} }
+        { xtype: 'ToolbarContext', disable : {} }
+    ]
+})
+
+     
+ * 
+ * @config : {Object} disable List of elements to disable.. (not done yet.)
+ * @config : {Object} styles  Map of styles available.
+ * 
  */
-Roo.form.DisplayField = function(config){
-    Roo.form.DisplayField.superclass.constructor.call(this, config);
-    
-    this.addEvents({
-        /**
-         * @event close
-         * Fires after the click the close btn
-            * @param {Roo.form.DisplayField} this
-            */
-        close : true
-    });
-};
 
-Roo.extend(Roo.form.DisplayField, Roo.form.TextField,  {
-    inputType:      'hidden',
-    allowBlank:     true,
-    readOnly:         true,
-    
-    /**
-     * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
-     */
-    focusClass : undefined,
-    /**
-     * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
-     */
-    fieldClass: 'x-form-field',
-    
-     /**
-     * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
-     */
-    valueRenderer: undefined,
+Roo.form.HtmlEditor.ToolbarContext = function(config)
+{
     
-    width: 100,
-    /**
-     * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
-     * {tag: "input", type: "checkbox", autocomplete: "off"})
-     */
-     
- //   defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
+    Roo.apply(this, config);
+    //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
+    // dont call parent... till later.
+    this.styles = this.styles || {};
+}
+
  
-    closable : false,
-    
-    onResize : function(){
-        Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
-        
-    },
 
-    initEvents : function(){
-        // Roo.form.Checkbox.superclass.initEvents.call(this);
-        // has no events...
-        
-        if(this.closable){
-            this.closeEl.on('click', this.onClose, this);
+Roo.form.HtmlEditor.ToolbarContext.types = {
+    'IMG' : [
+        {
+            name : 'width',
+            title: "Width",
+            width: 40
+        },
+        {
+            name : 'height',
+            title: "Height",
+            width: 40
+        },
+        {
+            name : 'align',
+            title: "Align",
+            opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
+            width : 80
+            
+        },
+        {
+            name : 'border',
+            title: "Border",
+            width: 40
+        },
+        {
+            name : 'alt',
+            title: "Alt",
+            width: 120
+        },
+        {
+            name : 'src',
+            title: "Src",
+            width: 220
         }
-       
-    },
-
-
-    getResizeEl : function(){
-        return this.wrap;
-    },
-
-    getPositionEl : function(){
-        return this.wrap;
-    },
-
-    // private
-    onRender : function(ct, position){
         
-        Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
-        //if(this.inputValue !== undefined){
-        this.wrap = this.el.wrap();
-        
-        this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
-        
-        if(this.closable){
-            this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
+    ],
+    
+    'FIGURE' : [
+        {
+            name : 'align',
+            title: "Align",
+            opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
+            width : 80  
         }
+    ],
+    'A' : [
+        {
+            name : 'name',
+            title: "Name",
+            width: 50
+        },
+        {
+            name : 'target',
+            title: "Target",
+            width: 120
+        },
+        {
+            name : 'href',
+            title: "Href",
+            width: 220
+        } // border?
         
-        if (this.bodyStyle) {
-            this.viewEl.applyStyles(this.bodyStyle);
+    ],
+    
+    'INPUT' : [
+        {
+            name : 'name',
+            title: "name",
+            width: 120
+        },
+        {
+            name : 'value',
+            title: "Value",
+            width: 120
+        },
+        {
+            name : 'width',
+            title: "Width",
+            width: 40
         }
-        //this.viewEl.setStyle('padding', '2px');
-        
-        this.setValue(this.value);
+    ],
+    'LABEL' : [
+         {
+            name : 'for',
+            title: "For",
+            width: 120
+        }
+    ],
+    'TEXTAREA' : [
+        {
+            name : 'name',
+            title: "name",
+            width: 120
+        },
+        {
+            name : 'rows',
+            title: "Rows",
+            width: 20
+        },
+        {
+            name : 'cols',
+            title: "Cols",
+            width: 20
+        }
+    ],
+    'SELECT' : [
+        {
+            name : 'name',
+            title: "name",
+            width: 120
+        },
+        {
+            name : 'selectoptions',
+            title: "Options",
+            width: 200
+        }
+    ],
+    
+    // should we really allow this??
+    // should this just be 
+    'BODY' : [
         
-    },
-/*
-    // private
-    initValue : Roo.emptyFn,
+        {
+            name : 'title',
+            title: "Title",
+            width: 200,
+            disabled : true
+        }
+    ],
+    '*' : [
+        // empty.
+    ]
 
-  */
+};
 
-       // private
-    onClick : function(){
-        
-    },
+// this should be configurable.. - you can either set it up using stores, or modify options somehwere..
+Roo.form.HtmlEditor.ToolbarContext.stores = false;
 
-    /**
-     * Sets the checked state of the checkbox.
-     * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
-     */
-    setValue : function(v){
-        this.value = v;
-        var html = this.valueRenderer ?  this.valueRenderer(v) : String.format('{0}', v);
-        // this might be called before we have a dom element..
-        if (!this.viewEl) {
-            return;
-        }
-        this.viewEl.dom.innerHTML = html;
-        Roo.form.DisplayField.superclass.setValue.call(this, v);
+Roo.form.HtmlEditor.ToolbarContext.options = {
+        'font-family'  : [ 
+                [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
+                [ 'Courier New', 'Courier New'],
+                [ 'Tahoma', 'Tahoma'],
+                [ 'Times New Roman,serif', 'Times'],
+                [ 'Verdana','Verdana' ]
+        ]
+};
 
-    },
-    
-    onClose : function(e)
-    {
-        e.preventDefault();
-        
-        this.fireEvent('close', this);
-    }
-});/*
- * 
- * Licence- LGPL
- * 
- */
+// fixme - these need to be configurable..
 
-/**
- * @class Roo.form.DayPicker
- * @extends Roo.form.Field
- * A Day picker show [M] [T] [W] ....
- * @constructor
- * Creates a new Day Picker
- * @param {Object} config Configuration options
- */
-Roo.form.DayPicker= function(config){
-    Roo.form.DayPicker.superclass.constructor.call(this, config);
-     
-};
+//Roo.form.HtmlEditor.ToolbarContext.types
 
-Roo.extend(Roo.form.DayPicker, Roo.form.Field,  {
+
+Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
+    
+    tb: false,
+    
+    rendered: false,
+    
+    editor : false,
+    editorcore : false,
     /**
-     * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
+     * @cfg {Object} disable  List of toolbar elements to disable
+         
      */
-    focusClass : undefined,
+    disable : false,
     /**
-     * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
+     * @cfg {Object} styles List of styles 
+     *    eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] } 
+     *
+     * These must be defined in the page, so they get rendered correctly..
+     * .headline { }
+     * TD.underline { }
+     * 
      */
-    fieldClass: "x-form-field",
-   
-    /**
-     * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
-     * {tag: "input", type: "checkbox", autocomplete: "off"})
-     */
-    defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
+    styles : false,
     
-   
-    actionMode : 'viewEl', 
-    //
-    // private
-    inputType : 'hidden',
+    options: false,
     
-     
-    inputElement: false, // real input element?
-    basedOn: false, // ????
+    toolbars : false,
     
-    isFormField: true, // not sure where this is needed!!!!
-
-    onResize : function(){
-        Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
-        if(!this.boxLabel){
-            this.el.alignTo(this.wrap, 'c-c');
+    init : function(editor)
+    {
+        this.editor = editor;
+        this.editorcore = editor.editorcore ? editor.editorcore : editor;
+        var editorcore = this.editorcore;
+        
+        var fid = editorcore.frameId;
+        var etb = this;
+        function btn(id, toggle, handler){
+            var xid = fid + '-'+ id ;
+            return {
+                id : xid,
+                cmd : id,
+                cls : 'x-btn-icon x-edit-'+id,
+                enableToggle:toggle !== false,
+                scope: editorcore, // was editor...
+                handler:handler||editorcore.relayBtnCmd,
+                clickEvent:'mousedown',
+                tooltip: etb.buttonTips[id] || undefined, ///tips ???
+                tabIndex:-1
+            };
         }
+        // create a new element.
+        var wdiv = editor.wrap.createChild({
+                tag: 'div'
+            }, editor.wrap.dom.firstChild.nextSibling, true);
+        
+        // can we do this more than once??
+        
+         // stop form submits
+      
+        // 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;
+        this.tb.el.show();
+        this.buildFooter();
+        this.footer.show();
+        editor.on('hide', function( ) { this.footer.hide() }, this);
+        editor.on('show', function( ) { this.footer.show() }, this);
+        
+         
+        this.rendered = true;
+        
+        // the all the btns;
+        editor.on('editorevent', this.updateToolbar, this);
+        // other toolbars need to implement this..
+        //editor.on('editmodechange', this.updateToolbar, this);
     },
-
-    initEvents : function(){
-        Roo.form.Checkbox.superclass.initEvents.call(this);
-        this.el.on("click", this.onClick,  this);
-        this.el.on("change", this.onClick,  this);
-    },
-
-
-    getResizeEl : function(){
-        return this.wrap;
-    },
-
-    getPositionEl : function(){
-        return this.wrap;
-    },
-
     
-    // private
-    onRender : function(ct, position){
-        Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
-       
-        this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
+    
+    
+    /**
+     * Protected method that will not generally be called directly. It triggers
+     * a toolbar update by reading the markup state of the current selection in the editor.
+     *
+     * Note you can force an update by calling on('editorevent', scope, false)
+     */
+    updateToolbar: function(editor ,ev, sel)
+    {
         
-        var r1 = '<table><tr>';
-        var r2 = '<tr class="x-form-daypick-icons">';
-        for (var i=0; i < 7; i++) {
-            r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
-            r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL  +'"></td>';
+        if (ev) {
+            ev.stopEvent(); // se if we can stop this looping with mutiple events.
         }
         
-        var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
-        viewEl.select('img').on('click', this.onClick, this);
-        this.viewEl = viewEl;   
+        //Roo.log(ev);
+        // capture mouse up - this is handy for selecting images..
+        // perhaps should go somewhere else...
+        if(!this.editorcore.activated){
+             this.editor.onFirstFocus();
+            return;
+        }
+        //Roo.log(ev ? ev.target : 'NOTARGET');
         
         
-        // this will not work on Chrome!!!
-        this.el.on('DOMAttrModified', this.setFromHidden,  this); //ff
-        this.el.on('propertychange', this.setFromHidden,  this);  //ie
+        // http://developer.yahoo.com/yui/docs/simple-editor.js.html
+        // selectNode - might want to handle IE?
         
         
-          
-
-    },
-
-    // private
-    initValue : Roo.emptyFn,
-
-    /**
-     * Returns the checked state of the checkbox.
-     * @return {Boolean} True if checked, else false
-     */
-    getValue : function(){
-        return this.el.dom.value;
         
-    },
-
-       // private
-    onClick : function(e){ 
-        //this.setChecked(!this.checked);
-        Roo.get(e.target).toggleClass('x-menu-item-checked');
-        this.refreshValue();
-        //if(this.el.dom.checked != this.checked){
-        //    this.setValue(this.el.dom.checked);
-       // }
-    },
-    
-    // private
-    refreshValue : function()
-    {
-        var val = '';
-        this.viewEl.select('img',true).each(function(e,i,n)  {
-            val += e.is(".x-menu-item-checked") ? String(n) : '';
+        if (ev &&
+            (ev.type == 'mouseup' || ev.type == 'click' ) &&
+            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;
+            
+            // 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');
         });
-        this.setValue(val, true);
-    },
-
-    /**
-     * Sets the checked state of the checkbox.
-     * On is always based on a string comparison between inputValue and the param.
-     * @param {Boolean/String} value - the value to set 
-     * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
-     */
-    setValue : function(v,suppressEvent){
-        if (!this.el.dom) {
-            return;
+        //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 ans = this.editorcore.getAllAncestors();
+        
+        // pick
+        var ty = Roo.form.HtmlEditor.ToolbarContext.types;
+        
+        if (!sel) { 
+            sel = ans.length ? (ans[0] ?  ans[0]  : ans[1]) : this.editorcore.doc.body;
+            sel = sel ? sel : this.editorcore.doc.body;
+            sel = sel.tagName.length ? sel : this.editorcore.doc.body;
+            
         }
-        var old = this.el.dom.value ;
-        this.el.dom.value = v;
-        if (suppressEvent) {
-            return ;
+        
+        var tn = sel.tagName.toUpperCase();
+        var lastSel = this.tb.selectedNode;
+        this.tb.selectedNode = sel;
+        var left_label = tn;
+        
+        // ok see if we are editing a block?
+        
+        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]')) {
+            
+            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!?
+            //}   
         }
-         
-        // update display..
-        this.viewEl.select('img',true).each(function(e,i,n)  {
+        
+        
+        var block = false;
+        //if (db && !sel.hasAttribute('contenteditable') && sel.getAttribute('contenteditable') != 'true' ) {
+        if (db && this.editorcore.enableBlocks) {
+            block = Roo.htmleditor.Block.factory(db);
             
-            var on = e.is(".x-menu-item-checked");
-            var newv = v.indexOf(String(n)) > -1;
-            if (on != newv) {
-                e.toggleClass('x-menu-item-checked');
+            
+            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');
+                
+                //this.editorcore.selectNode(db);
+                if (typeof(this.toolbars[tn]) == 'undefined') {
+                   this.toolbars[tn] = this.buildToolbar( false  ,tn ,block.friendly_name, block);
+                }
+                this.toolbars[tn].selectedNode = db;
+                left_label = block.friendly_name;
+                ans = this.editorcore.getAllAncestors();
             }
             
-        });
+                
+            
+        }
         
         
-        this.fireEvent('change', this, v, old);
+        if (this.tb.name == tn && lastSel == this.tb.selectedNode && ev !== false) {
+            return; // no change?
+        }
         
         
-    },
-   
-    // handle setting of hidden value by some other method!!?!?
-    setFromHidden: function()
-    {
-        if(!this.el){
-            return;
+          
+        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);  
         }
-        //console.log("SET FROM HIDDEN");
-        //alert('setFrom hidden');
-        this.setValue(this.el.dom.value);
+        
+        
+       
+        Roo.menu.MenuMgr.hideAll();
+
+        
+        
+    
+        // update the footer
+        //
+        this.updateFooter(ans);
+             
     },
     
-    onDestroy : function()
+    updateToolbarStyles : function(sel)
     {
-        if(this.viewEl){
-            Roo.get(this.viewEl).remove();
-        }
-         
-        Roo.form.DayPicker.superclass.onDestroy.call(this);
-    }
-
-});/*
- * RooJS Library 1.1.1
- * Copyright(c) 2008-2011  Alan Knowles
- *
- * License - LGPL
- */
-
-/**
- * @class Roo.form.ComboCheck
- * @extends Roo.form.ComboBox
- * A combobox for multiple select items.
- *
- * FIXME - could do with a reset button..
- * 
- * @constructor
- * Create a new ComboCheck
- * @param {Object} config Configuration options
- */
-Roo.form.ComboCheck = function(config){
-    Roo.form.ComboCheck.superclass.constructor.call(this, config);
-    // should verify some data...
-    // like
-    // hiddenName = required..
-    // displayField = required
-    // valudField == required
-    var req= [ 'hiddenName', 'displayField', 'valueField' ];
-    var _t = this;
-    Roo.each(req, function(e) {
-        if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
-            throw "Roo.form.ComboCheck : missing value for: " + e;
+        var hasStyles = false;
+        for(var i in this.styles) {
+            hasStyles = true;
+            break;
         }
-    });
-    
-    
-};
-
-Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
-     
-     
-    editable : false,
-     
-    selectedClass: 'x-menu-item-checked', 
-    
-    // private
-    onRender : function(ct, position){
-        var _t = this;
         
-        
-        
-        if(!this.tpl){
-            var cls = 'x-combo-list';
-
+        // update styles
+        if (hasStyles && this.tb.hasStyles) { 
+            var st = this.tb.fields.item(0);
             
-            this.tpl =  new Roo.Template({
-                html :  '<div class="'+cls+'-item x-menu-check-item">' +
-                   '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' + 
-                   '<span>{' + this.displayField + '}</span>' +
-                    '</div>' 
+            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;
         }
         
-        Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
-        this.view.singleSelect = false;
-        this.view.multiSelect = true;
-        this.view.toggleSelect = true;
-        this.pageTb.add(new Roo.Toolbar.Fill(), {
+        this.footerEls = ans.reverse();
+        Roo.each(this.footerEls, function(a,i) {
+            if (!a) { return; }
+            html += html.length ? ' &gt; '  :  '';
+            
+            html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
             
-            text: 'Done',
-            handler: function()
-            {
-                _t.collapse();
-            }
         });
-    },
-    
-    onViewOver : function(e, t){
-        // do nothing...
-        return;
+       
+        // 
+        var sz = this.footDisp.up('td').getSize();
+        this.footDisp.dom.style.width = (sz.width -10) + 'px';
+        this.footDisp.dom.style.marginLeft = '5px';
         
-    },
-    
-    onViewClick : function(doFocus,index){
-        return;
+        this.footDisp.dom.style.overflow = 'hidden';
         
-    },
-    select: function () {
-        //Roo.log("SELECT CALLED");
-    },
-     
-    selectByValue : function(xv, scrollIntoView){
-        var ar = this.getValueArray();
-        var sels = [];
+        this.footDisp.dom.innerHTML = html;
+            
         
-        Roo.each(ar, function(v) {
-            if(v === undefined || v === null){
-                return;
-            }
-            var r = this.findRecord(this.valueField, v);
-            if(r){
-                sels.push(this.store.indexOf(r))
-                
-            }
-        },this);
-        this.view.select(sels);
-        return false;
     },
-    
-    
-    
-    onSelect : function(record, index){
-       // Roo.log("onselect Called");
-       // this is only called by the clear button now..
-        this.view.clearSelections();
-        this.setValue('[]');
-        if (this.value != this.valueBefore) {
-            this.fireEvent('change', this, this.value, this.valueBefore);
-            this.valueBefore = this.value;
+   
+       
+    // private
+    onDestroy : function(){
+        if(this.rendered){
+            
+            this.tb.items.each(function(item){
+                if(item.menu){
+                    item.menu.removeAll();
+                    if(item.menu.el){
+                        item.menu.el.destroy();
+                    }
+                }
+                item.destroy();
+            });
+             
         }
     },
-    getValueArray : function()
+    onFirstFocus: function() {
+        // need to do this for all the toolbars..
+        this.tb.items.each(function(item){
+           item.enable();
+        });
+    },
+    buildToolbar: function(tlist, nm, friendly_name, block)
     {
-        var ar = [] ;
+        var editor = this.editor;
+        var editorcore = this.editorcore;
+         // create a new element.
+        var wdiv = editor.wrap.createChild({
+                tag: 'div'
+            }, editor.wrap.dom.firstChild.nextSibling, true);
         
-        try {
-            //Roo.log(this.value);
-            if (typeof(this.value) == 'undefined') {
-                return [];
-            }
-            var ar = Roo.decode(this.value);
-            return  ar instanceof Array ? ar : []; //?? valid?
-            
-        } catch(e) {
-            Roo.log(e + "\nRoo.form.ComboCheck:getValueArray  invalid data:" + this.getValue());
-            return [];
+       
+        var tb = new Roo.Toolbar(wdiv);
+        ///this.tb = tb; // << this sets the active toolbar..
+        if (tlist === false && block) {
+            tlist = block.contextMenu(this);
         }
-         
-    },
-    expand : function ()
-    {
         
-        Roo.form.ComboCheck.superclass.expand.call(this);
-        this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
-        //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
+        tb.hasStyles = false;
+        tb.name = nm;
         
-
-    },
+        tb.add((typeof(friendly_name) == 'undefined' ? nm : friendly_name) + ":&nbsp;");
+        
+        var styles = Array.from(this.styles);
+        
+        
+        // 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({
+                    id : 'val',
+                    fields: ['val', 'selected'],
+                    data : [] 
+                }),
+                name : '-roo-edit-className',
+                attrname : 'className',
+                displayField: 'val',
+                typeAhead: false,
+                mode: 'local',
+                editable : false,
+                triggerAction: 'all',
+                emptyText:'Select Style',
+                selectOnFocus:true,
+                width: 130,
+                listeners : {
+                    'select': function(c, r, i) {
+                        // initial support only for on class per el..
+                        tb.selectedNode.className =  r ? r.get('val') : '';
+                        editorcore.syncValue();
+                    }
+                }
     
-    collapse : function(){
-        Roo.form.ComboCheck.superclass.collapse.call(this);
-        var sl = this.view.getSelectedIndexes();
-        var st = this.store;
-        var nv = [];
-        var tv = [];
-        var r;
-        Roo.each(sl, function(i) {
-            r = st.getAt(i);
-            nv.push(r.get(this.valueField));
-        },this);
-        this.setValue(Roo.encode(nv));
-        if (this.value != this.valueBefore) {
-
-            this.fireEvent('change', this, this.value, this.valueBefore);
-            this.valueBefore = this.value;
+            }));
         }
         
-    },
-    
-    setValue : function(v){
-        // Roo.log(v);
-        this.value = v;
+        var tbc = Roo.form.HtmlEditor.ToolbarContext;
+        
+        
+        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;");
+            
+            
+            //optname == used so you can configure the options available..
+            var opts = item.opts ? item.opts : false;
+            if (item.optname) { // use the b
+                opts = Roo.form.HtmlEditor.ToolbarContext.options[item.optname];
+           
+            }
+            
+            if (opts) {
+                // opts == pulldown..
+                tb.addField( new Roo.form.ComboBox({
+                    store:   typeof(tbc.stores[i]) != 'undefined' ?  Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
+                        id : 'val',
+                        fields: ['val', 'display'],
+                        data : opts  
+                    }),
+                    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[tlist[i].name]) != 'undefined'  ? 'remote' : 'local',
+                    editable : false,
+                    triggerAction: 'all',
+                    emptyText:'Select',
+                    selectOnFocus:true,
+                    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();
+                        }
+                    }
+
+                }));
+                continue;
+                    
+                 
+                /*
+                tb.addField( new Roo.form.TextField({
+                    name: i,
+                    width: 100,
+                    //allowBlank:false,
+                    value: ''
+                }));
+                continue;
+                */
+            }
+            tb.addField( new Roo.form.TextField({
+                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();
+                    }
+                }
+            }));
+             
+        }
+        
+        var _this = this;
+        var show_delete = !block || block.deleteTitle !== false;
+        if(nm == 'BODY'){
+            show_delete = false;
+            tb.addSeparator();
+        
+            tb.addButton( {
+                text: 'Stylesheets',
+
+                listeners : {
+                    click : function ()
+                    {
+                        _this.editor.fireEvent('stylesheetsclick', _this.editor);
+                    }
+                }
+            });
+        }
+        
+        tb.addFill();
+        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);
+                        
+                    }
+                }
+                
+                        
+                    
+                
+            });
+        }    
+        
+        tb.el.on('click', function(e){
+            e.preventDefault(); // what does this do?
+        });
+        tb.el.setVisibilityMode( Roo.Element.DISPLAY);
+        tb.el.hide();
+        
+        // dont need to disable them... as they will get hidden
+        return tb;
+         
+        
+    },
+    buildFooter : function()
+    {
+        
+        var fel = this.editor.wrap.createChild();
+        this.footer = new Roo.Toolbar(fel);
+        // toolbar has scrolly on left / right?
+        var footDisp= new Roo.Toolbar.Fill();
+        var _t = this;
+        this.footer.add(
+            {
+                text : '&lt;',
+                xtype: 'Button',
+                handler : function() {
+                    _t.footDisp.scrollTo('left',0,true)
+                }
+            }
+        );
+        this.footer.add( footDisp );
+        this.footer.add( 
+            {
+                text : '&gt;',
+                xtype: 'Button',
+                handler : function() {
+                    // no animation..
+                    _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
+                }
+            }
+        );
+        var fel = Roo.get(footDisp.el);
+        fel.addClass('x-editor-context');
+        this.footDispWrap = fel; 
+        this.footDispWrap.overflow  = 'hidden';
+        
+        this.footDisp = fel.createChild();
+        this.footDispWrap.on('click', this.onContextClick, this)
+        
+        
+    },
+    // when the footer contect changes
+    onContextClick : function (ev,dom)
+    {
+        ev.preventDefault();
+        var  cn = dom.className;
+        //Roo.log(cn);
+        if (!cn.match(/x-ed-loc-/)) {
+            return;
+        }
+        var n = cn.split('-').pop();
+        var ans = this.footerEls;
+        var sel = ans[n];
+        
+        this.editorcore.selectNode(sel);
+        
+        
+        this.updateToolbar(null, null, sel);
         
-        var vals = this.getValueArray();
-        var tv = [];
-        Roo.each(vals, function(k) {
-            var r = this.findRecord(this.valueField, k);
-            if(r){
-                tv.push(r.data[this.displayField]);
-            }else if(this.valueNotFoundText !== undefined){
-                tv.push( this.valueNotFoundText );
-            }
-        },this);
-       // Roo.log(tv);
         
-        Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
-        this.hiddenField.value = v;
-        this.value = v;
     }
     
-});/*
+    
+    
+    
+    
+});
+
+
+
+
+
+/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -49820,1365 +53939,2009 @@ Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
  */
  
 /**
- * @class Roo.form.Signature
- * @extends Roo.form.Field
- * Signature field.  
+ * @class Roo.form.BasicForm
+ * @extends Roo.util.Observable
+ * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
  * @constructor
- * 
+ * @param {String/HTMLElement/Roo.Element} el The form element or its id
  * @param {Object} config Configuration options
  */
-
-Roo.form.Signature = function(config){
-    Roo.form.Signature.superclass.constructor.call(this, config);
-    
-    this.addEvents({// not in used??
-         /**
-         * @event confirm
-         * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
-            * @param {Roo.form.Signature} combo This combo box
-            */
-        'confirm' : true,
+Roo.form.BasicForm = function(el, config){
+    this.allItems = [];
+    this.childForms = [];
+    Roo.apply(this, config);
+    /*
+     * The Roo.form.Field items in this form.
+     * @type MixedCollection
+     */
+     
+     
+    this.items = new Roo.util.MixedCollection(false, function(o){
+        return o.id || (o.id = Roo.id());
+    });
+    this.addEvents({
         /**
-         * @event reset
-         * Fires when the 'edit' icon is pressed (add a listener to enable add button)
-            * @param {Roo.form.ComboBox} combo This combo box
-            * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
-            */
-        'reset' : true
+         * @event beforeaction
+         * Fires before any action is performed. Return false to cancel the action.
+         * @param {Form} this
+         * @param {Action} action The action to be performed
+         */
+        beforeaction: true,
+        /**
+         * @event actionfailed
+         * Fires when an action fails.
+         * @param {Form} this
+         * @param {Action} action The action that failed
+         */
+        actionfailed : true,
+        /**
+         * @event actioncomplete
+         * Fires when an action is completed.
+         * @param {Form} this
+         * @param {Action} action The action that completed
+         */
+        actioncomplete : true
     });
+    if(el){
+        this.initEl(el);
+    }
+    Roo.form.BasicForm.superclass.constructor.call(this);
+    
+    Roo.form.BasicForm.popover.apply();
 };
 
-Roo.extend(Roo.form.Signature, Roo.form.Field,  {
+Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
     /**
-     * @cfg {Object} labels Label to use when rendering a form.
-     * defaults to 
-     * labels : { 
-     *      clear : "Clear",
-     *      confirm : "Confirm"
-     *  }
+     * @cfg {String} method
+     * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
      */
-    labels : { 
-        clear : "Clear",
-        confirm : "Confirm"
-    },
     /**
-     * @cfg {Number} width The signature panel width (defaults to 300)
+     * @cfg {DataReader} reader
+     * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
+     * This is optional as there is built-in support for processing JSON.
      */
-    width: 300,
     /**
-     * @cfg {Number} height The signature panel height (defaults to 100)
+     * @cfg {DataReader} errorReader
+     * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
+     * This is completely optional as there is built-in support for processing JSON.
      */
-    height : 100,
     /**
-     * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
+     * @cfg {String} url
+     * The URL to use for form actions if one isn't supplied in the action options.
      */
-    allowBlank : false,
+    /**
+     * @cfg {Boolean} fileUpload
+     * Set to true if this form is a file upload.
+     */
+     
+    /**
+     * @cfg {Object} baseParams
+     * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
+     */
+     /**
+     
+    /**
+     * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
+     */
+    timeout: 30,
+
+    // private
+    activeAction : null,
+
+    /**
+     * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
+     * or setValues() data instead of when the form was first created.
+     */
+    trackResetOnLoad : false,
     
-    //private
-    // {Object} signPanel The signature SVG panel element (defaults to {})
-    signPanel : {},
-    // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
-    isMouseDown : false,
-    // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
-    isConfirmed : false,
-    // {String} signatureTmp SVG mapping string (defaults to empty string)
-    signatureTmp : '',
     
+    /**
+     * childForms - used for multi-tab forms
+     * @type {Array}
+     */
+    childForms : false,
     
-    defaultAutoCreate : { // modified by initCompnoent..
-        tag: "input",
-        type:"hidden"
+    /**
+     * allItems - full list of fields.
+     * @type {Array}
+     */
+    allItems : false,
+    
+    /**
+     * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
+     * element by passing it or its id or mask the form itself by passing in true.
+     * @type Mixed
+     */
+    waitMsgTarget : false,
+    
+    /**
+     * @type Boolean
+     */
+    disableMask : false,
+    
+    /**
+     * @cfg {Boolean} errorMask (true|false) default false
+     */
+    errorMask : false,
+    
+    /**
+     * @cfg {Number} maskOffset Default 100
+     */
+    maskOffset : 100,
+
+    // private
+    initEl : function(el){
+        this.el = Roo.get(el);
+        this.id = this.el.id || Roo.id();
+        this.el.on('submit', this.onSubmit, this);
+        this.el.addClass('x-form');
     },
 
     // private
-    onRender : function(ct, position){
-        
-        Roo.form.Signature.superclass.onRender.call(this, ct, position);
-        
-        this.wrap = this.el.wrap({
-            cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
-        });
-        
-        this.createToolbar(this);
-        this.signPanel = this.wrap.createChild({
-                tag: 'div',
-                style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
-            }, this.el
-        );
-            
-        this.svgID = Roo.id();
-        this.svgEl = this.signPanel.createChild({
-              xmlns : 'http://www.w3.org/2000/svg',
-              tag : 'svg',
-              id : this.svgID + "-svg",
-              width: this.width,
-              height: this.height,
-              viewBox: '0 0 '+this.width+' '+this.height,
-              cn : [
-                {
-                    tag: "rect",
-                    id: this.svgID + "-svg-r",
-                    width: this.width,
-                    height: this.height,
-                    fill: "#ffa"
-                },
-                {
-                    tag: "line",
-                    id: this.svgID + "-svg-l",
-                    x1: "0", // start
-                    y1: (this.height*0.8), // start set the line in 80% of height
-                    x2: this.width, // end
-                    y2: (this.height*0.8), // end set the line in 80% of height
-                    'stroke': "#666",
-                    'stroke-width': "1",
-                    'stroke-dasharray': "3",
-                    'shape-rendering': "crispEdges",
-                    'pointer-events': "none"
-                },
-                {
-                    tag: "path",
-                    id: this.svgID + "-svg-p",
-                    'stroke': "navy",
-                    'stroke-width': "3",
-                    'fill': "none",
-                    'pointer-events': 'none'
-                }
-              ]
-        });
-        this.createSVG();
-        this.svgBox = this.svgEl.dom.getScreenCTM();
+    onSubmit : function(e){
+        e.stopEvent();
     },
-    createSVG : function(){ 
-        var svg = this.signPanel;
-        var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
-        var t = this;
 
-        r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
-        r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
-        r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
-        r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
-        r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
-        r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
-        r.addEventListener('touchend', function(e) { return t.up(e); }, false);
+    /**
+     * Returns true if client-side validation on the form is successful.
+     * @return Boolean
+     */
+    isValid : function(){
+        var valid = true;
+        var target = false;
+        this.items.each(function(f){
+            if(f.validate()){
+                return;
+            }
+            
+            valid = false;
+                
+            if(!target && f.el.isVisible(true)){
+                target = f;
+            }
+        });
         
-    },
-    isTouchEvent : function(e){
-        return e.type.match(/^touch/);
-    },
-    getCoords : function (e) {
-        var pt    = this.svgEl.dom.createSVGPoint();
-        pt.x = e.clientX; 
-        pt.y = e.clientY;
-        if (this.isTouchEvent(e)) {
-            pt.x =  e.targetTouches[0].clientX;
-            pt.y = e.targetTouches[0].clientY;
+        if(this.errorMask && !valid){
+            Roo.form.BasicForm.popover.mask(this, target);
         }
-        var a = this.svgEl.dom.getScreenCTM();
-        var b = a.inverse();
-        var mx = pt.matrixTransform(b);
-        return mx.x + ',' + mx.y;
-    },
-    //mouse event headler 
-    down : function (e) {
-        this.signatureTmp += 'M' + this.getCoords(e) + ' ';
-        this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
-        
-        this.isMouseDown = true;
         
-        e.preventDefault();
+        return valid;
     },
-    move : function (e) {
-        if (this.isMouseDown) {
-            this.signatureTmp += 'L' + this.getCoords(e) + ' ';
-            this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
-        }
+    /**
+     * Returns array of invalid form fields.
+     * @return Array
+     */
+    
+    invalidFields : function()
+    {
+        var ret = [];
+        this.items.each(function(f){
+            if(f.validate()){
+                return;
+            }
+            ret.push(f);
+            
+        });
         
-        e.preventDefault();
+        return ret;
     },
-    up : function (e) {
-        this.isMouseDown = false;
-        var sp = this.signatureTmp.split(' ');
-        
-        if(sp.length > 1){
-            if(!sp[sp.length-2].match(/^L/)){
-                sp.pop();
-                sp.pop();
-                sp.push("");
-                this.signatureTmp = sp.join(" ");
-            }
-        }
-        if(this.getValue() != this.signatureTmp){
-            this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
-            this.isConfirmed = false;
-        }
-        e.preventDefault();
+    
+    
+    /**
+     * DEPRICATED Returns true if any fields in this form have changed since their original load. 
+     * @return Boolean
+     */
+    isDirty : function(){
+        var dirty = false;
+        this.items.each(function(f){
+           if(f.isDirty()){
+               dirty = true;
+               return false;
+           }
+        });
+        return dirty;
     },
     
     /**
-     * Protected method that will not generally be called directly. It
-     * is called when the editor creates its toolbar. Override this method if you need to
-     * add custom toolbar buttons.
-     * @param {HtmlEditor} editor
+     * Returns true if any fields in this form have changed since their original load. (New version)
+     * @return Boolean
      */
-    createToolbar : function(editor){
-         function btn(id, toggle, handler){
-            var xid = fid + '-'+ id ;
-            return {
-                id : xid,
-                cmd : id,
-                cls : 'x-btn-icon x-edit-'+id,
-                enableToggle:toggle !== false,
-                scope: editor, // was editor...
-                handler:handler||editor.relayBtnCmd,
-                clickEvent:'mousedown',
-                tooltip: etb.buttonTips[id] || undefined, ///tips ???
-                tabIndex:-1
-            };
-        }
+    
+    hasChanged : function()
+    {
+        var dirty = false;
+        this.items.each(function(f){
+           if(f.hasChanged()){
+               dirty = true;
+               return false;
+           }
+        });
+        return dirty;
         
+    },
+    /**
+     * Resets all hasChanged to 'false' -
+     * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
+     * So hasChanged storage is only to be used for this purpose
+     * @return Boolean
+     */
+    resetHasChanged : function()
+    {
+        this.items.each(function(f){
+           f.resetHasChanged();
+        });
         
-        var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
-        this.tb = tb;
-        this.tb.add(
-           {
-                cls : ' x-signature-btn x-signature-'+id,
-                scope: editor, // was editor...
-                handler: this.reset,
-                clickEvent:'mousedown',
-                text: this.labels.clear
-            },
-            {
-                 xtype : 'Fill',
-                 xns: Roo.Toolbar
-            }, 
-            {
-                cls : '  x-signature-btn x-signature-'+id,
-                scope: editor, // was editor...
-                handler: this.confirmHandler,
-                clickEvent:'mousedown',
-                text: this.labels.confirm
-            }
-        );
-    
     },
-    //public
+    
+    
     /**
-     * when user is clicked confirm then show this image.....
-     * 
-     * @return {String} Image Data URI
+     * Performs a predefined action (submit or load) or custom actions you define on this form.
+     * @param {String} actionName The name of the action type
+     * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
+     * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
+     * accept other config options):
+     * <pre>
+Property          Type             Description
+----------------  ---------------  ----------------------------------------------------------------------------------
+url               String           The url for the action (defaults to the form's url)
+method            String           The form method to use (defaults to the form's method, or POST if not defined)
+params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
+clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
+                                   validate the form on the client (defaults to false)
+     * </pre>
+     * @return {BasicForm} this
      */
-    getImageDataURI : function(){
-        var svg = this.svgEl.dom.parentNode.innerHTML;
-        var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
-        return src; 
+    doAction : function(action, options){
+        if(typeof action == 'string'){
+            action = new Roo.form.Action.ACTION_TYPES[action](this, options);
+        }
+        if(this.fireEvent('beforeaction', this, action) !== false){
+            this.beforeAction(action);
+            action.run.defer(100, action);
+        }
+        return this;
     },
+
     /**
-     * 
-     * @return {Boolean} this.isConfirmed
+     * Shortcut to do a submit action.
+     * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
+     * @return {BasicForm} this
      */
-    getConfirmed : function(){
-        return this.isConfirmed;
+    submit : function(options){
+        this.doAction('submit', options);
+        return this;
     },
+
     /**
-     * 
-     * @return {Number} this.width
+     * Shortcut to do a load action.
+     * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
+     * @return {BasicForm} this
      */
-    getWidth : function(){
-        return this.width;
+    load : function(options){
+        this.doAction('load', options);
+        return this;
     },
+
     /**
-     * 
-     * @return {Number} this.height
+     * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
+     * @param {Record} record The record to edit
+     * @return {BasicForm} this
      */
-    getHeight : function(){
-        return this.height;
+    updateRecord : function(record){
+        record.beginEdit();
+        var fs = record.fields;
+        fs.each(function(f){
+            var field = this.findField(f.name);
+            if(field){
+                record.set(f.name, field.getValue());
+            }
+        }, this);
+        record.endEdit();
+        return this;
     },
-    // private
-    getSignature : function(){
-        return this.signatureTmp;
+
+    /**
+     * Loads an Roo.data.Record into this form.
+     * @param {Record} record The record to load
+     * @return {BasicForm} this
+     */
+    loadRecord : function(record){
+        this.setValues(record.data);
+        return this;
     },
+
     // private
-    reset : function(){
-        this.signatureTmp = '';
-        this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
-        this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
-        this.isConfirmed = false;
-        Roo.form.Signature.superclass.reset.call(this);
-    },
-    setSignature : function(s){
-        this.signatureTmp = s;
-        this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
-        this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
-        this.setValue(s);
-        this.isConfirmed = false;
-        Roo.form.Signature.superclass.reset.call(this);
-    }, 
-    test : function(){
-//        Roo.log(this.signPanel.dom.contentWindow.up())
-    },
-    //private
-    setConfirmed : function(){
-        
-        
+    beforeAction : function(action){
+        var o = action.options;
         
-//        Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
-    },
-    // private
-    confirmHandler : function(){
-        if(!this.getSignature()){
-            return;
+        if(!this.disableMask) {
+            if(this.waitMsgTarget === true){
+                this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
+            }else if(this.waitMsgTarget){
+                this.waitMsgTarget = Roo.get(this.waitMsgTarget);
+                this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
+            }else {
+                Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
+            }
         }
         
-        this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
-        this.setValue(this.getSignature());
-        this.isConfirmed = true;
-        
-        this.fireEvent('confirm', this);
+         
     },
+
     // private
-    // Subclasses should provide the validation implementation by overriding this
-    validateValue : function(value){
-        if(this.allowBlank){
-            return true;
+    afterAction : function(action, success){
+        this.activeAction = null;
+        var o = action.options;
+        
+        if(!this.disableMask) {
+            if(this.waitMsgTarget === true){
+                this.el.unmask();
+            }else if(this.waitMsgTarget){
+                this.waitMsgTarget.unmask();
+            }else{
+                Roo.MessageBox.updateProgress(1);
+                Roo.MessageBox.hide();
+            }
         }
         
-        if(this.isConfirmed){
-            return true;
+        if(success){
+            if(o.reset){
+                this.reset();
+            }
+            Roo.callback(o.success, o.scope, [this, action]);
+            this.fireEvent('actioncomplete', this, action);
+            
+        }else{
+            
+            // failure condition..
+            // we have a scenario where updates need confirming.
+            // eg. if a locking scenario exists..
+            // we look for { errors : { needs_confirm : true }} in the response.
+            if (
+                (typeof(action.result) != 'undefined')  &&
+                (typeof(action.result.errors) != 'undefined')  &&
+                (typeof(action.result.errors.needs_confirm) != 'undefined')
+           ){
+                var _t = this;
+                Roo.MessageBox.confirm(
+                    "Change requires confirmation",
+                    action.result.errorMsg,
+                    function(r) {
+                        if (r != 'yes') {
+                            return;
+                        }
+                        _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
+                    }
+                    
+                );
+                
+                
+                
+                return;
+            }
+            
+            Roo.callback(o.failure, o.scope, [this, action]);
+            // show an error message if no failed handler is set..
+            if (!this.hasListener('actionfailed')) {
+                Roo.MessageBox.alert("Error",
+                    (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
+                        action.result.errorMsg :
+                        "Saving Failed, please check your entries or try again"
+                );
+            }
+            
+            this.fireEvent('actionfailed', this, action);
         }
-        return false;
-    }
-});/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-
-/**
- * @class Roo.form.ComboBox
- * @extends Roo.form.TriggerField
- * A combobox control with support for autocomplete, remote-loading, paging and many other features.
- * @constructor
- * Create a new ComboBox.
- * @param {Object} config Configuration options
- */
-Roo.form.Select = function(config){
-    Roo.form.Select.superclass.constructor.call(this, config);
-     
-};
+        
+    },
 
-Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
-    /**
-     * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
-     */
     /**
-     * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
-     * rendering into an Roo.Editor, defaults to false)
-     */
-    /**
-     * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
-     * {tag: "input", type: "text", size: "24", autocomplete: "off"})
+     * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
+     * @param {String} id The value to search for
+     * @return Field
      */
+    findField : function(id){
+        var field = this.items.get(id);
+        if(!field){
+            this.items.each(function(f){
+                if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
+                    field = f;
+                    return false;
+                }
+            });
+        }
+        return field || null;
+    },
+
     /**
-     * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
+     * Add a secondary form to this one, 
+     * Used to provide tabbed forms. One form is primary, with hidden values 
+     * which mirror the elements from the other forms.
+     * 
+     * @param {Roo.form.Form} form to add.
+     * 
      */
+    addForm : function(form)
+    {
+       
+        if (this.childForms.indexOf(form) > -1) {
+            // already added..
+            return;
+        }
+        this.childForms.push(form);
+        var n = '';
+        Roo.each(form.allItems, function (fe) {
+            
+            n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
+            if (this.findField(n)) { // already added..
+                return;
+            }
+            var add = new Roo.form.Hidden({
+                name : n
+            });
+            add.render(this.el);
+            
+            this.add( add );
+        }, this);
+        
+    },
     /**
-     * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
-     * the dropdown list (defaults to undefined, with no header element)
+     * Mark fields in this form invalid in bulk.
+     * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
+     * @return {BasicForm} this
      */
+    markInvalid : function(errors){
+        if(errors instanceof Array){
+            for(var i = 0, len = errors.length; i < len; i++){
+                var fieldError = errors[i];
+                var f = this.findField(fieldError.id);
+                if(f){
+                    f.markInvalid(fieldError.msg);
+                }
+            }
+        }else{
+            var field, id;
+            for(id in errors){
+                if(typeof errors[id] != 'function' && (field = this.findField(id))){
+                    field.markInvalid(errors[id]);
+                }
+            }
+        }
+        Roo.each(this.childForms || [], function (f) {
+            f.markInvalid(errors);
+        });
+        
+        return this;
+    },
 
-     /**
-     * @cfg {String/Roo.Template} tpl The template to use to render the output
-     */
-     
-    // private
-    defaultAutoCreate : {tag: "select"  },
-    /**
-     * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
-     */
-    listWidth: undefined,
     /**
-     * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
-     * mode = 'remote' or 'text' if mode = 'local')
+     * Set values for fields in this form in bulk.
+     * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
+     * @return {BasicForm} this
      */
-    displayField: undefined,
+    setValues : function(values){
+        if(values instanceof Array){ // array of objects
+            for(var i = 0, len = values.length; i < len; i++){
+                var v = values[i];
+                var f = this.findField(v.id);
+                if(f){
+                    f.setValue(v.value);
+                    if(this.trackResetOnLoad){
+                        f.originalValue = f.getValue();
+                    }
+                }
+            }
+        }else{ // object hash
+            var field, id;
+            for(id in values){
+                if(typeof values[id] != 'function' && (field = this.findField(id))){
+                    
+                    
+                    
+                    
+                    if (field.setFromData && 
+                        field.valueField && 
+                        field.displayField &&
+                        // combos' with local stores can 
+                        // be queried via setValue()
+                        // to set their value..
+                        (field.store && !field.store.isLocal)
+                        ) {
+                        // it's a combo
+                        var sd = { };
+                        sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
+                        sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
+                        field.setFromData(sd);
+                        
+                    } else if (field.inputType && field.inputType == 'radio') {
+                        
+                        field.setValue(values[id]);
+                    } else {
+                        field.setValue(values[id]);
+                    }
+                    
+                    
+                    if(this.trackResetOnLoad){
+                        field.originalValue = field.getValue();
+                    }
+                }
+            }
+        }
+        this.resetHasChanged();
+        
+        
+        Roo.each(this.childForms || [], function (f) {
+            f.setValues(values);
+            f.resetHasChanged();
+        });
+                
+        return this;
+    },
     /**
-     * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
-     * mode = 'remote' or 'value' if mode = 'local'). 
-     * Note: use of a valueField requires the user make a selection
-     * in order for a value to be mapped.
+     * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
+     * they are returned as an array.
+     * @param {Boolean} asString (def)
+     * @return {Object}
      */
-    valueField: undefined,
-    
+    getValues : function(asString)
+    {
+        if (this.childForms) {
+            // copy values from the child forms
+            Roo.each(this.childForms, function (f) {
+                this.setValues(f.getFieldValues()); // get the full set of data, as we might be copying comboboxes from external into this one.
+            }, this);
+        }
+        
+        // use formdata
+        if (typeof(FormData) != 'undefined' && asString !== true) {
+            // this relies on a 'recent' version of chrome apparently...
+            try {
+                var fd = (new FormData(this.el.dom)).entries();
+                var ret = {};
+                var ent = fd.next();
+                while (!ent.done) {
+                    ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
+                    ent = fd.next();
+                };
+                return ret;
+            } catch(e) {
+                
+            }
+            
+        }
+        
+        
+        var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
+        if(asString === true){
+            return fs;
+        }
+        return Roo.urlDecode(fs);
+    },
     
     /**
-     * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
-     * field's data value (defaults to the underlying DOM element's name)
+     * 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}
      */
-    hiddenName: undefined,
+    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.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;
+            }
+            var v = f.getValue();
+            if (f.inputType =='radio') {
+                if (typeof(ret[f.getName()]) == 'undefined') {
+                    ret[f.getName()] = ''; // empty..
+                }
+                
+                if (!f.el.dom.checked) {
+                    return;
+                    
+                }
+                v = f.el.dom.value;
+                
+            }
+            
+            // not sure if this supported any more..
+            if ((typeof(v) == 'object') && f.getRawValue) {
+                v = f.getRawValue() ; // dates..
+            }
+            // combo boxes where name != hiddenName...
+            if (f.name != f.getName()) {
+                ret[f.name] = f.getRawValue();
+            }
+            ret[f.getName()] = v;
+        });
+        
+        return ret;
+    },
+
     /**
-     * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
+     * Clears all invalid messages in this form.
+     * @return {BasicForm} this
      */
-    listClass: '',
+    clearInvalid : function(){
+        this.items.each(function(f){
+           f.clearInvalid();
+        });
+        
+        Roo.each(this.childForms || [], function (f) {
+            f.clearInvalid();
+        });
+        
+        
+        return this;
+    },
+
     /**
-     * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
+     * Resets this form.
+     * @return {BasicForm} this
      */
-    selectedClass: 'x-combo-selected',
+    reset : function(){
+        this.items.each(function(f){
+            f.reset();
+        });
+        
+        Roo.each(this.childForms || [], function (f) {
+            f.reset();
+        });
+        this.resetHasChanged();
+        
+        return this;
+    },
+
     /**
-     * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
-     * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
-     * which displays a downward arrow icon).
+     * Add Roo.form components to this form.
+     * @param {Field} field1
+     * @param {Field} field2 (optional)
+     * @param {Field} etc (optional)
+     * @return {BasicForm} this
      */
-    triggerClass : 'x-form-arrow-trigger',
+    add : function(){
+        this.items.addAll(Array.prototype.slice.call(arguments, 0));
+        return this;
+    },
+
+
     /**
-     * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
+     * Removes a field from the items collection (does NOT remove its markup).
+     * @param {Field} field
+     * @return {BasicForm} this
      */
-    shadow:'sides',
+    remove : function(field){
+        this.items.remove(field);
+        return this;
+    },
+
     /**
-     * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
-     * anchor positions (defaults to 'tl-bl')
+     * Looks at the fields in this form, checks them for an id attribute,
+     * and calls applyTo on the existing dom element with that id.
+     * @return {BasicForm} this
      */
-    listAlign: 'tl-bl?',
+    render : function(){
+        this.items.each(function(f){
+            if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
+                f.applyTo(f.id);
+            }
+        });
+        return this;
+    },
+
     /**
-     * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
+     * Calls {@link Ext#apply} for all fields in this form with the passed object.
+     * @param {Object} values
+     * @return {BasicForm} this
      */
-    maxHeight: 300,
+    applyToFields : function(o){
+        this.items.each(function(f){
+           Roo.apply(f, o);
+        });
+        return this;
+    },
+
     /**
-     * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
-     * query specified by the allQuery config option (defaults to 'query')
+     * Calls {@link Ext#applyIf} for all field in this form with the passed object.
+     * @param {Object} values
+     * @return {BasicForm} this
      */
-    triggerAction: 'query',
+    applyIfToFields : function(o){
+        this.items.each(function(f){
+           Roo.applyIf(f, o);
+        });
+        return this;
+    }
+});
+
+// back compat
+Roo.BasicForm = Roo.form.BasicForm;
+
+Roo.apply(Roo.form.BasicForm, {
+    
+    popover : {
+        
+        padding : 5,
+        
+        isApplied : false,
+        
+        isMasked : false,
+        
+        form : false,
+        
+        target : false,
+        
+        intervalID : false,
+        
+        maskEl : false,
+        
+        apply : function()
+        {
+            if(this.isApplied){
+                return;
+            }
+            
+            this.maskEl = {
+                top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
+                left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
+                bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
+                right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
+            };
+            
+            this.maskEl.top.enableDisplayMode("block");
+            this.maskEl.left.enableDisplayMode("block");
+            this.maskEl.bottom.enableDisplayMode("block");
+            this.maskEl.right.enableDisplayMode("block");
+            
+            Roo.get(document.body).on('click', function(){
+                this.unmask();
+            }, this);
+            
+            Roo.get(document.body).on('touchstart', function(){
+                this.unmask();
+            }, this);
+            
+            this.isApplied = true
+        },
+        
+        mask : function(form, target)
+        {
+            this.form = form;
+            
+            this.target = target;
+            
+            if(!this.form.errorMask || !target.el){
+                return;
+            }
+            
+            var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
+            
+            var ot = this.target.el.calcOffsetsTo(scrollable);
+            
+            var scrollTo = ot[1] - this.form.maskOffset;
+            
+            scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
+            
+            scrollable.scrollTo('top', scrollTo);
+            
+            var el = this.target.wrap || this.target.el;
+            
+            var box = el.getBox();
+            
+            this.maskEl.top.setStyle('position', 'absolute');
+            this.maskEl.top.setStyle('z-index', 10000);
+            this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
+            this.maskEl.top.setLeft(0);
+            this.maskEl.top.setTop(0);
+            this.maskEl.top.show();
+            
+            this.maskEl.left.setStyle('position', 'absolute');
+            this.maskEl.left.setStyle('z-index', 10000);
+            this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
+            this.maskEl.left.setLeft(0);
+            this.maskEl.left.setTop(box.y - this.padding);
+            this.maskEl.left.show();
+
+            this.maskEl.bottom.setStyle('position', 'absolute');
+            this.maskEl.bottom.setStyle('z-index', 10000);
+            this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
+            this.maskEl.bottom.setLeft(0);
+            this.maskEl.bottom.setTop(box.bottom + this.padding);
+            this.maskEl.bottom.show();
+
+            this.maskEl.right.setStyle('position', 'absolute');
+            this.maskEl.right.setStyle('z-index', 10000);
+            this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
+            this.maskEl.right.setLeft(box.right + this.padding);
+            this.maskEl.right.setTop(box.y - this.padding);
+            this.maskEl.right.show();
+
+            this.intervalID = window.setInterval(function() {
+                Roo.form.BasicForm.popover.unmask();
+            }, 10000);
+
+            window.onwheel = function(){ return false;};
+            
+            (function(){ this.isMasked = true; }).defer(500, this);
+            
+        },
+        
+        unmask : function()
+        {
+            if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
+                return;
+            }
+            
+            this.maskEl.top.setStyle('position', 'absolute');
+            this.maskEl.top.setSize(0, 0).setXY([0, 0]);
+            this.maskEl.top.hide();
+
+            this.maskEl.left.setStyle('position', 'absolute');
+            this.maskEl.left.setSize(0, 0).setXY([0, 0]);
+            this.maskEl.left.hide();
+
+            this.maskEl.bottom.setStyle('position', 'absolute');
+            this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
+            this.maskEl.bottom.hide();
+
+            this.maskEl.right.setStyle('position', 'absolute');
+            this.maskEl.right.setSize(0, 0).setXY([0, 0]);
+            this.maskEl.right.hide();
+            
+            window.onwheel = function(){ return true;};
+            
+            if(this.intervalID){
+                window.clearInterval(this.intervalID);
+                this.intervalID = false;
+            }
+            
+            this.isMasked = false;
+            
+        }
+        
+    }
+    
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+
+/**
+ * @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
+ */
+Roo.form.Form = function(config){
+    var xitems =  [];
+    if (config.items) {
+        xitems = config.items;
+        delete config.items;
+    }
+   
+    
+    Roo.form.Form.superclass.constructor.call(this, null, config);
+    this.url = this.url || this.action;
+    if(!this.root){
+        this.root = new Roo.form.Layout(Roo.applyIf({
+            id: Roo.id()
+        }, config));
+    }
+    this.active = this.root;
     /**
-     * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
-     * (defaults to 4, does not apply if editable = false)
+     * Array of all the buttons that have been added to this form via {@link addButton}
+     * @type Array
      */
-    minChars : 4,
-    /**
-     * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
-     * delay (typeAheadDelay) if it matches a known value (defaults to false)
+    this.buttons = [];
+    this.allItems = [];
+    this.addEvents({
+        /**
+         * @event clientvalidation
+         * If the monitorValid config option is true, this event fires repetitively to notify of valid state
+         * @param {Form} this
+         * @param {Boolean} valid true if the form has passed client-side validation
+         */
+        clientvalidation: true,
+        /**
+         * @event rendered
+         * Fires when the form is rendered
+         * @param {Roo.form.Form} form
+         */
+        rendered : true
+    });
+    
+    if (this.progressUrl) {
+            // push a hidden field onto the list of fields..
+            this.addxtype( {
+                    xns: Roo.form, 
+                    xtype : 'Hidden', 
+                    name : 'UPLOAD_IDENTIFIER' 
+            });
+        }
+        
+    
+    Roo.each(xitems, this.addxtype, this);
+    
+};
+
+Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
+     /**
+     * @cfg {Roo.Button} buttons[] buttons at bottom of form
      */
-    typeAhead: false,
+    
     /**
-     * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
-     * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
+     * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
      */
-    queryDelay: 500,
     /**
-     * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
-     * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
+     * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
      */
-    pageSize: 0,
     /**
-     * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
-     * when editable = true (defaults to false)
+     * @cfg {String} (left|center|right) buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
      */
-    selectOnFocus:false,
+    buttonAlign:'center',
+
     /**
-     * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
+     * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
      */
-    queryParam: 'query',
+    minButtonWidth:75,
+
     /**
-     * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
-     * when mode = 'remote' (defaults to 'Loading...')
+     * @cfg {String} labelAlign (left|top|right) Valid values are "left," "top" and "right" (defaults to "left").
+     * This property cascades to child containers if not set.
      */
-    loadingText: 'Loading...',
+    labelAlign:'left',
+
     /**
-     * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
+     * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
+     * fires a looping event with that state. This is required to bind buttons to the valid
+     * state using the config value formBind:true on the button.
      */
-    resizable: false,
+    monitorValid : false,
+
     /**
-     * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
+     * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
      */
-    handleHeight : 8,
+    monitorPoll : 200,
+    
     /**
-     * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
-     * traditional select (defaults to true)
+     * @cfg {String} progressUrl - Url to return progress data 
      */
-    editable: true,
+    
+    progressUrl : false,
     /**
-     * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
+     * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
+     * sending a formdata with extra parameters - eg uploaded elements.
      */
-    allQuery: '',
+    
+    formData : false,
+    
     /**
-     * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
+     * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
+     * fields are added and the column is closed. If no fields are passed the column remains open
+     * until end() is called.
+     * @param {Object} config The config to pass to the column
+     * @param {Field} field1 (optional)
+     * @param {Field} field2 (optional)
+     * @param {Field} etc (optional)
+     * @return Column The column container object
      */
-    mode: 'remote',
+    column : function(c){
+        var col = new Roo.form.Column(c);
+        this.start(col);
+        if(arguments.length > 1){ // duplicate code required because of Opera
+            this.add.apply(this, Array.prototype.slice.call(arguments, 1));
+            this.end();
+        }
+        return col;
+    },
+
     /**
-     * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
-     * listWidth has a higher value)
+     * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
+     * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
+     * until end() is called.
+     * @param {Object} config The config to pass to the fieldset
+     * @param {Field} field1 (optional)
+     * @param {Field} field2 (optional)
+     * @param {Field} etc (optional)
+     * @return FieldSet The fieldset container object
      */
-    minListWidth : 70,
+    fieldset : function(c){
+        var fs = new Roo.form.FieldSet(c);
+        this.start(fs);
+        if(arguments.length > 1){ // duplicate code required because of Opera
+            this.add.apply(this, Array.prototype.slice.call(arguments, 1));
+            this.end();
+        }
+        return fs;
+    },
+
     /**
-     * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
-     * allow the user to set arbitrary text into the field (defaults to false)
+     * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
+     * fields are added and the container is closed. If no fields are passed the container remains open
+     * until end() is called.
+     * @param {Object} config The config to pass to the Layout
+     * @param {Field} field1 (optional)
+     * @param {Field} field2 (optional)
+     * @param {Field} etc (optional)
+     * @return Layout The container object
      */
-    forceSelection:false,
+    container : function(c){
+        var l = new Roo.form.Layout(c);
+        this.start(l);
+        if(arguments.length > 1){ // duplicate code required because of Opera
+            this.add.apply(this, Array.prototype.slice.call(arguments, 1));
+            this.end();
+        }
+        return l;
+    },
+
     /**
-     * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
-     * if typeAhead = true (defaults to 250)
+     * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
+     * @param {Object} container A Roo.form.Layout or subclass of Layout
+     * @return {Form} this
      */
-    typeAheadDelay : 250,
+    start : function(c){
+        // cascade label info
+        Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
+        this.active.stack.push(c);
+        c.ownerCt = this.active;
+        this.active = c;
+        return this;
+    },
+
     /**
-     * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
-     * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
+     * Closes the current open container
+     * @return {Form} this
      */
-    valueNotFoundText : undefined,
-    
+    end : function(){
+        if(this.active == this.root){
+            return this;
+        }
+        this.active = this.active.ownerCt;
+        return this;
+    },
+
     /**
-     * @cfg {String} defaultValue The value displayed after loading the store.
+     * Add Roo.form components to the current open container (e.g. column, fieldset, etc.).  Fields added via this method
+     * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
+     * as the label of the field.
+     * @param {Field} field1
+     * @param {Field} field2 (optional)
+     * @param {Field} etc. (optional)
+     * @return {Form} this
      */
-    defaultValue: '',
+    add : function(){
+        this.active.stack.push.apply(this.active.stack, arguments);
+        this.allItems.push.apply(this.allItems,arguments);
+        var r = [];
+        for(var i = 0, a = arguments, len = a.length; i < len; i++) {
+            if(a[i].isFormField){
+                r.push(a[i]);
+            }
+        }
+        if(r.length > 0){
+            Roo.form.Form.superclass.add.apply(this, r);
+        }
+        return this;
+    },
     
-    /**
-     * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
-     */
-    blockFocus : false,
+
     
-    /**
-     * @cfg {Boolean} disableClear Disable showing of clear button.
-     */
-    disableClear : false,
-    /**
-     * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
-     */
-    alwaysQuery : false,
     
-    //private
-    addicon : false,
-    editicon: false,
     
-    // element that contains real text value.. (when hidden is used..)
+     /**
+     * Find any element that has been added to a form, using it's ID or name
+     * This can include framesets, columns etc. along with regular fields..
+     * @param {String} id - id or name to find.
      
-    // private
-    onRender : function(ct, position){
-        Roo.form.Field.prototype.onRender.call(this, ct, position);
-        
-        if(this.store){
-            this.store.on('beforeload', this.onBeforeLoad, this);
-            this.store.on('load', this.onLoad, this);
-            this.store.on('loadexception', this.onLoadException, this);
-            this.store.load({});
+     * @return {Element} e - or false if nothing found.
+     */
+    findbyId : function(id)
+    {
+        var ret = false;
+        if (!id) {
+            return ret;
         }
+        Roo.each(this.allItems, function(f){
+            if (f.id == id || f.name == id ){
+                ret = f;
+                return false;
+            }
+        });
+        return ret;
+    },
+
+    
+    
+    /**
+     * Render this form into the passed container. This should only be called once!
+     * @param {String/HTMLElement/Element} container The element this component should be rendered into
+     * @return {Form} this
+     */
+    render : function(ct)
+    {
         
         
         
-    },
-
-    // private
-    initEvents : function(){
-        //Roo.form.ComboBox.superclass.initEvents.call(this);
-    },
+        ct = Roo.get(ct);
+        var o = this.autoCreate || {
+            tag: 'form',
+            method : this.method || 'POST',
+            id : this.id || Roo.id()
+        };
+        this.initEl(ct.createChild(o));
 
-    onDestroy : function(){
+        this.root.render(this.el);
+        
        
-        if(this.store){
-            this.store.un('beforeload', this.onBeforeLoad, this);
-            this.store.un('load', this.onLoad, this);
-            this.store.un('loadexception', this.onLoadException, this);
-        }
-        //Roo.form.ComboBox.superclass.onDestroy.call(this);
-    },
+             
+        this.items.each(function(f){
+            f.render('x-form-el-'+f.id);
+        });
 
-    // private
-    fireKey : function(e){
-        if(e.isNavKeyPress() && !this.list.isVisible()){
-            this.fireEvent("specialkey", this, e);
+        if(this.buttons.length > 0){
+            // tables are required to maintain order and for correct IE layout
+            var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
+                cls:"x-form-btns x-form-btns-"+this.buttonAlign,
+                html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
+            }}, null, true);
+            var tr = tb.getElementsByTagName('tr')[0];
+            for(var i = 0, len = this.buttons.length; i < len; i++) {
+                var b = this.buttons[i];
+                var td = document.createElement('td');
+                td.className = 'x-form-btn-td';
+                b.render(tr.appendChild(td));
+            }
         }
-    },
-
-    // private
-    onResize: function(w, h){
-        
-        return; 
-    
-        
+        if(this.monitorValid){ // initialize after render
+            this.startMonitoring();
+        }
+        this.fireEvent('rendered', this);
+        return this;
     },
 
     /**
-     * Allow or prevent the user from directly editing the field text.  If false is passed,
-     * the user will only be able to select from the items defined in the dropdown list.  This method
-     * is the runtime equivalent of setting the 'editable' config option at config time.
-     * @param {Boolean} value True to allow the user to directly edit the field text
+     * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
+     * @param {String/Object} config A string becomes the button text, an object can either be a Button config
+     * object or a valid Roo.DomHelper element config
+     * @param {Function} handler The function called when the button is clicked
+     * @param {Object} scope (optional) The scope of the handler function
+     * @return {Roo.Button}
      */
-    setEditable : function(value){
-         
-    },
-
-    // private
-    onBeforeLoad : function(){
-        
-        Roo.log("Select before load");
-        return;
-    
-        this.innerList.update(this.loadingText ?
-               '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
-        //this.restrictHeight();
-        this.selectedIndex = -1;
+    addButton : function(config, handler, scope){
+        var bc = {
+            handler: handler,
+            scope: scope,
+            minWidth: this.minButtonWidth,
+            hideParent:true
+        };
+        if(typeof config == "string"){
+            bc.text = config;
+        }else{
+            Roo.apply(bc, config);
+        }
+        var btn = new Roo.Button(null, bc);
+        this.buttons.push(btn);
+        return btn;
     },
 
-    // private
-    onLoad : function(){
-
+     /**
+     * Adds a series of form elements (using the xtype property as the factory method.
+     * Valid xtypes are:  TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
+     * @param {Object} config 
+     */
     
-        var dom = this.el.dom;
-        dom.innerHTML = '';
-         var od = dom.ownerDocument;
-         
-        if (this.emptyText) {
-            var op = od.createElement('option');
-            op.setAttribute('value', '');
-            op.innerHTML = String.format('{0}', this.emptyText);
-            dom.appendChild(op);
-        }
-        if(this.store.getCount() > 0){
-           
-            var vf = this.valueField;
-            var df = this.displayField;
-            this.store.data.each(function(r) {
-                // which colmsn to use... testing - cdoe / title..
-                var op = od.createElement('option');
-                op.setAttribute('value', r.data[vf]);
-                op.innerHTML = String.format('{0}', r.data[df]);
-                dom.appendChild(op);
-            });
-            if (typeof(this.defaultValue != 'undefined')) {
-                this.setValue(this.defaultValue);
+    addxtype : function()
+    {
+        var ar = Array.prototype.slice.call(arguments, 0);
+        var ret = false;
+        for(var i = 0; i < ar.length; i++) {
+            if (!ar[i]) {
+                continue; // skip -- if this happends something invalid got sent, we 
+                // should ignore it, as basically that interface element will not show up
+                // and that should be pretty obvious!!
             }
             
-             
-        }else{
-            //this.onEmptyResults();
-        }
-        //this.el.focus();
-    },
-    // private
-    onLoadException : function()
-    {
-        dom.innerHTML = '';
+            if (Roo.form[ar[i].xtype]) {
+                ar[i].form = this;
+                var fe = Roo.factory(ar[i], Roo.form);
+                if (!ret) {
+                    ret = fe;
+                }
+                fe.form = this;
+                if (fe.store) {
+                    fe.store.form = this;
+                }
+                if (fe.isLayout) {  
+                         
+                    this.start(fe);
+                    this.allItems.push(fe);
+                    if (fe.items && fe.addxtype) {
+                        fe.addxtype.apply(fe, fe.items);
+                        delete fe.items;
+                    }
+                     this.end();
+                    continue;
+                }
+                
+                
+                 
+                this.add(fe);
+              //  console.log('adding ' + ar[i].xtype);
+            }
+            if (ar[i].xtype == 'Button') {  
+                //console.log('adding button');
+                //console.log(ar[i]);
+                this.addButton(ar[i]);
+                this.allItems.push(fe);
+                continue;
+            }
+            
+            if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
+                alert('end is not supported on xtype any more, use items');
+            //    this.end();
+            //    //console.log('adding end');
+            }
             
-        Roo.log("Select on load exception");
-        return;
-    
-        this.collapse();
-        Roo.log(this.store.reader.jsonData);
-        if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
-            Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
-        }
-        
-        
-    },
-    // private
-    onTypeAhead : function(){
-         
-    },
-
-    // private
-    onSelect : function(record, index){
-        Roo.log('on select?');
-        return;
-        if(this.fireEvent('beforeselect', this, record, index) !== false){
-            this.setFromData(index > -1 ? record.data : false);
-            this.collapse();
-            this.fireEvent('select', this, record, index);
         }
+        return ret;
     },
-
+    
     /**
-     * Returns the currently selected field value or empty string if no value is set.
-     * @return {String} value The selected value
+     * Starts monitoring of the valid state of this form. Usually this is done by passing the config
+     * option "monitorValid"
      */
-    getValue : function(){
-        var dom = this.el.dom;
-        this.value = dom.options[dom.selectedIndex].value;
-        return this.value;
-        
+    startMonitoring : function(){
+        if(!this.bound){
+            this.bound = true;
+            Roo.TaskMgr.start({
+                run : this.bindHandler,
+                interval : this.monitorPoll || 200,
+                scope: this
+            });
+        }
     },
 
     /**
-     * Clears any text/value currently set in the field
+     * Stops monitoring of the valid state of this form
      */
-    clearValue : function(){
-        this.value = '';
-        this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
-        
+    stopMonitoring : function(){
+        this.bound = false;
     },
 
-    /**
-     * Sets the specified value into the field.  If the value finds a match, the corresponding record text
-     * will be displayed in the field.  If the value does not match the data value of an existing item,
-     * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
-     * Otherwise the field will be blank (although the value will still be set).
-     * @param {String} value The value to match
-     */
-    setValue : function(v){
-        var d = this.el.dom;
-        for (var i =0; i < d.options.length;i++) {
-            if (v == d.options[i].value) {
-                d.selectedIndex = i;
-                this.value = v;
-                return;
+    // private
+    bindHandler : function(){
+        if(!this.bound){
+            return false; // stops binding
+        }
+        var valid = true;
+        this.items.each(function(f){
+            if(!f.isValid(true)){
+                valid = false;
+                return false;
+            }
+        });
+        for(var i = 0, len = this.buttons.length; i < len; i++){
+            var btn = this.buttons[i];
+            if(btn.formBind === true && btn.disabled === valid){
+                btn.setDisabled(!valid);
             }
         }
-        this.clearValue();
-    },
-    /**
-     * @property {Object} the last set data for the element
-     */
+        this.fireEvent('clientvalidation', this, valid);
+    }
     
-    lastData : false,
-    /**
-     * Sets the value of the field based on a object which is related to the record format for the store.
-     * @param {Object} value the value to set as. or false on reset?
-     */
-    setFromData : function(o){
-        Roo.log('setfrom data?');
-         
-        
-        
-    },
-    // private
-    reset : function(){
-        this.clearValue();
-    },
-    // private
-    findRecord : function(prop, value){
-        
-        return false;
     
-        var record;
-        if(this.store.getCount() > 0){
-            this.store.each(function(r){
-                if(r.data[prop] == value){
-                    record = r;
-                    return false;
-                }
-                return true;
-            });
-        }
-        return record;
-    },
     
-    getName: function()
-    {
-        // returns hidden if it's set..
-        if (!this.rendered) {return ''};
-        return !this.hiddenName && this.el.dom.name  ? this.el.dom.name : (this.hiddenName || '');
-        
+    
+    
+    
+    
+    
+});
+
+
+// back compat
+Roo.Form = Roo.form.Form;
+/*
+ * 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">
+ */
+
+// as we use this in bootstrap.
+Roo.namespace('Roo.form');
+ /**
+ * @class Roo.form.Action
+ * Internal Class used to handle form actions
+ * @constructor
+ * @param {Roo.form.BasicForm} el The form element or its id
+ * @param {Object} config Configuration options
+ */
+
+// define the action interface
+Roo.form.Action = function(form, options){
+    this.form = form;
+    this.options = options || {};
+};
+/**
+ * Client Validation Failed
+ * @const 
+ */
+Roo.form.Action.CLIENT_INVALID = 'client';
+/**
+ * Server Validation Failed
+ * @const 
+ */
+Roo.form.Action.SERVER_INVALID = 'server';
+ /**
+ * Connect to Server Failed
+ * @const 
+ */
+Roo.form.Action.CONNECT_FAILURE = 'connect';
+/**
+ * Reading Data from Server Failed
+ * @const 
+ */
+Roo.form.Action.LOAD_FAILURE = 'load';
+
+Roo.form.Action.prototype = {
+    type : 'default',
+    failureType : undefined,
+    response : undefined,
+    result : undefined,
+
+    // interface method
+    run : function(options){
+
     },
-     
 
-    
+    // interface method
+    success : function(response){
 
-    // private
-    onEmptyResults : function(){
-        Roo.log('empty results');
-        //this.collapse();
     },
 
-    /**
-     * Returns true if the dropdown list is expanded, else false.
-     */
-    isExpanded : function(){
-        return false;
+    // interface method
+    handleResponse : function(response){
+
     },
 
-    /**
-     * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
-     * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
-     * @param {String} value The data value of the item to select
-     * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
-     * selected item if it is not currently in view (defaults to true)
-     * @return {Boolean} True if the value matched an item in the list, else false
-     */
-    selectByValue : function(v, scrollIntoView){
-        Roo.log('select By Value');
-        return false;
-    
-        if(v !== undefined && v !== null){
-            var r = this.findRecord(this.valueField || this.displayField, v);
-            if(r){
-                this.select(this.store.indexOf(r), scrollIntoView);
-                return true;
-            }
+    // default connection failure
+    failure : function(response){
+        
+        this.response = response;
+        this.failureType = Roo.form.Action.CONNECT_FAILURE;
+        this.form.afterAction(this, false);
+    },
+
+    processResponse : function(response){
+        this.response = response;
+        if(!response.responseText){
+            return true;
         }
-        return false;
+        this.result = this.handleResponse(response);
+        return this.result;
     },
 
-    /**
-     * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
-     * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
-     * @param {Number} index The zero-based index of the list item to select
-     * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
-     * selected item if it is not currently in view (defaults to true)
-     */
-    select : function(index, scrollIntoView){
-        Roo.log('select ');
-        return  ;
-        
-        this.selectedIndex = index;
-        this.view.select(index);
-        if(scrollIntoView !== false){
-            var el = this.view.getNode(index);
-            if(el){
-                this.innerList.scrollChildIntoView(el, false);
+    // utility functions used internally
+    getUrl : function(appendParams){
+        var url = this.options.url || this.form.url || this.form.el.dom.action;
+        if(appendParams){
+            var p = this.getParams();
+            if(p){
+                url += (url.indexOf('?') != -1 ? '&' : '?') + p;
             }
         }
+        return url;
     },
 
-      
+    getMethod : function(){
+        return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
+    },
 
-    // private
-    validateBlur : function(){
-        
-        return;
-        
+    getParams : function(){
+        var bp = this.form.baseParams;
+        var p = this.options.params;
+        if(p){
+            if(typeof p == "object"){
+                p = Roo.urlEncode(Roo.applyIf(p, bp));
+            }else if(typeof p == 'string' && bp){
+                p += '&' + Roo.urlEncode(bp);
+            }
+        }else if(bp){
+            p = Roo.urlEncode(bp);
+        }
+        return p;
     },
 
-    // private
-    initQuery : function(){
-        this.doQuery(this.getRawValue());
+    createCallback : function(){
+        return {
+            success: this.success,
+            failure: this.failure,
+            scope: this,
+            timeout: (this.form.timeout*1000),
+            upload: this.form.fileUpload ? this.success : undefined
+        };
+    }
+};
+
+Roo.form.Action.Submit = function(form, options){
+    Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
+};
+
+Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
+    type : 'submit',
+
+    haveProgress : false,
+    uploadComplete : false,
+    
+    // uploadProgress indicator.
+    uploadProgress : function()
+    {
+        if (!this.form.progressUrl) {
+            return;
+        }
+        
+        if (!this.haveProgress) {
+            Roo.MessageBox.progress("Uploading", "Uploading");
+        }
+        if (this.uploadComplete) {
+           Roo.MessageBox.hide();
+           return;
+        }
+        
+        this.haveProgress = true;
+   
+        var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
+        
+        var c = new Roo.data.Connection();
+        c.request({
+            url : this.form.progressUrl,
+            params: {
+                id : uid
+            },
+            method: 'GET',
+            success : function(req){
+               //console.log(data);
+                var rdata = false;
+                var edata;
+                try  {
+                   rdata = Roo.decode(req.responseText)
+                } catch (e) {
+                    Roo.log("Invalid data from server..");
+                    Roo.log(edata);
+                    return;
+                }
+                if (!rdata || !rdata.success) {
+                    Roo.log(rdata);
+                    Roo.MessageBox.alert(Roo.encode(rdata));
+                    return;
+                }
+                var data = rdata.data;
+                
+                if (this.uploadComplete) {
+                   Roo.MessageBox.hide();
+                   return;
+                }
+                   
+                if (data){
+                    Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
+                       Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
+                    );
+                }
+                this.uploadProgress.defer(2000,this);
+            },
+       
+            failure: function(data) {
+                Roo.log('progress url failed ');
+                Roo.log(data);
+            },
+            scope : this
+        });
+           
     },
+    
+    
+    run : function()
+    {
+        // run get Values on the form, so it syncs any secondary forms.
+        this.form.getValues();
+        
+        var o = this.options;
+        var method = this.getMethod();
+        var isPost = method == 'POST';
+        if(o.clientValidation === false || this.form.isValid()){
+            
+            if (this.form.progressUrl) {
+                this.form.findField('UPLOAD_IDENTIFIER').setValue(
+                    (new Date() * 1) + '' + Math.random());
+                    
+            } 
+            
+            
+            Roo.Ajax.request(Roo.apply(this.createCallback(), {
+                form:this.form.el.dom,
+                url:this.getUrl(!isPost),
+                method: method,
+                params:isPost ? this.getParams() : null,
+                isUpload: this.form.fileUpload,
+                formData : this.form.formData
+            }));
+            
+            this.uploadProgress();
 
-    // private
-    doForce : function(){
-        if(this.el.dom.value.length > 0){
-            this.el.dom.value =
-                this.lastSelectionText === undefined ? '' : this.lastSelectionText;
-             
+        }else if (o.clientValidation !== false){ // client validation failed
+            this.failureType = Roo.form.Action.CLIENT_INVALID;
+            this.form.afterAction(this, false);
         }
     },
 
-    /**
-     * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
-     * query allowing the query action to be canceled if needed.
-     * @param {String} query The SQL query to execute
-     * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
-     * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
-     * saved in the current store (defaults to false)
-     */
-    doQuery : function(q, forceAll){
+    success : function(response)
+    {
+        this.uploadComplete= true;
+        if (this.haveProgress) {
+            Roo.MessageBox.hide();
+        }
         
-        Roo.log('doQuery?');
-        if(q === undefined || q === null){
-            q = '';
+        
+        var result = this.processResponse(response);
+        if(result === true || result.success){
+            this.form.afterAction(this, true);
+            return;
         }
-        var qe = {
-            query: q,
-            forceAll: forceAll,
-            combo: this,
-            cancel:false
-        };
-        if(this.fireEvent('beforequery', qe)===false || qe.cancel){
-            return false;
+        if(result.errors){
+            this.form.markInvalid(result.errors);
+            this.failureType = Roo.form.Action.SERVER_INVALID;
         }
-        q = qe.query;
-        forceAll = qe.forceAll;
-        if(forceAll === true || (q.length >= this.minChars)){
-            if(this.lastQuery != q || this.alwaysQuery){
-                this.lastQuery = q;
-                if(this.mode == 'local'){
-                    this.selectedIndex = -1;
-                    if(forceAll){
-                        this.store.clearFilter();
-                    }else{
-                        this.store.filter(this.displayField, q);
-                    }
-                    this.onLoad();
-                }else{
-                    this.store.baseParams[this.queryParam] = q;
-                    this.store.load({
-                        params: this.getParams(q)
-                    });
-                    this.expand();
+        this.form.afterAction(this, false);
+    },
+    failure : function(response)
+    {
+        this.uploadComplete= true;
+        if (this.haveProgress) {
+            Roo.MessageBox.hide();
+        }
+        
+        this.response = response;
+        this.failureType = Roo.form.Action.CONNECT_FAILURE;
+        this.form.afterAction(this, false);
+    },
+    
+    handleResponse : function(response){
+        if(this.form.errorReader){
+            var rs = this.form.errorReader.read(response);
+            var errors = [];
+            if(rs.records){
+                for(var i = 0, len = rs.records.length; i < len; i++) {
+                    var r = rs.records[i];
+                    errors[i] = r.data;
                 }
-            }else{
-                this.selectedIndex = -1;
-                this.onLoad();   
             }
+            if(errors.length < 1){
+                errors = null;
+            }
+            return {
+                success : rs.success,
+                errors : errors
+            };
         }
-    },
-
-    // private
-    getParams : function(q){
-        var p = {};
-        //p[this.queryParam] = q;
-        if(this.pageSize){
-            p.start = 0;
-            p.limit = this.pageSize;
+        var ret = false;
+        try {
+            var rt = response.responseText;
+            if (rt.match(/^\<!--\[CDATA\[/)) {
+                rt = rt.replace(/^\<!--\[CDATA\[/,'');
+                rt = rt.replace(/\]\]--\>$/,'');
+            }
+            
+            ret = Roo.decode(rt);
+        } catch (e) {
+            ret = {
+                success: false,
+                errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
+                errors : []
+            };
         }
-        return p;
-    },
+        return ret;
+        
+    }
+});
 
-    /**
-     * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
-     */
-    collapse : function(){
+
+Roo.form.Action.Load = function(form, options){
+    Roo.form.Action.Load.superclass.constructor.call(this, form, options);
+    this.reader = this.form.reader;
+};
+
+Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
+    type : 'load',
+
+    run : function(){
         
+        Roo.Ajax.request(Roo.apply(
+                this.createCallback(), {
+                    method:this.getMethod(),
+                    url:this.getUrl(false),
+                    params:this.getParams()
+        }));
     },
 
-    // private
-    collapseIf : function(e){
+    success : function(response){
         
+        var result = this.processResponse(response);
+        if(result === true || !result.success || !result.data){
+            this.failureType = Roo.form.Action.LOAD_FAILURE;
+            this.form.afterAction(this, false);
+            return;
+        }
+        this.form.clearInvalid();
+        this.form.setValues(result.data);
+        this.form.afterAction(this, true);
     },
 
+    handleResponse : function(response){
+        if(this.form.reader){
+            var rs = this.form.reader.read(response);
+            var data = rs.records && rs.records[0] ? rs.records[0].data : null;
+            return {
+                success : rs.success,
+                data : data
+            };
+        }
+        return Roo.decode(response.responseText);
+    }
+});
+
+Roo.form.Action.ACTION_TYPES = {
+    'load' : Roo.form.Action.Load,
+    'submit' : Roo.form.Action.Submit
+};/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+/**
+ * @class Roo.form.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
+ */
+Roo.form.Layout = function(config){
+    var xitems = [];
+    if (config.items) {
+        xitems = config.items;
+        delete config.items;
+    }
+    Roo.form.Layout.superclass.constructor.call(this, config);
+    this.stack = [];
+    Roo.each(xitems, this.addxtype, this);
+     
+};
+
+Roo.extend(Roo.form.Layout, Roo.Component, {
     /**
-     * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
+     * @cfg {String/Object} autoCreate
+     * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
      */
-    expand : function(){
-        
-    } ,
+    /**
+     * @cfg {String/Object/Function} style
+     * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
+     * a function which returns such a specification.
+     */
+    /**
+     * @cfg {String} labelAlign (left|top|right)
+     * Valid values are "left," "top" and "right" (defaults to "left")
+     */
+    /**
+     * @cfg {Number} labelWidth
+     * Fixed width in pixels of all field labels (defaults to undefined)
+     */
+    /**
+     * @cfg {Boolean} clear
+     * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
+     */
+    clear : true,
+    /**
+     * @cfg {String} labelSeparator
+     * The separator to use after field labels (defaults to ':')
+     */
+    labelSeparator : ':',
+    /**
+     * @cfg {Boolean} hideLabels
+     * True to suppress the display of field labels in this layout (defaults to false)
+     */
+    hideLabels : false,
 
     // private
-     
+    defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
+    
+    isLayout : true,
+    
+    // private
+    onRender : function(ct, position){
+        if(this.el){ // from markup
+            this.el = Roo.get(this.el);
+        }else {  // generate
+            var cfg = this.getAutoCreate();
+            this.el = ct.createChild(cfg, position);
+        }
+        if(this.style){
+            this.el.applyStyles(this.style);
+        }
+        if(this.labelAlign){
+            this.el.addClass('x-form-label-'+this.labelAlign);
+        }
+        if(this.hideLabels){
+            this.labelStyle = "display:none";
+            this.elementStyle = "padding-left:0;";
+        }else{
+            if(typeof this.labelWidth == 'number'){
+                this.labelStyle = "width:"+this.labelWidth+"px;";
+                this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
+            }
+            if(this.labelAlign == 'top'){
+                this.labelStyle = "width:auto;";
+                this.elementStyle = "padding-left:0;";
+            }
+        }
+        var stack = this.stack;
+        var slen = stack.length;
+        if(slen > 0){
+            if(!this.fieldTpl){
+                var t = new Roo.Template(
+                    '<div class="x-form-item {5}">',
+                        '<label for="{0}" style="{2}">{1}{4}</label>',
+                        '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
+                        '</div>',
+                    '</div><div class="x-form-clear-left"></div>'
+                );
+                t.disableFormats = true;
+                t.compile();
+                Roo.form.Layout.prototype.fieldTpl = t;
+            }
+            for(var i = 0; i < slen; i++) {
+                if(stack[i].isFormField){
+                    this.renderField(stack[i]);
+                }else{
+                    this.renderComponent(stack[i]);
+                }
+            }
+        }
+        if(this.clear){
+            this.el.createChild({cls:'x-form-clear'});
+        }
+    },
 
-    /** 
-    * @cfg {Boolean} grow 
-    * @hide 
-    */
-    /** 
-    * @cfg {Number} growMin 
-    * @hide 
-    */
-    /** 
-    * @cfg {Number} growMax 
-    * @hide 
-    */
+    // private
+    renderField : function(f){
+        f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
+               f.id, //0
+               f.fieldLabel, //1
+               f.labelStyle||this.labelStyle||'', //2
+               this.elementStyle||'', //3
+               typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
+               f.itemCls||this.itemCls||''  //5
+       ], true).getPrevSibling());
+    },
+
+    // private
+    renderComponent : function(c){
+        c.render(c.isLayout ? this.el : this.el.createChild());    
+    },
     /**
-     * @hide
-     * @method autoSize
+     * Adds a object form elements (using the xtype property as the factory method.)
+     * Valid xtypes are:  TextField, TextArea .... Button, Layout, FieldSet, Column
+     * @param {Object} config 
      */
-    
-    setWidth : function()
+    addxtype : function(o)
     {
+        // create the lement.
+        o.form = this.form;
+        var fe = Roo.factory(o, Roo.form);
+        this.form.allItems.push(fe);
+        this.stack.push(fe);
         
-    },
-    getResizeEl : function(){
-        return this.el;
+        if (fe.isFormField) {
+            this.form.items.add(fe);
+        }
+         
+        return fe;
     }
-});//<script type="text/javasscript">
+});
+
 
 /**
- * @class Roo.DDView
- * A DnD enabled version of Roo.View.
- * @param {Element/String} container The Element in which to create the View.
- * @param {String} tpl The template string used to create the markup for each element of the View
- * @param {Object} config The configuration properties. These include all the config options of
- * {@link Roo.View} plus some specific to this class.<br>
- * <p>
- * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
- * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
- * <p>
- * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
-.x-view-drag-insert-above {
-       border-top:1px dotted #3366cc;
-}
-.x-view-drag-insert-below {
-       border-bottom:1px dotted #3366cc;
-}
-</code></pre>
- * 
+ * @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
  */
-Roo.DDView = function(container, tpl, config) {
-    Roo.DDView.superclass.constructor.apply(this, arguments);
-    this.getEl().setStyle("outline", "0px none");
-    this.getEl().unselectable();
-    if (this.dragGroup) {
-               this.setDraggable(this.dragGroup.split(","));
-    }
-    if (this.dropGroup) {
-               this.setDroppable(this.dropGroup.split(","));
-    }
-    if (this.deletable) {
-       this.setDeletable();
-    }
-    this.isDirtyFlag = false;
-       this.addEvents({
-               "drop" : true
-       });
+Roo.form.Column = function(config){
+    Roo.form.Column.superclass.constructor.call(this, config);
 };
 
-Roo.extend(Roo.DDView, Roo.View, {
-/**    @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
-/**    @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
-/**    @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
-/**    @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
-
-       isFormField: true,
-
-       reset: Roo.emptyFn,
-       
-       clearInvalid: Roo.form.Field.prototype.clearInvalid,
-
-       validate: function() {
-               return true;
-       },
-       
-       destroy: function() {
-               this.purgeListeners();
-               this.getEl.removeAllListeners();
-               this.getEl().remove();
-               if (this.dragZone) {
-                       if (this.dragZone.destroy) {
-                               this.dragZone.destroy();
-                       }
-               }
-               if (this.dropZone) {
-                       if (this.dropZone.destroy) {
-                               this.dropZone.destroy();
-                       }
-               }
-       },
-
-/**    Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
-       getName: function() {
-               return this.name;
-       },
+Roo.extend(Roo.form.Column, Roo.form.Layout, {
+    /**
+     * @cfg {Number/String} width
+     * The fixed width of the column in pixels or CSS value (defaults to "auto")
+     */
+    /**
+     * @cfg {String/Object} autoCreate
+     * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
+     */
 
-/**    Loads the View from a JSON string representing the Records to put into the Store. */
-       setValue: function(v) {
-               if (!this.store) {
-                       throw "DDView.setValue(). DDView must be constructed with a valid Store";
-               }
-               var data = {};
-               data[this.store.reader.meta.root] = v ? [].concat(v) : [];
-               this.store.proxy = new Roo.data.MemoryProxy(data);
-               this.store.load();
-       },
+    // private
+    defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
 
-/**    @return {String} a parenthesised list of the ids of the Records in the View. */
-       getValue: function() {
-               var result = '(';
-               this.store.each(function(rec) {
-                       result += rec.id + ',';
-               });
-               return result.substr(0, result.length - 1) + ')';
-       },
-       
-       getIds: function() {
-               var i = 0, result = new Array(this.store.getCount());
-               this.store.each(function(rec) {
-                       result[i++] = rec.id;
-               });
-               return result;
-       },
-       
-       isDirty: function() {
-               return this.isDirtyFlag;
-       },
+    // private
+    onRender : function(ct, position){
+        Roo.form.Column.superclass.onRender.call(this, ct, position);
+        if(this.width){
+            this.el.setWidth(this.width);
+        }
+    }
+});
 
 /**
- *     Part of the Roo.dd.DropZone interface. If no target node is found, the
- *     whole Element becomes the target, and this causes the drop gesture to append.
+ * @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
  */
-    getTargetFromEvent : function(e) {
-               var target = e.getTarget();
-               while ((target !== null) && (target.parentNode != this.el.dom)) {
-               target = target.parentNode;
-               }
-               if (!target) {
-                       target = this.el.dom.lastChild || this.el.dom;
-               }
-               return target;
-    },
 
-/**
- *     Create the drag data which consists of an object which has the property "ddel" as
- *     the drag proxy element. 
- */
-    getDragData : function(e) {
-        var target = this.findItemFromChild(e.getTarget());
-               if(target) {
-                       this.handleSelection(e);
-                       var selNodes = this.getSelectedNodes();
-            var dragData = {
-                source: this,
-                copy: this.copy || (this.allowCopy && e.ctrlKey),
-                nodes: selNodes,
-                records: []
-                       };
-                       var selectedIndices = this.getSelectedIndexes();
-                       for (var i = 0; i < selectedIndices.length; i++) {
-                               dragData.records.push(this.store.getAt(selectedIndices[i]));
-                       }
-                       if (selNodes.length == 1) {
-                               dragData.ddel = target.cloneNode(true); // the div element
-                       } else {
-                               var div = document.createElement('div'); // create the multi element drag "ghost"
-                               div.className = 'multi-proxy';
-                               for (var i = 0, len = selNodes.length; i < len; i++) {
-                                       div.appendChild(selNodes[i].cloneNode(true));
-                               }
-                               dragData.ddel = div;
-                       }
-            //console.log(dragData)
-            //console.log(dragData.ddel.innerHTML)
-                       return dragData;
-               }
-        //console.log('nodragData')
-               return false;
-    },
+Roo.form.Row = function(config){
+    Roo.form.Row.superclass.constructor.call(this, config);
+};
+Roo.extend(Roo.form.Row, Roo.form.Layout, {
+      /**
+     * @cfg {Number/String} width
+     * The fixed width of the column in pixels or CSS value (defaults to "auto")
+     */
+    /**
+     * @cfg {Number/String} height
+     * The fixed height of the column in pixels or CSS value (defaults to "auto")
+     */
+    defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
     
-/**    Specify to which ddGroup items in this DDView may be dragged. */
-    setDraggable: function(ddGroup) {
-       if (ddGroup instanceof Array) {
-               Roo.each(ddGroup, this.setDraggable, this);
-               return;
-       }
-       if (this.dragZone) {
-               this.dragZone.addToGroup(ddGroup);
-       } else {
-                       this.dragZone = new Roo.dd.DragZone(this.getEl(), {
-                               containerScroll: true,
-                               ddGroup: ddGroup 
-
-                       });
-//                     Draggability implies selection. DragZone's mousedown selects the element.
-                       if (!this.multiSelect) { this.singleSelect = true; }
-
-//                     Wire the DragZone's handlers up to methods in *this*
-                       this.dragZone.getDragData = this.getDragData.createDelegate(this);
-               }
-    },
-
-/**    Specify from which ddGroup this DDView accepts drops. */
-    setDroppable: function(ddGroup) {
-       if (ddGroup instanceof Array) {
-               Roo.each(ddGroup, this.setDroppable, this);
-               return;
-       }
-       if (this.dropZone) {
-               this.dropZone.addToGroup(ddGroup);
-       } else {
-                       this.dropZone = new Roo.dd.DropZone(this.getEl(), {
-                               containerScroll: true,
-                               ddGroup: ddGroup
-                       });
-
-//                     Wire the DropZone's handlers up to methods in *this*
-                       this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
-                       this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
-                       this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
-                       this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
-                       this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
-               }
-    },
-
-/**    Decide whether to drop above or below a View node. */
-    getDropPoint : function(e, n, dd){
-       if (n == this.el.dom) { return "above"; }
-               var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
-               var c = t + (b - t) / 2;
-               var y = Roo.lib.Event.getPageY(e);
-               if(y <= c) {
-                       return "above";
-               }else{
-                       return "below";
-               }
-    },
-
-    onNodeEnter : function(n, dd, e, data){
-               return false;
+    padWidth : 20,
+    // private
+    onRender : function(ct, position){
+        //console.log('row render');
+        if(!this.rowTpl){
+            var t = new Roo.Template(
+                '<div class="x-form-item {5}" style="float:left;width:{6}px">',
+                    '<label for="{0}" style="{2}">{1}{4}</label>',
+                    '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
+                    '</div>',
+                '</div>'
+            );
+            t.disableFormats = true;
+            t.compile();
+            Roo.form.Layout.prototype.rowTpl = t;
+        }
+        this.fieldTpl = this.rowTpl;
+        
+        //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
+        var labelWidth = 100;
+        
+        if ((this.labelAlign != 'top')) {
+            if (typeof this.labelWidth == 'number') {
+                labelWidth = this.labelWidth
+            }
+            this.padWidth =  20 + labelWidth;
+            
+        }
+        
+        Roo.form.Column.superclass.onRender.call(this, ct, position);
+        if(this.width){
+            this.el.setWidth(this.width);
+        }
+        if(this.height){
+            this.el.setHeight(this.height);
+        }
     },
     
-    onNodeOver : function(n, dd, e, data){
-               var pt = this.getDropPoint(e, n, dd);
-               // set the insert point style on the target node
-               var dragElClass = this.dropNotAllowed;
-               if (pt) {
-                       var targetElClass;
-                       if (pt == "above"){
-                               dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
-                               targetElClass = "x-view-drag-insert-above";
-                       } else {
-                               dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
-                               targetElClass = "x-view-drag-insert-below";
-                       }
-                       if (this.lastInsertClass != targetElClass){
-                               Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
-                               this.lastInsertClass = targetElClass;
-                       }
-               }
-               return dragElClass;
-       },
-
-    onNodeOut : function(n, dd, e, data){
-               this.removeDropIndicators(n);
-    },
-
-    onNodeDrop : function(n, dd, e, data){
-       if (this.fireEvent("drop", this, n, dd, e, data) === false) {
-               return false;
-       }
-       var pt = this.getDropPoint(e, n, dd);
-               var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
-               if (pt == "below") { insertAt++; }
-               for (var i = 0; i < data.records.length; i++) {
-                       var r = data.records[i];
-                       var dup = this.store.getById(r.id);
-                       if (dup && (dd != this.dragZone)) {
-                               Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
-                       } else {
-                               if (data.copy) {
-                                       this.store.insert(insertAt++, r.copy());
-                               } else {
-                                       data.source.isDirtyFlag = true;
-                                       r.store.remove(r);
-                                       this.store.insert(insertAt++, r);
-                               }
-                               this.isDirtyFlag = true;
-                       }
-               }
-               this.dragZone.cachedTarget = null;
-               return true;
-    },
-
-    removeDropIndicators : function(n){
-               if(n){
-                       Roo.fly(n).removeClass([
-                               "x-view-drag-insert-above",
-                               "x-view-drag-insert-below"]);
-                       this.lastInsertClass = "_noclass";
-               }
-    },
+    // private
+    renderField : function(f){
+        f.fieldEl = this.fieldTpl.append(this.el, [
+               f.id, f.fieldLabel,
+               f.labelStyle||this.labelStyle||'',
+               this.elementStyle||'',
+               typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
+               f.itemCls||this.itemCls||'',
+               f.width ? f.width + this.padWidth : 160 + this.padWidth
+       ],true);
+    }
+});
 
 /**
- *     Utility method. Add a delete option to the DDView's context menu.
- *     @param {String} imageUrl The URL of the "delete" icon image.
+ * @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
  */
-       setDeletable: function(imageUrl) {
-               if (!this.singleSelect && !this.multiSelect) {
-                       this.singleSelect = true;
-               }
-               var c = this.getContextMenu();
-               this.contextMenu.on("itemclick", function(item) {
-                       switch (item.id) {
-                               case "delete":
-                                       this.remove(this.getSelectedIndexes());
-                                       break;
-                       }
-               }, this);
-               this.contextMenu.add({
-                       icon: imageUrl,
-                       id: "delete",
-                       text: 'Delete'
-               });
-       },
-       
-/**    Return the context menu for this DDView. */
-       getContextMenu: function() {
-               if (!this.contextMenu) {
-//                     Create the View's context menu
-                       this.contextMenu = new Roo.menu.Menu({
-                               id: this.id + "-contextmenu"
-                       });
-                       this.el.on("contextmenu", this.showContextMenu, this);
-               }
-               return this.contextMenu;
-       },
-       
-       disableContextMenu: function() {
-               if (this.contextMenu) {
-                       this.el.un("contextmenu", this.showContextMenu, this);
-               }
-       },
+Roo.form.FieldSet = function(config){
+    Roo.form.FieldSet.superclass.constructor.call(this, config);
+};
 
-       showContextMenu: function(e, item) {
-        item = this.findItemFromChild(e.getTarget());
-               if (item) {
-                       e.stopEvent();
-                       this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
-                       this.contextMenu.showAt(e.getXY());
-           }
-    },
+Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
+    /**
+     * @cfg {String} legend
+     * The text to display as the legend for the FieldSet (defaults to '')
+     */
+    /**
+     * @cfg {String/Object} autoCreate
+     * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
+     */
 
-/**
- *     Remove {@link Roo.data.Record}s at the specified indices.
- *     @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
- */
-    remove: function(selectedIndices) {
-               selectedIndices = [].concat(selectedIndices);
-               for (var i = 0; i < selectedIndices.length; i++) {
-                       var rec = this.store.getAt(selectedIndices[i]);
-                       this.store.remove(rec);
-               }
-    },
+    // private
+    defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
 
-/**
- *     Double click fires the event, but also, if this is draggable, and there is only one other
- *     related DropZone, it transfers the selected node.
- */
-    onDblClick : function(e){
-        var item = this.findItemFromChild(e.getTarget());
-        if(item){
-            if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
-               return false;
-            }
-            if (this.dragGroup) {
-                   var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
-                   while (targets.indexOf(this.dropZone) > -1) {
-                           targets.remove(this.dropZone);
-                               }
-                   if (targets.length == 1) {
-                                       this.dragZone.cachedTarget = null;
-                       var el = Roo.get(targets[0].getEl());
-                       var box = el.getBox(true);
-                       targets[0].onNodeDrop(el.dom, {
-                               target: el.dom,
-                               xy: [box.x, box.y + box.height - 1]
-                       }, null, this.getDragData(e));
-                   }
-               }
-        }
-    },
-    
-    handleSelection: function(e) {
-               this.dragZone.cachedTarget = null;
-        var item = this.findItemFromChild(e.getTarget());
-        if (!item) {
-               this.clearSelections(true);
-               return;
+    // private
+    onRender : function(ct, position){
+        Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
+        if(this.legend){
+            this.setLegend(this.legend);
         }
-               if (item && (this.multiSelect || this.singleSelect)){
-                       if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
-                               this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
-                       }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
-                               this.unselect(item);
-                       } else {
-                               this.select(item, this.multiSelect && e.ctrlKey);
-                               this.lastSelection = item;
-                       }
-               }
     },
 
-    onItemClick : function(item, index, e){
-               if(this.fireEvent("beforeclick", this, index, item, e) === false){
-                       return false;
-               }
-               return true;
-    },
-
-    unselect : function(nodeInfo, suppressEvent){
-               var node = this.getNode(nodeInfo);
-               if(node && this.isSelected(node)){
-                       if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
-                               Roo.fly(node).removeClass(this.selectedClass);
-                               this.selections.remove(node);
-                               if(!suppressEvent){
-                                       this.fireEvent("selectionchange", this, this.selections);
-                               }
-                       }
-               }
+    // private
+    setLegend : function(text){
+        if(this.rendered){
+            this.el.child('legend').update(text);
+        }
     }
-});
-/*
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -51188,1082 +55951,1078 @@ Roo.extend(Roo.DDView, Roo.View, {
  * Fork - LGPL
  * <script type="text/javascript">
  */
 /**
- * @class Roo.LayoutManager
- * @extends Roo.util.Observable
- * Base class for layout managers.
- */
-Roo.LayoutManager = function(container, config){
-    Roo.LayoutManager.superclass.constructor.call(this);
-    this.el = Roo.get(container);
-    // ie scrollbar fix
-    if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
-        document.body.scroll = "no";
-    }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
-        this.el.position('relative');
-    }
-    this.id = this.el.id;
-    this.el.addClass("x-layout-container");
-    /** false to disable window resize monitoring @type Boolean */
-    this.monitorWindowResize = true;
-    this.regions = {};
-    this.addEvents({
+ * @class Roo.form.VTypes
+ * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
+ * @static
+ */
+Roo.form.VTypes = function(){
+    // closure these in so they are only created once.
+    var alpha = /^[a-zA-Z_]+$/;
+    var alphanum = /^[a-zA-Z0-9_]+$/;
+    var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
+    var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
+
+    // All these messages and functions are configurable
+    return {
         /**
-         * @event layout
-         * Fires when a layout is performed. 
-         * @param {Roo.LayoutManager} this
+         * The function used to validate email addresses
+         * @param {String} value The email address
          */
-        "layout" : true,
+        email : function(v){
+            return email.test(v);
+        },
         /**
-         * @event regionresized
-         * Fires when the user resizes a region. 
-         * @param {Roo.LayoutRegion} region The resized region
-         * @param {Number} newSize The new size (width for east/west, height for north/south)
+         * The error text to display when the email validation function returns false
+         * @type String
          */
-        "regionresized" : true,
+        emailText : 'This field should be an e-mail address in the format "user@domain.com"',
         /**
-         * @event regioncollapsed
-         * Fires when a region is collapsed. 
-         * @param {Roo.LayoutRegion} region The collapsed region
+         * The keystroke filter mask to be applied on email input
+         * @type RegExp
          */
-        "regioncollapsed" : true,
+        emailMask : /[a-z0-9_\.\-@]/i,
+
         /**
-         * @event regionexpanded
-         * Fires when a region is expanded.  
-         * @param {Roo.LayoutRegion} region The expanded region
+         * The function used to validate URLs
+         * @param {String} value The URL
          */
-        "regionexpanded" : true
+        url : function(v){
+            return url.test(v);
+        },
+        /**
+         * The error text to display when the url validation function returns false
+         * @type String
+         */
+        urlText : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
+        
+        /**
+         * The function used to validate alpha values
+         * @param {String} value The value
+         */
+        alpha : function(v){
+            return alpha.test(v);
+        },
+        /**
+         * The error text to display when the alpha validation function returns false
+         * @type String
+         */
+        alphaText : 'This field should only contain letters and _',
+        /**
+         * The keystroke filter mask to be applied on alpha input
+         * @type RegExp
+         */
+        alphaMask : /[a-z_]/i,
+
+        /**
+         * The function used to validate alphanumeric values
+         * @param {String} value The value
+         */
+        alphanum : function(v){
+            return alphanum.test(v);
+        },
+        /**
+         * The error text to display when the alphanumeric validation function returns false
+         * @type String
+         */
+        alphanumText : 'This field should only contain letters, numbers and _',
+        /**
+         * The keystroke filter mask to be applied on alphanumeric input
+         * @type RegExp
+         */
+        alphanumMask : /[a-z0-9_]/i
+    };
+}();//<script type="text/javascript">
+
+/**
+ * @class Roo.form.FCKeditor
+ * @extends Roo.form.TextArea
+ * Wrapper around the FCKEditor http://www.fckeditor.net
+ * @constructor
+ * Creates a new FCKeditor
+ * @param {Object} config Configuration options
+ */
+Roo.form.FCKeditor = function(config){
+    Roo.form.FCKeditor.superclass.constructor.call(this, config);
+    this.addEvents({
+         /**
+         * @event editorinit
+         * Fired when the editor is initialized - you can add extra handlers here..
+         * @param {FCKeditor} this
+         * @param {Object} the FCK object.
+         */
+        editorinit : true
     });
-    this.updating = false;
-    Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
+    
+    
 };
-
-Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
+Roo.form.FCKeditor.editors = { };
+Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
+{
+    //defaultAutoCreate : {
+    //    tag : "textarea",style   : "width:100px;height:60px;" ,autocomplete    : "off"
+    //},
+    // private
     /**
-     * Returns true if this layout is currently being updated
-     * @return {Boolean}
+     * @cfg {Object} fck options - see fck manual for details.
      */
-    isUpdating : function(){
-        return this.updating; 
-    },
+    fckconfig : false,
     
     /**
-     * Suspend the LayoutManager from doing auto-layouts while
-     * making multiple add or remove calls
+     * @cfg {Object} fck toolbar set (Basic or Default)
      */
-    beginUpdate : function(){
-        this.updating = true;    
-    },
-    
+    toolbarSet : 'Basic',
     /**
-     * Restore auto-layouts and optionally disable the manager from performing a layout
-     * @param {Boolean} noLayout true to disable a layout update 
-     */
-    endUpdate : function(noLayout){
-        this.updating = false;
-        if(!noLayout){
-            this.layout();
-        }    
-    },
+     * @cfg {Object} fck BasePath
+     */ 
+    basePath : '/fckeditor/',
     
-    layout: function(){
+    
+    frame : false,
+    
+    value : '',
+    
+   
+    onRender : function(ct, position)
+    {
+        if(!this.el){
+            this.defaultAutoCreate = {
+                tag: "textarea",
+                style:"width:300px;height:60px;",
+                autocomplete: "new-password"
+            };
+        }
+        Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
+        /*
+        if(this.grow){
+            this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
+            if(this.preventScrollbars){
+                this.el.setStyle("overflow", "hidden");
+            }
+            this.el.setHeight(this.growMin);
+        }
+        */
+        //console.log('onrender' + this.getId() );
+        Roo.form.FCKeditor.editors[this.getId()] = this;
+         
+
+        this.replaceTextarea() ;
         
     },
     
-    onRegionResized : function(region, newSize){
-        this.fireEvent("regionresized", region, newSize);
-        this.layout();
+    getEditor : function() {
+        return this.fckEditor;
     },
+    /**
+     * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
+     * @param {Mixed} value The value to set
+     */
     
-    onRegionCollapsed : function(region){
-        this.fireEvent("regioncollapsed", region);
-    },
     
-    onRegionExpanded : function(region){
-        this.fireEvent("regionexpanded", region);
-    },
+    setValue : function(value)
+    {
+        //console.log('setValue: ' + value);
+        
+        if(typeof(value) == 'undefined') { // not sure why this is happending...
+            return;
+        }
+        Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
+        
+        //if(!this.el || !this.getEditor()) {
+        //    this.value = value;
+            //this.setValue.defer(100,this,[value]);    
+        //    return;
+        //} 
+        
+        if(!this.getEditor()) {
+            return;
+        }
         
+        this.getEditor().SetData(value);
+        
+        //
+
+    },
+
     /**
-     * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
-     * performs box-model adjustments.
-     * @return {Object} The size as an object {width: (the width), height: (the height)}
+     * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
+     * @return {Mixed} value The field value
      */
-    getViewSize : function(){
-        var size;
-        if(this.el.dom != document.body){
-            size = this.el.getSize();
-        }else{
-            size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
+    getValue : function()
+    {
+        
+        if (this.frame && this.frame.dom.style.display == 'none') {
+            return Roo.form.FCKeditor.superclass.getValue.call(this);
         }
-        size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
-        size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
-        return size;
+        
+        if(!this.el || !this.getEditor()) {
+           
+           // this.getValue.defer(100,this); 
+            return this.value;
+        }
+       
+        
+        var value=this.getEditor().GetData();
+        Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
+        return Roo.form.FCKeditor.superclass.getValue.call(this);
+        
+
     },
-    
+
     /**
-     * Returns the Element this layout is bound to.
-     * @return {Roo.Element}
+     * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
+     * @return {Mixed} value The field value
      */
-    getEl : function(){
-        return this.el;
+    getRawValue : function()
+    {
+        if (this.frame && this.frame.dom.style.display == 'none') {
+            return Roo.form.FCKeditor.superclass.getRawValue.call(this);
+        }
+        
+        if(!this.el || !this.getEditor()) {
+            //this.getRawValue.defer(100,this); 
+            return this.value;
+            return;
+        }
+        
+        
+        
+        var value=this.getEditor().GetData();
+        Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
+        return Roo.form.FCKeditor.superclass.getRawValue.call(this);
+         
     },
     
-    /**
-     * Returns the specified region.
-     * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
-     * @return {Roo.LayoutRegion}
-     */
-    getRegion : function(target){
-        return this.regions[target.toLowerCase()];
+    setSize : function(w,h) {
+        
+        
+        
+        //if (this.frame && this.frame.dom.style.display == 'none') {
+        //    Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
+        //    return;
+        //}
+        //if(!this.el || !this.getEditor()) {
+        //    this.setSize.defer(100,this, [w,h]); 
+        //    return;
+        //}
+        
+        
+        
+        Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
+        
+        this.frame.dom.setAttribute('width', w);
+        this.frame.dom.setAttribute('height', h);
+        this.frame.setSize(w,h);
+        
     },
     
-    onWindowResize : function(){
-        if(this.monitorWindowResize){
-            this.layout();
+    toggleSourceEdit : function(value) {
+        
+      
+         
+        this.el.dom.style.display = value ? '' : 'none';
+        this.frame.dom.style.display = value ?  'none' : '';
+        
+    },
+    
+    
+    focus: function(tag)
+    {
+        if (this.frame.dom.style.display == 'none') {
+            return Roo.form.FCKeditor.superclass.focus.call(this);
         }
-    }
-});/*
- * 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.BorderLayout
- * @extends Roo.LayoutManager
- * 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>
- * <a href="http://www.jackslocum.com/yui/2006/10/28/cross-browser-web-20-layouts-part-2-ajax-feed-viewer-20/">Cross Browser Layouts - Part 2</a><br><br>
- * Example:
- <pre><code>
- var layout = new Roo.BorderLayout(document.body, {
-    north: {
-        initialSize: 25,
-        titlebar: false
+        if(!this.el || !this.getEditor()) {
+            this.focus.defer(100,this, [tag]); 
+            return;
+        }
+        
+        
+        
+        
+        var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
+        this.getEditor().Focus();
+        if (tgs.length) {
+            if (!this.getEditor().Selection.GetSelection()) {
+                this.focus.defer(100,this, [tag]); 
+                return;
+            }
+            
+            
+            var r = this.getEditor().EditorDocument.createRange();
+            r.setStart(tgs[0],0);
+            r.setEnd(tgs[0],0);
+            this.getEditor().Selection.GetSelection().removeAllRanges();
+            this.getEditor().Selection.GetSelection().addRange(r);
+            this.getEditor().Focus();
+        }
+        
     },
-    west: {
-        split:true,
-        initialSize: 200,
-        minSize: 175,
-        maxSize: 400,
-        titlebar: true,
-        collapsible: true
+    
+    
+    
+    replaceTextarea : function()
+    {
+        if ( document.getElementById( this.getId() + '___Frame' ) ) {
+            return ;
+        }
+        //if ( !this.checkBrowser || this._isCompatibleBrowser() )
+        //{
+            // We must check the elements firstly using the Id and then the name.
+        var oTextarea = document.getElementById( this.getId() );
+        
+        var colElementsByName = document.getElementsByName( this.getId() ) ;
+         
+        oTextarea.style.display = 'none' ;
+
+        if ( oTextarea.tabIndex ) {            
+            this.TabIndex = oTextarea.tabIndex ;
+        }
+        
+        this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
+        this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
+        this.frame = Roo.get(this.getId() + '___Frame')
     },
-    east: {
-        split:true,
-        initialSize: 202,
-        minSize: 175,
-        maxSize: 400,
-        titlebar: true,
-        collapsible: true
+    
+    _getConfigHtml : function()
+    {
+        var sConfig = '' ;
+
+        for ( var o in this.fckconfig ) {
+            sConfig += sConfig.length > 0  ? '&amp;' : '';
+            sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
+        }
+
+        return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
     },
-    south: {
-        split:true,
-        initialSize: 100,
-        minSize: 100,
-        maxSize: 200,
-        titlebar: true,
-        collapsible: true
+    
+    
+    _getIFrameHtml : function()
+    {
+        var sFile = 'fckeditor.html' ;
+        /* no idea what this is about..
+        try
+        {
+            if ( (/fcksource=true/i).test( window.top.location.search ) )
+                sFile = 'fckeditor.original.html' ;
+        }
+        catch (e) { 
+        */
+
+        var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
+        sLink += this.toolbarSet ? ( '&amp;Toolbar=' + this.toolbarSet)  : '';
+        
+        
+        var html = '<iframe id="' + this.getId() +
+            '___Frame" src="' + sLink +
+            '" width="' + this.width +
+            '" height="' + this.height + '"' +
+            (this.tabIndex ?  ' tabindex="' + this.tabIndex + '"' :'' ) +
+            ' frameborder="0" scrolling="no"></iframe>' ;
+
+        return html ;
     },
-    center: {
-        titlebar: true,
-        autoScroll:true,
-        resizeTabs: true,
-        minTabWidth: 50,
-        preferredTabWidth: 150
+    
+    _insertHtmlBefore : function( html, element )
+    {
+        if ( element.insertAdjacentHTML )      {
+            // IE
+            element.insertAdjacentHTML( 'beforeBegin', html ) ;
+        } else { // Gecko
+            var oRange = document.createRange() ;
+            oRange.setStartBefore( element ) ;
+            var oFragment = oRange.createContextualFragment( html );
+            element.parentNode.insertBefore( oFragment, element ) ;
+        }
     }
+    
+    
+  
+    
+    
+    
+    
+
 });
 
-// shorthand
-var CP = Roo.ContentPanel;
+//Roo.reg('fckeditor', Roo.form.FCKeditor);
 
-layout.beginUpdate();
-layout.add("north", new CP("north", "North"));
-layout.add("south", new CP("south", {title: "South", closable: true}));
-layout.add("west", new CP("west", {title: "West"}));
-layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
-layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
-layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
-layout.getRegion("center").showPanel("center1");
-layout.endUpdate();
-</code></pre>
+function FCKeditor_OnComplete(editorInstance){
+    var f = Roo.form.FCKeditor.editors[editorInstance.Name];
+    f.fckEditor = editorInstance;
+    //console.log("loaded");
+    f.fireEvent('editorinit', f, editorInstance);
+} 
+  
 
-<b>The container the layout is rendered into can be either the body element or any other element.
-If it is not the body element, the container needs to either be an absolute positioned element,
-or you will need to add "position:relative" to the css of the container.  You will also need to specify
-the container size if it is not the body element.</b>
 
-* @constructor
-* Create a new BorderLayout
-* @param {String/HTMLElement/Element} container The container this layout is bound to
-* @param {Object} config Configuration options
- */
-Roo.BorderLayout = function(container, config){
-    config = config || {};
-    Roo.BorderLayout.superclass.constructor.call(this, container, config);
-    this.factory = config.factory || Roo.BorderLayout.RegionFactory;
-    for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
-       var target = this.factory.validRegions[i];
-       if(config[target]){
-           this.addRegion(target, config[target]);
-       }
-    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//<script type="text/javascript">
+/**
+ * @class Roo.form.GridField
+ * @extends Roo.form.Field
+ * Embed a grid (or editable grid into a form)
+ * STATUS ALPHA
+ * 
+ * This embeds a grid in a form, the value of the field should be the json encoded array of rows
+ * it needs 
+ * xgrid.store = Roo.data.Store
+ * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
+ * xgrid.store.reader = Roo.data.JsonReader 
+ * 
+ * 
+ * @constructor
+ * Creates a new GridField
+ * @param {Object} config Configuration options
+ */
+Roo.form.GridField = function(config){
+    Roo.form.GridField.superclass.constructor.call(this, config);
+     
 };
 
-Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
+Roo.extend(Roo.form.GridField, Roo.form.Field,  {
     /**
-     * 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).
-     * @param {Object} config The regions config object
-     * @return {BorderLayoutRegion} The new region
+     * @cfg {Number} width  - used to restrict width of grid..
      */
-    addRegion : function(target, config){
-        if(!this.regions[target]){
-            var r = this.factory.create(target, this, config);
-           this.bindRegion(target, r);
-        }
-        return this.regions[target];
+    width : 100,
+    /**
+     * @cfg {Number} height - used to restrict height of grid..
+     */
+    height : 50,
+     /**
+     * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
+         * 
+         *}
+     */
+    xgrid : false, 
+    /**
+     * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
+     * {tag: "input", type: "checkbox", autocomplete: "off"})
+     */
+   // defaultAutoCreate : { tag: 'div' },
+    defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
+    /**
+     * @cfg {String} addTitle Text to include for adding a title.
+     */
+    addTitle : false,
+    //
+    onResize : function(){
+        Roo.form.Field.superclass.onResize.apply(this, arguments);
     },
 
-    // private (kinda)
-    bindRegion : function(name, r){
-        this.regions[name] = r;
-        r.on("visibilitychange", this.layout, this);
-        r.on("paneladded", this.layout, this);
-        r.on("panelremoved", this.layout, this);
-        r.on("invalidated", this.layout, this);
-        r.on("resized", this.onRegionResized, this);
-        r.on("collapsed", this.onRegionCollapsed, this);
-        r.on("expanded", this.onRegionExpanded, this);
+    initEvents : function(){
+        // Roo.form.Checkbox.superclass.initEvents.call(this);
+        // has no events...
+       
     },
 
-    /**
-     * Performs a layout update.
-     */
-    layout : function(){
-        if(this.updating) {
-            return;
-        }
-        var size = this.getViewSize();
-        var w = size.width;
-        var h = size.height;
-        var centerW = w;
-        var centerH = h;
-        var centerY = 0;
-        var centerX = 0;
-        //var x = 0, y = 0;
 
-        var rs = this.regions;
-        var north = rs["north"];
-        var south = rs["south"]; 
-        var west = rs["west"];
-        var east = rs["east"];
-        var center = rs["center"];
-        //if(this.hideOnLayout){ // not supported anymore
-            //c.el.setStyle("display", "none");
-        //}
-        if(north && north.isVisible()){
-            var b = north.getBox();
-            var m = north.getMargins();
-            b.width = w - (m.left+m.right);
-            b.x = m.left;
-            b.y = m.top;
-            centerY = b.height + b.y + m.bottom;
-            centerH -= centerY;
-            north.updateBox(this.safeBox(b));
+    getResizeEl : function(){
+        return this.wrap;
+    },
+
+    getPositionEl : function(){
+        return this.wrap;
+    },
+
+    // private
+    onRender : function(ct, position){
+        
+        this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
+        var style = this.style;
+        delete this.style;
+        
+        Roo.form.GridField.superclass.onRender.call(this, ct, position);
+        this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
+        this.viewEl = this.wrap.createChild({ tag: 'div' });
+        if (style) {
+            this.viewEl.applyStyles(style);
         }
-        if(south && south.isVisible()){
-            var b = south.getBox();
-            var m = south.getMargins();
-            b.width = w - (m.left+m.right);
-            b.x = m.left;
-            var totalHeight = (b.height + m.top + m.bottom);
-            b.y = h - totalHeight + m.top;
-            centerH -= totalHeight;
-            south.updateBox(this.safeBox(b));
+        if (this.width) {
+            this.viewEl.setWidth(this.width);
         }
-        if(west && west.isVisible()){
-            var b = west.getBox();
-            var m = west.getMargins();
-            b.height = centerH - (m.top+m.bottom);
-            b.x = m.left;
-            b.y = centerY + m.top;
-            var totalWidth = (b.width + m.left + m.right);
-            centerX += totalWidth;
-            centerW -= totalWidth;
-            west.updateBox(this.safeBox(b));
+        if (this.height) {
+            this.viewEl.setHeight(this.height);
         }
-        if(east && east.isVisible()){
-            var b = east.getBox();
-            var m = east.getMargins();
-            b.height = centerH - (m.top+m.bottom);
-            var totalWidth = (b.width + m.left + m.right);
-            b.x = w - totalWidth + m.left;
-            b.y = centerY + m.top;
-            centerW -= totalWidth;
-            east.updateBox(this.safeBox(b));
+        //if(this.inputValue !== undefined){
+        //this.setValue(this.value);
+        
+        
+        this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
+        
+        
+        this.grid.render();
+        this.grid.getDataSource().on('remove', this.refreshValue, this);
+        this.grid.getDataSource().on('update', this.refreshValue, this);
+        this.grid.on('afteredit', this.refreshValue, this);
+    },
+     
+    
+    /**
+     * Sets the value of the item. 
+     * @param {String} either an object  or a string..
+     */
+    setValue : function(v){
+        //this.value = v;
+        v = v || []; // empty set..
+        // this does not seem smart - it really only affects memoryproxy grids..
+        if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
+            var ds = this.grid.getDataSource();
+            // assumes a json reader..
+            var data = {}
+            data[ds.reader.meta.root ] =  typeof(v) == 'string' ? Roo.decode(v) : v;
+            ds.loadData( data);
         }
-        if(center){
-            var m = center.getMargins();
-            var centerBox = {
-                x: centerX + m.left,
-                y: centerY + m.top,
-                width: centerW - (m.left+m.right),
-                height: centerH - (m.top+m.bottom)
-            };
-            //if(this.hideOnLayout){
-                //center.el.setStyle("display", "block");
-            //}
-            center.updateBox(this.safeBox(centerBox));
+        // clear selection so it does not get stale.
+        if (this.grid.sm) { 
+            this.grid.sm.clearSelections();
         }
-        this.el.repaint();
-        this.fireEvent("layout", this);
+        
+        Roo.form.GridField.superclass.setValue.call(this, v);
+        this.refreshValue();
+        // should load data in the grid really....
     },
-
+    
     // private
-    safeBox : function(box){
-        box.width = Math.max(0, box.width);
-        box.height = Math.max(0, box.height);
-        return box;
-    },
+    refreshValue: function() {
+         var val = [];
+        this.grid.getDataSource().each(function(r) {
+            val.push(r.data);
+        });
+        this.el.dom.value = Roo.encode(val);
+    }
+    
+     
+    
+    
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+/**
+ * @class Roo.form.DisplayField
+ * @extends Roo.form.Field
+ * A generic Field to display non-editable data.
+ * @cfg {Boolean} closable (true|false) default false
+ * @constructor
+ * Creates a new Display Field item.
+ * @param {Object} config Configuration options
+ */
+Roo.form.DisplayField = function(config){
+    Roo.form.DisplayField.superclass.constructor.call(this, config);
+    
+    this.addEvents({
+        /**
+         * @event close
+         * Fires after the click the close btn
+            * @param {Roo.form.DisplayField} this
+            */
+        close : true
+    });
+};
 
+Roo.extend(Roo.form.DisplayField, Roo.form.TextField,  {
+    inputType:      'hidden',
+    allowBlank:     true,
+    readOnly:         true,
+    
     /**
-     * Adds a ContentPanel (or subclass) to this layout.
-     * @param {String} target The target region key (north, south, east, west or center).
-     * @param {Roo.ContentPanel} panel The panel to add
-     * @return {Roo.ContentPanel} The added panel
+     * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
      */
-    add : function(target, panel){
-         
-        target = target.toLowerCase();
-        return this.regions[target].add(panel);
-    },
-
+    focusClass : undefined,
     /**
-     * Remove a ContentPanel (or subclass) to this layout.
-     * @param {String} target The target region key (north, south, east, west or center).
-     * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
-     * @return {Roo.ContentPanel} The removed panel
+     * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
      */
-    remove : function(target, panel){
-        target = target.toLowerCase();
-        return this.regions[target].remove(panel);
-    },
-
-    /**
-     * Searches all regions for a panel with the specified id
-     * @param {String} panelId
-     * @return {Roo.ContentPanel} The panel or null if it wasn't found
+    fieldClass: 'x-form-field',
+    
+     /**
+     * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
      */
-    findPanel : function(panelId){
-        var rs = this.regions;
-        for(var target in rs){
-            if(typeof rs[target] != "function"){
-                var p = rs[target].getPanel(panelId);
-                if(p){
-                    return p;
-                }
-            }
-        }
-        return null;
-    },
-
+    valueRenderer: undefined,
+    
+    width: 100,
     /**
-     * Searches all regions for a panel with the specified id and activates (shows) it.
-     * @param {String/ContentPanel} panelId The panels id or the panel itself
-     * @return {Roo.ContentPanel} The shown panel or null
+     * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
+     * {tag: "input", type: "checkbox", autocomplete: "off"})
      */
-    showPanel : function(panelId) {
-      var rs = this.regions;
-      for(var target in rs){
-         var r = rs[target];
-         if(typeof r != "function"){
-            if(r.hasPanel(panelId)){
-               return r.showPanel(panelId);
-            }
-         }
-      }
-      return null;
-   },
+     
+ //   defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
+    closable : false,
+    
+    onResize : function(){
+        Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
+        
+    },
 
-   /**
-     * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
-     * @param {Roo.state.Provider} provider (optional) An alternate state provider
-     */
-    restoreState : function(provider){
-        if(!provider){
-            provider = Roo.state.Manager;
+    initEvents : function(){
+        // Roo.form.Checkbox.superclass.initEvents.call(this);
+        // has no events...
+        
+        if(this.closable){
+            this.closeEl.on('click', this.onClose, this);
         }
-        var sm = new Roo.LayoutStateManager();
-        sm.init(this, provider);
+       
     },
 
-    /**
-     * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object.  This config
-     * object should contain properties for each region to add ContentPanels to, and each property's value should be
-     * a valid ContentPanel config object.  Example:
-     * <pre><code>
-// Create the main layout
-var layout = new Roo.BorderLayout('main-ct', {
-    west: {
-        split:true,
-        minSize: 175,
-        titlebar: true
+
+    getResizeEl : function(){
+        return this.wrap;
     },
-    center: {
-        title:'Components'
-    }
-}, 'main-ct');
 
-// Create and add multiple ContentPanels at once via configs
-layout.batchAdd({
-   west: {
-       id: 'source-files',
-       autoCreate:true,
-       title:'Ext Source Files',
-       autoScroll:true,
-       fitToFrame:true
-   },
-   center : {
-       el: cview,
-       autoScroll:true,
-       fitToFrame:true,
-       toolbar: tb,
-       resizeEl:'cbody'
-   }
-});
-</code></pre>
-     * @param {Object} regions An object containing ContentPanel configs by region name
-     */
-    batchAdd : function(regions){
-        this.beginUpdate();
-        for(var rname in regions){
-            var lr = this.regions[rname];
-            if(lr){
-                this.addTypedPanels(lr, regions[rname]);
-            }
-        }
-        this.endUpdate();
+    getPositionEl : function(){
+        return this.wrap;
     },
 
     // private
-    addTypedPanels : function(lr, ps){
-        if(typeof ps == 'string'){
-            lr.add(new Roo.ContentPanel(ps));
-        }
-        else if(ps instanceof Array){
-            for(var i =0, len = ps.length; i < len; i++){
-                this.addTypedPanels(lr, ps[i]);
-            }
-        }
-        else if(!ps.events){ // raw config?
-            var el = ps.el;
-            delete ps.el; // prevent conflict
-            lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
+    onRender : function(ct, position){
+        
+        Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
+        //if(this.inputValue !== undefined){
+        this.wrap = this.el.wrap();
+        
+        this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
+        
+        if(this.closable){
+            this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
         }
-        else {  // panel object assumed!
-            lr.add(ps);
+        
+        if (this.bodyStyle) {
+            this.viewEl.applyStyles(this.bodyStyle);
         }
+        //this.viewEl.setStyle('padding', '2px');
+        
+        this.setValue(this.value);
+        
     },
-    /**
-     * Adds a xtype elements to the layout.
-     * <pre><code>
+/*
+    // private
+    initValue : Roo.emptyFn,
 
-layout.addxtype({
-       xtype : 'ContentPanel',
-       region: 'west',
-       items: [ .... ]
-   }
-);
+  */
 
-layout.addxtype({
-        xtype : 'NestedLayoutPanel',
-        region: 'west',
-        layout: {
-           center: { },
-           west: { }   
-        },
-        items : [ ... list of content panels or nested layout panels.. ]
-   }
-);
-</code></pre>
-     * @param {Object} cfg Xtype definition of item to add.
-     */
-    addxtype : function(cfg)
-    {
-        // basically accepts a pannel...
-        // can accept a layout region..!?!?
-        //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
+       // private
+    onClick : function(){
         
-        if (!cfg.xtype.match(/Panel$/)) {
-            return false;
+    },
+
+    /**
+     * Sets the checked state of the checkbox.
+     * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
+     */
+    setValue : function(v){
+        this.value = v;
+        var html = this.valueRenderer ?  this.valueRenderer(v) : String.format('{0}', v);
+        // this might be called before we have a dom element..
+        if (!this.viewEl) {
+            return;
         }
-        var ret = false;
-        
-        if (typeof(cfg.region) == 'undefined') {
-            Roo.log("Failed to add Panel, region was not set");
-            Roo.log(cfg);
-            return false;
-        }
-        var region = cfg.region;
-        delete cfg.region;
-        
-          
-        var xitems = [];
-        if (cfg.items) {
-            xitems = cfg.items;
-            delete cfg.items;
-        }
-        var nb = false;
-        
-        switch(cfg.xtype) 
-        {
-            case 'ContentPanel':  // ContentPanel (el, cfg)
-            case 'ScrollPanel':  // ContentPanel (el, cfg)
-            case 'ViewPanel': 
-                if(cfg.autoCreate) {
-                    ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
-                } else {
-                    var el = this.el.createChild();
-                    ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
-                }
-                
-                this.add(region, ret);
-                break;
-            
-            
-            case 'TreePanel': // our new panel!
-                cfg.el = this.el.createChild();
-                ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
-                this.add(region, ret);
-                break;
-            
-            case 'NestedLayoutPanel': 
-                // create a new Layout (which is  a Border Layout...
-                var el = this.el.createChild();
-                var clayout = cfg.layout;
-                delete cfg.layout;
-                clayout.items   = clayout.items  || [];
-                // replace this exitems with the clayout ones..
-                xitems = clayout.items;
-                 
-                
-                if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
-                    cfg.background = false;
-                }
-                var layout = new Roo.BorderLayout(el, clayout);
-                
-                ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
-                //console.log('adding nested layout panel '  + cfg.toSource());
-                this.add(region, ret);
-                nb = {}; /// find first...
-                break;
-                
-            case 'GridPanel': 
-            
-                // needs grid and region
-                
-                //var el = this.getRegion(region).el.createChild();
-                var el = this.el.createChild();
-                // create the grid first...
-                
-                var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
-                delete cfg.grid;
-                if (region == 'center' && this.active ) {
-                    cfg.background = false;
-                }
-                ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
-                
-                this.add(region, ret);
-                if (cfg.background) {
-                    ret.on('activate', function(gp) {
-                        if (!gp.grid.rendered) {
-                            gp.grid.render();
-                        }
-                    });
-                } else {
-                    grid.render();
-                }
-                break;
-           
-           
-           
-                
-                
-                
-            default:
-                if (typeof(Roo[cfg.xtype]) != 'undefined') {
-                    
-                    ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
-                    this.add(region, ret);
-                } else {
-                
-                    alert("Can not add '" + cfg.xtype + "' to BorderLayout");
-                    return null;
-                }
-                
-             // GridPanel (grid, cfg)
-            
-        }
-        this.beginUpdate();
-        // add children..
-        var region = '';
-        var abn = {};
-        Roo.each(xitems, function(i)  {
-            region = nb && i.region ? i.region : false;
-            
-            var add = ret.addxtype(i);
-           
-            if (region) {
-                nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
-                if (!i.background) {
-                    abn[region] = nb[region] ;
-                }
-            }
-            
-        });
-        this.endUpdate();
-
-        // make the last non-background panel active..
-        //if (nb) { Roo.log(abn); }
-        if (nb) {
-            
-            for(var r in abn) {
-                region = this.getRegion(r);
-                if (region) {
-                    // tried using nb[r], but it does not work..
-                     
-                    region.showPanel(abn[r]);
-                   
-                }
-            }
-        }
-        return ret;
+        this.viewEl.dom.innerHTML = html;
+        Roo.form.DisplayField.superclass.setValue.call(this, v);
+
+    },
+    
+    onClose : function(e)
+    {
+        e.preventDefault();
         
+        this.fireEvent('close', this);
     }
-});
+});/*
+ * 
+ * Licence- LGPL
+ * 
+ */
 
 /**
- * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
- * the beginUpdate and endUpdate calls internally.  The key to this method is the <b>panels</b> property that can be
- * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
- * during creation.  The following code is equivalent to the constructor-based example at the beginning of this class:
- * <pre><code>
-// shorthand
-var CP = Roo.ContentPanel;
+ * @class Roo.form.DayPicker
+ * @extends Roo.form.Field
+ * A Day picker show [M] [T] [W] ....
+ * @constructor
+ * Creates a new Day Picker
+ * @param {Object} config Configuration options
+ */
+Roo.form.DayPicker= function(config){
+    Roo.form.DayPicker.superclass.constructor.call(this, config);
+     
+};
 
-var layout = Roo.BorderLayout.create({
-    north: {
-        initialSize: 25,
-        titlebar: false,
-        panels: [new CP("north", "North")]
+Roo.extend(Roo.form.DayPicker, Roo.form.Field,  {
+    /**
+     * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
+     */
+    focusClass : undefined,
+    /**
+     * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
+     */
+    fieldClass: "x-form-field",
+   
+    /**
+     * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
+     * {tag: "input", type: "checkbox", autocomplete: "off"})
+     */
+    defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
+    
+   
+    actionMode : 'viewEl', 
+    //
+    // private
+    inputType : 'hidden',
+    
+     
+    inputElement: false, // real input element?
+    basedOn: false, // ????
+    
+    isFormField: true, // not sure where this is needed!!!!
+
+    onResize : function(){
+        Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
+        if(!this.boxLabel){
+            this.el.alignTo(this.wrap, 'c-c');
+        }
     },
-    west: {
-        split:true,
-        initialSize: 200,
-        minSize: 175,
-        maxSize: 400,
-        titlebar: true,
-        collapsible: true,
-        panels: [new CP("west", {title: "West"})]
+
+    initEvents : function(){
+        Roo.form.Checkbox.superclass.initEvents.call(this);
+        this.el.on("click", this.onClick,  this);
+        this.el.on("change", this.onClick,  this);
     },
-    east: {
-        split:true,
-        initialSize: 202,
-        minSize: 175,
-        maxSize: 400,
-        titlebar: true,
-        collapsible: true,
-        panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
+
+
+    getResizeEl : function(){
+        return this.wrap;
     },
-    south: {
-        split:true,
-        initialSize: 100,
-        minSize: 100,
-        maxSize: 200,
-        titlebar: true,
-        collapsible: true,
-        panels: [new CP("south", {title: "South", closable: true})]
+
+    getPositionEl : function(){
+        return this.wrap;
     },
-    center: {
-        titlebar: true,
-        autoScroll:true,
-        resizeTabs: true,
-        minTabWidth: 50,
-        preferredTabWidth: 150,
-        panels: [
-            new CP("center1", {title: "Close Me", closable: true}),
-            new CP("center2", {title: "Center Panel", closable: false})
-        ]
-    }
-}, document.body);
 
-layout.getRegion("center").showPanel("center1");
-</code></pre>
- * @param config
- * @param targetEl
- */
-Roo.BorderLayout.create = function(config, targetEl){
-    var layout = new Roo.BorderLayout(targetEl || document.body, config);
-    layout.beginUpdate();
-    var regions = Roo.BorderLayout.RegionFactory.validRegions;
-    for(var j = 0, jlen = regions.length; j < jlen; j++){
-        var lr = regions[j];
-        if(layout.regions[lr] && config[lr].panels){
-            var r = layout.regions[lr];
-            var ps = config[lr].panels;
-            layout.addTypedPanels(r, ps);
+    
+    // private
+    onRender : function(ct, position){
+        Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
+       
+        this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
+        
+        var r1 = '<table><tr>';
+        var r2 = '<tr class="x-form-daypick-icons">';
+        for (var i=0; i < 7; i++) {
+            r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
+            r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL  +'"></td>';
         }
-    }
-    layout.endUpdate();
-    return layout;
-};
+        
+        var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
+        viewEl.select('img').on('click', this.onClick, this);
+        this.viewEl = viewEl;   
+        
+        
+        // this will not work on Chrome!!!
+        this.el.on('DOMAttrModified', this.setFromHidden,  this); //ff
+        this.el.on('propertychange', this.setFromHidden,  this);  //ie
+        
+        
+          
+
+    },
 
-// private
-Roo.BorderLayout.RegionFactory = {
     // private
-    validRegions : ["north","south","east","west","center"],
+    initValue : Roo.emptyFn,
+
+    /**
+     * Returns the checked state of the checkbox.
+     * @return {Boolean} True if checked, else false
+     */
+    getValue : function(){
+        return this.el.dom.value;
+        
+    },
 
+       // private
+    onClick : function(e){ 
+        //this.setChecked(!this.checked);
+        Roo.get(e.target).toggleClass('x-menu-item-checked');
+        this.refreshValue();
+        //if(this.el.dom.checked != this.checked){
+        //    this.setValue(this.el.dom.checked);
+       // }
+    },
+    
     // private
-    create : function(target, mgr, config){
-        target = target.toLowerCase();
-        if(config.lightweight || config.basic){
-            return new Roo.BasicLayoutRegion(mgr, config, target);
+    refreshValue : function()
+    {
+        var val = '';
+        this.viewEl.select('img',true).each(function(e,i,n)  {
+            val += e.is(".x-menu-item-checked") ? String(n) : '';
+        });
+        this.setValue(val, true);
+    },
+
+    /**
+     * Sets the checked state of the checkbox.
+     * On is always based on a string comparison between inputValue and the param.
+     * @param {Boolean/String} value - the value to set 
+     * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
+     */
+    setValue : function(v,suppressEvent){
+        if (!this.el.dom) {
+            return;
         }
-        switch(target){
-            case "north":
-                return new Roo.NorthLayoutRegion(mgr, config);
-            case "south":
-                return new Roo.SouthLayoutRegion(mgr, config);
-            case "east":
-                return new Roo.EastLayoutRegion(mgr, config);
-            case "west":
-                return new Roo.WestLayoutRegion(mgr, config);
-            case "center":
-                return new Roo.CenterLayoutRegion(mgr, config);
+        var old = this.el.dom.value ;
+        this.el.dom.value = v;
+        if (suppressEvent) {
+            return ;
         }
-        throw 'Layout region "'+target+'" not supported.';
+         
+        // update display..
+        this.viewEl.select('img',true).each(function(e,i,n)  {
+            
+            var on = e.is(".x-menu-item-checked");
+            var newv = v.indexOf(String(n)) > -1;
+            if (on != newv) {
+                e.toggleClass('x-menu-item-checked');
+            }
+            
+        });
+        
+        
+        this.fireEvent('change', this, v, old);
+        
+        
+    },
+   
+    // handle setting of hidden value by some other method!!?!?
+    setFromHidden: function()
+    {
+        if(!this.el){
+            return;
+        }
+        //console.log("SET FROM HIDDEN");
+        //alert('setFrom hidden');
+        this.setValue(this.el.dom.value);
+    },
+    
+    onDestroy : function()
+    {
+        if(this.viewEl){
+            Roo.get(this.viewEl).remove();
+        }
+         
+        Roo.form.DayPicker.superclass.onDestroy.call(this);
     }
-};/*
- * 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.
+
+});/*
+ * RooJS Library 1.1.1
+ * Copyright(c) 2008-2011  Alan Knowles
  *
- * Fork - LGPL
- * <script type="text/javascript">
+ * License - LGPL
  */
  
+
 /**
- * @class Roo.BasicLayoutRegion
- * @extends Roo.util.Observable
- * This class represents a lightweight region in a layout manager. This region does not move dom nodes
- * and does not have a titlebar, tabs or any other features. All it does is size and position 
- * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
+ * @class Roo.form.ComboCheck
+ * @extends Roo.form.ComboBox
+ * A combobox for multiple select items.
+ *
+ * FIXME - could do with a reset button..
+ * 
+ * @constructor
+ * Create a new ComboCheck
+ * @param {Object} config Configuration options
  */
-Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
-    this.mgr = mgr;
-    this.position  = pos;
-    this.events = {
-        /**
-         * @scope Roo.BasicLayoutRegion
-         */
+Roo.form.ComboCheck = function(config){
+    Roo.form.ComboCheck.superclass.constructor.call(this, config);
+    // should verify some data...
+    // like
+    // hiddenName = required..
+    // displayField = required
+    // valudField == required
+    var req= [ 'hiddenName', 'displayField', 'valueField' ];
+    var _t = this;
+    Roo.each(req, function(e) {
+        if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
+            throw "Roo.form.ComboCheck : missing value for: " + e;
+        }
+    });
+    
+    
+};
+
+Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
+     
+     
+    editable : false,
+     
+    selectedClass: 'x-menu-item-checked', 
+    
+    // private
+    onRender : function(ct, position){
+        var _t = this;
         
-        /**
-         * @event beforeremove
-         * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
-         * @param {Roo.LayoutRegion} this
-         * @param {Roo.ContentPanel} panel The panel
-         * @param {Object} e The cancel event object
-         */
-        "beforeremove" : true,
-        /**
-         * @event invalidated
-         * Fires when the layout for this region is changed.
-         * @param {Roo.LayoutRegion} this
-         */
-        "invalidated" : true,
-        /**
-         * @event visibilitychange
-         * Fires when this region is shown or hidden 
-         * @param {Roo.LayoutRegion} this
-         * @param {Boolean} visibility true or false
-         */
-        "visibilitychange" : true,
-        /**
-         * @event paneladded
-         * Fires when a panel is added. 
-         * @param {Roo.LayoutRegion} this
-         * @param {Roo.ContentPanel} panel The panel
-         */
-        "paneladded" : true,
-        /**
-         * @event panelremoved
-         * Fires when a panel is removed. 
-         * @param {Roo.LayoutRegion} this
-         * @param {Roo.ContentPanel} panel The panel
-         */
-        "panelremoved" : true,
-        /**
-         * @event beforecollapse
-         * Fires when this region before collapse.
-         * @param {Roo.LayoutRegion} this
-         */
-        "beforecollapse" : true,
-        /**
-         * @event collapsed
-         * Fires when this region is collapsed.
-         * @param {Roo.LayoutRegion} this
-         */
-        "collapsed" : true,
-        /**
-         * @event expanded
-         * Fires when this region is expanded.
-         * @param {Roo.LayoutRegion} this
-         */
-        "expanded" : true,
-        /**
-         * @event slideshow
-         * Fires when this region is slid into view.
-         * @param {Roo.LayoutRegion} this
-         */
-        "slideshow" : true,
-        /**
-         * @event slidehide
-         * Fires when this region slides out of view. 
-         * @param {Roo.LayoutRegion} this
-         */
-        "slidehide" : true,
-        /**
-         * @event panelactivated
-         * Fires when a panel is activated. 
-         * @param {Roo.LayoutRegion} this
-         * @param {Roo.ContentPanel} panel The activated panel
-         */
-        "panelactivated" : true,
-        /**
-         * @event resized
-         * Fires when the user resizes this region. 
-         * @param {Roo.LayoutRegion} this
-         * @param {Number} newSize The new size (width for east/west, height for north/south)
-         */
-        "resized" : true
-    };
-    /** A collection of panels in this region. @type Roo.util.MixedCollection */
-    this.panels = new Roo.util.MixedCollection();
-    this.panels.getKey = this.getPanelId.createDelegate(this);
-    this.box = null;
-    this.activePanel = null;
-    // ensure listeners are added...
-    
-    if (config.listeners || config.events) {
-        Roo.BasicLayoutRegion.superclass.constructor.call(this, {
-            listeners : config.listeners || {},
-            events : config.events || {}
-        });
-    }
-    
-    if(skipConfig !== true){
-        this.applyConfig(config);
-    }
-};
+        
+        
+        if(!this.tpl){
+            var cls = 'x-combo-list';
 
-Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
-    getPanelId : function(p){
-        return p.getId();
-    },
-    
-    applyConfig : function(config){
-        this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
-        this.config = config;
+            
+            this.tpl =  new Roo.Template({
+                html :  '<div class="'+cls+'-item x-menu-check-item">' +
+                   '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' + 
+                   '<span>{' + this.displayField + '}</span>' +
+                    '</div>' 
+                
+            });
+        }
         
-    },
-    
-    /**
-     * Resizes the region to the specified size. For vertical regions (west, east) this adjusts 
-     * the width, for horizontal (north, south) the height.
-     * @param {Number} newSize The new width or height
-     */
-    resizeTo : function(newSize){
-        var el = this.el ? this.el :
-                 (this.activePanel ? this.activePanel.getEl() : null);
-        if(el){
-            switch(this.position){
-                case "east":
-                case "west":
-                    el.setWidth(newSize);
-                    this.fireEvent("resized", this, newSize);
-                break;
-                case "north":
-                case "south":
-                    el.setHeight(newSize);
-                    this.fireEvent("resized", this, newSize);
-                break;                
+        Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
+        this.view.singleSelect = false;
+        this.view.multiSelect = true;
+        this.view.toggleSelect = true;
+        this.pageTb.add(new Roo.Toolbar.Fill(), {
+            
+            text: 'Done',
+            handler: function()
+            {
+                _t.collapse();
             }
-        }
+        });
     },
     
-    getBox : function(){
-        return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
+    onViewOver : function(e, t){
+        // do nothing...
+        return;
+        
     },
     
-    getMargins : function(){
-        return this.margins;
+    onViewClick : function(doFocus,index){
+        return;
+        
     },
-    
-    updateBox : function(box){
-        this.box = box;
-        var el = this.activePanel.getEl();
-        el.dom.style.left = box.x + "px";
-        el.dom.style.top = box.y + "px";
-        this.activePanel.setSize(box.width, box.height);
+    select: function () {
+        //Roo.log("SELECT CALLED");
     },
-    
-    /**
-     * Returns the container element for this region.
-     * @return {Roo.Element}
-     */
-    getEl : function(){
-        return this.activePanel;
+     
+    selectByValue : function(xv, scrollIntoView){
+        var ar = this.getValueArray();
+        var sels = [];
+        
+        Roo.each(ar, function(v) {
+            if(v === undefined || v === null){
+                return;
+            }
+            var r = this.findRecord(this.valueField, v);
+            if(r){
+                sels.push(this.store.indexOf(r))
+                
+            }
+        },this);
+        this.view.select(sels);
+        return false;
     },
     
-    /**
-     * Returns true if this region is currently visible.
-     * @return {Boolean}
-     */
-    isVisible : function(){
-        return this.activePanel ? true : false;
-    },
     
-    setActivePanel : function(panel){
-        panel = this.getPanel(panel);
-        if(this.activePanel && this.activePanel != panel){
-            this.activePanel.setActiveState(false);
-            this.activePanel.getEl().setLeftTop(-10000,-10000);
-        }
-        this.activePanel = panel;
-        panel.setActiveState(true);
-        if(this.box){
-            panel.setSize(this.box.width, this.box.height);
-        }
-        this.fireEvent("panelactivated", this, panel);
-        this.fireEvent("invalidated");
-    },
     
-    /**
-     * Show the specified panel.
-     * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
-     * @return {Roo.ContentPanel} The shown panel or null
-     */
-    showPanel : function(panel){
-        if(panel = this.getPanel(panel)){
-            this.setActivePanel(panel);
+    onSelect : function(record, index){
+       // Roo.log("onselect Called");
+       // this is only called by the clear button now..
+        this.view.clearSelections();
+        this.setValue('[]');
+        if (this.value != this.valueBefore) {
+            this.fireEvent('change', this, this.value, this.valueBefore);
+            this.valueBefore = this.value;
         }
-        return panel;
-    },
-    
-    /**
-     * Get the active panel for this region.
-     * @return {Roo.ContentPanel} The active panel or null
-     */
-    getActivePanel : function(){
-        return this.activePanel;
     },
-    
-    /**
-     * Add the passed ContentPanel(s)
-     * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
-     * @return {Roo.ContentPanel} The panel added (if only one was added)
-     */
-    add : function(panel){
-        if(arguments.length > 1){
-            for(var i = 0, len = arguments.length; i < len; i++) {
-               this.add(arguments[i]);
-            }
-            return null;
-        }
-        if(this.hasPanel(panel)){
-            this.showPanel(panel);
-            return panel;
-        }
-        var el = panel.getEl();
-        if(el.dom.parentNode != this.mgr.el.dom){
-            this.mgr.el.dom.appendChild(el.dom);
-        }
-        if(panel.setRegion){
-            panel.setRegion(this);
-        }
-        this.panels.add(panel);
-        el.setStyle("position", "absolute");
-        if(!panel.background){
-            this.setActivePanel(panel);
-            if(this.config.initialSize && this.panels.getCount()==1){
-                this.resizeTo(this.config.initialSize);
+    getValueArray : function()
+    {
+        var ar = [] ;
+        
+        try {
+            //Roo.log(this.value);
+            if (typeof(this.value) == 'undefined') {
+                return [];
             }
+            var ar = Roo.decode(this.value);
+            return  ar instanceof Array ? ar : []; //?? valid?
+            
+        } catch(e) {
+            Roo.log(e + "\nRoo.form.ComboCheck:getValueArray  invalid data:" + this.getValue());
+            return [];
         }
-        this.fireEvent("paneladded", this, panel);
-        return panel;
-    },
-    
-    /**
-     * Returns true if the panel is in this region.
-     * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
-     * @return {Boolean}
-     */
-    hasPanel : function(panel){
-        if(typeof panel == "object"){ // must be panel obj
-            panel = panel.getId();
-        }
-        return this.getPanel(panel) ? true : false;
+         
     },
-    
-    /**
-     * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
-     * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
-     * @param {Boolean} preservePanel Overrides the config preservePanel option
-     * @return {Roo.ContentPanel} The panel that was removed
-     */
-    remove : function(panel, preservePanel){
-        panel = this.getPanel(panel);
-        if(!panel){
-            return null;
-        }
-        var e = {};
-        this.fireEvent("beforeremove", this, panel, e);
-        if(e.cancel === true){
-            return null;
-        }
-        var panelId = panel.getId();
-        this.panels.removeKey(panelId);
-        return panel;
+    expand : function ()
+    {
+        
+        Roo.form.ComboCheck.superclass.expand.call(this);
+        this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
+        //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
+        
+
     },
     
-    /**
-     * Returns the panel specified or null if it's not in this region.
-     * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
-     * @return {Roo.ContentPanel}
-     */
-    getPanel : function(id){
-        if(typeof id == "object"){ // must be panel obj
-            return id;
+    collapse : function(){
+        Roo.form.ComboCheck.superclass.collapse.call(this);
+        var sl = this.view.getSelectedIndexes();
+        var st = this.store;
+        var nv = [];
+        var tv = [];
+        var r;
+        Roo.each(sl, function(i) {
+            r = st.getAt(i);
+            nv.push(r.get(this.valueField));
+        },this);
+        this.setValue(Roo.encode(nv));
+        if (this.value != this.valueBefore) {
+
+            this.fireEvent('change', this, this.value, this.valueBefore);
+            this.valueBefore = this.value;
         }
-        return this.panels.get(id);
+        
     },
     
-    /**
-     * Returns this regions position (north/south/east/west/center).
-     * @return {String} 
-     */
-    getPosition: function(){
-        return this.position;    
+    setValue : function(v){
+        // Roo.log(v);
+        this.value = v;
+        
+        var vals = this.getValueArray();
+        var tv = [];
+        Roo.each(vals, function(k) {
+            var r = this.findRecord(this.valueField, k);
+            if(r){
+                tv.push(r.data[this.displayField]);
+            }else if(this.valueNotFoundText !== undefined){
+                tv.push( this.valueNotFoundText );
+            }
+        },this);
+       // Roo.log(tv);
+        
+        Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
+        this.hiddenField.value = v;
+        this.value = v;
     }
+    
 });/*
  * Based on:
  * Ext JS Library 1.1.1
@@ -52276,1157 +57035,1362 @@ Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
  */
  
 /**
- * @class Roo.LayoutRegion
- * @extends Roo.BasicLayoutRegion
- * This class represents a region in a layout manager.
- * @cfg {Boolean}   collapsible     False to disable collapsing (defaults to true)
- * @cfg {Boolean}   collapsed       True to set the initial display to collapsed (defaults to false)
- * @cfg {Boolean}   floatable       False to disable floating (defaults to true)
- * @cfg {Object}    margins         Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
- * @cfg {Object}    cmargins        Margins for the element when collapsed (defaults to: north/south {top: 2, left: 0, right:0, bottom: 2} or east/west {top: 0, left: 2, right:2, bottom: 0})
- * @cfg {String}    tabPosition     (top|bottom) "top" or "bottom" (defaults to "bottom")
- * @cfg {String}    collapsedTitle  Optional string message to display in the collapsed block of a north or south region
- * @cfg {Boolean}   alwaysShowTabs  True to always display tabs even when there is only 1 panel (defaults to false)
- * @cfg {Boolean}   autoScroll      True to enable overflow scrolling (defaults to false)
- * @cfg {Boolean}   titlebar        True to display a title bar (defaults to true)
- * @cfg {String}    title           The title for the region (overrides panel titles)
- * @cfg {Boolean}   animate         True to animate expand/collapse (defaults to false)
- * @cfg {Boolean}   autoHide        False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
- * @cfg {Boolean}   preservePanels  True to preserve removed panels so they can be readded later (defaults to false)
- * @cfg {Boolean}   closeOnTab      True to place the close icon on the tabs instead of the region titlebar (defaults to false)
- * @cfg {Boolean}   hideTabs        True to hide the tab strip (defaults to false)
- * @cfg {Boolean}   resizeTabs      True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
- *                      the space available, similar to FireFox 1.5 tabs (defaults to false)
- * @cfg {Number}    minTabWidth     The minimum tab width (defaults to 40)
- * @cfg {Number}    preferredTabWidth The preferred tab width (defaults to 150)
- * @cfg {Boolean}   showPin         True to show a pin button
- * @cfg {Boolean}   hidden          True to start the region hidden (defaults to false)
- * @cfg {Boolean}   hideWhenEmpty   True to hide the region when it has no panels
- * @cfg {Boolean}   disableTabTips  True to disable tab tooltips
- * @cfg {Number}    width           For East/West panels
- * @cfg {Number}    height          For North/South panels
- * @cfg {Boolean}   split           To show the splitter
- * @cfg {Boolean}   toolbar         xtype configuration for a toolbar - shows on right of tabbar
+ * @class Roo.form.Signature
+ * @extends Roo.form.Field
+ * Signature field.  
+ * @constructor
+ * 
+ * @param {Object} config Configuration options
  */
-Roo.LayoutRegion = function(mgr, config, pos){
-    Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
-    var dh = Roo.DomHelper;
-    /** This region's container element 
-    * @type Roo.Element */
-    this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
-    /** This region's title element 
-    * @type Roo.Element */
-
-    this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
-        {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: "&#160;"},
-        {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
-    ]}, true);
-    this.titleEl.enableDisplayMode();
-    /** This region's title text element 
-    * @type HTMLElement */
-    this.titleTextEl = this.titleEl.dom.firstChild;
-    this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
-    this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
-    this.closeBtn.enableDisplayMode();
-    this.closeBtn.on("click", this.closeClicked, this);
-    this.closeBtn.hide();
-
-    this.createBody(config);
-    this.visible = true;
-    this.collapsed = false;
 
-    if(config.hideWhenEmpty){
-        this.hide();
-        this.on("paneladded", this.validateVisibility, this);
-        this.on("panelremoved", this.validateVisibility, this);
-    }
-    this.applyConfig(config);
+Roo.form.Signature = function(config){
+    Roo.form.Signature.superclass.constructor.call(this, config);
+    
+    this.addEvents({// not in used??
+         /**
+         * @event confirm
+         * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
+            * @param {Roo.form.Signature} combo This combo box
+            */
+        'confirm' : true,
+        /**
+         * @event reset
+         * Fires when the 'edit' icon is pressed (add a listener to enable add button)
+            * @param {Roo.form.ComboBox} combo This combo box
+            * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
+            */
+        'reset' : true
+    });
 };
 
-Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
-
-    createBody : function(){
-        /** This region's body element 
-        * @type Roo.Element */
-        this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
-    },
-
-    applyConfig : function(c){
-        if(c.collapsible && this.position != "center" && !this.collapsedEl){
-            var dh = Roo.DomHelper;
-            if(c.titlebar !== false){
-                this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
-                this.collapseBtn.on("click", this.collapse, this);
-                this.collapseBtn.enableDisplayMode();
-
-                if(c.showPin === true || this.showPin){
-                    this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
-                    this.stickBtn.enableDisplayMode();
-                    this.stickBtn.on("click", this.expand, this);
-                    this.stickBtn.hide();
-                }
-            }
-            /** This region's collapsed element
-            * @type Roo.Element */
-            this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
-                {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
-            ]}, true);
-            if(c.floatable !== false){
-               this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
-               this.collapsedEl.on("click", this.collapseClick, this);
-            }
-
-            if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
-                this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
-                   id: "message", unselectable: "on", style:{"float":"left"}});
-               this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
-             }
-            this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
-            this.expandBtn.on("click", this.expand, this);
-        }
-        if(this.collapseBtn){
-            this.collapseBtn.setVisible(c.collapsible == true);
-        }
-        this.cmargins = c.cmargins || this.cmargins ||
-                         (this.position == "west" || this.position == "east" ?
-                             {top: 0, left: 2, right:2, bottom: 0} :
-                             {top: 2, left: 0, right:0, bottom: 2});
-        this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
-        this.bottomTabs = c.tabPosition != "top";
-        this.autoScroll = c.autoScroll || false;
-        if(this.autoScroll){
-            this.bodyEl.setStyle("overflow", "auto");
-        }else{
-            this.bodyEl.setStyle("overflow", "hidden");
-        }
-        //if(c.titlebar !== false){
-            if((!c.titlebar && !c.title) || c.titlebar === false){
-                this.titleEl.hide();
-            }else{
-                this.titleEl.show();
-                if(c.title){
-                    this.titleTextEl.innerHTML = c.title;
-                }
-            }
-        //}
-        this.duration = c.duration || .30;
-        this.slideDuration = c.slideDuration || .45;
-        this.config = c;
-        if(c.collapsed){
-            this.collapse(true);
-        }
-        if(c.hidden){
-            this.hide();
-        }
-    },
+Roo.extend(Roo.form.Signature, Roo.form.Field,  {
     /**
-     * Returns true if this region is currently visible.
-     * @return {Boolean}
+     * @cfg {Object} labels Label to use when rendering a form.
+     * defaults to 
+     * labels : { 
+     *      clear : "Clear",
+     *      confirm : "Confirm"
+     *  }
      */
-    isVisible : function(){
-        return this.visible;
+    labels : { 
+        clear : "Clear",
+        confirm : "Confirm"
     },
-
     /**
-     * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
-     * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&amp;#160;")
+     * @cfg {Number} width The signature panel width (defaults to 300)
      */
-    setCollapsedTitle : function(title){
-        title = title || "&#160;";
-        if(this.collapsedTitleTextEl){
-            this.collapsedTitleTextEl.innerHTML = title;
-        }
-    },
-
-    getBox : function(){
-        var b;
-        if(!this.collapsed){
-            b = this.el.getBox(false, true);
-        }else{
-            b = this.collapsedEl.getBox(false, true);
-        }
-        return b;
+    width: 300,
+    /**
+     * @cfg {Number} height The signature panel height (defaults to 100)
+     */
+    height : 100,
+    /**
+     * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
+     */
+    allowBlank : false,
+    
+    //private
+    // {Object} signPanel The signature SVG panel element (defaults to {})
+    signPanel : {},
+    // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
+    isMouseDown : false,
+    // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
+    isConfirmed : false,
+    // {String} signatureTmp SVG mapping string (defaults to empty string)
+    signatureTmp : '',
+    
+    
+    defaultAutoCreate : { // modified by initCompnoent..
+        tag: "input",
+        type:"hidden"
     },
 
-    getMargins : function(){
-        return this.collapsed ? this.cmargins : this.margins;
+    // private
+    onRender : function(ct, position){
+        
+        Roo.form.Signature.superclass.onRender.call(this, ct, position);
+        
+        this.wrap = this.el.wrap({
+            cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
+        });
+        
+        this.createToolbar(this);
+        this.signPanel = this.wrap.createChild({
+                tag: 'div',
+                style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
+            }, this.el
+        );
+            
+        this.svgID = Roo.id();
+        this.svgEl = this.signPanel.createChild({
+              xmlns : 'http://www.w3.org/2000/svg',
+              tag : 'svg',
+              id : this.svgID + "-svg",
+              width: this.width,
+              height: this.height,
+              viewBox: '0 0 '+this.width+' '+this.height,
+              cn : [
+                {
+                    tag: "rect",
+                    id: this.svgID + "-svg-r",
+                    width: this.width,
+                    height: this.height,
+                    fill: "#ffa"
+                },
+                {
+                    tag: "line",
+                    id: this.svgID + "-svg-l",
+                    x1: "0", // start
+                    y1: (this.height*0.8), // start set the line in 80% of height
+                    x2: this.width, // end
+                    y2: (this.height*0.8), // end set the line in 80% of height
+                    'stroke': "#666",
+                    'stroke-width': "1",
+                    'stroke-dasharray': "3",
+                    'shape-rendering': "crispEdges",
+                    'pointer-events': "none"
+                },
+                {
+                    tag: "path",
+                    id: this.svgID + "-svg-p",
+                    'stroke': "navy",
+                    'stroke-width': "3",
+                    'fill': "none",
+                    'pointer-events': 'none'
+                }
+              ]
+        });
+        this.createSVG();
+        this.svgBox = this.svgEl.dom.getScreenCTM();
     },
+    createSVG : function(){ 
+        var svg = this.signPanel;
+        var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
+        var t = this;
 
-    highlight : function(){
-        this.el.addClass("x-layout-panel-dragover");
+        r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
+        r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
+        r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
+        r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
+        r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
+        r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
+        r.addEventListener('touchend', function(e) { return t.up(e); }, false);
+        
     },
-
-    unhighlight : function(){
-        this.el.removeClass("x-layout-panel-dragover");
+    isTouchEvent : function(e){
+        return e.type.match(/^touch/);
     },
-
-    updateBox : function(box){
-        this.box = box;
-        if(!this.collapsed){
-            this.el.dom.style.left = box.x + "px";
-            this.el.dom.style.top = box.y + "px";
-            this.updateBody(box.width, box.height);
-        }else{
-            this.collapsedEl.dom.style.left = box.x + "px";
-            this.collapsedEl.dom.style.top = box.y + "px";
-            this.collapsedEl.setSize(box.width, box.height);
-        }
-        if(this.tabs){
-            this.tabs.autoSizeTabs();
+    getCoords : function (e) {
+        var pt    = this.svgEl.dom.createSVGPoint();
+        pt.x = e.clientX; 
+        pt.y = e.clientY;
+        if (this.isTouchEvent(e)) {
+            pt.x =  e.targetTouches[0].clientX;
+            pt.y = e.targetTouches[0].clientY;
         }
+        var a = this.svgEl.dom.getScreenCTM();
+        var b = a.inverse();
+        var mx = pt.matrixTransform(b);
+        return mx.x + ',' + mx.y;
     },
-
-    updateBody : function(w, h){
-        if(w !== null){
-            this.el.setWidth(w);
-            w -= this.el.getBorderWidth("rl");
-            if(this.config.adjustments){
-                w += this.config.adjustments[0];
-            }
+    //mouse event headler 
+    down : function (e) {
+        this.signatureTmp += 'M' + this.getCoords(e) + ' ';
+        this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
+        
+        this.isMouseDown = true;
+        
+        e.preventDefault();
+    },
+    move : function (e) {
+        if (this.isMouseDown) {
+            this.signatureTmp += 'L' + this.getCoords(e) + ' ';
+            this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
         }
-        if(h !== null){
-            this.el.setHeight(h);
-            h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
-            h -= this.el.getBorderWidth("tb");
-            if(this.config.adjustments){
-                h += this.config.adjustments[1];
-            }
-            this.bodyEl.setHeight(h);
-            if(this.tabs){
-                h = this.tabs.syncHeight(h);
+        
+        e.preventDefault();
+    },
+    up : function (e) {
+        this.isMouseDown = false;
+        var sp = this.signatureTmp.split(' ');
+        
+        if(sp.length > 1){
+            if(!sp[sp.length-2].match(/^L/)){
+                sp.pop();
+                sp.pop();
+                sp.push("");
+                this.signatureTmp = sp.join(" ");
             }
         }
-        if(this.panelSize){
-            w = w !== null ? w : this.panelSize.width;
-            h = h !== null ? h : this.panelSize.height;
-        }
-        if(this.activePanel){
-            var el = this.activePanel.getEl();
-            w = w !== null ? w : el.getWidth();
-            h = h !== null ? h : el.getHeight();
-            this.panelSize = {width: w, height: h};
-            this.activePanel.setSize(w, h);
-        }
-        if(Roo.isIE && this.tabs){
-            this.tabs.el.repaint();
+        if(this.getValue() != this.signatureTmp){
+            this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
+            this.isConfirmed = false;
         }
+        e.preventDefault();
     },
-
+    
     /**
-     * Returns the container element for this region.
-     * @return {Roo.Element}
+     * Protected method that will not generally be called directly. It
+     * is called when the editor creates its toolbar. Override this method if you need to
+     * add custom toolbar buttons.
+     * @param {HtmlEditor} editor
      */
-    getEl : function(){
-        return this.el;
+    createToolbar : function(editor){
+         function btn(id, toggle, handler){
+            var xid = fid + '-'+ id ;
+            return {
+                id : xid,
+                cmd : id,
+                cls : 'x-btn-icon x-edit-'+id,
+                enableToggle:toggle !== false,
+                scope: editor, // was editor...
+                handler:handler||editor.relayBtnCmd,
+                clickEvent:'mousedown',
+                tooltip: etb.buttonTips[id] || undefined, ///tips ???
+                tabIndex:-1
+            };
+        }
+        
+        
+        var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
+        this.tb = tb;
+        this.tb.add(
+           {
+                cls : ' x-signature-btn x-signature-'+id,
+                scope: editor, // was editor...
+                handler: this.reset,
+                clickEvent:'mousedown',
+                text: this.labels.clear
+            },
+            {
+                 xtype : 'Fill',
+                 xns: Roo.Toolbar
+            }, 
+            {
+                cls : '  x-signature-btn x-signature-'+id,
+                scope: editor, // was editor...
+                handler: this.confirmHandler,
+                clickEvent:'mousedown',
+                text: this.labels.confirm
+            }
+        );
+    
     },
-
+    //public
     /**
-     * Hides this region.
+     * when user is clicked confirm then show this image.....
+     * 
+     * @return {String} Image Data URI
      */
-    hide : function(){
-        if(!this.collapsed){
-            this.el.dom.style.left = "-2000px";
-            this.el.hide();
-        }else{
-            this.collapsedEl.dom.style.left = "-2000px";
-            this.collapsedEl.hide();
-        }
-        this.visible = false;
-        this.fireEvent("visibilitychange", this, false);
+    getImageDataURI : function(){
+        var svg = this.svgEl.dom.parentNode.innerHTML;
+        var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
+        return src; 
     },
-
     /**
-     * Shows this region if it was previously hidden.
+     * 
+     * @return {Boolean} this.isConfirmed
      */
-    show : function(){
-        if(!this.collapsed){
-            this.el.show();
-        }else{
-            this.collapsedEl.show();
-        }
-        this.visible = true;
-        this.fireEvent("visibilitychange", this, true);
-    },
-
-    closeClicked : function(){
-        if(this.activePanel){
-            this.remove(this.activePanel);
-        }
-    },
-
-    collapseClick : function(e){
-        if(this.isSlid){
-           e.stopPropagation();
-           this.slideIn();
-        }else{
-           e.stopPropagation();
-           this.slideOut();
-        }
+    getConfirmed : function(){
+        return this.isConfirmed;
     },
-
     /**
-     * Collapses this region.
-     * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
+     * 
+     * @return {Number} this.width
      */
-    collapse : function(skipAnim, skipCheck = false){
-        if(this.collapsed) {
-            return;
-        }
-        
-        if(skipCheck || this.fireEvent("beforecollapse", this) != false){
-            
-            this.collapsed = true;
-            if(this.split){
-                this.split.el.hide();
-            }
-            if(this.config.animate && skipAnim !== true){
-                this.fireEvent("invalidated", this);
-                this.animateCollapse();
-            }else{
-                this.el.setLocation(-20000,-20000);
-                this.el.hide();
-                this.collapsedEl.show();
-                this.fireEvent("collapsed", this);
-                this.fireEvent("invalidated", this);
-            }
-        }
-        
-    },
-
-    animateCollapse : function(){
-        // overridden
+    getWidth : function(){
+        return this.width;
     },
-
     /**
-     * Expands this region if it was previously collapsed.
-     * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
-     * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
+     * 
+     * @return {Number} this.height
      */
-    expand : function(e, skipAnim){
-        if(e) {
-            e.stopPropagation();
-        }
-        if(!this.collapsed || this.el.hasActiveFx()) {
-            return;
-        }
-        if(this.isSlid){
-            this.afterSlideIn();
-            skipAnim = true;
-        }
-        this.collapsed = false;
-        if(this.config.animate && skipAnim !== true){
-            this.animateExpand();
-        }else{
-            this.el.show();
-            if(this.split){
-                this.split.el.show();
-            }
-            this.collapsedEl.setLocation(-2000,-2000);
-            this.collapsedEl.hide();
-            this.fireEvent("invalidated", this);
-            this.fireEvent("expanded", this);
-        }
+    getHeight : function(){
+        return this.height;
     },
-
-    animateExpand : function(){
-        // overridden
+    // private
+    getSignature : function(){
+        return this.signatureTmp;
     },
-
-    initTabs : function()
-    {
-        this.bodyEl.setStyle("overflow", "hidden");
-        var ts = new Roo.TabPanel(
-                this.bodyEl.dom,
-                {
-                    tabPosition: this.bottomTabs ? 'bottom' : 'top',
-                    disableTooltips: this.config.disableTabTips,
-                    toolbar : this.config.toolbar
-                }
-        );
-        if(this.config.hideTabs){
-            ts.stripWrap.setDisplayed(false);
-        }
-        this.tabs = ts;
-        ts.resizeTabs = this.config.resizeTabs === true;
-        ts.minTabWidth = this.config.minTabWidth || 40;
-        ts.maxTabWidth = this.config.maxTabWidth || 250;
-        ts.preferredTabWidth = this.config.preferredTabWidth || 150;
-        ts.monitorResize = false;
-        ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
-        ts.bodyEl.addClass('x-layout-tabs-body');
-        this.panels.each(this.initPanelAsTab, this);
+    // private
+    reset : function(){
+        this.signatureTmp = '';
+        this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
+        this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
+        this.isConfirmed = false;
+        Roo.form.Signature.superclass.reset.call(this);
     },
-
-    initPanelAsTab : function(panel){
-        var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
-                    this.config.closeOnTab && panel.isClosable());
-        if(panel.tabTip !== undefined){
-            ti.setTooltip(panel.tabTip);
-        }
-        ti.on("activate", function(){
-              this.setActivePanel(panel);
-        }, this);
-        if(this.config.closeOnTab){
-            ti.on("beforeclose", function(t, e){
-                e.cancel = true;
-                this.remove(panel);
-            }, this);
-        }
-        return ti;
+    setSignature : function(s){
+        this.signatureTmp = s;
+        this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
+        this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
+        this.setValue(s);
+        this.isConfirmed = false;
+        Roo.form.Signature.superclass.reset.call(this);
+    }, 
+    test : function(){
+//        Roo.log(this.signPanel.dom.contentWindow.up())
     },
-
-    updatePanelTitle : function(panel, title){
-        if(this.activePanel == panel){
-            this.updateTitle(title);
-        }
-        if(this.tabs){
-            var ti = this.tabs.getTab(panel.getEl().id);
-            ti.setText(title);
-            if(panel.tabTip !== undefined){
-                ti.setTooltip(panel.tabTip);
-            }
-        }
+    //private
+    setConfirmed : function(){
+        
+        
+        
+//        Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
     },
-
-    updateTitle : function(title){
-        if(this.titleTextEl && !this.config.title){
-            this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : "&#160;");
+    // private
+    confirmHandler : function(){
+        if(!this.getSignature()){
+            return;
         }
+        
+        this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
+        this.setValue(this.getSignature());
+        this.isConfirmed = true;
+        
+        this.fireEvent('confirm', this);
     },
-
-    setActivePanel : function(panel){
-        panel = this.getPanel(panel);
-        if(this.activePanel && this.activePanel != panel){
-            this.activePanel.setActiveState(false);
-        }
-        this.activePanel = panel;
-        panel.setActiveState(true);
-        if(this.panelSize){
-            panel.setSize(this.panelSize.width, this.panelSize.height);
-        }
-        if(this.closeBtn){
-            this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
+    // private
+    // Subclasses should provide the validation implementation by overriding this
+    validateValue : function(value){
+        if(this.allowBlank){
+            return true;
         }
-        this.updateTitle(panel.getTitle());
-        if(this.tabs){
-            this.fireEvent("invalidated", this);
+        
+        if(this.isConfirmed){
+            return true;
         }
-        this.fireEvent("panelactivated", this, panel);
-    },
+        return false;
+    }
+});/*
+ * 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">
+ */
 
-    /**
-     * Shows the specified panel.
-     * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
-     * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
-     */
-    showPanel : function(panel)
-    {
-        panel = this.getPanel(panel);
-        if(panel){
-            if(this.tabs){
-                var tab = this.tabs.getTab(panel.getEl().id);
-                if(tab.isHidden()){
-                    this.tabs.unhideTab(tab.id);
-                }
-                tab.activate();
-            }else{
-                this.setActivePanel(panel);
-            }
-        }
-        return panel;
-    },
+/**
+ * @class Roo.form.ComboBox
+ * @extends Roo.form.TriggerField
+ * A combobox control with support for autocomplete, remote-loading, paging and many other features.
+ * @constructor
+ * Create a new ComboBox.
+ * @param {Object} config Configuration options
+ */
+Roo.form.Select = function(config){
+    Roo.form.Select.superclass.constructor.call(this, config);
+     
+};
 
+Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
     /**
-     * Get the active panel for this region.
-     * @return {Roo.ContentPanel} The active panel or null
+     * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
      */
-    getActivePanel : function(){
-        return this.activePanel;
-    },
-
-    validateVisibility : function(){
-        if(this.panels.getCount() < 1){
-            this.updateTitle("&#160;");
-            this.closeBtn.hide();
-            this.hide();
-        }else{
-            if(!this.isVisible()){
-                this.show();
-            }
-        }
-    },
-
     /**
-     * Adds the passed ContentPanel(s) to this region.
-     * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
-     * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
+     * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
+     * rendering into an Roo.Editor, defaults to false)
      */
-    add : function(panel){
-        if(arguments.length > 1){
-            for(var i = 0, len = arguments.length; i < len; i++) {
-                this.add(arguments[i]);
-            }
-            return null;
-        }
-        if(this.hasPanel(panel)){
-            this.showPanel(panel);
-            return panel;
-        }
-        panel.setRegion(this);
-        this.panels.add(panel);
-        if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
-            this.bodyEl.dom.appendChild(panel.getEl().dom);
-            if(panel.background !== true){
-                this.setActivePanel(panel);
-            }
-            this.fireEvent("paneladded", this, panel);
-            return panel;
-        }
-        if(!this.tabs){
-            this.initTabs();
-        }else{
-            this.initPanelAsTab(panel);
-        }
-        if(panel.background !== true){
-            this.tabs.activate(panel.getEl().id);
-        }
-        this.fireEvent("paneladded", this, panel);
-        return panel;
-    },
-
     /**
-     * Hides the tab for the specified panel.
-     * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
+     * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
+     * {tag: "input", type: "text", size: "24", autocomplete: "off"})
      */
-    hidePanel : function(panel){
-        if(this.tabs && (panel = this.getPanel(panel))){
-            this.tabs.hideTab(panel.getEl().id);
-        }
-    },
-
     /**
-     * Unhides the tab for a previously hidden panel.
-     * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
+     * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
      */
-    unhidePanel : function(panel){
-        if(this.tabs && (panel = this.getPanel(panel))){
-            this.tabs.unhideTab(panel.getEl().id);
-        }
-    },
-
-    clearPanels : function(){
-        while(this.panels.getCount() > 0){
-             this.remove(this.panels.first());
-        }
-    },
-
     /**
-     * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
-     * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
-     * @param {Boolean} preservePanel Overrides the config preservePanel option
-     * @return {Roo.ContentPanel} The panel that was removed
+     * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
+     * the dropdown list (defaults to undefined, with no header element)
      */
-    remove : function(panel, preservePanel){
-        panel = this.getPanel(panel);
-        if(!panel){
-            return null;
-        }
-        var e = {};
-        this.fireEvent("beforeremove", this, panel, e);
-        if(e.cancel === true){
-            return null;
-        }
-        preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
-        var panelId = panel.getId();
-        this.panels.removeKey(panelId);
-        if(preservePanel){
-            document.body.appendChild(panel.getEl().dom);
-        }
-        if(this.tabs){
-            this.tabs.removeTab(panel.getEl().id);
-        }else if (!preservePanel){
-            this.bodyEl.dom.removeChild(panel.getEl().dom);
-        }
-        if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
-            var p = this.panels.first();
-            var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
-            tempEl.appendChild(p.getEl().dom);
-            this.bodyEl.update("");
-            this.bodyEl.dom.appendChild(p.getEl().dom);
-            tempEl = null;
-            this.updateTitle(p.getTitle());
-            this.tabs = null;
-            this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
-            this.setActivePanel(p);
-        }
-        panel.setRegion(null);
-        if(this.activePanel == panel){
-            this.activePanel = null;
-        }
-        if(this.config.autoDestroy !== false && preservePanel !== true){
-            try{panel.destroy();}catch(e){}
-        }
-        this.fireEvent("panelremoved", this, panel);
-        return panel;
-    },
 
+     /**
+     * @cfg {String/Roo.Template} tpl The template to use to render the output
+     */
+     
+    // private
+    defaultAutoCreate : {tag: "select"  },
     /**
-     * Returns the TabPanel component used by this region
-     * @return {Roo.TabPanel}
+     * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
      */
-    getTabs : function(){
-        return this.tabs;
+    listWidth: undefined,
+    /**
+     * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
+     * mode = 'remote' or 'text' if mode = 'local')
+     */
+    displayField: undefined,
+    /**
+     * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
+     * mode = 'remote' or 'value' if mode = 'local'). 
+     * Note: use of a valueField requires the user make a selection
+     * in order for a value to be mapped.
+     */
+    valueField: undefined,
+    
+    
+    /**
+     * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
+     * field's data value (defaults to the underlying DOM element's name)
+     */
+    hiddenName: undefined,
+    /**
+     * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
+     */
+    listClass: '',
+    /**
+     * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
+     */
+    selectedClass: 'x-combo-selected',
+    /**
+     * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
+     * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
+     * which displays a downward arrow icon).
+     */
+    triggerClass : 'x-form-arrow-trigger',
+    /**
+     * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
+     */
+    shadow:'sides',
+    /**
+     * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
+     * anchor positions (defaults to 'tl-bl')
+     */
+    listAlign: 'tl-bl?',
+    /**
+     * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
+     */
+    maxHeight: 300,
+    /**
+     * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
+     * query specified by the allQuery config option (defaults to 'query')
+     */
+    triggerAction: 'query',
+    /**
+     * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
+     * (defaults to 4, does not apply if editable = false)
+     */
+    minChars : 4,
+    /**
+     * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
+     * delay (typeAheadDelay) if it matches a known value (defaults to false)
+     */
+    typeAhead: false,
+    /**
+     * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
+     * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
+     */
+    queryDelay: 500,
+    /**
+     * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
+     * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
+     */
+    pageSize: 0,
+    /**
+     * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
+     * when editable = true (defaults to false)
+     */
+    selectOnFocus:false,
+    /**
+     * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
+     */
+    queryParam: 'query',
+    /**
+     * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
+     * when mode = 'remote' (defaults to 'Loading...')
+     */
+    loadingText: 'Loading...',
+    /**
+     * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
+     */
+    resizable: false,
+    /**
+     * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
+     */
+    handleHeight : 8,
+    /**
+     * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
+     * traditional select (defaults to true)
+     */
+    editable: true,
+    /**
+     * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
+     */
+    allQuery: '',
+    /**
+     * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
+     */
+    mode: 'remote',
+    /**
+     * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
+     * listWidth has a higher value)
+     */
+    minListWidth : 70,
+    /**
+     * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
+     * allow the user to set arbitrary text into the field (defaults to false)
+     */
+    forceSelection:false,
+    /**
+     * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
+     * if typeAhead = true (defaults to 250)
+     */
+    typeAheadDelay : 250,
+    /**
+     * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
+     * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
+     */
+    valueNotFoundText : undefined,
+    
+    /**
+     * @cfg {String} defaultValue The value displayed after loading the store.
+     */
+    defaultValue: '',
+    
+    /**
+     * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
+     */
+    blockFocus : false,
+    
+    /**
+     * @cfg {Boolean} disableClear Disable showing of clear button.
+     */
+    disableClear : false,
+    /**
+     * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
+     */
+    alwaysQuery : false,
+    
+    //private
+    addicon : false,
+    editicon: false,
+    
+    // element that contains real text value.. (when hidden is used..)
+     
+    // private
+    onRender : function(ct, position){
+        Roo.form.Field.prototype.onRender.call(this, ct, position);
+        
+        if(this.store){
+            this.store.on('beforeload', this.onBeforeLoad, this);
+            this.store.on('load', this.onLoad, this);
+            this.store.on('loadexception', this.onLoadException, this);
+            this.store.load({});
+        }
+        
+        
+        
     },
 
-    createTool : function(parentEl, className){
-        var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
-            children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: "&#160;"}]}, true);
-        btn.addClassOnOver("x-layout-tools-button-over");
-        return btn;
-    }
-});/*
- * 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">
- */
+    // private
+    initEvents : function(){
+        //Roo.form.ComboBox.superclass.initEvents.call(this);
  
+    },
 
-
-/**
- * @class Roo.SplitLayoutRegion
- * @extends Roo.LayoutRegion
- * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
- */
-Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
-    this.cursor = cursor;
-    Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
-};
-
-Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
-    splitTip : "Drag to resize.",
-    collapsibleSplitTip : "Drag to resize. Double click to hide.",
-    useSplitTips : false,
-
-    applyConfig : function(config){
-        Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
-        if(config.split){
-            if(!this.split){
-                var splitEl = Roo.DomHelper.append(this.mgr.el.dom, 
-                        {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: "&#160;"});
-                /** The SplitBar for this region 
-                * @type Roo.SplitBar */
-                this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
-                this.split.on("moved", this.onSplitMove, this);
-                this.split.useShim = config.useShim === true;
-                this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
-                if(this.useSplitTips){
-                    this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
-                }
-                if(config.collapsible){
-                    this.split.el.on("dblclick", this.collapse,  this);
-                }
-            }
-            if(typeof config.minSize != "undefined"){
-                this.split.minSize = config.minSize;
-            }
-            if(typeof config.maxSize != "undefined"){
-                this.split.maxSize = config.maxSize;
-            }
-            if(config.hideWhenEmpty || config.hidden || config.collapsed){
-                this.hideSplitter();
-            }
+    onDestroy : function(){
+       
+        if(this.store){
+            this.store.un('beforeload', this.onBeforeLoad, this);
+            this.store.un('load', this.onLoad, this);
+            this.store.un('loadexception', this.onLoadException, this);
         }
+        //Roo.form.ComboBox.superclass.onDestroy.call(this);
     },
 
-    getHMaxSize : function(){
-         var cmax = this.config.maxSize || 10000;
-         var center = this.mgr.getRegion("center");
-         return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
+    // private
+    fireKey : function(e){
+        if(e.isNavKeyPress() && !this.list.isVisible()){
+            this.fireEvent("specialkey", this, e);
+        }
     },
 
-    getVMaxSize : function(){
-         var cmax = this.config.maxSize || 10000;
-         var center = this.mgr.getRegion("center");
-         return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
+    // private
+    onResize: function(w, h){
+        
+        return; 
+    
+        
     },
 
-    onSplitMove : function(split, newSize){
-        this.fireEvent("resized", this, newSize);
-    },
-    
-    /** 
-     * Returns the {@link Roo.SplitBar} for this region.
-     * @return {Roo.SplitBar}
+    /**
+     * Allow or prevent the user from directly editing the field text.  If false is passed,
+     * the user will only be able to select from the items defined in the dropdown list.  This method
+     * is the runtime equivalent of setting the 'editable' config option at config time.
+     * @param {Boolean} value True to allow the user to directly edit the field text
      */
-    getSplitBar : function(){
-        return this.split;
+    setEditable : function(value){
+         
     },
+
+    // private
+    onBeforeLoad : function(){
+        
+        Roo.log("Select before load");
+        return;
     
-    hide : function(){
-        this.hideSplitter();
-        Roo.SplitLayoutRegion.superclass.hide.call(this);
+        this.innerList.update(this.loadingText ?
+               '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
+        //this.restrictHeight();
+        this.selectedIndex = -1;
     },
 
-    hideSplitter : function(){
-        if(this.split){
-            this.split.el.setLocation(-2000,-2000);
-            this.split.el.hide();
-        }
-    },
+    // private
+    onLoad : function(){
 
-    show : function(){
-        if(this.split){
-            this.split.el.show();
-        }
-        Roo.SplitLayoutRegion.superclass.show.call(this);
-    },
     
-    beforeSlide: function(){
-        if(Roo.isGecko){// firefox overflow auto bug workaround
-            this.bodyEl.clip();
-            if(this.tabs) {
-                this.tabs.bodyEl.clip();
-            }
-            if(this.activePanel){
-                this.activePanel.getEl().clip();
-                
-                if(this.activePanel.beforeSlide){
-                    this.activePanel.beforeSlide();
-                }
+        var dom = this.el.dom;
+        dom.innerHTML = '';
+         var od = dom.ownerDocument;
+         
+        if (this.emptyText) {
+            var op = od.createElement('option');
+            op.setAttribute('value', '');
+            op.innerHTML = String.format('{0}', this.emptyText);
+            dom.appendChild(op);
+        }
+        if(this.store.getCount() > 0){
+           
+            var vf = this.valueField;
+            var df = this.displayField;
+            this.store.data.each(function(r) {
+                // which colmsn to use... testing - cdoe / title..
+                var op = od.createElement('option');
+                op.setAttribute('value', r.data[vf]);
+                op.innerHTML = String.format('{0}', r.data[df]);
+                dom.appendChild(op);
+            });
+            if (typeof(this.defaultValue != 'undefined')) {
+                this.setValue(this.defaultValue);
             }
+            
+             
+        }else{
+            //this.onEmptyResults();
         }
+        //this.el.focus();
     },
+    // private
+    onLoadException : function()
+    {
+        dom.innerHTML = '';
+            
+        Roo.log("Select on load exception");
+        return;
     
-    afterSlide : function(){
-        if(Roo.isGecko){// firefox overflow auto bug workaround
-            this.bodyEl.unclip();
-            if(this.tabs) {
-                this.tabs.bodyEl.unclip();
-            }
-            if(this.activePanel){
-                this.activePanel.getEl().unclip();
-                if(this.activePanel.afterSlide){
-                    this.activePanel.afterSlide();
-                }
-            }
+        this.collapse();
+        Roo.log(this.store.reader.jsonData);
+        if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
+            Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
         }
+        
+        
     },
-
-    initAutoHide : function(){
-        if(this.autoHide !== false){
-            if(!this.autoHideHd){
-                var st = new Roo.util.DelayedTask(this.slideIn, this);
-                this.autoHideHd = {
-                    "mouseout": function(e){
-                        if(!e.within(this.el, true)){
-                            st.delay(500);
-                        }
-                    },
-                    "mouseover" : function(e){
-                        st.cancel();
-                    },
-                    scope : this
-                };
-            }
-            this.el.on(this.autoHideHd);
-        }
+    // private
+    onTypeAhead : function(){
+         
     },
 
-    clearAutoHide : function(){
-        if(this.autoHide !== false){
-            this.el.un("mouseout", this.autoHideHd.mouseout);
-            this.el.un("mouseover", this.autoHideHd.mouseover);
+    // private
+    onSelect : function(record, index){
+        Roo.log('on select?');
+        return;
+        if(this.fireEvent('beforeselect', this, record, index) !== false){
+            this.setFromData(index > -1 ? record.data : false);
+            this.collapse();
+            this.fireEvent('select', this, record, index);
         }
     },
 
-    clearMonitor : function(){
-        Roo.get(document).un("click", this.slideInIf, this);
+    /**
+     * Returns the currently selected field value or empty string if no value is set.
+     * @return {String} value The selected value
+     */
+    getValue : function(){
+        var dom = this.el.dom;
+        this.value = dom.options[dom.selectedIndex].value;
+        return this.value;
+        
     },
 
-    // these names are backwards but not changed for compat
-    slideOut : function(){
-        if(this.isSlid || this.el.hasActiveFx()){
-            return;
-        }
-        this.isSlid = true;
-        if(this.collapseBtn){
-            this.collapseBtn.hide();
-        }
-        this.closeBtnState = this.closeBtn.getStyle('display');
-        this.closeBtn.hide();
-        if(this.stickBtn){
-            this.stickBtn.show();
-        }
-        this.el.show();
-        this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
-        this.beforeSlide();
-        this.el.setStyle("z-index", 10001);
-        this.el.slideIn(this.getSlideAnchor(), {
-            callback: function(){
-                this.afterSlide();
-                this.initAutoHide();
-                Roo.get(document).on("click", this.slideInIf, this);
-                this.fireEvent("slideshow", this);
-            },
-            scope: this,
-            block: true
-        });
+    /**
+     * Clears any text/value currently set in the field
+     */
+    clearValue : function(){
+        this.value = '';
+        this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
+        
     },
 
-    afterSlideIn : function(){
-        this.clearAutoHide();
-        this.isSlid = false;
-        this.clearMonitor();
-        this.el.setStyle("z-index", "");
-        if(this.collapseBtn){
-            this.collapseBtn.show();
-        }
-        this.closeBtn.setStyle('display', this.closeBtnState);
-        if(this.stickBtn){
-            this.stickBtn.hide();
+    /**
+     * Sets the specified value into the field.  If the value finds a match, the corresponding record text
+     * will be displayed in the field.  If the value does not match the data value of an existing item,
+     * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
+     * Otherwise the field will be blank (although the value will still be set).
+     * @param {String} value The value to match
+     */
+    setValue : function(v){
+        var d = this.el.dom;
+        for (var i =0; i < d.options.length;i++) {
+            if (v == d.options[i].value) {
+                d.selectedIndex = i;
+                this.value = v;
+                return;
+            }
         }
-        this.fireEvent("slidehide", this);
+        this.clearValue();
     },
-
-    slideIn : function(cb){
-        if(!this.isSlid || this.el.hasActiveFx()){
-            Roo.callback(cb);
-            return;
-        }
-        this.isSlid = false;
-        this.beforeSlide();
-        this.el.slideOut(this.getSlideAnchor(), {
-            callback: function(){
-                this.el.setLeftTop(-10000, -10000);
-                this.afterSlide();
-                this.afterSlideIn();
-                Roo.callback(cb);
-            },
-            scope: this,
-            block: true
-        });
+    /**
+     * @property {Object} the last set data for the element
+     */
+    
+    lastData : false,
+    /**
+     * Sets the value of the field based on a object which is related to the record format for the store.
+     * @param {Object} value the value to set as. or false on reset?
+     */
+    setFromData : function(o){
+        Roo.log('setfrom data?');
+         
+        
+        
+    },
+    // private
+    reset : function(){
+        this.clearValue();
     },
+    // private
+    findRecord : function(prop, value){
+        
+        return false;
     
-    slideInIf : function(e){
-        if(!e.within(this.el)){
-            this.slideIn();
+        var record;
+        if(this.store.getCount() > 0){
+            this.store.each(function(r){
+                if(r.data[prop] == value){
+                    record = r;
+                    return false;
+                }
+                return true;
+            });
         }
+        return record;
     },
-
-    animateCollapse : function(){
-        this.beforeSlide();
-        this.el.setStyle("z-index", 20000);
-        var anchor = this.getSlideAnchor();
-        this.el.slideOut(anchor, {
-            callback : function(){
-                this.el.setStyle("z-index", "");
-                this.collapsedEl.slideIn(anchor, {duration:.3});
-                this.afterSlide();
-                this.el.setLocation(-10000,-10000);
-                this.el.hide();
-                this.fireEvent("collapsed", this);
-            },
-            scope: this,
-            block: true
-        });
+    
+    getName: function()
+    {
+        // returns hidden if it's set..
+        if (!this.rendered) {return ''};
+        return !this.hiddenName && this.el.dom.name  ? this.el.dom.name : (this.hiddenName || '');
+        
     },
+     
 
-    animateExpand : function(){
-        this.beforeSlide();
-        this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
-        this.el.setStyle("z-index", 20000);
-        this.collapsedEl.hide({
-            duration:.1
-        });
-        this.el.slideIn(this.getSlideAnchor(), {
-            callback : function(){
-                this.el.setStyle("z-index", "");
-                this.afterSlide();
-                if(this.split){
-                    this.split.el.show();
-                }
-                this.fireEvent("invalidated", this);
-                this.fireEvent("expanded", this);
-            },
-            scope: this,
-            block: true
-        });
+    
+
+    // private
+    onEmptyResults : function(){
+        Roo.log('empty results');
+        //this.collapse();
     },
 
-    anchors : {
-        "west" : "left",
-        "east" : "right",
-        "north" : "top",
-        "south" : "bottom"
+    /**
+     * Returns true if the dropdown list is expanded, else false.
+     */
+    isExpanded : function(){
+        return false;
     },
 
-    sanchors : {
-        "west" : "l",
-        "east" : "r",
-        "north" : "t",
-        "south" : "b"
+    /**
+     * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
+     * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
+     * @param {String} value The data value of the item to select
+     * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
+     * selected item if it is not currently in view (defaults to true)
+     * @return {Boolean} True if the value matched an item in the list, else false
+     */
+    selectByValue : function(v, scrollIntoView){
+        Roo.log('select By Value');
+        return false;
+    
+        if(v !== undefined && v !== null){
+            var r = this.findRecord(this.valueField || this.displayField, v);
+            if(r){
+                this.select(this.store.indexOf(r), scrollIntoView);
+                return true;
+            }
+        }
+        return false;
     },
 
-    canchors : {
-        "west" : "tl-tr",
-        "east" : "tr-tl",
-        "north" : "tl-bl",
-        "south" : "bl-tl"
+    /**
+     * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
+     * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
+     * @param {Number} index The zero-based index of the list item to select
+     * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
+     * selected item if it is not currently in view (defaults to true)
+     */
+    select : function(index, scrollIntoView){
+        Roo.log('select ');
+        return  ;
+        
+        this.selectedIndex = index;
+        this.view.select(index);
+        if(scrollIntoView !== false){
+            var el = this.view.getNode(index);
+            if(el){
+                this.innerList.scrollChildIntoView(el, false);
+            }
+        }
     },
 
-    getAnchor : function(){
-        return this.anchors[this.position];
+      
+
+    // private
+    validateBlur : function(){
+        
+        return;
+        
     },
 
-    getCollapseAnchor : function(){
-        return this.canchors[this.position];
+    // private
+    initQuery : function(){
+        this.doQuery(this.getRawValue());
     },
 
-    getSlideAnchor : function(){
-        return this.sanchors[this.position];
+    // private
+    doForce : function(){
+        if(this.el.dom.value.length > 0){
+            this.el.dom.value =
+                this.lastSelectionText === undefined ? '' : this.lastSelectionText;
+             
+        }
     },
 
-    getAlignAdj : function(){
-        var cm = this.cmargins;
-        switch(this.position){
-            case "west":
-                return [0, 0];
-            break;
-            case "east":
-                return [0, 0];
-            break;
-            case "north":
-                return [0, 0];
-            break;
-            case "south":
-                return [0, 0];
-            break;
+    /**
+     * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
+     * query allowing the query action to be canceled if needed.
+     * @param {String} query The SQL query to execute
+     * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
+     * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
+     * saved in the current store (defaults to false)
+     */
+    doQuery : function(q, forceAll){
+        
+        Roo.log('doQuery?');
+        if(q === undefined || q === null){
+            q = '';
+        }
+        var qe = {
+            query: q,
+            forceAll: forceAll,
+            combo: this,
+            cancel:false
+        };
+        if(this.fireEvent('beforequery', qe)===false || qe.cancel){
+            return false;
+        }
+        q = qe.query;
+        forceAll = qe.forceAll;
+        if(forceAll === true || (q.length >= this.minChars)){
+            if(this.lastQuery != q || this.alwaysQuery){
+                this.lastQuery = q;
+                if(this.mode == 'local'){
+                    this.selectedIndex = -1;
+                    if(forceAll){
+                        this.store.clearFilter();
+                    }else{
+                        this.store.filter(this.displayField, q);
+                    }
+                    this.onLoad();
+                }else{
+                    this.store.baseParams[this.queryParam] = q;
+                    this.store.load({
+                        params: this.getParams(q)
+                    });
+                    this.expand();
+                }
+            }else{
+                this.selectedIndex = -1;
+                this.onLoad();   
+            }
         }
     },
 
-    getExpandAdj : function(){
-        var c = this.collapsedEl, cm = this.cmargins;
-        switch(this.position){
-            case "west":
-                return [-(cm.right+c.getWidth()+cm.left), 0];
-            break;
-            case "east":
-                return [cm.right+c.getWidth()+cm.left, 0];
-            break;
-            case "north":
-                return [0, -(cm.top+cm.bottom+c.getHeight())];
-            break;
-            case "south":
-                return [0, cm.top+cm.bottom+c.getHeight()];
-            break;
+    // private
+    getParams : function(q){
+        var p = {};
+        //p[this.queryParam] = q;
+        if(this.pageSize){
+            p.start = 0;
+            p.limit = this.pageSize;
         }
-    }
-});/*
- * 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">
- */
-/*
- * These classes are private internal classes
- */
-Roo.CenterLayoutRegion = function(mgr, config){
-    Roo.LayoutRegion.call(this, mgr, config, "center");
-    this.visible = true;
-    this.minWidth = config.minWidth || 20;
-    this.minHeight = config.minHeight || 20;
-};
+        return p;
+    },
 
-Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
-    hide : function(){
-        // center panel can't be hidden
+    /**
+     * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
+     */
+    collapse : function(){
+        
     },
-    
-    show : function(){
-        // center panel can't be hidden
+
+    // private
+    collapseIf : function(e){
+        
     },
+
+    /**
+     * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
+     */
+    expand : function(){
+        
+    } ,
+
+    // private
+     
+
+    /** 
+    * @cfg {Boolean} grow 
+    * @hide 
+    */
+    /** 
+    * @cfg {Number} growMin 
+    * @hide 
+    */
+    /** 
+    * @cfg {Number} growMax 
+    * @hide 
+    */
+    /**
+     * @hide
+     * @method autoSize
+     */
     
-    getMinWidth: function(){
-        return this.minWidth;
+    setWidth : function()
+    {
+        
     },
-    
-    getMinHeight: function(){
-        return this.minHeight;
+    getResizeEl : function(){
+        return this.el;
     }
-});
-
+});//<script type="text/javasscript">
 
-Roo.NorthLayoutRegion = function(mgr, config){
-    Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
-    if(this.split){
-        this.split.placement = Roo.SplitBar.TOP;
-        this.split.orientation = Roo.SplitBar.VERTICAL;
-        this.split.el.addClass("x-layout-split-v");
+/**
+ * @class Roo.DDView
+ * A DnD enabled version of Roo.View.
+ * @param {Element/String} container The Element in which to create the View.
+ * @param {String} tpl The template string used to create the markup for each element of the View
+ * @param {Object} config The configuration properties. These include all the config options of
+ * {@link Roo.View} plus some specific to this class.<br>
+ * <p>
+ * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
+ * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
+ * <p>
+ * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
+.x-view-drag-insert-above {
+       border-top:1px dotted #3366cc;
+}
+.x-view-drag-insert-below {
+       border-bottom:1px dotted #3366cc;
+}
+</code></pre>
+ * 
+ */
+Roo.DDView = function(container, tpl, config) {
+    Roo.DDView.superclass.constructor.apply(this, arguments);
+    this.getEl().setStyle("outline", "0px none");
+    this.getEl().unselectable();
+    if (this.dragGroup) {
+       this.setDraggable(this.dragGroup.split(","));
     }
-    var size = config.initialSize || config.height;
-    if(typeof size != "undefined"){
-        this.el.setHeight(size);
+    if (this.dropGroup) {
+       this.setDroppable(this.dropGroup.split(","));
     }
-};
-Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
-    orientation: Roo.SplitBar.VERTICAL,
-    getBox : function(){
-        if(this.collapsed){
-            return this.collapsedEl.getBox();
-        }
-        var box = this.el.getBox();
-        if(this.split){
-            box.height += this.split.el.getHeight();
-        }
-        return box;
+    if (this.deletable) {
+       this.setDeletable();
+    }
+    this.isDirtyFlag = false;
+       this.addEvents({
+               "drop" : true
+       });
+};
+
+Roo.extend(Roo.DDView, Roo.View, {
+/**    @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
+/**    @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
+/**    @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
+/**    @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
+
+       isFormField: true,
+
+       reset: Roo.emptyFn,
+       
+       clearInvalid: Roo.form.Field.prototype.clearInvalid,
+
+       validate: function() {
+               return true;
+       },
+       
+       destroy: function() {
+               this.purgeListeners();
+               this.getEl.removeAllListeners();
+               this.getEl().remove();
+               if (this.dragZone) {
+                       if (this.dragZone.destroy) {
+                               this.dragZone.destroy();
+                       }
+               }
+               if (this.dropZone) {
+                       if (this.dropZone.destroy) {
+                               this.dropZone.destroy();
+                       }
+               }
+       },
+
+/**    Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
+       getName: function() {
+               return this.name;
+       },
+
+/**    Loads the View from a JSON string representing the Records to put into the Store. */
+       setValue: function(v) {
+               if (!this.store) {
+                       throw "DDView.setValue(). DDView must be constructed with a valid Store";
+               }
+               var data = {};
+               data[this.store.reader.meta.root] = v ? [].concat(v) : [];
+               this.store.proxy = new Roo.data.MemoryProxy(data);
+               this.store.load();
+       },
+
+/**    @return {String} a parenthesised list of the ids of the Records in the View. */
+       getValue: function() {
+               var result = '(';
+               this.store.each(function(rec) {
+                       result += rec.id + ',';
+               });
+               return result.substr(0, result.length - 1) + ')';
+       },
+       
+       getIds: function() {
+               var i = 0, result = new Array(this.store.getCount());
+               this.store.each(function(rec) {
+                       result[i++] = rec.id;
+               });
+               return result;
+       },
+       
+       isDirty: function() {
+               return this.isDirtyFlag;
+       },
+
+/**
+ *     Part of the Roo.dd.DropZone interface. If no target node is found, the
+ *     whole Element becomes the target, and this causes the drop gesture to append.
+ */
+    getTargetFromEvent : function(e) {
+               var target = e.getTarget();
+               while ((target !== null) && (target.parentNode != this.el.dom)) {
+               target = target.parentNode;
+               }
+               if (!target) {
+                       target = this.el.dom.lastChild || this.el.dom;
+               }
+               return target;
+    },
+
+/**
+ *     Create the drag data which consists of an object which has the property "ddel" as
+ *     the drag proxy element. 
+ */
+    getDragData : function(e) {
+        var target = this.findItemFromChild(e.getTarget());
+               if(target) {
+                       this.handleSelection(e);
+                       var selNodes = this.getSelectedNodes();
+            var dragData = {
+                source: this,
+                copy: this.copy || (this.allowCopy && e.ctrlKey),
+                nodes: selNodes,
+                records: []
+                       };
+                       var selectedIndices = this.getSelectedIndexes();
+                       for (var i = 0; i < selectedIndices.length; i++) {
+                               dragData.records.push(this.store.getAt(selectedIndices[i]));
+                       }
+                       if (selNodes.length == 1) {
+                               dragData.ddel = target.cloneNode(true); // the div element
+                       } else {
+                               var div = document.createElement('div'); // create the multi element drag "ghost"
+                               div.className = 'multi-proxy';
+                               for (var i = 0, len = selNodes.length; i < len; i++) {
+                                       div.appendChild(selNodes[i].cloneNode(true));
+                               }
+                               dragData.ddel = div;
+                       }
+            //console.log(dragData)
+            //console.log(dragData.ddel.innerHTML)
+                       return dragData;
+               }
+        //console.log('nodragData')
+               return false;
     },
     
-    updateBox : function(box){
-        if(this.split && !this.collapsed){
-            box.height -= this.split.el.getHeight();
-            this.split.el.setLeft(box.x);
-            this.split.el.setTop(box.y+box.height);
-            this.split.el.setWidth(box.width);
-        }
-        if(this.collapsed){
-            this.updateBody(box.width, null);
-        }
-        Roo.LayoutRegion.prototype.updateBox.call(this, box);
-    }
-});
+/**    Specify to which ddGroup items in this DDView may be dragged. */
+    setDraggable: function(ddGroup) {
+       if (ddGroup instanceof Array) {
+               Roo.each(ddGroup, this.setDraggable, this);
+               return;
+       }
+       if (this.dragZone) {
+               this.dragZone.addToGroup(ddGroup);
+       } else {
+                       this.dragZone = new Roo.dd.DragZone(this.getEl(), {
+                               containerScroll: true,
+                               ddGroup: ddGroup 
 
-Roo.SouthLayoutRegion = function(mgr, config){
-    Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
-    if(this.split){
-        this.split.placement = Roo.SplitBar.BOTTOM;
-        this.split.orientation = Roo.SplitBar.VERTICAL;
-        this.split.el.addClass("x-layout-split-v");
-    }
-    var size = config.initialSize || config.height;
-    if(typeof size != "undefined"){
-        this.el.setHeight(size);
-    }
-};
-Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
-    orientation: Roo.SplitBar.VERTICAL,
-    getBox : function(){
-        if(this.collapsed){
-            return this.collapsedEl.getBox();
-        }
-        var box = this.el.getBox();
-        if(this.split){
-            var sh = this.split.el.getHeight();
-            box.height += sh;
-            box.y -= sh;
-        }
-        return box;
+                       });
+//                     Draggability implies selection. DragZone's mousedown selects the element.
+                       if (!this.multiSelect) { this.singleSelect = true; }
+
+//                     Wire the DragZone's handlers up to methods in *this*
+                       this.dragZone.getDragData = this.getDragData.createDelegate(this);
+               }
+    },
+
+/**    Specify from which ddGroup this DDView accepts drops. */
+    setDroppable: function(ddGroup) {
+       if (ddGroup instanceof Array) {
+               Roo.each(ddGroup, this.setDroppable, this);
+               return;
+       }
+       if (this.dropZone) {
+               this.dropZone.addToGroup(ddGroup);
+       } else {
+                       this.dropZone = new Roo.dd.DropZone(this.getEl(), {
+                               containerScroll: true,
+                               ddGroup: ddGroup
+                       });
+
+//                     Wire the DropZone's handlers up to methods in *this*
+                       this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
+                       this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
+                       this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
+                       this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
+                       this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
+               }
+    },
+
+/**    Decide whether to drop above or below a View node. */
+    getDropPoint : function(e, n, dd){
+       if (n == this.el.dom) { return "above"; }
+               var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
+               var c = t + (b - t) / 2;
+               var y = Roo.lib.Event.getPageY(e);
+               if(y <= c) {
+                       return "above";
+               }else{
+                       return "below";
+               }
+    },
+
+    onNodeEnter : function(n, dd, e, data){
+               return false;
     },
     
-    updateBox : function(box){
-        if(this.split && !this.collapsed){
-            var sh = this.split.el.getHeight();
-            box.height -= sh;
-            box.y += sh;
-            this.split.el.setLeft(box.x);
-            this.split.el.setTop(box.y-sh);
-            this.split.el.setWidth(box.width);
-        }
-        if(this.collapsed){
-            this.updateBody(box.width, null);
-        }
-        Roo.LayoutRegion.prototype.updateBox.call(this, box);
-    }
-});
+    onNodeOver : function(n, dd, e, data){
+               var pt = this.getDropPoint(e, n, dd);
+               // set the insert point style on the target node
+               var dragElClass = this.dropNotAllowed;
+               if (pt) {
+                       var targetElClass;
+                       if (pt == "above"){
+                               dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
+                               targetElClass = "x-view-drag-insert-above";
+                       } else {
+                               dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
+                               targetElClass = "x-view-drag-insert-below";
+                       }
+                       if (this.lastInsertClass != targetElClass){
+                               Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
+                               this.lastInsertClass = targetElClass;
+                       }
+               }
+               return dragElClass;
+       },
 
-Roo.EastLayoutRegion = function(mgr, config){
-    Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
-    if(this.split){
-        this.split.placement = Roo.SplitBar.RIGHT;
-        this.split.orientation = Roo.SplitBar.HORIZONTAL;
-        this.split.el.addClass("x-layout-split-h");
-    }
-    var size = config.initialSize || config.width;
-    if(typeof size != "undefined"){
-        this.el.setWidth(size);
-    }
-};
-Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
-    orientation: Roo.SplitBar.HORIZONTAL,
-    getBox : function(){
-        if(this.collapsed){
-            return this.collapsedEl.getBox();
-        }
-        var box = this.el.getBox();
-        if(this.split){
-            var sw = this.split.el.getWidth();
-            box.width += sw;
-            box.x -= sw;
-        }
-        return box;
+    onNodeOut : function(n, dd, e, data){
+               this.removeDropIndicators(n);
     },
 
-    updateBox : function(box){
-        if(this.split && !this.collapsed){
-            var sw = this.split.el.getWidth();
-            box.width -= sw;
-            this.split.el.setLeft(box.x);
-            this.split.el.setTop(box.y);
-            this.split.el.setHeight(box.height);
-            box.x += sw;
-        }
-        if(this.collapsed){
-            this.updateBody(null, box.height);
-        }
-        Roo.LayoutRegion.prototype.updateBox.call(this, box);
-    }
-});
+    onNodeDrop : function(n, dd, e, data){
+       if (this.fireEvent("drop", this, n, dd, e, data) === false) {
+               return false;
+       }
+       var pt = this.getDropPoint(e, n, dd);
+               var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
+               if (pt == "below") { insertAt++; }
+               for (var i = 0; i < data.records.length; i++) {
+                       var r = data.records[i];
+                       var dup = this.store.getById(r.id);
+                       if (dup && (dd != this.dragZone)) {
+                               Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
+                       } else {
+                               if (data.copy) {
+                                       this.store.insert(insertAt++, r.copy());
+                               } else {
+                                       data.source.isDirtyFlag = true;
+                                       r.store.remove(r);
+                                       this.store.insert(insertAt++, r);
+                               }
+                               this.isDirtyFlag = true;
+                       }
+               }
+               this.dragZone.cachedTarget = null;
+               return true;
+    },
 
-Roo.WestLayoutRegion = function(mgr, config){
-    Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
-    if(this.split){
-        this.split.placement = Roo.SplitBar.LEFT;
-        this.split.orientation = Roo.SplitBar.HORIZONTAL;
-        this.split.el.addClass("x-layout-split-h");
-    }
-    var size = config.initialSize || config.width;
-    if(typeof size != "undefined"){
-        this.el.setWidth(size);
-    }
-};
-Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
-    orientation: Roo.SplitBar.HORIZONTAL,
-    getBox : function(){
-        if(this.collapsed){
-            return this.collapsedEl.getBox();
-        }
-        var box = this.el.getBox();
-        if(this.split){
-            box.width += this.split.el.getWidth();
+    removeDropIndicators : function(n){
+               if(n){
+                       Roo.fly(n).removeClass([
+                               "x-view-drag-insert-above",
+                               "x-view-drag-insert-below"]);
+                       this.lastInsertClass = "_noclass";
+               }
+    },
+
+/**
+ *     Utility method. Add a delete option to the DDView's context menu.
+ *     @param {String} imageUrl The URL of the "delete" icon image.
+ */
+       setDeletable: function(imageUrl) {
+               if (!this.singleSelect && !this.multiSelect) {
+                       this.singleSelect = true;
+               }
+               var c = this.getContextMenu();
+               this.contextMenu.on("itemclick", function(item) {
+                       switch (item.id) {
+                               case "delete":
+                                       this.remove(this.getSelectedIndexes());
+                                       break;
+                       }
+               }, this);
+               this.contextMenu.add({
+                       icon: imageUrl,
+                       id: "delete",
+                       text: 'Delete'
+               });
+       },
+       
+/**    Return the context menu for this DDView. */
+       getContextMenu: function() {
+               if (!this.contextMenu) {
+//                     Create the View's context menu
+                       this.contextMenu = new Roo.menu.Menu({
+                               id: this.id + "-contextmenu"
+                       });
+                       this.el.on("contextmenu", this.showContextMenu, this);
+               }
+               return this.contextMenu;
+       },
+       
+       disableContextMenu: function() {
+               if (this.contextMenu) {
+                       this.el.un("contextmenu", this.showContextMenu, this);
+               }
+       },
+
+       showContextMenu: function(e, item) {
+        item = this.findItemFromChild(e.getTarget());
+               if (item) {
+                       e.stopEvent();
+                       this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
+                       this.contextMenu.showAt(e.getXY());
+           }
+    },
+
+/**
+ *     Remove {@link Roo.data.Record}s at the specified indices.
+ *     @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
+ */
+    remove: function(selectedIndices) {
+               selectedIndices = [].concat(selectedIndices);
+               for (var i = 0; i < selectedIndices.length; i++) {
+                       var rec = this.store.getAt(selectedIndices[i]);
+                       this.store.remove(rec);
+               }
+    },
+
+/**
+ *     Double click fires the event, but also, if this is draggable, and there is only one other
+ *     related DropZone, it transfers the selected node.
+ */
+    onDblClick : function(e){
+        var item = this.findItemFromChild(e.getTarget());
+        if(item){
+            if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
+               return false;
+            }
+            if (this.dragGroup) {
+                   var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
+                   while (targets.indexOf(this.dropZone) > -1) {
+                           targets.remove(this.dropZone);
+                               }
+                   if (targets.length == 1) {
+                                       this.dragZone.cachedTarget = null;
+                       var el = Roo.get(targets[0].getEl());
+                       var box = el.getBox(true);
+                       targets[0].onNodeDrop(el.dom, {
+                               target: el.dom,
+                               xy: [box.x, box.y + box.height - 1]
+                       }, null, this.getDragData(e));
+                   }
+               }
         }
-        return box;
     },
     
-    updateBox : function(box){
-        if(this.split && !this.collapsed){
-            var sw = this.split.el.getWidth();
-            box.width -= sw;
-            this.split.el.setLeft(box.x+box.width);
-            this.split.el.setTop(box.y);
-            this.split.el.setHeight(box.height);
-        }
-        if(this.collapsed){
-            this.updateBody(null, box.height);
+    handleSelection: function(e) {
+               this.dragZone.cachedTarget = null;
+        var item = this.findItemFromChild(e.getTarget());
+        if (!item) {
+               this.clearSelections(true);
+               return;
         }
-        Roo.LayoutRegion.prototype.updateBox.call(this, box);
+               if (item && (this.multiSelect || this.singleSelect)){
+                       if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
+                               this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
+                       }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
+                               this.unselect(item);
+                       } else {
+                               this.select(item, this.multiSelect && e.ctrlKey);
+                               this.lastSelection = item;
+                       }
+               }
+    },
+
+    onItemClick : function(item, index, e){
+               if(this.fireEvent("beforeclick", this, index, item, e) === false){
+                       return false;
+               }
+               return true;
+    },
+
+    unselect : function(nodeInfo, suppressEvent){
+               var node = this.getNode(nodeInfo);
+               if(node && this.isSelected(node)){
+                       if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
+                               Roo.fly(node).removeClass(this.selectedClass);
+                               this.selections.remove(node);
+                               if(!suppressEvent){
+                                       this.fireEvent("selectionchange", this, this.selections);
+                               }
+                       }
+               }
     }
 });
 /*
@@ -53440,970 +58404,785 @@ Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
  * <script type="text/javascript">
  */
  
-/*
- * Private internal class for reading and applying state
+/**
+ * @class Roo.LayoutManager
+ * @extends Roo.util.Observable
+ * Base class for layout managers.
  */
-Roo.LayoutStateManager = function(layout){
-     // default empty state
-     this.state = {
-        north: {},
-        south: {},
-        east: {},
-        west: {}       
-    };
-};
-
-Roo.LayoutStateManager.prototype = {
-    init : function(layout, provider){
-        this.provider = provider;
-        var state = provider.get(layout.id+"-layout-state");
-        if(state){
-            var wasUpdating = layout.isUpdating();
-            if(!wasUpdating){
-                layout.beginUpdate();
-            }
-            for(var key in state){
-                if(typeof state[key] != "function"){
-                    var rstate = state[key];
-                    var r = layout.getRegion(key);
-                    if(r && rstate){
-                        if(rstate.size){
-                            r.resizeTo(rstate.size);
-                        }
-                        if(rstate.collapsed == true){
-                            r.collapse(true);
-                        }else{
-                            r.expand(null, true);
-                        }
-                    }
-                }
-            }
-            if(!wasUpdating){
-                layout.endUpdate();
-            }
-            this.state = state; 
-        }
-        this.layout = layout;
-        layout.on("regionresized", this.onRegionResized, this);
-        layout.on("regioncollapsed", this.onRegionCollapsed, this);
-        layout.on("regionexpanded", this.onRegionExpanded, this);
-    },
-    
-    storeState : function(){
-        this.provider.set(this.layout.id+"-layout-state", this.state);
-    },
-    
-    onRegionResized : function(region, newSize){
-        this.state[region.getPosition()].size = newSize;
-        this.storeState();
-    },
-    
-    onRegionCollapsed : function(region){
-        this.state[region.getPosition()].collapsed = true;
-        this.storeState();
-    },
-    
-    onRegionExpanded : function(region){
-        this.state[region.getPosition()].collapsed = false;
-        this.storeState();
-    }
-};/*
- * 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.ContentPanel
- * @extends Roo.util.Observable
- * 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}   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 {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 {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.)
-
- * @constructor
- * Create a new ContentPanel.
- * @param {String/HTMLElement/Roo.Element} el The container element for this panel
- * @param {String/Object} config A string to set only the title or a config object
- * @param {String} content (optional) Set the HTML content for this panel
- * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
- */
-Roo.ContentPanel = function(el, config, content){
-    
-     
-    /*
-    if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
-        config = el;
-        el = Roo.id();
-    }
-    if (config && config.parentLayout) { 
-        el = config.parentLayout.el.createChild(); 
-    }
-    */
-    if(el.autoCreate){ // xtype is available if this is called from factory
-        config = el;
-        el = Roo.id();
-    }
-    this.el = Roo.get(el);
-    if(!this.el && config && config.autoCreate){
-        if(typeof config.autoCreate == "object"){
-            if(!config.autoCreate.id){
-                config.autoCreate.id = config.id||el;
-            }
-            this.el = Roo.DomHelper.append(document.body,
-                        config.autoCreate, true);
-        }else{
-            this.el = Roo.DomHelper.append(document.body,
-                        {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
-        }
-    }
-    this.closable = false;
-    this.loaded = false;
-    this.active = false;
-    if(typeof config == "string"){
-        this.title = config;
-    }else{
-        Roo.apply(this, config);
-    }
-    
-    if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
-        this.wrapEl = this.el.wrap();
-        this.toolbar.container = this.el.insertSibling(false, 'before');
-        this.toolbar = new Roo.Toolbar(this.toolbar);
-    }
-    
-    // xtype created footer. - not sure if will work as we normally have to render first..
-    if (this.footer && !this.footer.el && this.footer.xtype) {
-        if (!this.wrapEl) {
-            this.wrapEl = this.el.wrap();
-        }
-    
-        this.footer.container = this.wrapEl.createChild();
-         
-        this.footer = Roo.factory(this.footer, Roo);
-        
-    }
-    
-    if(this.resizeEl){
-        this.resizeEl = Roo.get(this.resizeEl, true);
-    }else{
-        this.resizeEl = this.el;
+Roo.LayoutManager = function(container, config){
+    Roo.LayoutManager.superclass.constructor.call(this);
+    this.el = Roo.get(container);
+    // ie scrollbar fix
+    if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
+        document.body.scroll = "no";
+    }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
+        this.el.position('relative');
     }
-    // handle view.xtype
-    
-    
-    
+    this.id = this.el.id;
+    this.el.addClass("x-layout-container");
+    /** false to disable window resize monitoring @type Boolean */
+    this.monitorWindowResize = true;
+    this.regions = {};
     this.addEvents({
         /**
-         * @event activate
-         * Fires when this panel is activated. 
-         * @param {Roo.ContentPanel} this
+         * @event layout
+         * Fires when a layout is performed. 
+         * @param {Roo.LayoutManager} this
          */
-        "activate" : true,
+        "layout" : true,
         /**
-         * @event deactivate
-         * Fires when this panel is activated. 
-         * @param {Roo.ContentPanel} this
+         * @event regionresized
+         * Fires when the user resizes a region. 
+         * @param {Roo.LayoutRegion} region The resized region
+         * @param {Number} newSize The new size (width for east/west, height for north/south)
          */
-        "deactivate" : true,
-
+        "regionresized" : true,
         /**
-         * @event resize
-         * Fires when this panel is resized if fitToFrame is true.
-         * @param {Roo.ContentPanel} this
-         * @param {Number} width The width after any component adjustments
-         * @param {Number} height The height after any component adjustments
+         * @event regioncollapsed
+         * Fires when a region is collapsed. 
+         * @param {Roo.LayoutRegion} region The collapsed region
          */
-        "resize" : true,
-        
-         /**
-         * @event render
-         * Fires when this tab is created
-         * @param {Roo.ContentPanel} this
+        "regioncollapsed" : true,
+        /**
+         * @event regionexpanded
+         * Fires when a region is expanded.  
+         * @param {Roo.LayoutRegion} region The expanded region
          */
-        "render" : true
-         
-        
+        "regionexpanded" : true
     });
-    
-
-    
-    
-    if(this.autoScroll){
-        this.resizeEl.setStyle("overflow", "auto");
-    } else {
-        // fix randome scrolling
-        this.el.on('scroll', function() {
-            Roo.log('fix random scolling');
-            this.scrollTo('top',0); 
-        });
-    }
-    content = content || this.content;
-    if(content){
-        this.setContent(content);
-    }
-    if(config && config.url){
-        this.setUrl(this.url, this.params, this.loadOnce);
-    }
-    
-    
-    
-    Roo.ContentPanel.superclass.constructor.call(this);
-    
-    if (this.view && typeof(this.view.xtype) != 'undefined') {
-        this.view.el = this.el.appendChild(document.createElement("div"));
-        this.view = Roo.factory(this.view); 
-        this.view.render  &&  this.view.render(false, '');  
-    }
-    
-    
-    this.fireEvent('render', this);
+    this.updating = false;
+    Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
 };
 
-Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
-    tabTip:'',
-    setRegion : function(region){
-        this.region = region;
-        if(region){
-           this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
-        }else{
-           this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
-        } 
-    },
-    
+Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
     /**
-     * Returns the toolbar for this Panel if one was configured. 
-     * @return {Roo.Toolbar} 
+     * Returns true if this layout is currently being updated
+     * @return {Boolean}
      */
-    getToolbar : function(){
-        return this.toolbar;
+    isUpdating : function(){
+        return this.updating; 
     },
     
-    setActiveState : function(active){
-        this.active = active;
-        if(!active){
-            this.fireEvent("deactivate", this);
-        }else{
-            this.fireEvent("activate", this);
-        }
-    },
-    /**
-     * Updates this panel's element
-     * @param {String} content The new content
-     * @param {Boolean} loadScripts (optional) true to look for and process scripts
-    */
-    setContent : function(content, loadScripts){
-        this.el.update(content, loadScripts);
-    },
-
-    ignoreResize : function(w, h){
-        if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
-            return true;
-        }else{
-            this.lastSize = {width: w, height: h};
-            return false;
-        }
-    },
-    /**
-     * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
-     * @return {Roo.UpdateManager} The UpdateManager
-     */
-    getUpdateManager : function(){
-        return this.el.getUpdateManager();
-    },
-     /**
-     * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
-     * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
-<pre><code>
-panel.load({
-    url: "your-url.php",
-    params: {param1: "foo", param2: "bar"}, // or a URL encoded string
-    callback: yourFunction,
-    scope: yourObject, //(optional scope)
-    discardUrl: false,
-    nocache: false,
-    text: "Loading...",
-    timeout: 30,
-    scripts: false
-});
-</code></pre>
-     * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
-     * are shorthand for <i>disableCaching</i>, <i>indicatorText</i> and <i>loadScripts</i> and are used to set their associated property on this panel UpdateManager instance.
-     * @param {String/Object} params (optional) The parameters to pass as either a URL encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
-     * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
-     * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used URL. If true, it will not store the URL.
-     * @return {Roo.ContentPanel} this
-     */
-    load : function(){
-        var um = this.el.getUpdateManager();
-        um.update.apply(um, arguments);
-        return this;
-    },
-
-
     /**
-     * Set a URL to be used to load the content for this panel. When this panel is activated, the content will be loaded from that URL.
-     * @param {String/Function} url The URL to load the content from or a function to call to get the URL
-     * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
-     * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this panel is activated. (Defaults to false)
-     * @return {Roo.UpdateManager} The UpdateManager
+     * Suspend the LayoutManager from doing auto-layouts while
+     * making multiple add or remove calls
      */
-    setUrl : function(url, params, loadOnce){
-        if(this.refreshDelegate){
-            this.removeListener("activate", this.refreshDelegate);
-        }
-        this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
-        this.on("activate", this.refreshDelegate);
-        return this.el.getUpdateManager();
-    },
-    
-    _handleRefresh : function(url, params, loadOnce){
-        if(!loadOnce || !this.loaded){
-            var updater = this.el.getUpdateManager();
-            updater.update(url, params, this._setLoaded.createDelegate(this));
-        }
+    beginUpdate : function(){
+        this.updating = true;    
     },
     
-    _setLoaded : function(){
-        this.loaded = true;
-    }, 
-    
     /**
-     * Returns this panel's id
-     * @return {String} 
-     */
-    getId : function(){
-        return this.el.id;
-    },
-    
-    /** 
-     * Returns this panel's element - used by regiosn to add.
-     * @return {Roo.Element} 
+     * Restore auto-layouts and optionally disable the manager from performing a layout
+     * @param {Boolean} noLayout true to disable a layout update 
      */
-    getEl : function(){
-        return this.wrapEl || this.el;
+    endUpdate : function(noLayout){
+        this.updating = false;
+        if(!noLayout){
+            this.layout();
+        }    
     },
     
-    adjustForComponents : function(width, height)
-    {
-        //Roo.log('adjustForComponents ');
-        if(this.resizeEl != this.el){
-            width -= this.el.getFrameWidth('lr');
-            height -= this.el.getFrameWidth('tb');
-        }
-        if(this.toolbar){
-            var te = this.toolbar.getEl();
-            height -= te.getHeight();
-            te.setWidth(width);
-        }
-        if(this.footer){
-            var te = this.footer.getEl();
-            //Roo.log("footer:" + te.getHeight());
-            
-            height -= te.getHeight();
-            te.setWidth(width);
-        }
-        
+    layout: function(){
         
-        if(this.adjustments){
-            width += this.adjustments[0];
-            height += this.adjustments[1];
-        }
-        return {"width": width, "height": height};
     },
     
-    setSize : function(width, height){
-        if(this.fitToFrame && !this.ignoreResize(width, height)){
-            if(this.fitContainer && this.resizeEl != this.el){
-                this.el.setSize(width, height);
-            }
-            var size = this.adjustForComponents(width, height);
-            this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
-            this.fireEvent('resize', this, size.width, size.height);
-        }
+    onRegionResized : function(region, newSize){
+        this.fireEvent("regionresized", region, newSize);
+        this.layout();
     },
     
-    /**
-     * Returns this panel's title
-     * @return {String} 
-     */
-    getTitle : function(){
-        return this.title;
+    onRegionCollapsed : function(region){
+        this.fireEvent("regioncollapsed", region);
     },
     
+    onRegionExpanded : function(region){
+        this.fireEvent("regionexpanded", region);
+    },
+        
     /**
-     * Set this panel's title
-     * @param {String} title
+     * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
+     * performs box-model adjustments.
+     * @return {Object} The size as an object {width: (the width), height: (the height)}
      */
-    setTitle : function(title){
-        this.title = title;
-        if(this.region){
-            this.region.updatePanelTitle(this, title);
+    getViewSize : function(){
+        var size;
+        if(this.el.dom != document.body){
+            size = this.el.getSize();
+        }else{
+            size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
         }
+        size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
+        size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
+        return size;
     },
     
     /**
-     * Returns true is this panel was configured to be closable
-     * @return {Boolean} 
+     * Returns the Element this layout is bound to.
+     * @return {Roo.Element}
      */
-    isClosable : function(){
-        return this.closable;
-    },
-    
-    beforeSlide : function(){
-        this.el.clip();
-        this.resizeEl.clip();
-    },
-    
-    afterSlide : function(){
-        this.el.unclip();
-        this.resizeEl.unclip();
+    getEl : function(){
+        return this.el;
     },
     
     /**
-     *   Force a content refresh from the URL specified in the {@link #setUrl} method.
-     *   Will fail silently if the {@link #setUrl} method has not been called.
-     *   This does not activate the panel, just updates its content.
+     * Returns the specified region.
+     * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
+     * @return {Roo.LayoutRegion}
      */
-    refresh : function(){
-        if(this.refreshDelegate){
-           this.loaded = false;
-           this.refreshDelegate();
-        }
+    getRegion : function(target){
+        return this.regions[target.toLowerCase()];
     },
     
-    /**
-     * Destroys this panel
-     */
-    destroy : function(){
-        this.el.removeAllListeners();
-        var tempEl = document.createElement("span");
-        tempEl.appendChild(this.el.dom);
-        tempEl.innerHTML = "";
-        this.el.remove();
-        this.el = null;
+    onWindowResize : function(){
+        if(this.monitorWindowResize){
+            this.layout();
+        }
+    }
+});/*
+ * 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.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>
+ * <a href="http://www.jackslocum.com/yui/2006/10/28/cross-browser-web-20-layouts-part-2-ajax-feed-viewer-20/">Cross Browser Layouts - Part 2</a><br><br>
+ * Example:
+ <pre><code>
+ var layout = new Roo.BorderLayout(document.body, {
+    north: {
+        initialSize: 25,
+        titlebar: false
     },
-    
-    /**
-     * form - if the content panel contains a form - this is a reference to it.
-     * @type {Roo.form.Form}
-     */
-    form : false,
-    /**
-     * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
-     *    This contains a reference to it.
-     * @type {Roo.View}
-     */
-    view : false,
-    
-      /**
-     * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
-     * <pre><code>
+    west: {
+        split:true,
+        initialSize: 200,
+        minSize: 175,
+        maxSize: 400,
+        titlebar: true,
+        collapsible: true
+    },
+    east: {
+        split:true,
+        initialSize: 202,
+        minSize: 175,
+        maxSize: 400,
+        titlebar: true,
+        collapsible: true
+    },
+    south: {
+        split:true,
+        initialSize: 100,
+        minSize: 100,
+        maxSize: 200,
+        titlebar: true,
+        collapsible: true
+    },
+    center: {
+        titlebar: true,
+        autoScroll:true,
+        resizeTabs: true,
+        minTabWidth: 50,
+        preferredTabWidth: 150
+    }
+});
 
-layout.addxtype({
-       xtype : 'Form',
-       items: [ .... ]
-   }
-);
+// shorthand
+var CP = Roo.ContentPanel;
 
+layout.beginUpdate();
+layout.add("north", new CP("north", "North"));
+layout.add("south", new CP("south", {title: "South", closable: true}));
+layout.add("west", new CP("west", {title: "West"}));
+layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
+layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
+layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
+layout.getRegion("center").showPanel("center1");
+layout.endUpdate();
 </code></pre>
-     * @param {Object} cfg Xtype definition of item to add.
-     */
-    
-    addxtype : function(cfg) {
-        // add form..
-        if (cfg.xtype.match(/^Form$/)) {
-            
-            var el;
-            //if (this.footer) {
-            //    el = this.footer.container.insertSibling(false, 'before');
-            //} else {
-                el = this.el.createChild();
-            //}
 
-            this.form = new  Roo.form.Form(cfg);
-            
-            
-            if ( this.form.allItems.length) {
-                this.form.render(el.dom);
-            }
-            return this.form;
-        }
-        // should only have one of theses..
-        if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
-            // views.. should not be just added - used named prop 'view''
-            
-            cfg.el = this.el.appendChild(document.createElement("div"));
-            // factory?
-            
-            var ret = new Roo.factory(cfg);
-             
-             ret.render && ret.render(false, ''); // render blank..
-            this.view = ret;
-            return ret;
-        }
-        return false;
-    }
-});
+<b>The container the layout is rendered into can be either the body element or any other element.
+If it is not the body element, the container needs to either be an absolute positioned element,
+or you will need to add "position:relative" to the css of the container.  You will also need to specify
+the container size if it is not the body element.</b>
 
-/**
- * @class Roo.GridPanel
- * @extends Roo.ContentPanel
- * @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
+* @constructor
+* Create a new BorderLayout
+* @param {String/HTMLElement/Element} container The container this layout is bound to
+* @param {Object} config Configuration options
  */
-Roo.GridPanel = function(grid, config){
-    
-  
-    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);
-        
-    this.wrapper.dom.appendChild(grid.getGridEl().dom);
-    
-    Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
-    
-    if(this.toolbar){
-        this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
-    }
-    // xtype created footer. - not sure if will work as we normally have to render first..
-    if (this.footer && !this.footer.el && this.footer.xtype) {
-        
-        this.footer.container = this.grid.getView().getFooterPanel(true);
-        this.footer.dataSource = this.grid.dataSource;
-        this.footer = Roo.factory(this.footer, Roo);
-        
+Roo.BorderLayout = function(container, config){
+    config = config || {};
+    Roo.BorderLayout.superclass.constructor.call(this, container, config);
+    this.factory = config.factory || Roo.BorderLayout.RegionFactory;
+    for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
+       var target = this.factory.validRegions[i];
+       if(config[target]){
+           this.addRegion(target, config[target]);
+       }
     }
-    
-    grid.monitorWindowResize = false; // turn off autosizing
-    grid.autoHeight = false;
-    grid.autoWidth = false;
-    this.grid = grid;
-    this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
 };
 
-Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
-    getId : function(){
-        return this.grid.id;
-    },
-    
+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
+        */
     /**
-     * Returns the grid for this panel
-     * @return {Roo.grid.Grid} 
+     * 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).
+     * @param {Object} config The regions config object
+     * @return {BorderLayoutRegion} The new region
      */
-    getGrid : function(){
-        return this.grid;    
-    },
-    
-    setSize : function(width, height){
-        if(!this.ignoreResize(width, height)){
-            var grid = this.grid;
-            var size = this.adjustForComponents(width, height);
-            grid.getGridEl().setSize(size.width, size.height);
-            grid.autoSize();
+    addRegion : function(target, config){
+        if(!this.regions[target]){
+            var r = this.factory.create(target, this, config);
+           this.bindRegion(target, r);
         }
+        return this.regions[target];
     },
-    
-    beforeSlide : function(){
-        this.grid.getView().scroller.clip();
-    },
-    
-    afterSlide : function(){
-        this.grid.getView().scroller.unclip();
-    },
-    
-    destroy : function(){
-        this.grid.destroy();
-        delete this.grid;
-        Roo.GridPanel.superclass.destroy.call(this); 
-    }
-});
 
+    // private (kinda)
+    bindRegion : function(name, r){
+        this.regions[name] = r;
+        r.on("visibilitychange", this.layout, this);
+        r.on("paneladded", this.layout, this);
+        r.on("panelremoved", this.layout, this);
+        r.on("invalidated", this.layout, this);
+        r.on("resized", this.onRegionResized, this);
+        r.on("collapsed", this.onRegionCollapsed, this);
+        r.on("expanded", this.onRegionExpanded, this);
+    },
 
-/**
- * @class Roo.NestedLayoutPanel
- * @extends Roo.ContentPanel
- * @constructor
- * Create a new NestedLayoutPanel.
- * 
- * 
- * @param {Roo.BorderLayout} layout 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)
-{
-    // construct with only one argument..
-    /* FIXME - implement nicer consturctors
-    if (layout.layout) {
-        config = layout;
-        layout = config.layout;
-        delete config.layout;
-    }
-    if (layout.xtype && !layout.getEl) {
-        // then layout needs constructing..
-        layout = Roo.factory(layout, Roo);
-    }
-    */
-    
-    
-    Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
-    
-    layout.monitorWindowResize = false; // turn off autosizing
-    this.layout = layout;
-    this.layout.getEl().addClass("x-layout-nested-layout");
-    
-    
-    
-    
-};
-
-Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
+    /**
+     * Performs a layout update.
+     */
+    layout : function(){
+        if(this.updating) {
+            return;
+        }
+        var size = this.getViewSize();
+        var w = size.width;
+        var h = size.height;
+        var centerW = w;
+        var centerH = h;
+        var centerY = 0;
+        var centerX = 0;
+        //var x = 0, y = 0;
 
-    setSize : function(width, height){
-        if(!this.ignoreResize(width, height)){
-            var size = this.adjustForComponents(width, height);
-            var el = this.layout.getEl();
-            el.setSize(size.width, size.height);
-            var touch = el.dom.offsetWidth;
-            this.layout.layout();
-            // ie requires a double layout on the first pass
-            if(Roo.isIE && !this.initialized){
-                this.initialized = true;
-                this.layout.layout();
-            }
+        var rs = this.regions;
+        var north = rs["north"];
+        var south = rs["south"]; 
+        var west = rs["west"];
+        var east = rs["east"];
+        var center = rs["center"];
+        //if(this.hideOnLayout){ // not supported anymore
+            //c.el.setStyle("display", "none");
+        //}
+        if(north && north.isVisible()){
+            var b = north.getBox();
+            var m = north.getMargins();
+            b.width = w - (m.left+m.right);
+            b.x = m.left;
+            b.y = m.top;
+            centerY = b.height + b.y + m.bottom;
+            centerH -= centerY;
+            north.updateBox(this.safeBox(b));
         }
-    },
-    
-    // activate all subpanels if not currently active..
-    
-    setActiveState : function(active){
-        this.active = active;
-        if(!active){
-            this.fireEvent("deactivate", this);
-            return;
+        if(south && south.isVisible()){
+            var b = south.getBox();
+            var m = south.getMargins();
+            b.width = w - (m.left+m.right);
+            b.x = m.left;
+            var totalHeight = (b.height + m.top + m.bottom);
+            b.y = h - totalHeight + m.top;
+            centerH -= totalHeight;
+            south.updateBox(this.safeBox(b));
         }
-        
-        this.fireEvent("activate", this);
-        // not sure if this should happen before or after..
-        if (!this.layout) {
-            return; // should not happen..
+        if(west && west.isVisible()){
+            var b = west.getBox();
+            var m = west.getMargins();
+            b.height = centerH - (m.top+m.bottom);
+            b.x = m.left;
+            b.y = centerY + m.top;
+            var totalWidth = (b.width + m.left + m.right);
+            centerX += totalWidth;
+            centerW -= totalWidth;
+            west.updateBox(this.safeBox(b));
         }
-        var reg = false;
-        for (var r in this.layout.regions) {
-            reg = this.layout.getRegion(r);
-            if (reg.getActivePanel()) {
-                //reg.showPanel(reg.getActivePanel()); // force it to activate.. 
-                reg.setActivePanel(reg.getActivePanel());
-                continue;
-            }
-            if (!reg.panels.length) {
-                continue;
-            }
-            reg.showPanel(reg.getPanel(0));
+        if(east && east.isVisible()){
+            var b = east.getBox();
+            var m = east.getMargins();
+            b.height = centerH - (m.top+m.bottom);
+            var totalWidth = (b.width + m.left + m.right);
+            b.x = w - totalWidth + m.left;
+            b.y = centerY + m.top;
+            centerW -= totalWidth;
+            east.updateBox(this.safeBox(b));
         }
-        
-        
-        
-        
+        if(center){
+            var m = center.getMargins();
+            var centerBox = {
+                x: centerX + m.left,
+                y: centerY + m.top,
+                width: centerW - (m.left+m.right),
+                height: centerH - (m.top+m.bottom)
+            };
+            //if(this.hideOnLayout){
+                //center.el.setStyle("display", "block");
+            //}
+            center.updateBox(this.safeBox(centerBox));
+        }
+        this.el.repaint();
+        this.fireEvent("layout", this);
     },
-    
+
+    // private
+    safeBox : function(box){
+        box.width = Math.max(0, box.width);
+        box.height = Math.max(0, box.height);
+        return box;
+    },
+
     /**
-     * Returns the nested BorderLayout for this panel
-     * @return {Roo.BorderLayout} 
+     * Adds a ContentPanel (or subclass) to this layout.
+     * @param {String} target The target region key (north, south, east, west or center).
+     * @param {Roo.ContentPanel} panel The panel to add
+     * @return {Roo.ContentPanel} The added panel
      */
-    getLayout : function(){
-        return this.layout;
+    add : function(target, panel){
+         
+        target = target.toLowerCase();
+        return this.regions[target].add(panel);
     },
-    
-     /**
-     * Adds a xtype elements to the layout of the nested panel
-     * <pre><code>
 
-panel.addxtype({
-       xtype : 'ContentPanel',
-       region: 'west',
-       items: [ .... ]
-   }
-);
-
-panel.addxtype({
-        xtype : 'NestedLayoutPanel',
-        region: 'west',
-        layout: {
-           center: { },
-           west: { }   
-        },
-        items : [ ... list of content panels or nested layout panels.. ]
-   }
-);
-</code></pre>
-     * @param {Object} cfg Xtype definition of item to add.
+    /**
+     * Remove a ContentPanel (or subclass) to this layout.
+     * @param {String} target The target region key (north, south, east, west or center).
+     * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
+     * @return {Roo.ContentPanel} The removed panel
      */
-    addxtype : function(cfg) {
-        return this.layout.addxtype(cfg);
-    
-    }
-});
-
-Roo.ScrollPanel = function(el, config, content){
-    config = config || {};
-    config.fitToFrame = true;
-    Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
-    
-    this.el.dom.style.overflow = "hidden";
-    var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
-    this.el.removeClass("x-layout-inactive-content");
-    this.el.on("mousewheel", this.onWheel, this);
-
-    var up = wrap.createChild({cls: "x-scroller-up", html: "&#160;"}, this.el.dom);
-    var down = wrap.createChild({cls: "x-scroller-down", html: "&#160;"});
-    up.unselectable(); down.unselectable();
-    up.on("click", this.scrollUp, this);
-    down.on("click", this.scrollDown, this);
-    up.addClassOnOver("x-scroller-btn-over");
-    down.addClassOnOver("x-scroller-btn-over");
-    up.addClassOnClick("x-scroller-btn-click");
-    down.addClassOnClick("x-scroller-btn-click");
-    this.adjustments = [0, -(up.getHeight() + down.getHeight())];
-
-    this.resizeEl = this.el;
-    this.el = wrap; this.up = up; this.down = down;
-};
-
-Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
-    increment : 100,
-    wheelIncrement : 5,
-    scrollUp : function(){
-        this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
+    remove : function(target, panel){
+        target = target.toLowerCase();
+        return this.regions[target].remove(panel);
     },
 
-    scrollDown : function(){
-        this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
+    /**
+     * Searches all regions for a panel with the specified id
+     * @param {String} panelId
+     * @return {Roo.ContentPanel} The panel or null if it wasn't found
+     */
+    findPanel : function(panelId){
+        var rs = this.regions;
+        for(var target in rs){
+            if(typeof rs[target] != "function"){
+                var p = rs[target].getPanel(panelId);
+                if(p){
+                    return p;
+                }
+            }
+        }
+        return null;
     },
 
-    afterScroll : function(){
-        var el = this.resizeEl;
-        var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
-        this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
-        this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
-    },
+    /**
+     * Searches all regions for a panel with the specified id and activates (shows) it.
+     * @param {String/ContentPanel} panelId The panels id or the panel itself
+     * @return {Roo.ContentPanel} The shown panel or null
+     */
+    showPanel : function(panelId) {
+      var rs = this.regions;
+      for(var target in rs){
+         var r = rs[target];
+         if(typeof r != "function"){
+            if(r.hasPanel(panelId)){
+               return r.showPanel(panelId);
+            }
+         }
+      }
+      return null;
+   },
 
-    setSize : function(){
-        Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
-        this.afterScroll();
+   /**
+     * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
+     * @param {Roo.state.Provider} provider (optional) An alternate state provider
+     */
+    restoreState : function(provider){
+        if(!provider){
+            provider = Roo.state.Manager;
+        }
+        var sm = new Roo.LayoutStateManager();
+        sm.init(this, provider);
     },
 
-    onWheel : function(e){
-        var d = e.getWheelDelta();
-        this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
-        this.afterScroll();
-        e.stopEvent();
+    /**
+     * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object.  This config
+     * object should contain properties for each region to add ContentPanels to, and each property's value should be
+     * a valid ContentPanel config object.  Example:
+     * <pre><code>
+// Create the main layout
+var layout = new Roo.BorderLayout('main-ct', {
+    west: {
+        split:true,
+        minSize: 175,
+        titlebar: true
     },
-
-    setContent : function(content, loadScripts){
-        this.resizeEl.update(content, loadScripts);
+    center: {
+        title:'Components'
     }
+}, 'main-ct');
 
+// Create and add multiple ContentPanels at once via configs
+layout.batchAdd({
+   west: {
+       id: 'source-files',
+       autoCreate:true,
+       title:'Ext Source Files',
+       autoScroll:true,
+       fitToFrame:true
+   },
+   center : {
+       el: cview,
+       autoScroll:true,
+       fitToFrame:true,
+       toolbar: tb,
+       resizeEl:'cbody'
+   }
 });
+</code></pre>
+     * @param {Object} regions An object containing ContentPanel configs by region name
+     */
+    batchAdd : function(regions){
+        this.beginUpdate();
+        for(var rname in regions){
+            var lr = this.regions[rname];
+            if(lr){
+                this.addTypedPanels(lr, regions[rname]);
+            }
+        }
+        this.endUpdate();
+    },
 
+    // private
+    addTypedPanels : function(lr, ps){
+        if(typeof ps == 'string'){
+            lr.add(new Roo.ContentPanel(ps));
+        }
+        else if(ps instanceof Array){
+            for(var i =0, len = ps.length; i < len; i++){
+                this.addTypedPanels(lr, ps[i]);
+            }
+        }
+        else if(!ps.events){ // raw config?
+            var el = ps.el;
+            delete ps.el; // prevent conflict
+            lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
+        }
+        else {  // panel object assumed!
+            lr.add(ps);
+        }
+    },
+    /**
+     * Adds a xtype elements to the layout.
+     * <pre><code>
 
+layout.addxtype({
+       xtype : 'ContentPanel',
+       region: 'west',
+       items: [ .... ]
+   }
+);
 
-
-
-
-
-
-
-/**
- * @class Roo.TreePanel
- * @extends Roo.ContentPanel
- * @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;
-    var tree = config.tree;
-    delete config.tree; 
-    delete config.el; // hopefull!
-    
-    // wrapper for IE7 strict & safari scroll issue
-    
-    var treeEl = el.createChild();
-    config.resizeEl = treeEl;
-    
-    
-    
-    Roo.TreePanel.superclass.constructor.call(this, el, config);
-    this.tree = new Roo.tree.TreePanel(treeEl , tree);
-    //console.log(tree);
-    this.on('activate', function()
+layout.addxtype({
+        xtype : 'NestedLayoutPanel',
+        region: 'west',
+        layout: {
+           center: { },
+           west: { }   
+        },
+        items : [ ... list of content panels or nested layout panels.. ]
+   }
+);
+</code></pre>
+     * @param {Object} cfg Xtype definition of item to add.
+     */
+    addxtype : function(cfg)
     {
-        if (this.tree.rendered) {
-            return;
+        // basically accepts a pannel...
+        // can accept a layout region..!?!?
+        //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
+        
+        if (!cfg.xtype.match(/Panel$/)) {
+            return false;
         }
-        //console.log('render tree');
-        this.tree.render();
-    });
-    // this should not be needed.. - it's actually the 'el' that resizes?
-    // actuall it breaks the containerScroll - dragging nodes auto scroll at top
-    
-    //this.on('resize',  function (cp, w, h) {
-    //        this.tree.innerCt.setWidth(w);
-    //        this.tree.innerCt.setHeight(h);
-    //        //this.tree.innerCt.setStyle('overflow-y', 'auto');
-    //});
-
+        var ret = false;
         
-    
-};
+        if (typeof(cfg.region) == 'undefined') {
+            Roo.log("Failed to add Panel, region was not set");
+            Roo.log(cfg);
+            return false;
+        }
+        var region = cfg.region;
+        delete cfg.region;
+        
+          
+        var xitems = [];
+        if (cfg.items) {
+            xitems = cfg.items;
+            delete cfg.items;
+        }
+        var nb = false;
+        
+        switch(cfg.xtype) 
+        {
+            case 'ContentPanel':  // ContentPanel (el, cfg)
+            case 'ScrollPanel':  // ContentPanel (el, cfg)
+            case 'ViewPanel': 
+                if(cfg.autoCreate) {
+                    ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
+                } else {
+                    var el = this.el.createChild();
+                    ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
+                }
+                
+                this.add(region, ret);
+                break;
+            
+            
+            case 'TreePanel': // our new panel!
+                cfg.el = this.el.createChild();
+                ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
+                this.add(region, ret);
+                break;
+            
+            case 'NestedLayoutPanel': 
+                // create a new Layout (which is  a Border Layout...
+                var el = this.el.createChild();
+                var clayout = cfg.layout;
+                delete cfg.layout;
+                clayout.items   = clayout.items  || [];
+                // replace this exitems with the clayout ones..
+                xitems = clayout.items;
+                 
+                
+                if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
+                    cfg.background = false;
+                }
+                var layout = new Roo.BorderLayout(el, clayout);
+                
+                ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
+                //console.log('adding nested layout panel '  + cfg.toSource());
+                this.add(region, ret);
+                nb = {}; /// find first...
+                break;
+                
+            case 'GridPanel': 
+            
+                // needs grid and region
+                
+                //var el = this.getRegion(region).el.createChild();
+                var el = this.el.createChild();
+                // create the grid first...
+                
+                var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
+                delete cfg.grid;
+                if (region == 'center' && this.active ) {
+                    cfg.background = false;
+                }
+                ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
+                
+                this.add(region, ret);
+                if (cfg.background) {
+                    ret.on('activate', function(gp) {
+                        if (!gp.grid.rendered) {
+                            gp.grid.render();
+                        }
+                    });
+                } else {
+                    grid.render();
+                }
+                break;
+           
+           
+           
+                
+                
+                
+            default:
+                if (typeof(Roo[cfg.xtype]) != 'undefined') {
+                    
+                    ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
+                    this.add(region, ret);
+                } else {
+                
+                    alert("Can not add '" + cfg.xtype + "' to BorderLayout");
+                    return null;
+                }
+                
+             // GridPanel (grid, cfg)
+            
+        }
+        this.beginUpdate();
+        // add children..
+        var region = '';
+        var abn = {};
+        Roo.each(xitems, function(i)  {
+            region = nb && i.region ? i.region : false;
+            
+            var add = ret.addxtype(i);
+           
+            if (region) {
+                nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
+                if (!i.background) {
+                    abn[region] = nb[region] ;
+                }
+            }
+            
+        });
+        this.endUpdate();
 
-Roo.extend(Roo.TreePanel, Roo.ContentPanel, {   
-    fitToFrame : true,
-    autoScroll : true
+        // make the last non-background panel active..
+        //if (nb) { Roo.log(abn); }
+        if (nb) {
+            
+            for(var r in abn) {
+                region = this.getRegion(r);
+                if (region) {
+                    // tried using nb[r], but it does not work..
+                     
+                    region.showPanel(abn[r]);
+                   
+                }
+            }
+        }
+        return ret;
+        
+    }
 });
 
-
-
-
-
-
-
-
-
-
-
-/*
- * 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.ReaderLayout
- * @extends Roo.BorderLayout
- * This is a pre-built layout that represents a classic, 5-pane application.  It consists of a header, a primary
- * center region containing two nested regions (a top one for a list view and one for item preview below),
- * and regions on either side that can be used for navigation, application commands, informational displays, etc.
- * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
- * expedites the setup of the overall layout and regions for this common application style.
- * Example:
- <pre><code>
-var reader = new Roo.ReaderLayout();
-var CP = Roo.ContentPanel;  // shortcut for adding
+ * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
+ * the beginUpdate and endUpdate calls internally.  The key to this method is the <b>panels</b> property that can be
+ * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
+ * during creation.  The following code is equivalent to the constructor-based example at the beginning of this class:
+ * <pre><code>
+// shorthand
+var CP = Roo.ContentPanel;
 
-reader.beginUpdate();
-reader.add("north", new CP("north", "North"));
-reader.add("west", new CP("west", {title: "West"}));
-reader.add("east", new CP("east", {title: "East"}));
+var layout = Roo.BorderLayout.create({
+    north: {
+        initialSize: 25,
+        titlebar: false,
+        panels: [new CP("north", "North")]
+    },
+    west: {
+        split:true,
+        initialSize: 200,
+        minSize: 175,
+        maxSize: 400,
+        titlebar: true,
+        collapsible: true,
+        panels: [new CP("west", {title: "West"})]
+    },
+    east: {
+        split:true,
+        initialSize: 202,
+        minSize: 175,
+        maxSize: 400,
+        titlebar: true,
+        collapsible: true,
+        panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
+    },
+    south: {
+        split:true,
+        initialSize: 100,
+        minSize: 100,
+        maxSize: 200,
+        titlebar: true,
+        collapsible: true,
+        panels: [new CP("south", {title: "South", closable: true})]
+    },
+    center: {
+        titlebar: true,
+        autoScroll:true,
+        resizeTabs: true,
+        minTabWidth: 50,
+        preferredTabWidth: 150,
+        panels: [
+            new CP("center1", {title: "Close Me", closable: true}),
+            new CP("center2", {title: "Center Panel", closable: false})
+        ]
+    }
+}, document.body);
 
-reader.regions.listView.add(new CP("listView", "List"));
-reader.regions.preview.add(new CP("preview", "Preview"));
-reader.endUpdate();
+layout.getRegion("center").showPanel("center1");
 </code></pre>
-* @constructor
-* Create a new ReaderLayout
-* @param {Object} config Configuration options
-* @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
-* document.body if omitted)
-*/
-Roo.ReaderLayout = function(config, renderTo){
-    var c = config || {size:{}};
-    Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
-        north: c.north !== false ? Roo.apply({
-            split:false,
-            initialSize: 32,
-            titlebar: false
-        }, c.north) : false,
-        west: c.west !== false ? Roo.apply({
-            split:true,
-            initialSize: 200,
-            minSize: 175,
-            maxSize: 400,
-            titlebar: true,
-            collapsible: true,
-            animate: true,
-            margins:{left:5,right:0,bottom:5,top:5},
-            cmargins:{left:5,right:5,bottom:5,top:5}
-        }, c.west) : false,
-        east: c.east !== false ? Roo.apply({
-            split:true,
-            initialSize: 200,
-            minSize: 175,
-            maxSize: 400,
-            titlebar: true,
-            collapsible: true,
-            animate: true,
-            margins:{left:0,right:5,bottom:5,top:5},
-            cmargins:{left:5,right:5,bottom:5,top:5}
-        }, c.east) : false,
-        center: Roo.apply({
-            tabPosition: 'top',
-            autoScroll:false,
-            closeOnTab: true,
-            titlebar:false,
-            margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
-        }, c.center)
-    });
-
-    this.el.addClass('x-reader');
-
-    this.beginUpdate();
-
-    var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
-        south: c.preview !== false ? Roo.apply({
-            split:true,
-            initialSize: 200,
-            minSize: 100,
-            autoScroll:true,
-            collapsible:true,
-            titlebar: true,
-            cmargins:{top:5,left:0, right:0, bottom:0}
-        }, c.preview) : false,
-        center: Roo.apply({
-            autoScroll:false,
-            titlebar:false,
-            minHeight:200
-        }, c.listView)
-    });
-    this.add('center', new Roo.NestedLayoutPanel(inner,
-            Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
-
-    this.endUpdate();
-
-    this.regions.preview = inner.getRegion('south');
-    this.regions.listView = inner.getRegion('center');
+ * @param config
+ * @param targetEl
+ */
+Roo.BorderLayout.create = function(config, targetEl){
+    var layout = new Roo.BorderLayout(targetEl || document.body, config);
+    layout.beginUpdate();
+    var regions = Roo.BorderLayout.RegionFactory.validRegions;
+    for(var j = 0, jlen = regions.length; j < jlen; j++){
+        var lr = regions[j];
+        if(layout.regions[lr] && config[lr].panels){
+            var r = layout.regions[lr];
+            var ps = config[lr].panels;
+            layout.addTypedPanels(r, ps);
+        }
+    }
+    layout.endUpdate();
+    return layout;
 };
 
-Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
+// private
+Roo.BorderLayout.RegionFactory = {
+    // private
+    validRegions : ["north","south","east","west","center"],
+
+    // private
+    create : function(target, mgr, config){
+        target = target.toLowerCase();
+        if(config.lightweight || config.basic){
+            return new Roo.BasicLayoutRegion(mgr, config, target);
+        }
+        switch(target){
+            case "north":
+                return new Roo.NorthLayoutRegion(mgr, config);
+            case "south":
+                return new Roo.SouthLayoutRegion(mgr, config);
+            case "east":
+                return new Roo.EastLayoutRegion(mgr, config);
+            case "west":
+                return new Roo.WestLayoutRegion(mgr, config);
+            case "center":
+                return new Roo.CenterLayoutRegion(mgr, config);
+        }
+        throw 'Layout region "'+target+'" not supported.';
+    }
+};/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -54415,1035 +59194,929 @@ Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
  */
  
 /**
- * @class Roo.grid.Grid
+ * @class Roo.BasicLayoutRegion
  * @extends Roo.util.Observable
- * This class represents the primary interface of a component based grid control.
- * <br><br>Usage:<pre><code>
- var grid = new Roo.grid.Grid("my-container-id", {
-     ds: myDataStore,
-     cm: myColModel,
-     selModel: mySelectionModel,
-     autoSizeColumns: true,
-     monitorWindowResize: false,
-     trackMouseOver: true
- });
- // set any options
- grid.render();
- * </code></pre>
- * <b>Common Problems:</b><br/>
- * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
- * element will correct this<br/>
- * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
- * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
- * are unpredictable.<br/>
- * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
- * grid to calculate dimensions/offsets.<br/>
-  * @constructor
- * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
- * The container MUST have some type of size defined for the grid to fill. The container will be
- * automatically set to position relative if it isn't already.
- * @param {Object} config A config object that sets properties on this grid.
+ * This class represents a lightweight region in a layout manager. This region does not move dom nodes
+ * and does not have a titlebar, tabs or any other features. All it does is size and position 
+ * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
  */
-Roo.grid.Grid = function(container, config){
-       // initialize the container
-       this.container = Roo.get(container);
-       this.container.update("");
-       this.container.setStyle("overflow", "hidden");
-    this.container.addClass('x-grid-container');
-
-    this.id = this.container.id;
-
-    Roo.apply(this, config);
-    // check and correct shorthanded configs
-    if(this.ds){
-        this.dataSource = this.ds;
-        delete this.ds;
-    }
-    if(this.cm){
-        this.colModel = this.cm;
-        delete this.cm;
-    }
-    if(this.sm){
-        this.selModel = this.sm;
-        delete this.sm;
-    }
-
-    if (this.selModel) {
-        this.selModel = Roo.factory(this.selModel, Roo.grid);
-        this.sm = this.selModel;
-        this.sm.xmodule = this.xmodule || false;
-    }
-    if (typeof(this.colModel.config) == 'undefined') {
-        this.colModel = new Roo.grid.ColumnModel(this.colModel);
-        this.cm = this.colModel;
-        this.cm.xmodule = this.xmodule || false;
-    }
-    if (this.dataSource) {
-        this.dataSource= Roo.factory(this.dataSource, Roo.data);
-        this.ds = this.dataSource;
-        this.ds.xmodule = this.xmodule || false;
-         
-    }
-    
-    
-    
-    if(this.width){
-        this.container.setWidth(this.width);
-    }
-
-    if(this.height){
-        this.container.setHeight(this.height);
-    }
-    /** @private */
-       this.addEvents({
-        // raw events
-        /**
-         * @event click
-         * The raw click event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        "click" : true,
-        /**
-         * @event dblclick
-         * The raw dblclick event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        "dblclick" : true,
-        /**
-         * @event contextmenu
-         * The raw contextmenu event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        "contextmenu" : true,
-        /**
-         * @event mousedown
-         * The raw mousedown event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        "mousedown" : true,
-        /**
-         * @event mouseup
-         * The raw mouseup event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        "mouseup" : true,
-        /**
-         * @event mouseover
-         * The raw mouseover event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        "mouseover" : true,
-        /**
-         * @event mouseout
-         * The raw mouseout event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        "mouseout" : true,
-        /**
-         * @event keypress
-         * The raw keypress event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        "keypress" : true,
-        /**
-         * @event keydown
-         * The raw keydown event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        "keydown" : true,
-
-        // custom events
-
-        /**
-         * @event cellclick
-         * Fires when a cell is clicked
-         * @param {Grid} this
-         * @param {Number} rowIndex
-         * @param {Number} columnIndex
-         * @param {Roo.EventObject} e
-         */
-        "cellclick" : true,
-        /**
-         * @event celldblclick
-         * Fires when a cell is double clicked
-         * @param {Grid} this
-         * @param {Number} rowIndex
-         * @param {Number} columnIndex
-         * @param {Roo.EventObject} e
-         */
-        "celldblclick" : true,
-        /**
-         * @event rowclick
-         * Fires when a row is clicked
-         * @param {Grid} this
-         * @param {Number} rowIndex
-         * @param {Roo.EventObject} e
-         */
-        "rowclick" : true,
-        /**
-         * @event rowdblclick
-         * Fires when a row is double clicked
-         * @param {Grid} this
-         * @param {Number} rowIndex
-         * @param {Roo.EventObject} e
-         */
-        "rowdblclick" : true,
-        /**
-         * @event headerclick
-         * Fires when a header is clicked
-         * @param {Grid} this
-         * @param {Number} columnIndex
-         * @param {Roo.EventObject} e
-         */
-        "headerclick" : true,
-        /**
-         * @event headerdblclick
-         * Fires when a header cell is double clicked
-         * @param {Grid} this
-         * @param {Number} columnIndex
-         * @param {Roo.EventObject} e
-         */
-        "headerdblclick" : true,
-        /**
-         * @event rowcontextmenu
-         * Fires when a row is right clicked
-         * @param {Grid} this
-         * @param {Number} rowIndex
-         * @param {Roo.EventObject} e
-         */
-        "rowcontextmenu" : true,
+Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
+    this.mgr = mgr;
+    this.position  = pos;
+    this.events = {
         /**
-         * @event cellcontextmenu
-         * Fires when a cell is right clicked
-         * @param {Grid} this
-         * @param {Number} rowIndex
-         * @param {Number} cellIndex
-         * @param {Roo.EventObject} e
+         * @scope Roo.BasicLayoutRegion
          */
-         "cellcontextmenu" : true,
+        
         /**
-         * @event headercontextmenu
-         * Fires when a header is right clicked
-         * @param {Grid} this
-         * @param {Number} columnIndex
-         * @param {Roo.EventObject} e
+         * @event beforeremove
+         * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
+         * @param {Roo.LayoutRegion} this
+         * @param {Roo.ContentPanel} panel The panel
+         * @param {Object} e The cancel event object
          */
-        "headercontextmenu" : true,
+        "beforeremove" : true,
         /**
-         * @event bodyscroll
-         * Fires when the body element is scrolled
-         * @param {Number} scrollLeft
-         * @param {Number} scrollTop
+         * @event invalidated
+         * Fires when the layout for this region is changed.
+         * @param {Roo.LayoutRegion} this
          */
-        "bodyscroll" : true,
+        "invalidated" : true,
         /**
-         * @event columnresize
-         * Fires when the user resizes a column
-         * @param {Number} columnIndex
-         * @param {Number} newSize
+         * @event visibilitychange
+         * Fires when this region is shown or hidden 
+         * @param {Roo.LayoutRegion} this
+         * @param {Boolean} visibility true or false
          */
-        "columnresize" : true,
+        "visibilitychange" : true,
         /**
-         * @event columnmove
-         * Fires when the user moves a column
-         * @param {Number} oldIndex
-         * @param {Number} newIndex
+         * @event paneladded
+         * Fires when a panel is added. 
+         * @param {Roo.LayoutRegion} this
+         * @param {Roo.ContentPanel} panel The panel
          */
-        "columnmove" : true,
+        "paneladded" : true,
         /**
-         * @event startdrag
-         * Fires when row(s) start being dragged
-         * @param {Grid} this
-         * @param {Roo.GridDD} dd The drag drop object
-         * @param {event} e The raw browser event
+         * @event panelremoved
+         * Fires when a panel is removed. 
+         * @param {Roo.LayoutRegion} this
+         * @param {Roo.ContentPanel} panel The panel
          */
-        "startdrag" : true,
+        "panelremoved" : true,
         /**
-         * @event enddrag
-         * Fires when a drag operation is complete
-         * @param {Grid} this
-         * @param {Roo.GridDD} dd The drag drop object
-         * @param {event} e The raw browser event
+         * @event beforecollapse
+         * Fires when this region before collapse.
+         * @param {Roo.LayoutRegion} this
          */
-        "enddrag" : true,
+        "beforecollapse" : true,
         /**
-         * @event dragdrop
-         * Fires when dragged row(s) are dropped on a valid DD target
-         * @param {Grid} this
-         * @param {Roo.GridDD} dd The drag drop object
-         * @param {String} targetId The target drag drop object
-         * @param {event} e The raw browser event
+         * @event collapsed
+         * Fires when this region is collapsed.
+         * @param {Roo.LayoutRegion} this
          */
-        "dragdrop" : true,
+        "collapsed" : true,
         /**
-         * @event dragover
-         * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
-         * @param {Grid} this
-         * @param {Roo.GridDD} dd The drag drop object
-         * @param {String} targetId The target drag drop object
-         * @param {event} e The raw browser event
+         * @event expanded
+         * Fires when this region is expanded.
+         * @param {Roo.LayoutRegion} this
          */
-        "dragover" : true,
+        "expanded" : true,
         /**
-         * @event dragenter
-         *  Fires when the dragged row(s) first cross another DD target while being dragged
-         * @param {Grid} this
-         * @param {Roo.GridDD} dd The drag drop object
-         * @param {String} targetId The target drag drop object
-         * @param {event} e The raw browser event
+         * @event slideshow
+         * Fires when this region is slid into view.
+         * @param {Roo.LayoutRegion} this
          */
-        "dragenter" : true,
+        "slideshow" : true,
         /**
-         * @event dragout
-         * Fires when the dragged row(s) leave another DD target while being dragged
-         * @param {Grid} this
-         * @param {Roo.GridDD} dd The drag drop object
-         * @param {String} targetId The target drag drop object
-         * @param {event} e The raw browser event
+         * @event slidehide
+         * Fires when this region slides out of view. 
+         * @param {Roo.LayoutRegion} this
          */
-        "dragout" : true,
+        "slidehide" : true,
         /**
-         * @event rowclass
-         * Fires when a row is rendered, so you can change add a style to it.
-         * @param {GridView} gridview   The grid view
-         * @param {Object} rowcfg   contains record  rowIndex and rowClass - set rowClass to add a style.
+         * @event panelactivated
+         * Fires when a panel is activated. 
+         * @param {Roo.LayoutRegion} this
+         * @param {Roo.ContentPanel} panel The activated panel
          */
-        'rowclass' : true,
-
+        "panelactivated" : true,
         /**
-         * @event render
-         * Fires when the grid is rendered
-         * @param {Grid} grid
+         * @event resized
+         * Fires when the user resizes this region. 
+         * @param {Roo.LayoutRegion} this
+         * @param {Number} newSize The new size (width for east/west, height for north/south)
          */
-        'render' : true
-    });
-
-    Roo.grid.Grid.superclass.constructor.call(this);
-};
-Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
+        "resized" : true
+    };
+    /** A collection of panels in this region. @type Roo.util.MixedCollection */
+    this.panels = new Roo.util.MixedCollection();
+    this.panels.getKey = this.getPanelId.createDelegate(this);
+    this.box = null;
+    this.activePanel = null;
+    // ensure listeners are added...
     
-    /**
-     * @cfg {String} ddGroup - drag drop group.
-     */
+    if (config.listeners || config.events) {
+        Roo.BasicLayoutRegion.superclass.constructor.call(this, {
+            listeners : config.listeners || {},
+            events : config.events || {}
+        });
+    }
+    
+    if(skipConfig !== true){
+        this.applyConfig(config);
+    }
+};
 
+Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
+    getPanelId : function(p){
+        return p.getId();
+    },
+    
+    applyConfig : function(config){
+        this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
+        this.config = config;
+        
+    },
+    
     /**
-     * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
+     * Resizes the region to the specified size. For vertical regions (west, east) this adjusts 
+     * the width, for horizontal (north, south) the height.
+     * @param {Number} newSize The new width or height
      */
-    minColumnWidth : 25,
-
+    resizeTo : function(newSize){
+        var el = this.el ? this.el :
+                 (this.activePanel ? this.activePanel.getEl() : null);
+        if(el){
+            switch(this.position){
+                case "east":
+                case "west":
+                    el.setWidth(newSize);
+                    this.fireEvent("resized", this, newSize);
+                break;
+                case "north":
+                case "south":
+                    el.setHeight(newSize);
+                    this.fireEvent("resized", this, newSize);
+                break;                
+            }
+        }
+    },
+    
+    getBox : function(){
+        return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
+    },
+    
+    getMargins : function(){
+        return this.margins;
+    },
+    
+    updateBox : function(box){
+        this.box = box;
+        var el = this.activePanel.getEl();
+        el.dom.style.left = box.x + "px";
+        el.dom.style.top = box.y + "px";
+        this.activePanel.setSize(box.width, box.height);
+    },
+    
     /**
-     * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
-     * <b>on initial render.</b> It is more efficient to explicitly size the columns
-     * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option.  Default is false.
+     * Returns the container element for this region.
+     * @return {Roo.Element}
      */
-    autoSizeColumns : false,
-
+    getEl : function(){
+        return this.activePanel;
+    },
+    
     /**
-     * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
+     * Returns true if this region is currently visible.
+     * @return {Boolean}
      */
-    autoSizeHeaders : true,
-
+    isVisible : function(){
+        return this.activePanel ? true : false;
+    },
+    
+    setActivePanel : function(panel){
+        panel = this.getPanel(panel);
+        if(this.activePanel && this.activePanel != panel){
+            this.activePanel.setActiveState(false);
+            this.activePanel.getEl().setLeftTop(-10000,-10000);
+        }
+        this.activePanel = panel;
+        panel.setActiveState(true);
+        if(this.box){
+            panel.setSize(this.box.width, this.box.height);
+        }
+        this.fireEvent("panelactivated", this, panel);
+        this.fireEvent("invalidated");
+    },
+    
     /**
-     * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
+     * Show the specified panel.
+     * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
+     * @return {Roo.ContentPanel} The shown panel or null
      */
-    monitorWindowResize : true,
-
+    showPanel : function(panel){
+        if(panel = this.getPanel(panel)){
+            this.setActivePanel(panel);
+        }
+        return panel;
+    },
+    
     /**
-     * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
-     * rows measured to get a columns size. Default is 0 (all rows).
+     * Get the active panel for this region.
+     * @return {Roo.ContentPanel} The active panel or null
      */
-    maxRowsToMeasure : 0,
-
+    getActivePanel : function(){
+        return this.activePanel;
+    },
+    
     /**
-     * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
+     * Add the passed ContentPanel(s)
+     * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
+     * @return {Roo.ContentPanel} The panel added (if only one was added)
      */
-    trackMouseOver : true,
-
-    /**
-    * @cfg {Boolean} enableDrag  True to enable drag of rows. Default is false. (double check if this is needed?)
-    */
+    add : function(panel){
+        if(arguments.length > 1){
+            for(var i = 0, len = arguments.length; i < len; i++) {
+               this.add(arguments[i]);
+            }
+            return null;
+        }
+        if(this.hasPanel(panel)){
+            this.showPanel(panel);
+            return panel;
+        }
+        var el = panel.getEl();
+        if(el.dom.parentNode != this.mgr.el.dom){
+            this.mgr.el.dom.appendChild(el.dom);
+        }
+        if(panel.setRegion){
+            panel.setRegion(this);
+        }
+        this.panels.add(panel);
+        el.setStyle("position", "absolute");
+        if(!panel.background){
+            this.setActivePanel(panel);
+            if(this.config.initialSize && this.panels.getCount()==1){
+                this.resizeTo(this.config.initialSize);
+            }
+        }
+        this.fireEvent("paneladded", this, panel);
+        return panel;
+    },
     
     /**
-    * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
-    */
-    enableDragDrop : false,
+     * Returns true if the panel is in this region.
+     * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
+     * @return {Boolean}
+     */
+    hasPanel : function(panel){
+        if(typeof panel == "object"){ // must be panel obj
+            panel = panel.getId();
+        }
+        return this.getPanel(panel) ? true : false;
+    },
     
     /**
-    * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
-    */
-    enableColumnMove : true,
-    
-    /**
-    * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
-    */
-    enableColumnHide : true,
-    
-    /**
-    * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
-    */
-    enableRowHeightSync : false,
+     * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
+     * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
+     * @param {Boolean} preservePanel Overrides the config preservePanel option
+     * @return {Roo.ContentPanel} The panel that was removed
+     */
+    remove : function(panel, preservePanel){
+        panel = this.getPanel(panel);
+        if(!panel){
+            return null;
+        }
+        var e = {};
+        this.fireEvent("beforeremove", this, panel, e);
+        if(e.cancel === true){
+            return null;
+        }
+        var panelId = panel.getId();
+        this.panels.removeKey(panelId);
+        return panel;
+    },
     
     /**
-    * @cfg {Boolean} stripeRows True to stripe the rows.  Default is true.
-    */
-    stripeRows : true,
+     * Returns the panel specified or null if it's not in this region.
+     * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
+     * @return {Roo.ContentPanel}
+     */
+    getPanel : function(id){
+        if(typeof id == "object"){ // must be panel obj
+            return id;
+        }
+        return this.panels.get(id);
+    },
     
     /**
-    * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
-    */
-    autoHeight : false,
-
-    /**
-     * @cfg {String} autoExpandColumn The id (or dataIndex) of a column in this grid that should expand to fill unused space. This id can not be 0. Default is false.
+     * Returns this regions position (north/south/east/west/center).
+     * @return {String} 
      */
-    autoExpandColumn : false,
-
-    /**
-    * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
-    * Default is 50.
-    */
-    autoExpandMin : 50,
-
-    /**
-    * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
-    */
-    autoExpandMax : 1000,
+    getPosition: function(){
+        return this.position;    
+    }
+});/*
+ * 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.LayoutRegion
+ * @extends Roo.BasicLayoutRegion
+ * This class represents a region in a layout manager.
+ * @cfg {Boolean}   collapsible     False to disable collapsing (defaults to true)
+ * @cfg {Boolean}   collapsed       True to set the initial display to collapsed (defaults to false)
+ * @cfg {Boolean}   floatable       False to disable floating (defaults to true)
+ * @cfg {Object}    margins         Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
+ * @cfg {Object}    cmargins        Margins for the element when collapsed (defaults to: north/south {top: 2, left: 0, right:0, bottom: 2} or east/west {top: 0, left: 2, right:2, bottom: 0})
+ * @cfg {String}    tabPosition     (top|bottom) "top" or "bottom" (defaults to "bottom")
+ * @cfg {String}    collapsedTitle  Optional string message to display in the collapsed block of a north or south region
+ * @cfg {Boolean}   alwaysShowTabs  True to always display tabs even when there is only 1 panel (defaults to false)
+ * @cfg {Boolean}   autoScroll      True to enable overflow scrolling (defaults to false)
+ * @cfg {Boolean}   titlebar        True to display a title bar (defaults to true)
+ * @cfg {String}    title           The title for the region (overrides panel titles)
+ * @cfg {Boolean}   animate         True to animate expand/collapse (defaults to false)
+ * @cfg {Boolean}   autoHide        False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
+ * @cfg {Boolean}   preservePanels  True to preserve removed panels so they can be readded later (defaults to false)
+ * @cfg {Boolean}   closeOnTab      True to place the close icon on the tabs instead of the region titlebar (defaults to false)
+ * @cfg {Boolean}   hideTabs        True to hide the tab strip (defaults to false)
+ * @cfg {Boolean}   resizeTabs      True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
+ *                      the space available, similar to FireFox 1.5 tabs (defaults to false)
+ * @cfg {Number}    minTabWidth     The minimum tab width (defaults to 40)
+ * @cfg {Number}    preferredTabWidth The preferred tab width (defaults to 150)
+ * @cfg {Boolean}   showPin         True to show a pin button
+ * @cfg {Boolean}   hidden          True to start the region hidden (defaults to false)
+ * @cfg {Boolean}   hideWhenEmpty   True to hide the region when it has no panels
+ * @cfg {Boolean}   disableTabTips  True to disable tab tooltips
+ * @cfg {Number}    width           For East/West panels
+ * @cfg {Number}    height          For North/South panels
+ * @cfg {Boolean}   split           To show the splitter
+ * @cfg {Boolean}   toolbar         xtype configuration for a toolbar - shows on right of tabbar
+ */
+Roo.LayoutRegion = function(mgr, config, pos){
+    Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
+    var dh = Roo.DomHelper;
+    /** This region's container element 
+    * @type Roo.Element */
+    this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
+    /** This region's title element 
+    * @type Roo.Element */
 
-    /**
-    * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
-    */
-    view : null,
+    this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
+        {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: "&#160;"},
+        {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
+    ]}, true);
+    this.titleEl.enableDisplayMode();
+    /** This region's title text element 
+    * @type HTMLElement */
+    this.titleTextEl = this.titleEl.dom.firstChild;
+    this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
+    this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
+    this.closeBtn.enableDisplayMode();
+    this.closeBtn.on("click", this.closeClicked, this);
+    this.closeBtn.hide();
 
-    /**
-    * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
-    */
-    loadMask : false,
-    /**
-    * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
-    */
-    dropTarget: false,
-    
-   
-    
-    // private
-    rendered : false,
+    this.createBody(config);
+    this.visible = true;
+    this.collapsed = false;
 
-    /**
-    * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
-    * of a fixed width. Default is false.
-    */
-    /**
-    * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
-    */
-    /**
-     * Called once after all setup has been completed and the grid is ready to be rendered.
-     * @return {Roo.grid.Grid} this
-     */
-    render : function()
-    {
-        var c = this.container;
-        // try to detect autoHeight/width mode
-        if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
-           this.autoHeight = true;
-       }
-       var view = this.getView();
-        view.init(this);
+    if(config.hideWhenEmpty){
+        this.hide();
+        this.on("paneladded", this.validateVisibility, this);
+        this.on("panelremoved", this.validateVisibility, this);
+    }
+    this.applyConfig(config);
+};
 
-        c.on("click", this.onClick, this);
-        c.on("dblclick", this.onDblClick, this);
-        c.on("contextmenu", this.onContextMenu, this);
-        c.on("keydown", this.onKeyDown, this);
-        if (Roo.isTouch) {
-            c.on("touchstart", this.onTouchStart, this);
-        }
+Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
 
-        this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
+    createBody : function(){
+        /** This region's body element 
+        * @type Roo.Element */
+        this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
+    },
 
-        this.getSelectionModel().init(this);
+    applyConfig : function(c){
+        if(c.collapsible && this.position != "center" && !this.collapsedEl){
+            var dh = Roo.DomHelper;
+            if(c.titlebar !== false){
+                this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
+                this.collapseBtn.on("click", this.collapse, this);
+                this.collapseBtn.enableDisplayMode();
 
-        view.render();
+                if(c.showPin === true || this.showPin){
+                    this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
+                    this.stickBtn.enableDisplayMode();
+                    this.stickBtn.on("click", this.expand, this);
+                    this.stickBtn.hide();
+                }
+            }
+            /** This region's collapsed element
+            * @type Roo.Element */
+            this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
+                {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
+            ]}, true);
+            if(c.floatable !== false){
+               this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
+               this.collapsedEl.on("click", this.collapseClick, this);
+            }
 
-        if(this.loadMask){
-            this.loadMask = new Roo.LoadMask(this.container,
-                    Roo.apply({store:this.dataSource}, this.loadMask));
+            if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
+                this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
+                   id: "message", unselectable: "on", style:{"float":"left"}});
+               this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
+             }
+            this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
+            this.expandBtn.on("click", this.expand, this);
         }
-        
-        
-        if (this.toolbar && this.toolbar.xtype) {
-            this.toolbar.container = this.getView().getHeaderPanel(true);
-            this.toolbar = new Roo.Toolbar(this.toolbar);
+        if(this.collapseBtn){
+            this.collapseBtn.setVisible(c.collapsible == true);
         }
-        if (this.footer && this.footer.xtype) {
-            this.footer.dataSource = this.getDataSource();
-            this.footer.container = this.getView().getFooterPanel(true);
-            this.footer = Roo.factory(this.footer, Roo);
+        this.cmargins = c.cmargins || this.cmargins ||
+                         (this.position == "west" || this.position == "east" ?
+                             {top: 0, left: 2, right:2, bottom: 0} :
+                             {top: 2, left: 0, right:0, bottom: 2});
+        this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
+        this.bottomTabs = c.tabPosition != "top";
+        this.autoScroll = c.autoScroll || false;
+        if(this.autoScroll){
+            this.bodyEl.setStyle("overflow", "auto");
+        }else{
+            this.bodyEl.setStyle("overflow", "hidden");
         }
-        if (this.dropTarget && this.dropTarget.xtype) {
-            delete this.dropTarget.xtype;
-            this.dropTarget =  new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
+        //if(c.titlebar !== false){
+            if((!c.titlebar && !c.title) || c.titlebar === false){
+                this.titleEl.hide();
+            }else{
+                this.titleEl.show();
+                if(c.title){
+                    this.titleTextEl.innerHTML = c.title;
+                }
+            }
+        //}
+        this.duration = c.duration || .30;
+        this.slideDuration = c.slideDuration || .45;
+        this.config = c;
+        if(c.collapsed){
+            this.collapse(true);
         }
-        
-        
-        this.rendered = true;
-        this.fireEvent('render', this);
-        return this;
-    },
-
-       /**
-        * Reconfigures the grid to use a different Store and Column Model.
-        * The View will be bound to the new objects and refreshed.
-        * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
-        * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
-        */
-    reconfigure : function(dataSource, colModel){
-        if(this.loadMask){
-            this.loadMask.destroy();
-            this.loadMask = new Roo.LoadMask(this.container,
-                    Roo.apply({store:dataSource}, this.loadMask));
+        if(c.hidden){
+            this.hide();
         }
-        this.view.bind(dataSource, colModel);
-        this.dataSource = dataSource;
-        this.colModel = colModel;
-        this.view.refresh(true);
     },
-
-    // private
-    onKeyDown : function(e){
-        this.fireEvent("keydown", e);
+    /**
+     * Returns true if this region is currently visible.
+     * @return {Boolean}
+     */
+    isVisible : function(){
+        return this.visible;
     },
 
     /**
-     * Destroy this grid.
-     * @param {Boolean} removeEl True to remove the element
+     * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
+     * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&amp;#160;")
      */
-    destroy : function(removeEl, keepListeners){
-        if(this.loadMask){
-            this.loadMask.destroy();
-        }
-        var c = this.container;
-        c.removeAllListeners();
-        this.view.destroy();
-        this.colModel.purgeListeners();
-        if(!keepListeners){
-            this.purgeListeners();
-        }
-        c.update("");
-        if(removeEl === true){
-            c.remove();
+    setCollapsedTitle : function(title){
+        title = title || "&#160;";
+        if(this.collapsedTitleTextEl){
+            this.collapsedTitleTextEl.innerHTML = title;
         }
     },
 
-    // private
-    processEvent : function(name, e){
-        // does this fire select???
-        //Roo.log('grid:processEvent '  + name);
-        
-        if (name != 'touchstart' ) {
-            this.fireEvent(name, e);    
-        }
-        
-        var t = e.getTarget();
-        var v = this.view;
-        var header = v.findHeaderIndex(t);
-        if(header !== false){
-            var ename = name == 'touchstart' ? 'click' : name;
-             
-            this.fireEvent("header" + ename, this, header, e);
+    getBox : function(){
+        var b;
+        if(!this.collapsed){
+            b = this.el.getBox(false, true);
         }else{
-            var row = v.findRowIndex(t);
-            var cell = v.findCellIndex(t);
-            if (name == 'touchstart') {
-                // first touch is always a click.
-                // hopefull this happens after selection is updated.?
-                name = false;
-                
-                if (typeof(this.selModel.getSelectedCell) != 'undefined') {
-                    var cs = this.selModel.getSelectedCell();
-                    if (row == cs[0] && cell == cs[1]){
-                        name = 'dblclick';
-                    }
-                }
-                if (typeof(this.selModel.getSelections) != 'undefined') {
-                    var cs = this.selModel.getSelections();
-                    var ds = this.dataSource;
-                    if (cs.length == 1 && ds.getAt(row) == cs[0]){
-                        name = 'dblclick';
-                    }
-                }
-                if (!name) {
-                    return;
-                }
-            }
-            
-            
-            if(row !== false){
-                this.fireEvent("row" + name, this, row, e);
-                if(cell !== false){
-                    this.fireEvent("cell" + name, this, row, cell, e);
-                }
-            }
+            b = this.collapsedEl.getBox(false, true);
         }
+        return b;
     },
 
-    // private
-    onClick : function(e){
-        this.processEvent("click", e);
+    getMargins : function(){
+        return this.collapsed ? this.cmargins : this.margins;
     },
-   // private
-    onTouchStart : function(e){
-        this.processEvent("touchstart", e);
+
+    highlight : function(){
+        this.el.addClass("x-layout-panel-dragover");
     },
 
-    // private
-    onContextMenu : function(e, t){
-        this.processEvent("contextmenu", e);
+    unhighlight : function(){
+        this.el.removeClass("x-layout-panel-dragover");
     },
 
-    // private
-    onDblClick : function(e){
-        this.processEvent("dblclick", e);
+    updateBox : function(box){
+        this.box = box;
+        if(!this.collapsed){
+            this.el.dom.style.left = box.x + "px";
+            this.el.dom.style.top = box.y + "px";
+            this.updateBody(box.width, box.height);
+        }else{
+            this.collapsedEl.dom.style.left = box.x + "px";
+            this.collapsedEl.dom.style.top = box.y + "px";
+            this.collapsedEl.setSize(box.width, box.height);
+        }
+        if(this.tabs){
+            this.tabs.autoSizeTabs();
+        }
     },
 
-    // private
-    walkCells : function(row, col, step, fn, scope){
-        var cm = this.colModel, clen = cm.getColumnCount();
-        var ds = this.dataSource, rlen = ds.getCount(), first = true;
-        if(step < 0){
-            if(col < 0){
-                row--;
-                first = false;
-            }
-            while(row >= 0){
-                if(!first){
-                    col = clen-1;
-                }
-                first = false;
-                while(col >= 0){
-                    if(fn.call(scope || this, row, col, cm) === true){
-                        return [row, col];
-                    }
-                    col--;
-                }
-                row--;
+    updateBody : function(w, h){
+        if(w !== null){
+            this.el.setWidth(w);
+            w -= this.el.getBorderWidth("rl");
+            if(this.config.adjustments){
+                w += this.config.adjustments[0];
             }
-        } else {
-            if(col >= clen){
-                row++;
-                first = false;
+        }
+        if(h !== null){
+            this.el.setHeight(h);
+            h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
+            h -= this.el.getBorderWidth("tb");
+            if(this.config.adjustments){
+                h += this.config.adjustments[1];
             }
-            while(row < rlen){
-                if(!first){
-                    col = 0;
-                }
-                first = false;
-                while(col < clen){
-                    if(fn.call(scope || this, row, col, cm) === true){
-                        return [row, col];
-                    }
-                    col++;
-                }
-                row++;
+            this.bodyEl.setHeight(h);
+            if(this.tabs){
+                h = this.tabs.syncHeight(h);
             }
         }
-        return null;
-    },
-
-    // private
-    getSelections : function(){
-        return this.selModel.getSelections();
+        if(this.panelSize){
+            w = w !== null ? w : this.panelSize.width;
+            h = h !== null ? h : this.panelSize.height;
+        }
+        if(this.activePanel){
+            var el = this.activePanel.getEl();
+            w = w !== null ? w : el.getWidth();
+            h = h !== null ? h : el.getHeight();
+            this.panelSize = {width: w, height: h};
+            this.activePanel.setSize(w, h);
+        }
+        if(Roo.isIE && this.tabs){
+            this.tabs.el.repaint();
+        }
     },
 
     /**
-     * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
-     * but if manual update is required this method will initiate it.
+     * Returns the container element for this region.
+     * @return {Roo.Element}
      */
-    autoSize : function(){
-        if(this.rendered){
-            this.view.layout();
-            if(this.view.adjustForScroll){
-                this.view.adjustForScroll();
-            }
-        }
+    getEl : function(){
+        return this.el;
     },
 
     /**
-     * Returns the grid's underlying element.
-     * @return {Element} The element
+     * Hides this region.
      */
-    getGridEl : function(){
-        return this.container;
+    hide : function(){
+        if(!this.collapsed){
+            this.el.dom.style.left = "-2000px";
+            this.el.hide();
+        }else{
+            this.collapsedEl.dom.style.left = "-2000px";
+            this.collapsedEl.hide();
+        }
+        this.visible = false;
+        this.fireEvent("visibilitychange", this, false);
     },
 
-    // private for compatibility, overridden by editor grid
-    stopEditing : function(){},
-
     /**
-     * Returns the grid's SelectionModel.
-     * @return {SelectionModel}
+     * Shows this region if it was previously hidden.
      */
-    getSelectionModel : function(){
-        if(!this.selModel){
-            this.selModel = new Roo.grid.RowSelectionModel();
+    show : function(){
+        if(!this.collapsed){
+            this.el.show();
+        }else{
+            this.collapsedEl.show();
         }
-        return this.selModel;
+        this.visible = true;
+        this.fireEvent("visibilitychange", this, true);
     },
 
-    /**
-     * Returns the grid's DataSource.
-     * @return {DataSource}
-     */
-    getDataSource : function(){
-        return this.dataSource;
+    closeClicked : function(){
+        if(this.activePanel){
+            this.remove(this.activePanel);
+        }
     },
 
-    /**
-     * Returns the grid's ColumnModel.
-     * @return {ColumnModel}
-     */
-    getColumnModel : function(){
-        return this.colModel;
+    collapseClick : function(e){
+        if(this.isSlid){
+           e.stopPropagation();
+           this.slideIn();
+        }else{
+           e.stopPropagation();
+           this.slideOut();
+        }
     },
 
     /**
-     * Returns the grid's GridView object.
-     * @return {GridView}
+     * Collapses this region.
+     * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
      */
-    getView : function(){
-        if(!this.view){
-            this.view = new Roo.grid.GridView(this.viewConfig);
+    collapse : function(skipAnim, skipCheck){
+        if(this.collapsed) {
+            return;
         }
-        return this.view;
+        
+        if(skipCheck || this.fireEvent("beforecollapse", this) != false){
+            
+            this.collapsed = true;
+            if(this.split){
+                this.split.el.hide();
+            }
+            if(this.config.animate && skipAnim !== true){
+                this.fireEvent("invalidated", this);
+                this.animateCollapse();
+            }else{
+                this.el.setLocation(-20000,-20000);
+                this.el.hide();
+                this.collapsedEl.show();
+                this.fireEvent("collapsed", this);
+                this.fireEvent("invalidated", this);
+            }
+        }
+        
     },
+
+    animateCollapse : function(){
+        // overridden
+    },
+
     /**
-     * Called to get grid's drag proxy text, by default returns this.ddText.
-     * @return {String}
+     * Expands this region if it was previously collapsed.
+     * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
+     * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
      */
-    getDragDropText : function(){
-        var count = this.selModel.getCount();
-        return String.format(this.ddText, count, count == 1 ? '' : 's');
-    }
-});
-/**
- * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
- * %0 is replaced with the number of selected rows.
- * @type String
- */
-Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
- * 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">
- */
-Roo.grid.AbstractGridView = function(){
-       this.grid = null;
-       
-       this.events = {
-           "beforerowremoved" : true,
-           "beforerowsinserted" : true,
-           "beforerefresh" : true,
-           "rowremoved" : true,
-           "rowsinserted" : true,
-           "rowupdated" : true,
-           "refresh" : true
-       };
-    Roo.grid.AbstractGridView.superclass.constructor.call(this);
-};
-
-Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
-    rowClass : "x-grid-row",
-    cellClass : "x-grid-cell",
-    tdClass : "x-grid-td",
-    hdClass : "x-grid-hd",
-    splitClass : "x-grid-hd-split",
-    
-    init: function(grid){
-        this.grid = grid;
-               var cid = this.grid.getGridEl().id;
-        this.colSelector = "#" + cid + " ." + this.cellClass + "-";
-        this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
-        this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
-        this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
-       },
-       
-    getColumnRenderers : function(){
-       var renderers = [];
-       var cm = this.grid.colModel;
-        var colCount = cm.getColumnCount();
-        for(var i = 0; i < colCount; i++){
-            renderers[i] = cm.getRenderer(i);
+    expand : function(e, skipAnim){
+        if(e) {
+            e.stopPropagation();
         }
-        return renderers;
-    },
-    
-    getColumnIds : function(){
-       var ids = [];
-       var cm = this.grid.colModel;
-        var colCount = cm.getColumnCount();
-        for(var i = 0; i < colCount; i++){
-            ids[i] = cm.getColumnId(i);
+        if(!this.collapsed || this.el.hasActiveFx()) {
+            return;
         }
-        return ids;
-    },
-    
-    getDataIndexes : function(){
-       if(!this.indexMap){
-            this.indexMap = this.buildIndexMap();
+        if(this.isSlid){
+            this.afterSlideIn();
+            skipAnim = true;
         }
-        return this.indexMap.colToData;
-    },
-    
-    getColumnIndexByDataIndex : function(dataIndex){
-        if(!this.indexMap){
-            this.indexMap = this.buildIndexMap();
+        this.collapsed = false;
+        if(this.config.animate && skipAnim !== true){
+            this.animateExpand();
+        }else{
+            this.el.show();
+            if(this.split){
+                this.split.el.show();
+            }
+            this.collapsedEl.setLocation(-2000,-2000);
+            this.collapsedEl.hide();
+            this.fireEvent("invalidated", this);
+            this.fireEvent("expanded", this);
         }
-       return this.indexMap.dataToCol[dataIndex];
     },
-    
-    /**
-     * Set a css style for a column dynamically. 
-     * @param {Number} colIndex The index of the column
-     * @param {String} name The css property name
-     * @param {String} value The css value
-     */
-    setCSSStyle : function(colIndex, name, value){
-        var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
-        Roo.util.CSS.updateRule(selector, name, value);
+
+    animateExpand : function(){
+        // overridden
     },
-    
-    generateRules : function(cm){
-        var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
-        Roo.util.CSS.removeStyleSheet(rulesId);
-        for(var i = 0, len = cm.getColumnCount(); i < len; i++){
-            var cid = cm.getColumnId(i);
-            ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
-                         this.tdSelector, cid, " {\n}\n",
-                         this.hdSelector, cid, " {\n}\n",
-                         this.splitSelector, cid, " {\n}\n");
-        }
-        return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
-    }
-});/*
- * 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">
- */
 
-// private
-// This is a support class used internally by the Grid components
-Roo.grid.HeaderDragZone = function(grid, hd, hd2){
-    this.grid = grid;
-    this.view = grid.getView();
-    this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
-    Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
-    if(hd2){
-        this.setHandleElId(Roo.id(hd));
-        this.setOuterHandleElId(Roo.id(hd2));
-    }
-    this.scroll = false;
-};
-Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
-    maxDragWidth: 120,
-    getDragData : function(e){
-        var t = Roo.lib.Event.getTarget(e);
-        var h = this.view.findHeaderCell(t);
-        if(h){
-            return {ddel: h.firstChild, header:h};
+    initTabs : function()
+    {
+        this.bodyEl.setStyle("overflow", "hidden");
+        var ts = new Roo.TabPanel(
+                this.bodyEl.dom,
+                {
+                    tabPosition: this.bottomTabs ? 'bottom' : 'top',
+                    disableTooltips: this.config.disableTabTips,
+                    toolbar : this.config.toolbar
+                }
+        );
+        if(this.config.hideTabs){
+            ts.stripWrap.setDisplayed(false);
         }
-        return false;
+        this.tabs = ts;
+        ts.resizeTabs = this.config.resizeTabs === true;
+        ts.minTabWidth = this.config.minTabWidth || 40;
+        ts.maxTabWidth = this.config.maxTabWidth || 250;
+        ts.preferredTabWidth = this.config.preferredTabWidth || 150;
+        ts.monitorResize = false;
+        ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
+        ts.bodyEl.addClass('x-layout-tabs-body');
+        this.panels.each(this.initPanelAsTab, this);
     },
 
-    onInitDrag : function(e){
-        this.view.headersDisabled = true;
-        var clone = this.dragData.ddel.cloneNode(true);
-        clone.id = Roo.id();
-        clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
-        this.proxy.update(clone);
-        return true;
+    initPanelAsTab : function(panel){
+        var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
+                    this.config.closeOnTab && panel.isClosable());
+        if(panel.tabTip !== undefined){
+            ti.setTooltip(panel.tabTip);
+        }
+        ti.on("activate", function(){
+              this.setActivePanel(panel);
+        }, this);
+        if(this.config.closeOnTab){
+            ti.on("beforeclose", function(t, e){
+                e.cancel = true;
+                this.remove(panel);
+            }, this);
+        }
+        return ti;
     },
 
-    afterValidDrop : function(){
-        var v = this.view;
-        setTimeout(function(){
-            v.headersDisabled = false;
-        }, 50);
+    updatePanelTitle : function(panel, title){
+        if(this.activePanel == panel){
+            this.updateTitle(title);
+        }
+        if(this.tabs){
+            var ti = this.tabs.getTab(panel.getEl().id);
+            ti.setText(title);
+            if(panel.tabTip !== undefined){
+                ti.setTooltip(panel.tabTip);
+            }
+        }
     },
 
-    afterInvalidDrop : function(){
-        var v = this.view;
-        setTimeout(function(){
-            v.headersDisabled = false;
-        }, 50);
-    }
-});
-/*
- * 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">
- */
-// private
-// This is a support class used internally by the Grid components
-Roo.grid.HeaderDropZone = function(grid, hd, hd2){
-    this.grid = grid;
-    this.view = grid.getView();
-    // split the proxies so they don't interfere with mouse events
-    this.proxyTop = Roo.DomHelper.append(document.body, {
-        cls:"col-move-top", html:"&#160;"
-    }, true);
-    this.proxyBottom = Roo.DomHelper.append(document.body, {
-        cls:"col-move-bottom", html:"&#160;"
-    }, true);
-    this.proxyTop.hide = this.proxyBottom.hide = function(){
-        this.setLeftTop(-100,-100);
-        this.setStyle("visibility", "hidden");
-    };
-    this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
-    // temporarily disabled
-    //Roo.dd.ScrollManager.register(this.view.scroller.dom);
-    Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
-};
-Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
-    proxyOffsets : [-4, -9],
-    fly: Roo.Element.fly,
-
-    getTargetFromEvent : function(e){
-        var t = Roo.lib.Event.getTarget(e);
-        var cindex = this.view.findCellIndex(t);
-        if(cindex !== false){
-            return this.view.getHeaderCell(cindex);
+    updateTitle : function(title){
+        if(this.titleTextEl && !this.config.title){
+            this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : "&#160;");
         }
-        return null;
     },
 
-    nextVisible : function(h){
-        var v = this.view, cm = this.grid.colModel;
-        h = h.nextSibling;
-        while(h){
-            if(!cm.isHidden(v.getCellIndex(h))){
-                return h;
-            }
-            h = h.nextSibling;
+    setActivePanel : function(panel){
+        panel = this.getPanel(panel);
+        if(this.activePanel && this.activePanel != panel){
+            this.activePanel.setActiveState(false);
         }
-        return null;
+        this.activePanel = panel;
+        panel.setActiveState(true);
+        if(this.panelSize){
+            panel.setSize(this.panelSize.width, this.panelSize.height);
+        }
+        if(this.closeBtn){
+            this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
+        }
+        this.updateTitle(panel.getTitle());
+        if(this.tabs){
+            this.fireEvent("invalidated", this);
+        }
+        this.fireEvent("panelactivated", this, panel);
     },
 
-    prevVisible : function(h){
-        var v = this.view, cm = this.grid.colModel;
-        h = h.prevSibling;
-        while(h){
-            if(!cm.isHidden(v.getCellIndex(h))){
-                return h;
+    /**
+     * Shows the specified panel.
+     * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
+     * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
+     */
+    showPanel : function(panel)
+    {
+        panel = this.getPanel(panel);
+        if(panel){
+            if(this.tabs){
+                var tab = this.tabs.getTab(panel.getEl().id);
+                if(tab.isHidden()){
+                    this.tabs.unhideTab(tab.id);
+                }
+                tab.activate();
+            }else{
+                this.setActivePanel(panel);
             }
-            h = h.prevSibling;
         }
-        return null;
+        return panel;
     },
 
-    positionIndicator : function(h, n, e){
-        var x = Roo.lib.Event.getPageX(e);
-        var r = Roo.lib.Dom.getRegion(n.firstChild);
-        var px, pt, py = r.top + this.proxyOffsets[1];
-        if((r.right - x) <= (r.right-r.left)/2){
-            px = r.right+this.view.borderWidth;
-            pt = "after";
+    /**
+     * Get the active panel for this region.
+     * @return {Roo.ContentPanel} The active panel or null
+     */
+    getActivePanel : function(){
+        return this.activePanel;
+    },
+
+    validateVisibility : function(){
+        if(this.panels.getCount() < 1){
+            this.updateTitle("&#160;");
+            this.closeBtn.hide();
+            this.hide();
         }else{
-            px = r.left;
-            pt = "before";
+            if(!this.isVisible()){
+                this.show();
+            }
         }
-        var oldIndex = this.view.getCellIndex(h);
-        var newIndex = this.view.getCellIndex(n);
+    },
 
-        if(this.grid.colModel.isFixed(newIndex)){
-            return false;
+    /**
+     * Adds the passed ContentPanel(s) to this region.
+     * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
+     * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
+     */
+    add : function(panel){
+        if(arguments.length > 1){
+            for(var i = 0, len = arguments.length; i < len; i++) {
+                this.add(arguments[i]);
+            }
+            return null;
         }
-
-        var locked = this.grid.colModel.isLocked(newIndex);
-
-        if(pt == "after"){
-            newIndex++;
+        if(this.hasPanel(panel)){
+            this.showPanel(panel);
+            return panel;
         }
-        if(oldIndex < newIndex){
-            newIndex--;
+        panel.setRegion(this);
+        this.panels.add(panel);
+        if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
+            this.bodyEl.dom.appendChild(panel.getEl().dom);
+            if(panel.background !== true){
+                this.setActivePanel(panel);
+            }
+            this.fireEvent("paneladded", this, panel);
+            return panel;
         }
-        if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
-            return false;
+        if(!this.tabs){
+            this.initTabs();
+        }else{
+            this.initPanelAsTab(panel);
         }
-        px +=  this.proxyOffsets[0];
-        this.proxyTop.setLeftTop(px, py);
-        this.proxyTop.show();
-        if(!this.bottomOffset){
-            this.bottomOffset = this.view.mainHd.getHeight();
+        if(panel.background !== true){
+            this.tabs.activate(panel.getEl().id);
         }
-        this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
-        this.proxyBottom.show();
-        return pt;
+        this.fireEvent("paneladded", this, panel);
+        return panel;
     },
 
-    onNodeEnter : function(n, dd, e, data){
-        if(data.header != n){
-            this.positionIndicator(data.header, n, e);
+    /**
+     * Hides the tab for the specified panel.
+     * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
+     */
+    hidePanel : function(panel){
+        if(this.tabs && (panel = this.getPanel(panel))){
+            this.tabs.hideTab(panel.getEl().id);
         }
     },
 
-    onNodeOver : function(n, dd, e, data){
-        var result = false;
-        if(data.header != n){
-            result = this.positionIndicator(data.header, n, e);
-        }
-        if(!result){
-            this.proxyTop.hide();
-            this.proxyBottom.hide();
+    /**
+     * Unhides the tab for a previously hidden panel.
+     * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
+     */
+    unhidePanel : function(panel){
+        if(this.tabs && (panel = this.getPanel(panel))){
+            this.tabs.unhideTab(panel.getEl().id);
         }
-        return result ? this.dropAllowed : this.dropNotAllowed;
     },
 
-    onNodeOut : function(n, dd, e, data){
-        this.proxyTop.hide();
-        this.proxyBottom.hide();
+    clearPanels : function(){
+        while(this.panels.getCount() > 0){
+             this.remove(this.panels.first());
+        }
     },
 
-    onNodeDrop : function(n, dd, e, data){
-        var h = data.header;
-        if(h != n){
-            var cm = this.grid.colModel;
-            var x = Roo.lib.Event.getPageX(e);
-            var r = Roo.lib.Dom.getRegion(n.firstChild);
-            var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
-            var oldIndex = this.view.getCellIndex(h);
-            var newIndex = this.view.getCellIndex(n);
-            var locked = cm.isLocked(newIndex);
-            if(pt == "after"){
-                newIndex++;
-            }
-            if(oldIndex < newIndex){
-                newIndex--;
-            }
-            if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
-                return false;
-            }
-            cm.setLocked(oldIndex, locked, true);
-            cm.moveColumn(oldIndex, newIndex);
-            this.grid.fireEvent("columnmove", oldIndex, newIndex);
-            return true;
+    /**
+     * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
+     * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
+     * @param {Boolean} preservePanel Overrides the config preservePanel option
+     * @return {Roo.ContentPanel} The panel that was removed
+     */
+    remove : function(panel, preservePanel){
+        panel = this.getPanel(panel);
+        if(!panel){
+            return null;
         }
-        return false;
+        var e = {};
+        this.fireEvent("beforeremove", this, panel, e);
+        if(e.cancel === true){
+            return null;
+        }
+        preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
+        var panelId = panel.getId();
+        this.panels.removeKey(panelId);
+        if(preservePanel){
+            document.body.appendChild(panel.getEl().dom);
+        }
+        if(this.tabs){
+            this.tabs.removeTab(panel.getEl().id);
+        }else if (!preservePanel){
+            this.bodyEl.dom.removeChild(panel.getEl().dom);
+        }
+        if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
+            var p = this.panels.first();
+            var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
+            tempEl.appendChild(p.getEl().dom);
+            this.bodyEl.update("");
+            this.bodyEl.dom.appendChild(p.getEl().dom);
+            tempEl = null;
+            this.updateTitle(p.getTitle());
+            this.tabs = null;
+            this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
+            this.setActivePanel(p);
+        }
+        panel.setRegion(null);
+        if(this.activePanel == panel){
+            this.activePanel = null;
+        }
+        if(this.config.autoDestroy !== false && preservePanel !== true){
+            try{panel.destroy();}catch(e){}
+        }
+        this.fireEvent("panelremoved", this, panel);
+        return panel;
+    },
+
+    /**
+     * Returns the TabPanel component used by this region
+     * @return {Roo.TabPanel}
+     */
+    getTabs : function(){
+        return this.tabs;
+    },
+
+    createTool : function(parentEl, className){
+        var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
+            children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: "&#160;"}]}, true);
+        btn.addClassOnOver("x-layout-tools-button-over");
+        return btn;
     }
-});
-/*
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -55453,1737 +60126,1430 @@ Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
  * Fork - LGPL
  * <script type="text/javascript">
  */
-  
+
+
 /**
- * @class Roo.grid.GridView
- * @extends Roo.util.Observable
- *
- * @constructor
- * @param {Object} config
+ * @class Roo.SplitLayoutRegion
+ * @extends Roo.LayoutRegion
+ * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
  */
-Roo.grid.GridView = function(config){
-    Roo.grid.GridView.superclass.constructor.call(this);
-    this.el = null;
-
-    Roo.apply(this, config);
+Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
+    this.cursor = cursor;
+    Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
 };
 
-Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
-
-    unselectable :  'unselectable="on"',
-    unselectableCls :  'x-unselectable',
-    
-    
-    rowClass : "x-grid-row",
-
-    cellClass : "x-grid-col",
-
-    tdClass : "x-grid-td",
-
-    hdClass : "x-grid-hd",
-
-    splitClass : "x-grid-split",
-
-    sortClasses : ["sort-asc", "sort-desc"],
-
-    enableMoveAnim : false,
-
-    hlColor: "C3DAF9",
-
-    dh : Roo.DomHelper,
-
-    fly : Roo.Element.fly,
-
-    css : Roo.util.CSS,
-
-    borderWidth: 1,
+Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
+    splitTip : "Drag to resize.",
+    collapsibleSplitTip : "Drag to resize. Double click to hide.",
+    useSplitTips : false,
 
-    splitOffset: 3,
+    applyConfig : function(config){
+        Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
+        if(config.split){
+            if(!this.split){
+                var splitEl = Roo.DomHelper.append(this.mgr.el.dom, 
+                        {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: "&#160;"});
+                /** The SplitBar for this region 
+                * @type Roo.SplitBar */
+                this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
+                this.split.on("moved", this.onSplitMove, this);
+                this.split.useShim = config.useShim === true;
+                this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
+                if(this.useSplitTips){
+                    this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
+                }
+                if(config.collapsible){
+                    this.split.el.on("dblclick", this.collapse,  this);
+                }
+            }
+            if(typeof config.minSize != "undefined"){
+                this.split.minSize = config.minSize;
+            }
+            if(typeof config.maxSize != "undefined"){
+                this.split.maxSize = config.maxSize;
+            }
+            if(config.hideWhenEmpty || config.hidden || config.collapsed){
+                this.hideSplitter();
+            }
+        }
+    },
 
-    scrollIncrement : 22,
+    getHMaxSize : function(){
+         var cmax = this.config.maxSize || 10000;
+         var center = this.mgr.getRegion("center");
+         return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
+    },
 
-    cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
+    getVMaxSize : function(){
+         var cmax = this.config.maxSize || 10000;
+         var center = this.mgr.getRegion("center");
+         return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
+    },
 
-    findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
+    onSplitMove : function(split, newSize){
+        this.fireEvent("resized", this, newSize);
+    },
+    
+    /** 
+     * Returns the {@link Roo.SplitBar} for this region.
+     * @return {Roo.SplitBar}
+     */
+    getSplitBar : function(){
+        return this.split;
+    },
+    
+    hide : function(){
+        this.hideSplitter();
+        Roo.SplitLayoutRegion.superclass.hide.call(this);
+    },
 
-    bind : function(ds, cm){
-        if(this.ds){
-            this.ds.un("load", this.onLoad, this);
-            this.ds.un("datachanged", this.onDataChange, this);
-            this.ds.un("add", this.onAdd, this);
-            this.ds.un("remove", this.onRemove, this);
-            this.ds.un("update", this.onUpdate, this);
-            this.ds.un("clear", this.onClear, this);
-        }
-        if(ds){
-            ds.on("load", this.onLoad, this);
-            ds.on("datachanged", this.onDataChange, this);
-            ds.on("add", this.onAdd, this);
-            ds.on("remove", this.onRemove, this);
-            ds.on("update", this.onUpdate, this);
-            ds.on("clear", this.onClear, this);
+    hideSplitter : function(){
+        if(this.split){
+            this.split.el.setLocation(-2000,-2000);
+            this.split.el.hide();
         }
-        this.ds = ds;
+    },
 
-        if(this.cm){
-            this.cm.un("widthchange", this.onColWidthChange, this);
-            this.cm.un("headerchange", this.onHeaderChange, this);
-            this.cm.un("hiddenchange", this.onHiddenChange, this);
-            this.cm.un("columnmoved", this.onColumnMove, this);
-            this.cm.un("columnlockchange", this.onColumnLock, this);
+    show : function(){
+        if(this.split){
+            this.split.el.show();
         }
-        if(cm){
-            this.generateRules(cm);
-            cm.on("widthchange", this.onColWidthChange, this);
-            cm.on("headerchange", this.onHeaderChange, this);
-            cm.on("hiddenchange", this.onHiddenChange, this);
-            cm.on("columnmoved", this.onColumnMove, this);
-            cm.on("columnlockchange", this.onColumnLock, this);
+        Roo.SplitLayoutRegion.superclass.show.call(this);
+    },
+    
+    beforeSlide: function(){
+        if(Roo.isGecko){// firefox overflow auto bug workaround
+            this.bodyEl.clip();
+            if(this.tabs) {
+                this.tabs.bodyEl.clip();
+            }
+            if(this.activePanel){
+                this.activePanel.getEl().clip();
+                
+                if(this.activePanel.beforeSlide){
+                    this.activePanel.beforeSlide();
+                }
+            }
+        }
+    },
+    
+    afterSlide : function(){
+        if(Roo.isGecko){// firefox overflow auto bug workaround
+            this.bodyEl.unclip();
+            if(this.tabs) {
+                this.tabs.bodyEl.unclip();
+            }
+            if(this.activePanel){
+                this.activePanel.getEl().unclip();
+                if(this.activePanel.afterSlide){
+                    this.activePanel.afterSlide();
+                }
+            }
         }
-        this.cm = cm;
     },
 
-    init: function(grid){
-        Roo.grid.GridView.superclass.init.call(this, grid);
-
-        this.bind(grid.dataSource, grid.colModel);
-
-        grid.on("headerclick", this.handleHeaderClick, this);
+    initAutoHide : function(){
+        if(this.autoHide !== false){
+            if(!this.autoHideHd){
+                var st = new Roo.util.DelayedTask(this.slideIn, this);
+                this.autoHideHd = {
+                    "mouseout": function(e){
+                        if(!e.within(this.el, true)){
+                            st.delay(500);
+                        }
+                    },
+                    "mouseover" : function(e){
+                        st.cancel();
+                    },
+                    scope : this
+                };
+            }
+            this.el.on(this.autoHideHd);
+        }
+    },
 
-        if(grid.trackMouseOver){
-            grid.on("mouseover", this.onRowOver, this);
-            grid.on("mouseout", this.onRowOut, this);
+    clearAutoHide : function(){
+        if(this.autoHide !== false){
+            this.el.un("mouseout", this.autoHideHd.mouseout);
+            this.el.un("mouseover", this.autoHideHd.mouseover);
         }
-        grid.cancelTextSelection = function(){};
-        this.gridId = grid.id;
+    },
 
-        var tpls = this.templates || {};
+    clearMonitor : function(){
+        Roo.get(document).un("click", this.slideInIf, this);
+    },
 
-        if(!tpls.master){
-            tpls.master = new Roo.Template(
-               '<div class="x-grid" hidefocus="true">',
-                '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
-                  '<div class="x-grid-topbar"></div>',
-                  '<div class="x-grid-scroller"><div></div></div>',
-                  '<div class="x-grid-locked">',
-                      '<div class="x-grid-header">{lockedHeader}</div>',
-                      '<div class="x-grid-body">{lockedBody}</div>',
-                  "</div>",
-                  '<div class="x-grid-viewport">',
-                      '<div class="x-grid-header">{header}</div>',
-                      '<div class="x-grid-body">{body}</div>',
-                  "</div>",
-                  '<div class="x-grid-bottombar"></div>',
-                 
-                  '<div class="x-grid-resize-proxy">&#160;</div>',
-               "</div>"
-            );
-            tpls.master.disableformats = true;
+    // these names are backwards but not changed for compat
+    slideOut : function(){
+        if(this.isSlid || this.el.hasActiveFx()){
+            return;
         }
-
-        if(!tpls.header){
-            tpls.header = new Roo.Template(
-               '<table border="0" cellspacing="0" cellpadding="0">',
-               '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
-               "</table>{splits}"
-            );
-            tpls.header.disableformats = true;
+        this.isSlid = true;
+        if(this.collapseBtn){
+            this.collapseBtn.hide();
         }
-        tpls.header.compile();
-
-        if(!tpls.hcell){
-            tpls.hcell = new Roo.Template(
-                '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
-                '<div class="x-grid-hd-text ' + this.unselectableCls +  '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
-                "</div></td>"
-             );
-             tpls.hcell.disableFormats = true;
+        this.closeBtnState = this.closeBtn.getStyle('display');
+        this.closeBtn.hide();
+        if(this.stickBtn){
+            this.stickBtn.show();
         }
-        tpls.hcell.compile();
+        this.el.show();
+        this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
+        this.beforeSlide();
+        this.el.setStyle("z-index", 10001);
+        this.el.slideIn(this.getSlideAnchor(), {
+            callback: function(){
+                this.afterSlide();
+                this.initAutoHide();
+                Roo.get(document).on("click", this.slideInIf, this);
+                this.fireEvent("slideshow", this);
+            },
+            scope: this,
+            block: true
+        });
+    },
 
-        if(!tpls.hsplit){
-            tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
-                                            this.unselectableCls +  '" ' + this.unselectable +'>&#160;</div>');
-            tpls.hsplit.disableFormats = true;
+    afterSlideIn : function(){
+        this.clearAutoHide();
+        this.isSlid = false;
+        this.clearMonitor();
+        this.el.setStyle("z-index", "");
+        if(this.collapseBtn){
+            this.collapseBtn.show();
         }
-        tpls.hsplit.compile();
-
-        if(!tpls.body){
-            tpls.body = new Roo.Template(
-               '<table border="0" cellspacing="0" cellpadding="0">',
-               "<tbody>{rows}</tbody>",
-               "</table>"
-            );
-            tpls.body.disableFormats = true;
+        this.closeBtn.setStyle('display', this.closeBtnState);
+        if(this.stickBtn){
+            this.stickBtn.hide();
         }
-        tpls.body.compile();
+        this.fireEvent("slidehide", this);
+    },
 
-        if(!tpls.row){
-            tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
-            tpls.row.disableFormats = true;
+    slideIn : function(cb){
+        if(!this.isSlid || this.el.hasActiveFx()){
+            Roo.callback(cb);
+            return;
         }
-        tpls.row.compile();
-
-        if(!tpls.cell){
-            tpls.cell = new Roo.Template(
-                '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
-                '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
-                    this.unselectableCls +  '" ' + this.unselectable +'" {attr}>{value}</div></div>',
-                "</td>"
-            );
-            tpls.cell.disableFormats = true;
+        this.isSlid = false;
+        this.beforeSlide();
+        this.el.slideOut(this.getSlideAnchor(), {
+            callback: function(){
+                this.el.setLeftTop(-10000, -10000);
+                this.afterSlide();
+                this.afterSlideIn();
+                Roo.callback(cb);
+            },
+            scope: this,
+            block: true
+        });
+    },
+    
+    slideInIf : function(e){
+        if(!e.within(this.el)){
+            this.slideIn();
         }
-        tpls.cell.compile();
+    },
 
-        this.templates = tpls;
+    animateCollapse : function(){
+        this.beforeSlide();
+        this.el.setStyle("z-index", 20000);
+        var anchor = this.getSlideAnchor();
+        this.el.slideOut(anchor, {
+            callback : function(){
+                this.el.setStyle("z-index", "");
+                this.collapsedEl.slideIn(anchor, {duration:.3});
+                this.afterSlide();
+                this.el.setLocation(-10000,-10000);
+                this.el.hide();
+                this.fireEvent("collapsed", this);
+            },
+            scope: this,
+            block: true
+        });
     },
 
-    // remap these for backwards compat
-    onColWidthChange : function(){
-        this.updateColumns.apply(this, arguments);
+    animateExpand : function(){
+        this.beforeSlide();
+        this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
+        this.el.setStyle("z-index", 20000);
+        this.collapsedEl.hide({
+            duration:.1
+        });
+        this.el.slideIn(this.getSlideAnchor(), {
+            callback : function(){
+                this.el.setStyle("z-index", "");
+                this.afterSlide();
+                if(this.split){
+                    this.split.el.show();
+                }
+                this.fireEvent("invalidated", this);
+                this.fireEvent("expanded", this);
+            },
+            scope: this,
+            block: true
+        });
     },
-    onHeaderChange : function(){
-        this.updateHeaders.apply(this, arguments);
-    }, 
-    onHiddenChange : function(){
-        this.handleHiddenChange.apply(this, arguments);
+
+    anchors : {
+        "west" : "left",
+        "east" : "right",
+        "north" : "top",
+        "south" : "bottom"
     },
-    onColumnMove : function(){
-        this.handleColumnMove.apply(this, arguments);
+
+    sanchors : {
+        "west" : "l",
+        "east" : "r",
+        "north" : "t",
+        "south" : "b"
     },
-    onColumnLock : function(){
-        this.handleLockChange.apply(this, arguments);
+
+    canchors : {
+        "west" : "tl-tr",
+        "east" : "tr-tl",
+        "north" : "tl-bl",
+        "south" : "bl-tl"
     },
 
-    onDataChange : function(){
-        this.refresh();
-        this.updateHeaderSortState();
+    getAnchor : function(){
+        return this.anchors[this.position];
     },
 
-    onClear : function(){
-        this.refresh();
+    getCollapseAnchor : function(){
+        return this.canchors[this.position];
     },
 
-    onUpdate : function(ds, record){
-        this.refreshRow(record);
+    getSlideAnchor : function(){
+        return this.sanchors[this.position];
     },
 
-    refreshRow : function(record){
-        var ds = this.ds, index;
-        if(typeof record == 'number'){
-            index = record;
-            record = ds.getAt(index);
-        }else{
-            index = ds.indexOf(record);
-        }
-        this.insertRows(ds, index, index, true);
-        this.onRemove(ds, record, index+1, true);
-        this.syncRowHeights(index, index);
-        this.layout();
-        this.fireEvent("rowupdated", this, index, record);
-    },
-
-    onAdd : function(ds, records, index){
-        this.insertRows(ds, index, index + (records.length-1));
-    },
-
-    onRemove : function(ds, record, index, isUpdate){
-        if(isUpdate !== true){
-            this.fireEvent("beforerowremoved", this, index, record);
-        }
-        var bt = this.getBodyTable(), lt = this.getLockedTable();
-        if(bt.rows[index]){
-            bt.firstChild.removeChild(bt.rows[index]);
-        }
-        if(lt.rows[index]){
-            lt.firstChild.removeChild(lt.rows[index]);
-        }
-        if(isUpdate !== true){
-            this.stripeRows(index);
-            this.syncRowHeights(index, index);
-            this.layout();
-            this.fireEvent("rowremoved", this, index, record);
-        }
-    },
-
-    onLoad : function(){
-        this.scrollToTop();
-    },
-
-    /**
-     * Scrolls the grid to the top
-     */
-    scrollToTop : function(){
-        if(this.scroller){
-            this.scroller.dom.scrollTop = 0;
-            this.syncScroll();
-        }
-    },
-
-    /**
-     * Gets a panel in the header of the grid that can be used for toolbars etc.
-     * After modifying the contents of this panel a call to grid.autoSize() may be
-     * required to register any changes in size.
-     * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
-     * @return Roo.Element
-     */
-    getHeaderPanel : function(doShow){
-        if(doShow){
-            this.headerPanel.show();
+    getAlignAdj : function(){
+        var cm = this.cmargins;
+        switch(this.position){
+            case "west":
+                return [0, 0];
+            break;
+            case "east":
+                return [0, 0];
+            break;
+            case "north":
+                return [0, 0];
+            break;
+            case "south":
+                return [0, 0];
+            break;
         }
-        return this.headerPanel;
     },
 
-    /**
-     * Gets a panel in the footer of the grid that can be used for toolbars etc.
-     * After modifying the contents of this panel a call to grid.autoSize() may be
-     * required to register any changes in size.
-     * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
-     * @return Roo.Element
-     */
-    getFooterPanel : function(doShow){
-        if(doShow){
-            this.footerPanel.show();
+    getExpandAdj : function(){
+        var c = this.collapsedEl, cm = this.cmargins;
+        switch(this.position){
+            case "west":
+                return [-(cm.right+c.getWidth()+cm.left), 0];
+            break;
+            case "east":
+                return [cm.right+c.getWidth()+cm.left, 0];
+            break;
+            case "north":
+                return [0, -(cm.top+cm.bottom+c.getHeight())];
+            break;
+            case "south":
+                return [0, cm.top+cm.bottom+c.getHeight()];
+            break;
         }
-        return this.footerPanel;
-    },
-
-    initElements : function(){
-        var E = Roo.Element;
-        var el = this.grid.getGridEl().dom.firstChild;
-        var cs = el.childNodes;
-
-        this.el = new E(el);
-        
-         this.focusEl = new E(el.firstChild);
-        this.focusEl.swallowEvent("click", true);
-        
-        this.headerPanel = new E(cs[1]);
-        this.headerPanel.enableDisplayMode("block");
-
-        this.scroller = new E(cs[2]);
-        this.scrollSizer = new E(this.scroller.dom.firstChild);
-
-        this.lockedWrap = new E(cs[3]);
-        this.lockedHd = new E(this.lockedWrap.dom.firstChild);
-        this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
-
-        this.mainWrap = new E(cs[4]);
-        this.mainHd = new E(this.mainWrap.dom.firstChild);
-        this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
-
-        this.footerPanel = new E(cs[5]);
-        this.footerPanel.enableDisplayMode("block");
-
-        this.resizeProxy = new E(cs[6]);
-
-        this.headerSelector = String.format(
-           '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
-           this.lockedHd.id, this.mainHd.id
-        );
-
-        this.splitterSelector = String.format(
-           '#{0} div.x-grid-split, #{1} div.x-grid-split',
-           this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
-        );
-    },
-    idToCssName : function(s)
-    {
-        return s.replace(/[^a-z0-9]+/ig, '-');
-    },
-
-    getHeaderCell : function(index){
-        return Roo.DomQuery.select(this.headerSelector)[index];
-    },
-
-    getHeaderCellMeasure : function(index){
-        return this.getHeaderCell(index).firstChild;
-    },
-
-    getHeaderCellText : function(index){
-        return this.getHeaderCell(index).firstChild.firstChild;
-    },
+    }
+});/*
+ * 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">
+ */
+/*
+ * These classes are private internal classes
+ */
+Roo.CenterLayoutRegion = function(mgr, config){
+    Roo.LayoutRegion.call(this, mgr, config, "center");
+    this.visible = true;
+    this.minWidth = config.minWidth || 20;
+    this.minHeight = config.minHeight || 20;
+};
 
-    getLockedTable : function(){
-        return this.lockedBody.dom.firstChild;
+Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
+    hide : function(){
+        // center panel can't be hidden
     },
-
-    getBodyTable : function(){
-        return this.mainBody.dom.firstChild;
+    
+    show : function(){
+        // center panel can't be hidden
     },
-
-    getLockedRow : function(index){
-        return this.getLockedTable().rows[index];
+    
+    getMinWidth: function(){
+        return this.minWidth;
     },
+    
+    getMinHeight: function(){
+        return this.minHeight;
+    }
+});
 
-    getRow : function(index){
-        return this.getBodyTable().rows[index];
-    },
 
-    getRowComposite : function(index){
-        if(!this.rowEl){
-            this.rowEl = new Roo.CompositeElementLite();
-        }
-        var els = [], lrow, mrow;
-        if(lrow = this.getLockedRow(index)){
-            els.push(lrow);
+Roo.NorthLayoutRegion = function(mgr, config){
+    Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
+    if(this.split){
+        this.split.placement = Roo.SplitBar.TOP;
+        this.split.orientation = Roo.SplitBar.VERTICAL;
+        this.split.el.addClass("x-layout-split-v");
+    }
+    var size = config.initialSize || config.height;
+    if(typeof size != "undefined"){
+        this.el.setHeight(size);
+    }
+};
+Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
+    orientation: Roo.SplitBar.VERTICAL,
+    getBox : function(){
+        if(this.collapsed){
+            return this.collapsedEl.getBox();
         }
-        if(mrow = this.getRow(index)){
-            els.push(mrow);
+        var box = this.el.getBox();
+        if(this.split){
+            box.height += this.split.el.getHeight();
         }
-        this.rowEl.elements = els;
-        return this.rowEl;
+        return box;
     },
-    /**
-     * Gets the 'td' of the cell
-     * 
-     * @param {Integer} rowIndex row to select
-     * @param {Integer} colIndex column to select
-     * 
-     * @return {Object} 
-     */
-    getCell : function(rowIndex, colIndex){
-        var locked = this.cm.getLockedCount();
-        var source;
-        if(colIndex < locked){
-            source = this.lockedBody.dom.firstChild;
-        }else{
-            source = this.mainBody.dom.firstChild;
-            colIndex -= locked;
+    
+    updateBox : function(box){
+        if(this.split && !this.collapsed){
+            box.height -= this.split.el.getHeight();
+            this.split.el.setLeft(box.x);
+            this.split.el.setTop(box.y+box.height);
+            this.split.el.setWidth(box.width);
         }
-        return source.rows[rowIndex].childNodes[colIndex];
-    },
-
-    getCellText : function(rowIndex, colIndex){
-        return this.getCell(rowIndex, colIndex).firstChild.firstChild;
-    },
-
-    getCellBox : function(cell){
-        var b = this.fly(cell).getBox();
-        if(Roo.isOpera){ // opera fails to report the Y
-            b.y = cell.offsetTop + this.mainBody.getY();
+        if(this.collapsed){
+            this.updateBody(box.width, null);
         }
-        return b;
-    },
+        Roo.LayoutRegion.prototype.updateBox.call(this, box);
+    }
+});
 
-    getCellIndex : function(cell){
-        var id = String(cell.className).match(this.cellRE);
-        if(id){
-            return parseInt(id[1], 10);
+Roo.SouthLayoutRegion = function(mgr, config){
+    Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
+    if(this.split){
+        this.split.placement = Roo.SplitBar.BOTTOM;
+        this.split.orientation = Roo.SplitBar.VERTICAL;
+        this.split.el.addClass("x-layout-split-v");
+    }
+    var size = config.initialSize || config.height;
+    if(typeof size != "undefined"){
+        this.el.setHeight(size);
+    }
+};
+Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
+    orientation: Roo.SplitBar.VERTICAL,
+    getBox : function(){
+        if(this.collapsed){
+            return this.collapsedEl.getBox();
         }
-        return 0;
-    },
-
-    findHeaderIndex : function(n){
-        var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
-        return r ? this.getCellIndex(r) : false;
-    },
-
-    findHeaderCell : function(n){
-        var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
-        return r ? r : false;
-    },
-
-    findRowIndex : function(n){
-        if(!n){
-            return false;
+        var box = this.el.getBox();
+        if(this.split){
+            var sh = this.split.el.getHeight();
+            box.height += sh;
+            box.y -= sh;
         }
-        var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
-        return r ? r.rowIndex : false;
+        return box;
     },
-
-    findCellIndex : function(node){
-        var stop = this.el.dom;
-        while(node && node != stop){
-            if(this.findRE.test(node.className)){
-                return this.getCellIndex(node);
-            }
-            node = node.parentNode;
+    
+    updateBox : function(box){
+        if(this.split && !this.collapsed){
+            var sh = this.split.el.getHeight();
+            box.height -= sh;
+            box.y += sh;
+            this.split.el.setLeft(box.x);
+            this.split.el.setTop(box.y-sh);
+            this.split.el.setWidth(box.width);
         }
-        return false;
-    },
-
-    getColumnId : function(index){
-        return this.cm.getColumnId(index);
-    },
-
-    getSplitters : function()
-    {
-        if(this.splitterSelector){
-           return Roo.DomQuery.select(this.splitterSelector);
-        }else{
-            return null;
-      }
-    },
-
-    getSplitter : function(index){
-        return this.getSplitters()[index];
-    },
-
-    onRowOver : function(e, t){
-        var row;
-        if((row = this.findRowIndex(t)) !== false){
-            this.getRowComposite(row).addClass("x-grid-row-over");
+        if(this.collapsed){
+            this.updateBody(box.width, null);
         }
-    },
+        Roo.LayoutRegion.prototype.updateBox.call(this, box);
+    }
+});
 
-    onRowOut : function(e, t){
-        var row;
-        if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
-            this.getRowComposite(row).removeClass("x-grid-row-over");
+Roo.EastLayoutRegion = function(mgr, config){
+    Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
+    if(this.split){
+        this.split.placement = Roo.SplitBar.RIGHT;
+        this.split.orientation = Roo.SplitBar.HORIZONTAL;
+        this.split.el.addClass("x-layout-split-h");
+    }
+    var size = config.initialSize || config.width;
+    if(typeof size != "undefined"){
+        this.el.setWidth(size);
+    }
+};
+Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
+    orientation: Roo.SplitBar.HORIZONTAL,
+    getBox : function(){
+        if(this.collapsed){
+            return this.collapsedEl.getBox();
         }
-    },
-
-    renderHeaders : function(){
-        var cm = this.cm;
-        var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
-        var cb = [], lb = [], sb = [], lsb = [], p = {};
-        for(var i = 0, len = cm.getColumnCount(); i < len; i++){
-            p.cellId = "x-grid-hd-0-" + i;
-            p.splitId = "x-grid-csplit-0-" + i;
-            p.id = cm.getColumnId(i);
-            p.value = cm.getColumnHeader(i) || "";
-            p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</)  ? '' :  p.value  || "";
-            p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
-            if(!cm.isLocked(i)){
-                cb[cb.length] = ct.apply(p);
-                sb[sb.length] = st.apply(p);
-            }else{
-                lb[lb.length] = ct.apply(p);
-                lsb[lsb.length] = st.apply(p);
-            }
+        var box = this.el.getBox();
+        if(this.split){
+            var sw = this.split.el.getWidth();
+            box.width += sw;
+            box.x -= sw;
         }
-        return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
-                ht.apply({cells: cb.join(""), splits:sb.join("")})];
-    },
-
-    updateHeaders : function(){
-        var html = this.renderHeaders();
-        this.lockedHd.update(html[0]);
-        this.mainHd.update(html[1]);
-    },
-
-    /**
-     * Focuses the specified row.
-     * @param {Number} row The row index
-     */
-    focusRow : function(row)
-    {
-        //Roo.log('GridView.focusRow');
-        var x = this.scroller.dom.scrollLeft;
-        this.focusCell(row, 0, false);
-        this.scroller.dom.scrollLeft = x;
+        return box;
     },
 
-    /**
-     * Focuses the specified cell.
-     * @param {Number} row The row index
-     * @param {Number} col The column index
-     * @param {Boolean} hscroll false to disable horizontal scrolling
-     */
-    focusCell : function(row, col, hscroll)
-    {
-        //Roo.log('GridView.focusCell');
-        var el = this.ensureVisible(row, col, hscroll);
-        this.focusEl.alignTo(el, "tl-tl");
-        if(Roo.isGecko){
-            this.focusEl.focus();
-        }else{
-            this.focusEl.focus.defer(1, this.focusEl);
+    updateBox : function(box){
+        if(this.split && !this.collapsed){
+            var sw = this.split.el.getWidth();
+            box.width -= sw;
+            this.split.el.setLeft(box.x);
+            this.split.el.setTop(box.y);
+            this.split.el.setHeight(box.height);
+            box.x += sw;
         }
-    },
+        if(this.collapsed){
+            this.updateBody(null, box.height);
+        }
+        Roo.LayoutRegion.prototype.updateBox.call(this, box);
+    }
+});
 
-    /**
-     * Scrolls the specified cell into view
-     * @param {Number} row The row index
-     * @param {Number} col The column index
-     * @param {Boolean} hscroll false to disable horizontal scrolling
-     */
-    ensureVisible : function(row, col, hscroll)
-    {
-        //Roo.log('GridView.ensureVisible,' + row + ',' + col);
-        //return null; //disable for testing.
-        if(typeof row != "number"){
-            row = row.rowIndex;
+Roo.WestLayoutRegion = function(mgr, config){
+    Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
+    if(this.split){
+        this.split.placement = Roo.SplitBar.LEFT;
+        this.split.orientation = Roo.SplitBar.HORIZONTAL;
+        this.split.el.addClass("x-layout-split-h");
+    }
+    var size = config.initialSize || config.width;
+    if(typeof size != "undefined"){
+        this.el.setWidth(size);
+    }
+};
+Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
+    orientation: Roo.SplitBar.HORIZONTAL,
+    getBox : function(){
+        if(this.collapsed){
+            return this.collapsedEl.getBox();
         }
-        if(row < 0 && row >= this.ds.getCount()){
-            return  null;
+        var box = this.el.getBox();
+        if(this.split){
+            box.width += this.split.el.getWidth();
         }
-        col = (col !== undefined ? col : 0);
-        var cm = this.grid.colModel;
-        while(cm.isHidden(col)){
-            col++;
+        return box;
+    },
+    
+    updateBox : function(box){
+        if(this.split && !this.collapsed){
+            var sw = this.split.el.getWidth();
+            box.width -= sw;
+            this.split.el.setLeft(box.x+box.width);
+            this.split.el.setTop(box.y);
+            this.split.el.setHeight(box.height);
         }
-
-        var el = this.getCell(row, col);
-        if(!el){
-            return null;
+        if(this.collapsed){
+            this.updateBody(null, box.height);
         }
-        var c = this.scroller.dom;
+        Roo.LayoutRegion.prototype.updateBox.call(this, box);
+    }
+});
+/*
+ * 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">
+ */
+/*
+ * Private internal class for reading and applying state
+ */
+Roo.LayoutStateManager = function(layout){
+     // default empty state
+     this.state = {
+        north: {},
+        south: {},
+        east: {},
+        west: {}       
+    };
+};
 
-        var ctop = parseInt(el.offsetTop, 10);
-        var cleft = parseInt(el.offsetLeft, 10);
-        var cbot = ctop + el.offsetHeight;
-        var cright = cleft + el.offsetWidth;
-        
-        var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
-        var stop = parseInt(c.scrollTop, 10);
-        var sleft = parseInt(c.scrollLeft, 10);
-        var sbot = stop + ch;
-        var sright = sleft + c.clientWidth;
-        /*
-        Roo.log('GridView.ensureVisible:' +
-                ' ctop:' + ctop +
-                ' c.clientHeight:' + c.clientHeight +
-                ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
-                ' stop:' + stop +
-                ' cbot:' + cbot +
-                ' sbot:' + sbot +
-                ' ch:' + ch  
-                );
-        */
-        if(ctop < stop){
-             c.scrollTop = ctop;
-            //Roo.log("set scrolltop to ctop DISABLE?");
-        }else if(cbot > sbot){
-            //Roo.log("set scrolltop to cbot-ch");
-            c.scrollTop = cbot-ch;
-        }
-        
-        if(hscroll !== false){
-            if(cleft < sleft){
-                c.scrollLeft = cleft;
-            }else if(cright > sright){
-                c.scrollLeft = cright-c.clientWidth;
+Roo.LayoutStateManager.prototype = {
+    init : function(layout, provider){
+        this.provider = provider;
+        var state = provider.get(layout.id+"-layout-state");
+        if(state){
+            var wasUpdating = layout.isUpdating();
+            if(!wasUpdating){
+                layout.beginUpdate();
             }
-        }
-         
-        return el;
-    },
-
-    updateColumns : function(){
-        this.grid.stopEditing();
-        var cm = this.grid.colModel, colIds = this.getColumnIds();
-        //var totalWidth = cm.getTotalWidth();
-        var pos = 0;
-        for(var i = 0, len = cm.getColumnCount(); i < len; i++){
-            //if(cm.isHidden(i)) continue;
-            var w = cm.getColumnWidth(i);
-            this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
-            this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
-        }
-        this.updateSplitters();
-    },
-
-    generateRules : function(cm){
-        var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
-        Roo.util.CSS.removeStyleSheet(rulesId);
-        for(var i = 0, len = cm.getColumnCount(); i < len; i++){
-            var cid = cm.getColumnId(i);
-            var align = '';
-            if(cm.config[i].align){
-                align = 'text-align:'+cm.config[i].align+';';
+            for(var key in state){
+                if(typeof state[key] != "function"){
+                    var rstate = state[key];
+                    var r = layout.getRegion(key);
+                    if(r && rstate){
+                        if(rstate.size){
+                            r.resizeTo(rstate.size);
+                        }
+                        if(rstate.collapsed == true){
+                            r.collapse(true);
+                        }else{
+                            r.expand(null, true);
+                        }
+                    }
+                }
             }
-            var hidden = '';
-            if(cm.isHidden(i)){
-                hidden = 'display:none;';
+            if(!wasUpdating){
+                layout.endUpdate();
             }
-            var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
-            ruleBuf.push(
-                    this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
-                    this.hdSelector, cid, " {\n", align, width, "}\n",
-                    this.tdSelector, cid, " {\n",hidden,"\n}\n",
-                    this.splitSelector, cid, " {\n", hidden , "\n}\n");
+            this.state = state; 
         }
-        return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
+        this.layout = layout;
+        layout.on("regionresized", this.onRegionResized, this);
+        layout.on("regioncollapsed", this.onRegionCollapsed, this);
+        layout.on("regionexpanded", this.onRegionExpanded, this);
     },
-
-    updateSplitters : function(){
-        var cm = this.cm, s = this.getSplitters();
-        if(s){ // splitters not created yet
-            var pos = 0, locked = true;
-            for(var i = 0, len = cm.getColumnCount(); i < len; i++){
-                if(cm.isHidden(i)) {
-                    continue;
-                }
-                var w = cm.getColumnWidth(i); // make sure it's a number
-                if(!cm.isLocked(i) && locked){
-                    pos = 0;
-                    locked = false;
-                }
-                pos += w;
-                s[i].style.left = (pos-this.splitOffset) + "px";
-            }
-        }
+    
+    storeState : function(){
+        this.provider.set(this.layout.id+"-layout-state", this.state);
+    },
+    
+    onRegionResized : function(region, newSize){
+        this.state[region.getPosition()].size = newSize;
+        this.storeState();
     },
+    
+    onRegionCollapsed : function(region){
+        this.state[region.getPosition()].collapsed = true;
+        this.storeState();
+    },
+    
+    onRegionExpanded : function(region){
+        this.state[region.getPosition()].collapsed = false;
+        this.storeState();
+    }
+};/*
+ * 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.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}   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 {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) [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 {Roo.menu.Menu} menu  popup menu
 
-    handleHiddenChange : function(colModel, colIndex, hidden){
-        if(hidden){
-            this.hideColumn(colIndex);
+ * @constructor
+ * Create a new ContentPanel.
+ * @param {String/HTMLElement/Roo.Element} el The container element for this panel
+ * @param {String/Object} config A string to set only the title or a config object
+ * @param {String} content (optional) Set the HTML content for this panel
+ * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
+ */
+Roo.ContentPanel = function(el, config, content){
+    
+    /*
+    if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
+        config = el;
+        el = Roo.id();
+    }
+    if (config && config.parentLayout) { 
+        el = config.parentLayout.el.createChild(); 
+    }
+    */
+    if(el.autoCreate){ // xtype is available if this is called from factory
+        config = el;
+        el = Roo.id();
+    }
+    this.el = Roo.get(el);
+    if(!this.el && config && config.autoCreate){
+        if(typeof config.autoCreate == "object"){
+            if(!config.autoCreate.id){
+                config.autoCreate.id = config.id||el;
+            }
+            this.el = Roo.DomHelper.append(document.body,
+                        config.autoCreate, true);
         }else{
-            this.unhideColumn(colIndex);
+            this.el = Roo.DomHelper.append(document.body,
+                        {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
         }
-    },
-
-    hideColumn : function(colIndex){
-        var cid = this.getColumnId(colIndex);
-        this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
-        this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
-        if(Roo.isSafari){
-            this.updateHeaders();
+    }
+    
+    
+    this.closable = false;
+    this.loaded = false;
+    this.active = false;
+    if(typeof config == "string"){
+        this.title = config;
+    }else{
+        Roo.apply(this, config);
+    }
+    
+    if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
+        this.wrapEl = this.el.wrap();
+        this.toolbar.container = this.el.insertSibling(false, 'before');
+        this.toolbar = new Roo.Toolbar(this.toolbar);
+    }
+    
+    // xtype created footer. - not sure if will work as we normally have to render first..
+    if (this.footer && !this.footer.el && this.footer.xtype) {
+        if (!this.wrapEl) {
+            this.wrapEl = this.el.wrap();
         }
-        this.updateSplitters();
-        this.layout();
-    },
+    
+        this.footer.container = this.wrapEl.createChild();
+         
+        this.footer = Roo.factory(this.footer, Roo);
+        
+    }
+    
+    if(this.resizeEl){
+        this.resizeEl = Roo.get(this.resizeEl, true);
+    }else{
+        this.resizeEl = this.el;
+    }
+    // handle view.xtype
+    
+    
+    
+    this.addEvents({
+        /**
+         * @event activate
+         * Fires when this panel is activated. 
+         * @param {Roo.ContentPanel} this
+         */
+        "activate" : true,
+        /**
+         * @event deactivate
+         * Fires when this panel is activated. 
+         * @param {Roo.ContentPanel} this
+         */
+        "deactivate" : true,
 
-    unhideColumn : function(colIndex){
-        var cid = this.getColumnId(colIndex);
-        this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
-        this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
+        /**
+         * @event resize
+         * Fires when this panel is resized if fitToFrame is true.
+         * @param {Roo.ContentPanel} this
+         * @param {Number} width The width after any component adjustments
+         * @param {Number} height The height after any component adjustments
+         */
+        "resize" : true,
+        
+         /**
+         * @event render
+         * Fires when this tab is created
+         * @param {Roo.ContentPanel} this
+         */
+        "render" : true
+         
+        
+    });
+    
 
-        if(Roo.isSafari){
-            this.updateHeaders();
-        }
-        this.updateSplitters();
-        this.layout();
-    },
+    
+    
+    if(this.autoScroll){
+        this.resizeEl.setStyle("overflow", "auto");
+    } else {
+        // fix randome scrolling
+        this.el.on('scroll', function() {
+            Roo.log('fix random scolling');
+            this.scrollTo('top',0); 
+        });
+    }
+    content = content || this.content;
+    if(content){
+        this.setContent(content);
+    }
+    if(config && config.url){
+        this.setUrl(this.url, this.params, this.loadOnce);
+    }
+    
+    
+    
+    Roo.ContentPanel.superclass.constructor.call(this);
+    
+    if (this.view && typeof(this.view.xtype) != 'undefined') {
+        this.view.el = this.el.appendChild(document.createElement("div"));
+        this.view = Roo.factory(this.view); 
+        this.view.render  &&  this.view.render(false, '');  
+    }
+    
+    
+    this.fireEvent('render', this);
+};
 
-    insertRows : function(dm, firstRow, lastRow, isUpdate){
-        if(firstRow == 0 && lastRow == dm.getCount()-1){
-            this.refresh();
+Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
+    tabTip:'',
+    setRegion : function(region){
+        this.region = region;
+        if(region){
+           this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
         }else{
-            if(!isUpdate){
-                this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
-            }
-            var s = this.getScrollState();
-            var markup = this.renderRows(firstRow, lastRow);
-            this.bufferRows(markup[0], this.getLockedTable(), firstRow);
-            this.bufferRows(markup[1], this.getBodyTable(), firstRow);
-            this.restoreScroll(s);
-            if(!isUpdate){
-                this.fireEvent("rowsinserted", this, firstRow, lastRow);
-                this.syncRowHeights(firstRow, lastRow);
-                this.stripeRows(firstRow);
-                this.layout();
-            }
-        }
+           this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
+        } 
     },
-
-    bufferRows : function(markup, target, index){
-        var before = null, trows = target.rows, tbody = target.tBodies[0];
-        if(index < trows.length){
-            before = trows[index];
-        }
-        var b = document.createElement("div");
-        b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
-        var rows = b.firstChild.rows;
-        for(var i = 0, len = rows.length; i < len; i++){
-            if(before){
-                tbody.insertBefore(rows[0], before);
-            }else{
-                tbody.appendChild(rows[0]);
-            }
-        }
-        b.innerHTML = "";
-        b = null;
+    
+    /**
+     * Returns the toolbar for this Panel if one was configured. 
+     * @return {Roo.Toolbar} 
+     */
+    getToolbar : function(){
+        return this.toolbar;
     },
-
-    deleteRows : function(dm, firstRow, lastRow){
-        if(dm.getRowCount()<1){
-            this.fireEvent("beforerefresh", this);
-            this.mainBody.update("");
-            this.lockedBody.update("");
-            this.fireEvent("refresh", this);
+    
+    setActiveState : function(active){
+        this.active = active;
+        if(!active){
+            this.fireEvent("deactivate", this);
         }else{
-            this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
-            var bt = this.getBodyTable();
-            var tbody = bt.firstChild;
-            var rows = bt.rows;
-            for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
-                tbody.removeChild(rows[firstRow]);
-            }
-            this.stripeRows(firstRow);
-            this.fireEvent("rowsdeleted", this, firstRow, lastRow);
+            this.fireEvent("activate", this);
         }
     },
-
-    updateRows : function(dataSource, firstRow, lastRow){
-        var s = this.getScrollState();
-        this.refresh();
-        this.restoreScroll(s);
+    /**
+     * Updates this panel's element
+     * @param {String} content The new content
+     * @param {Boolean} loadScripts (optional) true to look for and process scripts
+    */
+    setContent : function(content, loadScripts){
+        this.el.update(content, loadScripts);
     },
 
-    handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
-        if(!noRefresh){
-           this.refresh();
+    ignoreResize : function(w, h){
+        if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
+            return true;
+        }else{
+            this.lastSize = {width: w, height: h};
+            return false;
         }
-        this.updateHeaderSortState();
     },
-
-    getScrollState : function(){
-        
-        var sb = this.scroller.dom;
-        return {left: sb.scrollLeft, top: sb.scrollTop};
+    /**
+     * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
+     * @return {Roo.UpdateManager} The UpdateManager
+     */
+    getUpdateManager : function(){
+        return this.el.getUpdateManager();
     },
-
-    stripeRows : function(startRow){
-        if(!this.grid.stripeRows || this.ds.getCount() < 1){
-            return;
-        }
-        startRow = startRow || 0;
-        var rows = this.getBodyTable().rows;
-        var lrows = this.getLockedTable().rows;
-        var cls = ' x-grid-row-alt ';
-        for(var i = startRow, len = rows.length; i < len; i++){
-            var row = rows[i], lrow = lrows[i];
-            var isAlt = ((i+1) % 2 == 0);
-            var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
-            if(isAlt == hasAlt){
-                continue;
-            }
-            if(isAlt){
-                row.className += " x-grid-row-alt";
-            }else{
-                row.className = row.className.replace("x-grid-row-alt", "");
-            }
-            if(lrow){
-                lrow.className = row.className;
-            }
-        }
+     /**
+     * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
+     * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
+<pre><code>
+panel.load({
+    url: "your-url.php",
+    params: {param1: "foo", param2: "bar"}, // or a URL encoded string
+    callback: yourFunction,
+    scope: yourObject, //(optional scope)
+    discardUrl: false,
+    nocache: false,
+    text: "Loading...",
+    timeout: 30,
+    scripts: false
+});
+</code></pre>
+     * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
+     * are shorthand for <i>disableCaching</i>, <i>indicatorText</i> and <i>loadScripts</i> and are used to set their associated property on this panel UpdateManager instance.
+     * @param {String/Object} params (optional) The parameters to pass as either a URL encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
+     * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
+     * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used URL. If true, it will not store the URL.
+     * @return {Roo.ContentPanel} this
+     */
+    load : function(){
+        var um = this.el.getUpdateManager();
+        um.update.apply(um, arguments);
+        return this;
     },
 
-    restoreScroll : function(state){
-        //Roo.log('GridView.restoreScroll');
-        var sb = this.scroller.dom;
-        sb.scrollLeft = state.left;
-        sb.scrollTop = state.top;
-        this.syncScroll();
-    },
-
-    syncScroll : function(){
-        //Roo.log('GridView.syncScroll');
-        var sb = this.scroller.dom;
-        var sh = this.mainHd.dom;
-        var bs = this.mainBody.dom;
-        var lv = this.lockedBody.dom;
-        sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
-        lv.scrollTop = bs.scrollTop = sb.scrollTop;
-    },
-
-    handleScroll : function(e){
-        this.syncScroll();
-        var sb = this.scroller.dom;
-        this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
-        e.stopEvent();
-    },
-
-    handleWheel : function(e){
-        var d = e.getWheelDelta();
-        this.scroller.dom.scrollTop -= d*22;
-        // set this here to prevent jumpy scrolling on large tables
-        this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
-        e.stopEvent();
-    },
 
-    renderRows : function(startRow, endRow){
-        // pull in all the crap needed to render rows
-        var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
-        var colCount = cm.getColumnCount();
-
-        if(ds.getCount() < 1){
-            return ["", ""];
-        }
-
-        // build a map for all the columns
-        var cs = [];
-        for(var i = 0; i < colCount; i++){
-            var name = cm.getDataIndex(i);
-            cs[i] = {
-                name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
-                renderer : cm.getRenderer(i),
-                id : cm.getColumnId(i),
-                locked : cm.isLocked(i),
-                has_editor : cm.isCellEditable(i)
-            };
+    /**
+     * Set a URL to be used to load the content for this panel. When this panel is activated, the content will be loaded from that URL.
+     * @param {String/Function} url The URL to load the content from or a function to call to get the URL
+     * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
+     * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this panel is activated. (Defaults to false)
+     * @return {Roo.UpdateManager} The UpdateManager
+     */
+    setUrl : function(url, params, loadOnce){
+        if(this.refreshDelegate){
+            this.removeListener("activate", this.refreshDelegate);
         }
-
-        startRow = startRow || 0;
-        endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
-
-        // records to render
-        var rs = ds.getRange(startRow, endRow);
-
-        return this.doRender(cs, rs, ds, startRow, colCount, stripe);
+        this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
+        this.on("activate", this.refreshDelegate);
+        return this.el.getUpdateManager();
     },
-
-    // As much as I hate to duplicate code, this was branched because FireFox really hates
-    // [].join("") on strings. The performance difference was substantial enough to
-    // branch this function
-    doRender : Roo.isGecko ?
-            function(cs, rs, ds, startRow, colCount, stripe){
-                var ts = this.templates, ct = ts.cell, rt = ts.row;
-                // buffers
-                var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
-                
-                var hasListener = this.grid.hasListener('rowclass');
-                var rowcfg = {};
-                for(var j = 0, len = rs.length; j < len; j++){
-                    r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
-                    for(var i = 0; i < colCount; i++){
-                        c = cs[i];
-                        p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
-                        p.id = c.id;
-                        p.css = p.attr = "";
-                        p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
-                        if(p.value == undefined || p.value === "") {
-                            p.value = "&#160;";
-                        }
-                        if(c.has_editor){
-                            p.css += ' x-grid-editable-cell';
-                        }
-                        if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
-                            p.css +=  ' x-grid-dirty-cell';
-                        }
-                        var markup = ct.apply(p);
-                        if(!c.locked){
-                            cb+= markup;
-                        }else{
-                            lcb+= markup;
-                        }
-                    }
-                    var alt = [];
-                    if(stripe && ((rowIndex+1) % 2 == 0)){
-                        alt.push("x-grid-row-alt")
-                    }
-                    if(r.dirty){
-                        alt.push(  " x-grid-dirty-row");
-                    }
-                    rp.cells = lcb;
-                    if(this.getRowClass){
-                        alt.push(this.getRowClass(r, rowIndex));
-                    }
-                    if (hasListener) {
-                        rowcfg = {
-                             
-                            record: r,
-                            rowIndex : rowIndex,
-                            rowClass : ''
-                        };
-                        this.grid.fireEvent('rowclass', this, rowcfg);
-                        alt.push(rowcfg.rowClass);
-                    }
-                    rp.alt = alt.join(" ");
-                    lbuf+= rt.apply(rp);
-                    rp.cells = cb;
-                    buf+=  rt.apply(rp);
-                }
-                return [lbuf, buf];
-            } :
-            function(cs, rs, ds, startRow, colCount, stripe){
-                var ts = this.templates, ct = ts.cell, rt = ts.row;
-                // buffers
-                var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
-                var hasListener = this.grid.hasListener('rowclass');
-                var rowcfg = {};
-                for(var j = 0, len = rs.length; j < len; j++){
-                    r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
-                    for(var i = 0; i < colCount; i++){
-                        c = cs[i];
-                        p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
-                        p.id = c.id;
-                        p.css = p.attr = "";
-                        p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
-                        if(p.value == undefined || p.value === "") {
-                            p.value = "&#160;";
-                        }
-                        //Roo.log(c);
-                         if(c.has_editor){
-                            p.css += ' x-grid-editable-cell';
-                        }
-                        if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
-                            p.css += ' x-grid-dirty-cell' 
-                        }
-                        
-                        var markup = ct.apply(p);
-                        if(!c.locked){
-                            cb[cb.length] = markup;
-                        }else{
-                            lcb[lcb.length] = markup;
-                        }
-                    }
-                    var alt = [];
-                    if(stripe && ((rowIndex+1) % 2 == 0)){
-                        alt.push( "x-grid-row-alt");
-                    }
-                    if(r.dirty){
-                        alt.push(" x-grid-dirty-row");
-                    }
-                    rp.cells = lcb;
-                    if(this.getRowClass){
-                        alt.push( this.getRowClass(r, rowIndex));
-                    }
-                    if (hasListener) {
-                        rowcfg = {
-                             
-                            record: r,
-                            rowIndex : rowIndex,
-                            rowClass : ''
-                        };
-                        this.grid.fireEvent('rowclass', this, rowcfg);
-                        alt.push(rowcfg.rowClass);
-                    }
-                    
-                    rp.alt = alt.join(" ");
-                    rp.cells = lcb.join("");
-                    lbuf[lbuf.length] = rt.apply(rp);
-                    rp.cells = cb.join("");
-                    buf[buf.length] =  rt.apply(rp);
-                }
-                return [lbuf.join(""), buf.join("")];
-            },
-
-    renderBody : function(){
-        var markup = this.renderRows();
-        var bt = this.templates.body;
-        return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
+    
+    _handleRefresh : function(url, params, loadOnce){
+        if(!loadOnce || !this.loaded){
+            var updater = this.el.getUpdateManager();
+            updater.update(url, params, this._setLoaded.createDelegate(this));
+        }
     },
-
+    
+    _setLoaded : function(){
+        this.loaded = true;
+    }, 
+    
     /**
-     * Refreshes the grid
-     * @param {Boolean} headersToo
+     * Returns this panel's id
+     * @return {String} 
      */
-    refresh : function(headersToo){
-        this.fireEvent("beforerefresh", this);
-        this.grid.stopEditing();
-        var result = this.renderBody();
-        this.lockedBody.update(result[0]);
-        this.mainBody.update(result[1]);
-        if(headersToo === true){
-            this.updateHeaders();
-            this.updateColumns();
-            this.updateSplitters();
-            this.updateHeaderSortState();
-        }
-        this.syncRowHeights();
-        this.layout();
-        this.fireEvent("refresh", this);
+    getId : function(){
+        return this.el.id;
     },
-
-    handleColumnMove : function(cm, oldIndex, newIndex){
-        this.indexMap = null;
-        var s = this.getScrollState();
-        this.refresh(true);
-        this.restoreScroll(s);
-        this.afterMove(newIndex);
+    
+    /** 
+     * Returns this panel's element - used by regiosn to add.
+     * @return {Roo.Element} 
+     */
+    getEl : function(){
+        return this.wrapEl || this.el;
     },
-
-    afterMove : function(colIndex){
-        if(this.enableMoveAnim && Roo.enableFx){
-            this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
+    
+    adjustForComponents : function(width, height)
+    {
+        //Roo.log('adjustForComponents ');
+        if(this.resizeEl != this.el){
+            width -= this.el.getFrameWidth('lr');
+            height -= this.el.getFrameWidth('tb');
         }
-        // if multisort - fix sortOrder, and reload..
-        if (this.grid.dataSource.multiSort) {
-            // the we can call sort again..
-            var dm = this.grid.dataSource;
-            var cm = this.grid.colModel;
-            var so = [];
-            for(var i = 0; i < cm.config.length; i++ ) {
-                
-                if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
-                    continue; // dont' bother, it's not in sort list or being set.
-                }
-                
-                so.push(cm.config[i].dataIndex);
-            };
-            dm.sortOrder = so;
-            dm.load(dm.lastOptions);
-            
+        if(this.toolbar){
+            var te = this.toolbar.getEl();
+            height -= te.getHeight();
+            te.setWidth(width);
+        }
+        if(this.footer){
+            var te = this.footer.getEl();
+            //Roo.log("footer:" + te.getHeight());
             
+            height -= te.getHeight();
+            te.setWidth(width);
         }
         
-    },
-
-    updateCell : function(dm, rowIndex, dataIndex){
-        var colIndex = this.getColumnIndexByDataIndex(dataIndex);
-        if(typeof colIndex == "undefined"){ // not present in grid
-            return;
-        }
-        var cm = this.grid.colModel;
-        var cell = this.getCell(rowIndex, colIndex);
-        var cellText = this.getCellText(rowIndex, colIndex);
-
-        var p = {
-            cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
-            id : cm.getColumnId(colIndex),
-            css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
-        };
-        var renderer = cm.getRenderer(colIndex);
-        var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
-        if(typeof val == "undefined" || val === "") {
-            val = "&#160;";
+        
+        if(this.adjustments){
+            width += this.adjustments[0];
+            height += this.adjustments[1];
         }
-        cellText.innerHTML = val;
-        cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
-        this.syncRowHeights(rowIndex, rowIndex);
+        return {"width": width, "height": height};
     },
-
-    calcColumnWidth : function(colIndex, maxRowsToMeasure){
-        var maxWidth = 0;
-        if(this.grid.autoSizeHeaders){
-            var h = this.getHeaderCellMeasure(colIndex);
-            maxWidth = Math.max(maxWidth, h.scrollWidth);
-        }
-        var tb, index;
-        if(this.cm.isLocked(colIndex)){
-            tb = this.getLockedTable();
-            index = colIndex;
-        }else{
-            tb = this.getBodyTable();
-            index = colIndex - this.cm.getLockedCount();
-        }
-        if(tb && tb.rows){
-            var rows = tb.rows;
-            var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
-            for(var i = 0; i < stopIndex; i++){
-                var cell = rows[i].childNodes[index].firstChild;
-                maxWidth = Math.max(maxWidth, cell.scrollWidth);
+    
+    setSize : function(width, height){
+        if(this.fitToFrame && !this.ignoreResize(width, height)){
+            if(this.fitContainer && this.resizeEl != this.el){
+                this.el.setSize(width, height);
             }
+            var size = this.adjustForComponents(width, height);
+            this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
+            this.fireEvent('resize', this, size.width, size.height);
         }
-        return maxWidth + /*margin for error in IE*/ 5;
     },
+    
     /**
-     * Autofit a column to its content.
-     * @param {Number} colIndex
-     * @param {Boolean} forceMinSize true to force the column to go smaller if possible
+     * Returns this panel's title
+     * @return {String} 
      */
-     autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
-         if(this.cm.isHidden(colIndex)){
-             return; // can't calc a hidden column
-         }
-        if(forceMinSize){
-            var cid = this.cm.getColumnId(colIndex);
-            this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
-           if(this.grid.autoSizeHeaders){
-               this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
-           }
-        }
-        var newWidth = this.calcColumnWidth(colIndex);
-        this.cm.setColumnWidth(colIndex,
-            Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
-        if(!suppressEvent){
-            this.grid.fireEvent("columnresize", colIndex, newWidth);
-        }
+    getTitle : function(){
+        return this.title;
     },
-
+    
     /**
-     * Autofits all columns to their content and then expands to fit any extra space in the grid
+     * Set this panel's title
+     * @param {String} title
      */
-     autoSizeColumns : function(){
-        var cm = this.grid.colModel;
-        var colCount = cm.getColumnCount();
-        for(var i = 0; i < colCount; i++){
-            this.autoSizeColumn(i, true, true);
-        }
-        if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
-            this.fitColumns();
-        }else{
-            this.updateColumns();
-            this.layout();
+    setTitle : function(title){
+        this.title = title;
+        if(this.region){
+            this.region.updatePanelTitle(this, title);
         }
     },
-
+    
     /**
-     * Autofits all columns to the grid's width proportionate with their current size
-     * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
+     * Returns true is this panel was configured to be closable
+     * @return {Boolean} 
      */
-    fitColumns : function(reserveScrollSpace){
-        var cm = this.grid.colModel;
-        var colCount = cm.getColumnCount();
-        var cols = [];
-        var width = 0;
-        var i, w;
-        for (i = 0; i < colCount; i++){
-            if(!cm.isHidden(i) && !cm.isFixed(i)){
-                w = cm.getColumnWidth(i);
-                cols.push(i);
-                cols.push(w);
-                width += w;
-            }
-        }
-        var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
-        if(reserveScrollSpace){
-            avail -= 17;
-        }
-        var frac = (avail - cm.getTotalWidth())/width;
-        while (cols.length){
-            w = cols.pop();
-            i = cols.pop();
-            cm.setColumnWidth(i, Math.floor(w + w*frac), true);
-        }
-        this.updateColumns();
-        this.layout();
+    isClosable : function(){
+        return this.closable;
     },
-
-    onRowSelect : function(rowIndex){
-        var row = this.getRowComposite(rowIndex);
-        row.addClass("x-grid-row-selected");
+    
+    beforeSlide : function(){
+        this.el.clip();
+        this.resizeEl.clip();
     },
-
-    onRowDeselect : function(rowIndex){
-        var row = this.getRowComposite(rowIndex);
-        row.removeClass("x-grid-row-selected");
+    
+    afterSlide : function(){
+        this.el.unclip();
+        this.resizeEl.unclip();
     },
-
-    onCellSelect : function(row, col){
-        var cell = this.getCell(row, col);
-        if(cell){
-            Roo.fly(cell).addClass("x-grid-cell-selected");
+    
+    /**
+     *   Force a content refresh from the URL specified in the {@link #setUrl} method.
+     *   Will fail silently if the {@link #setUrl} method has not been called.
+     *   This does not activate the panel, just updates its content.
+     */
+    refresh : function(){
+        if(this.refreshDelegate){
+           this.loaded = false;
+           this.refreshDelegate();
         }
     },
-
-    onCellDeselect : function(row, col){
-        var cell = this.getCell(row, col);
-        if(cell){
-            Roo.fly(cell).removeClass("x-grid-cell-selected");
-        }
+    
+    /**
+     * Destroys this panel
+     */
+    destroy : function(){
+        this.el.removeAllListeners();
+        var tempEl = document.createElement("span");
+        tempEl.appendChild(this.el.dom);
+        tempEl.innerHTML = "";
+        this.el.remove();
+        this.el = null;
     },
+    
+    /**
+     * form - if the content panel contains a form - this is a reference to it.
+     * @type {Roo.form.Form}
+     */
+    form : false,
+    /**
+     * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
+     *    This contains a reference to it.
+     * @type {Roo.View}
+     */
+    view : false,
+    
+      /**
+     * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
+     * <pre><code>
 
-    updateHeaderSortState : function(){
-        
-        // sort state can be single { field: xxx, direction : yyy}
-        // or   { xxx=>ASC , yyy : DESC ..... }
-        
-        var mstate = {};
-        if (!this.ds.multiSort) { 
-            var state = this.ds.getSortState();
-            if(!state){
-                return;
-            }
-            mstate[state.field] = state.direction;
-            // FIXME... - this is not used here.. but might be elsewhere..
-            this.sortState = state;
-            
-        } else {
-            mstate = this.ds.sortToggle;
-        }
-        //remove existing sort classes..
-        
-        var sc = this.sortClasses;
-        var hds = this.el.select(this.headerSelector).removeClass(sc);
-        
-        for(var f in mstate) {
-        
-            var sortColumn = this.cm.findColumnIndex(f);
-            
-            if(sortColumn != -1){
-                var sortDir = mstate[f];        
-                hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
-            }
-        }
-        
-         
-        
-    },
+layout.addxtype({
+       xtype : 'Form',
+       items: [ .... ]
+   }
+);
 
+</code></pre>
+     * @param {Object} cfg Xtype definition of item to add.
+     */
+    
+    addxtype : function(cfg) {
+        if(cfg.xtype.match(/^UploadCropbox$/)) {
 
-    handleHeaderClick : function(g, index,e){
-        
-        Roo.log("header click");
-        
-        if (Roo.isTouch) {
-            // touch events on header are handled by context
-            this.handleHdCtx(g,index,e);
-            return;
+            this.cropbox = new Roo.factory(cfg);
+
+            this.cropbox.render(this.el);
+
+            return this.cropbox;
         }
-        
-        
-        if(this.headersDisabled){
-            return;
+        // add form..
+        if (cfg.xtype.match(/^Form$/)) {
+            
+            var el;
+            //if (this.footer) {
+            //    el = this.footer.container.insertSibling(false, 'before');
+            //} else {
+                el = this.el.createChild();
+            //}
+
+            this.form = new  Roo.form.Form(cfg);
+            
+            
+            if ( this.form.allItems.length) {
+                this.form.render(el.dom);
+            }
+            return this.form;
         }
-        var dm = g.dataSource, cm = g.colModel;
-        if(!cm.isSortable(index)){
-            return;
+        // should only have one of theses..
+        if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
+            // views.. should not be just added - used named prop 'view''
+            
+            cfg.el = this.el.appendChild(document.createElement("div"));
+            // factory?
+            
+            var ret = new Roo.factory(cfg);
+             
+             ret.render && ret.render(false, ''); // render blank..
+            this.view = ret;
+            return ret;
         }
-        g.stopEditing();
+        return false;
+    }
+});
+
+
+
+
+
+
+
+
+
+
+
+
+/**
+ * @class Roo.GridPanel
+ * @extends Roo.ContentPanel
+ * @parent Roo.BorderLayout Roo.LayoutDialog builder
+ * @constructor
+ * Create a new GridPanel.
+ * @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);
         
-        if (dm.multiSort) {
-            // update the sortOrder
-            var so = [];
-            for(var i = 0; i < cm.config.length; i++ ) {
-                
-                if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
-                    continue; // dont' bother, it's not in sort list or being set.
-                }
-                
-                so.push(cm.config[i].dataIndex);
-            };
-            dm.sortOrder = so;
-        }
+    this.wrapper.dom.appendChild(grid.getGridEl().dom);
+    
+    Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
+    
+    if(this.toolbar){
+        this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
+    }
+    // xtype created footer. - not sure if will work as we normally have to render first..
+    if (this.footer && !this.footer.el && this.footer.xtype) {
         
+        this.footer.container = this.grid.getView().getFooterPanel(true);
+        this.footer.dataSource = this.grid.dataSource;
+        this.footer = Roo.factory(this.footer, Roo);
         
-        dm.sort(cm.getDataIndex(index));
-    },
-
+    }
+    
+    grid.monitorWindowResize = false; // turn off autosizing
+    grid.autoHeight = false;
+    grid.autoWidth = false;
+    this.grid = grid;
+    this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
+};
 
-    destroy : function(){
-        if(this.colMenu){
-            this.colMenu.removeAll();
-            Roo.menu.MenuMgr.unregister(this.colMenu);
-            this.colMenu.getEl().remove();
-            delete this.colMenu;
-        }
-        if(this.hmenu){
-            this.hmenu.removeAll();
-            Roo.menu.MenuMgr.unregister(this.hmenu);
-            this.hmenu.getEl().remove();
-            delete this.hmenu;
-        }
-        if(this.grid.enableColumnMove){
-            var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
-            if(dds){
-                for(var dd in dds){
-                    if(!dds[dd].config.isTarget && dds[dd].dragElId){
-                        var elid = dds[dd].dragElId;
-                        dds[dd].unreg();
-                        Roo.get(elid).remove();
-                    } else if(dds[dd].config.isTarget){
-                        dds[dd].proxyTop.remove();
-                        dds[dd].proxyBottom.remove();
-                        dds[dd].unreg();
-                    }
-                    if(Roo.dd.DDM.locationCache[dd]){
-                        delete Roo.dd.DDM.locationCache[dd];
-                    }
-                }
-                delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
-            }
+Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
+    getId : function(){
+        return this.grid.id;
+    },
+    
+    /**
+     * Returns the grid for this panel
+     * @return {Roo.grid.Grid} 
+     */
+    getGrid : function(){
+        return this.grid;    
+    },
+    
+    setSize : function(width, height){
+        if(!this.ignoreResize(width, height)){
+            var grid = this.grid;
+            var size = this.adjustForComponents(width, height);
+            grid.getGridEl().setSize(size.width, size.height);
+            grid.autoSize();
         }
-        Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
-        this.bind(null, null);
-        Roo.EventManager.removeResizeListener(this.onWindowResize, this);
     },
-
-    handleLockChange : function(){
-        this.refresh(true);
+    
+    beforeSlide : function(){
+        this.grid.getView().scroller.clip();
+    },
+    
+    afterSlide : function(){
+        this.grid.getView().scroller.unclip();
     },
+    
+    destroy : function(){
+        this.grid.destroy();
+        delete this.grid;
+        Roo.GridPanel.superclass.destroy.call(this); 
+    }
+});
 
-    onDenyColumnLock : function(){
 
-    },
+/**
+ * @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 [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)
+{
+    // construct with only one argument..
+    /* FIXME - implement nicer consturctors
+    if (layout.layout) {
+        config = layout;
+        layout = config.layout;
+        delete config.layout;
+    }
+    if (layout.xtype && !layout.getEl) {
+        // then layout needs constructing..
+        layout = Roo.factory(layout, Roo);
+    }
+    */
+    
+    
+    Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
+    
+    layout.monitorWindowResize = false; // turn off autosizing
+    this.layout = layout;
+    this.layout.getEl().addClass("x-layout-nested-layout");
+    
+    
+    
+    
+};
 
-    onDenyColumnHide : function(){
+Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
 
-    },
+    layout : false,
 
-    handleHdMenuClick : function(item){
-        var index = this.hdCtxIndex;
-        var cm = this.cm, ds = this.ds;
-        switch(item.id){
-            case "asc":
-                ds.sort(cm.getDataIndex(index), "ASC");
-                break;
-            case "desc":
-                ds.sort(cm.getDataIndex(index), "DESC");
-                break;
-            case "lock":
-                var lc = cm.getLockedCount();
-                if(cm.getColumnCount(true) <= lc+1){
-                    this.onDenyColumnLock();
-                    return;
-                }
-                if(lc != index){
-                    cm.setLocked(index, true, true);
-                    cm.moveColumn(index, lc);
-                    this.grid.fireEvent("columnmove", index, lc);
-                }else{
-                    cm.setLocked(index, true);
-                }
-            break;
-            case "unlock":
-                var lc = cm.getLockedCount();
-                if((lc-1) != index){
-                    cm.setLocked(index, false, true);
-                    cm.moveColumn(index, lc-1);
-                    this.grid.fireEvent("columnmove", index, lc-1);
-                }else{
-                    cm.setLocked(index, false);
-                }
-            break;
-            case 'wider': // used to expand cols on touch..
-            case 'narrow':
-                var cw = cm.getColumnWidth(index);
-                cw += (item.id == 'wider' ? 1 : -1) * 50;
-                cw = Math.max(0, cw);
-                cw = Math.min(cw,4000);
-                cm.setColumnWidth(index, cw);
-                break;
-                
-            default:
-                index = cm.getIndexById(item.id.substr(4));
-                if(index != -1){
-                    if(item.checked && cm.getColumnCount(true) <= 1){
-                        this.onDenyColumnHide();
-                        return false;
-                    }
-                    cm.setHidden(index, item.checked);
-                }
+    setSize : function(width, height){
+        if(!this.ignoreResize(width, height)){
+            var size = this.adjustForComponents(width, height);
+            var el = this.layout.getEl();
+            el.setSize(size.width, size.height);
+            var touch = el.dom.offsetWidth;
+            this.layout.layout();
+            // ie requires a double layout on the first pass
+            if(Roo.isIE && !this.initialized){
+                this.initialized = true;
+                this.layout.layout();
+            }
         }
-        return true;
     },
-
-    beforeColMenuShow : function(){
-        var cm = this.cm,  colCount = cm.getColumnCount();
-        this.colMenu.removeAll();
-        for(var i = 0; i < colCount; i++){
-            this.colMenu.add(new Roo.menu.CheckItem({
-                id: "col-"+cm.getColumnId(i),
-                text: cm.getColumnHeader(i),
-                checked: !cm.isHidden(i),
-                hideOnClick:false
-            }));
+    
+    // activate all subpanels if not currently active..
+    
+    setActiveState : function(active){
+        this.active = active;
+        if(!active){
+            this.fireEvent("deactivate", this);
+            return;
         }
-    },
-
-    handleHdCtx : function(g, index, e){
-        e.stopEvent();
-        var hd = this.getHeaderCell(index);
-        this.hdCtxIndex = index;
-        var ms = this.hmenu.items, cm = this.cm;
-        ms.get("asc").setDisabled(!cm.isSortable(index));
-        ms.get("desc").setDisabled(!cm.isSortable(index));
-        if(this.grid.enableColLock !== false){
-            ms.get("lock").setDisabled(cm.isLocked(index));
-            ms.get("unlock").setDisabled(!cm.isLocked(index));
+        
+        this.fireEvent("activate", this);
+        // not sure if this should happen before or after..
+        if (!this.layout) {
+            return; // should not happen..
         }
-        this.hmenu.show(hd, "tl-bl");
-    },
-
-    handleHdOver : function(e){
-        var hd = this.findHeaderCell(e.getTarget());
-        if(hd && !this.headersDisabled){
-            if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
-               this.fly(hd).addClass("x-grid-hd-over");
+        var reg = false;
+        for (var r in this.layout.regions) {
+            reg = this.layout.getRegion(r);
+            if (reg.getActivePanel()) {
+                //reg.showPanel(reg.getActivePanel()); // force it to activate.. 
+                reg.setActivePanel(reg.getActivePanel());
+                continue;
+            }
+            if (!reg.panels.length) {
+                continue;
             }
+            reg.showPanel(reg.getPanel(0));
         }
+        
+        
+        
+        
     },
-
-    handleHdOut : function(e){
-        var hd = this.findHeaderCell(e.getTarget());
-        if(hd){
-            this.fly(hd).removeClass("x-grid-hd-over");
-        }
+    
+    /**
+     * Returns the nested BorderLayout for this panel
+     * @return {Roo.BorderLayout}
+     */
+    getLayout : function(){
+        return this.layout;
     },
+    
+     /**
+     * Adds a xtype elements to the layout of the nested panel
+     * <pre><code>
 
-    handleSplitDblClick : function(e, t){
-        var i = this.getCellIndex(t);
-        if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
-            this.autoSizeColumn(i, true);
-            this.layout();
-        }
-    },
+panel.addxtype({
+       xtype : 'ContentPanel',
+       region: 'west',
+       items: [ .... ]
+   }
+);
 
-    render : function(){
+panel.addxtype({
+        xtype : 'NestedLayoutPanel',
+        region: 'west',
+        layout: {
+           center: { },
+           west: { }   
+        },
+        items : [ ... list of content panels or nested layout panels.. ]
+   }
+);
+</code></pre>
+     * @param {Object} cfg Xtype definition of item to add.
+     */
+    addxtype : function(cfg) {
+        return this.layout.addxtype(cfg);
+    
+    }
+});
 
-        var cm = this.cm;
-        var colCount = cm.getColumnCount();
+Roo.ScrollPanel = function(el, config, content){
+    config = config || {};
+    config.fitToFrame = true;
+    Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
+    
+    this.el.dom.style.overflow = "hidden";
+    var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
+    this.el.removeClass("x-layout-inactive-content");
+    this.el.on("mousewheel", this.onWheel, this);
 
-        if(this.grid.monitorWindowResize === true){
-            Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
-        }
-        var header = this.renderHeaders();
-        var body = this.templates.body.apply({rows:""});
-        var html = this.templates.master.apply({
-            lockedBody: body,
-            body: body,
-            lockedHeader: header[0],
-            header: header[1]
-        });
+    var up = wrap.createChild({cls: "x-scroller-up", html: "&#160;"}, this.el.dom);
+    var down = wrap.createChild({cls: "x-scroller-down", html: "&#160;"});
+    up.unselectable(); down.unselectable();
+    up.on("click", this.scrollUp, this);
+    down.on("click", this.scrollDown, this);
+    up.addClassOnOver("x-scroller-btn-over");
+    down.addClassOnOver("x-scroller-btn-over");
+    up.addClassOnClick("x-scroller-btn-click");
+    down.addClassOnClick("x-scroller-btn-click");
+    this.adjustments = [0, -(up.getHeight() + down.getHeight())];
 
-        //this.updateColumns();
+    this.resizeEl = this.el;
+    this.el = wrap; this.up = up; this.down = down;
+};
 
-        this.grid.getGridEl().dom.innerHTML = html;
+Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
+    increment : 100,
+    wheelIncrement : 5,
+    scrollUp : function(){
+        this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
+    },
 
-        this.initElements();
-        
-        // a kludge to fix the random scolling effect in webkit
-        this.el.on("scroll", function() {
-            this.el.dom.scrollTop=0; // hopefully not recursive..
-        },this);
+    scrollDown : function(){
+        this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
+    },
 
-        this.scroller.on("scroll", this.handleScroll, this);
-        this.lockedBody.on("mousewheel", this.handleWheel, this);
-        this.mainBody.on("mousewheel", this.handleWheel, this);
+    afterScroll : function(){
+        var el = this.resizeEl;
+        var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
+        this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
+        this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
+    },
 
-        this.mainHd.on("mouseover", this.handleHdOver, this);
-        this.mainHd.on("mouseout", this.handleHdOut, this);
-        this.mainHd.on("dblclick", this.handleSplitDblClick, this,
-                {delegate: "."+this.splitClass});
+    setSize : function(){
+        Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
+        this.afterScroll();
+    },
 
-        this.lockedHd.on("mouseover", this.handleHdOver, this);
-        this.lockedHd.on("mouseout", this.handleHdOut, this);
-        this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
-                {delegate: "."+this.splitClass});
+    onWheel : function(e){
+        var d = e.getWheelDelta();
+        this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
+        this.afterScroll();
+        e.stopEvent();
+    },
 
-        if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
-            new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
-        }
+    setContent : function(content, loadScripts){
+        this.resizeEl.update(content, loadScripts);
+    }
 
-        this.updateSplitters();
+});
 
-        if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
-            new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
-            new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
-        }
 
-        if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
-            this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
-            this.hmenu.add(
-                {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
-                {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
-            );
-            if(this.grid.enableColLock !== false){
-                this.hmenu.add('-',
-                    {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
-                    {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
-                );
-            }
-            if (Roo.isTouch) {
-                 this.hmenu.add('-',
-                    {id:"wider", text: this.columnsWiderText},
-                    {id:"narrow", text: this.columnsNarrowText }
-                );
-                
-                 
-            }
-            
-            if(this.grid.enableColumnHide !== false){
-
-                this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
-                this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
-                this.colMenu.on("itemclick", this.handleHdMenuClick, this);
-
-                this.hmenu.add('-',
-                    {id:"columns", text: this.columnsText, menu: this.colMenu}
-                );
-            }
-            this.hmenu.on("itemclick", this.handleHdMenuClick, this);
-
-            this.grid.on("headercontextmenu", this.handleHdCtx, this);
-        }
-
-        if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
-            this.dd = new Roo.grid.GridDragZone(this.grid, {
-                ddGroup : this.grid.ddGroup || 'GridDD'
-            });
-            
-        }
-
-        /*
-        for(var i = 0; i < colCount; i++){
-            if(cm.isHidden(i)){
-                this.hideColumn(i);
-            }
-            if(cm.config[i].align){
-                this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
-                this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
-            }
-        }*/
-        
-        this.updateHeaderSortState();
-
-        this.beforeInitialResize();
-        this.layout(true);
-
-        // two part rendering gives faster view to the user
-        this.renderPhase2.defer(1, this);
-    },
-
-    renderPhase2 : function(){
-        // render the rows now
-        this.refresh();
-        if(this.grid.autoSizeColumns){
-            this.autoSizeColumns();
-        }
-    },
-
-    beforeInitialResize : function(){
-
-    },
-
-    onColumnSplitterMoved : function(i, w){
-        this.userResized = true;
-        var cm = this.grid.colModel;
-        cm.setColumnWidth(i, w, true);
-        var cid = cm.getColumnId(i);
-        this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
-        this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
-        this.updateSplitters();
-        this.layout();
-        this.grid.fireEvent("columnresize", i, w);
-    },
-
-    syncRowHeights : function(startIndex, endIndex){
-        if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
-            startIndex = startIndex || 0;
-            var mrows = this.getBodyTable().rows;
-            var lrows = this.getLockedTable().rows;
-            var len = mrows.length-1;
-            endIndex = Math.min(endIndex || len, len);
-            for(var i = startIndex; i <= endIndex; i++){
-                var m = mrows[i], l = lrows[i];
-                var h = Math.max(m.offsetHeight, l.offsetHeight);
-                m.style.height = l.style.height = h + "px";
-            }
-        }
-    },
-
-    layout : function(initialRender, is2ndPass){
-        var g = this.grid;
-        var auto = g.autoHeight;
-        var scrollOffset = 16;
-        var c = g.getGridEl(), cm = this.cm,
-                expandCol = g.autoExpandColumn,
-                gv = this;
-        //c.beginMeasure();
 
-        if(!c.dom.offsetWidth){ // display:none?
-            if(initialRender){
-                this.lockedWrap.show();
-                this.mainWrap.show();
-            }
+/**
+ * @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
+ */
+Roo.TreePanel = function(config){
+    var el = config.el;
+    var tree = config.tree;
+    delete config.tree; 
+    delete config.el; // hopefull!
+    
+    // wrapper for IE7 strict & safari scroll issue
+    
+    var treeEl = el.createChild();
+    config.resizeEl = treeEl;
+    
+    
+    
+    Roo.TreePanel.superclass.constructor.call(this, el, config);
+    this.tree = new Roo.tree.TreePanel(treeEl , tree);
+    //console.log(tree);
+    this.on('activate', function()
+    {
+        if (this.tree.rendered) {
             return;
         }
+        //console.log('render tree');
+        this.tree.render();
+    });
+    // this should not be needed.. - it's actually the 'el' that resizes?
+    // actuall it breaks the containerScroll - dragging nodes auto scroll at top
+    
+    //this.on('resize',  function (cp, w, h) {
+    //        this.tree.innerCt.setWidth(w);
+    //        this.tree.innerCt.setHeight(h);
+    //        //this.tree.innerCt.setStyle('overflow-y', 'auto');
+    //});
 
-        var hasLock = this.cm.isLocked(0);
-
-        var tbh = this.headerPanel.getHeight();
-        var bbh = this.footerPanel.getHeight();
-
-        if(auto){
-            var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
-            var newHeight = ch + c.getBorderWidth("tb");
-            if(g.maxHeight){
-                newHeight = Math.min(g.maxHeight, newHeight);
-            }
-            c.setHeight(newHeight);
-        }
-
-        if(g.autoWidth){
-            c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
-        }
-
-        var s = this.scroller;
-
-        var csize = c.getSize(true);
-
-        this.el.setSize(csize.width, csize.height);
-
-        this.headerPanel.setWidth(csize.width);
-        this.footerPanel.setWidth(csize.width);
-
-        var hdHeight = this.mainHd.getHeight();
-        var vw = csize.width;
-        var vh = csize.height - (tbh + bbh);
-
-        s.setSize(vw, vh);
-
-        var bt = this.getBodyTable();
-        
-        if(cm.getLockedCount() == cm.config.length){
-            bt = this.getLockedTable();
-        }
         
-        var ltWidth = hasLock ?
-                      Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
-
-        var scrollHeight = bt.offsetHeight;
-        var scrollWidth = ltWidth + bt.offsetWidth;
-        var vscroll = false, hscroll = false;
-
-        this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
-
-        var lw = this.lockedWrap, mw = this.mainWrap;
-        var lb = this.lockedBody, mb = this.mainBody;
-
-        setTimeout(function(){
-            var t = s.dom.offsetTop;
-            var w = s.dom.clientWidth,
-                h = s.dom.clientHeight;
-
-            lw.setTop(t);
-            lw.setSize(ltWidth, h);
-
-            mw.setLeftTop(ltWidth, t);
-            mw.setSize(w-ltWidth, h);
-
-            lb.setHeight(h-hdHeight);
-            mb.setHeight(h-hdHeight);
-
-            if(is2ndPass !== true && !gv.userResized && expandCol){
-                // high speed resize without full column calculation
-                
-                var ci = cm.getIndexById(expandCol);
-                if (ci < 0) {
-                    ci = cm.findColumnIndex(expandCol);
-                }
-                ci = Math.max(0, ci); // make sure it's got at least the first col.
-                var expandId = cm.getColumnId(ci);
-                var  tw = cm.getTotalWidth(false);
-                var currentWidth = cm.getColumnWidth(ci);
-                var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
-                if(currentWidth != cw){
-                    cm.setColumnWidth(ci, cw, true);
-                    gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
-                    gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
-                    gv.updateSplitters();
-                    gv.layout(false, true);
-                }
-            }
-
-            if(initialRender){
-                lw.show();
-                mw.show();
-            }
-            //c.endMeasure();
-        }, 10);
-    },
-
-    onWindowResize : function(){
-        if(!this.grid.monitorWindowResize || this.grid.autoHeight){
-            return;
-        }
-        this.layout();
-    },
-
-    appendFooter : function(parentEl){
-        return null;
-    },
-
-    sortAscText : "Sort Ascending",
-    sortDescText : "Sort Descending",
-    lockText : "Lock Column",
-    unlockText : "Unlock Column",
-    columnsText : "Columns",
-    columnsWiderText : "Wider",
-    columnsNarrowText : "Thinner"
-});
-
-
-Roo.grid.GridView.ColumnDragZone = function(grid, hd){
-    Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
-    this.proxy.el.addClass('x-grid3-col-dd');
+    
 };
 
-Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
-    handleMouseDown : function(e){
-
-    },
+Roo.extend(Roo.TreePanel, Roo.ContentPanel, {   
+    fitToFrame : true,
+    autoScroll : true,
+    /*
+     * @cfg {Roo.tree.TreePanel} tree [required] The tree TreePanel, with config etc.
+     */
+    tree : false
 
-    callHandleMouseDown : function(e){
-        Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
-    }
 });
 /*
  * Based on:
@@ -57196,62 +61562,104 @@ Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
  * <script type="text/javascript">
  */
  
-// 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
+
+/**
+ * @class Roo.ReaderLayout
+ * @extends Roo.BorderLayout
+ * This is a pre-built layout that represents a classic, 5-pane application.  It consists of a header, a primary
+ * center region containing two nested regions (a top one for a list view and one for item preview below),
+ * and regions on either side that can be used for navigation, application commands, informational displays, etc.
+ * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
+ * expedites the setup of the overall layout and regions for this common application style.
+ * Example:
+ <pre><code>
+var reader = new Roo.ReaderLayout();
+var CP = Roo.ContentPanel;  // shortcut for adding
+
+reader.beginUpdate();
+reader.add("north", new CP("north", "North"));
+reader.add("west", new CP("west", {title: "West"}));
+reader.add("east", new CP("east", {title: "East"}));
+
+reader.regions.listView.add(new CP("listView", "List"));
+reader.regions.preview.add(new CP("preview", "Preview"));
+reader.endUpdate();
+</code></pre>
+* @constructor
+* Create a new ReaderLayout
+* @param {Object} config Configuration options
+* @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
+* document.body if omitted)
+*/
+Roo.ReaderLayout = function(config, renderTo){
+    var c = config || {size:{}};
+    Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
+        north: c.north !== false ? Roo.apply({
+            split:false,
+            initialSize: 32,
+            titlebar: false
+        }, c.north) : false,
+        west: c.west !== false ? Roo.apply({
+            split:true,
+            initialSize: 200,
+            minSize: 175,
+            maxSize: 400,
+            titlebar: true,
+            collapsible: true,
+            animate: true,
+            margins:{left:5,right:0,bottom:5,top:5},
+            cmargins:{left:5,right:5,bottom:5,top:5}
+        }, c.west) : false,
+        east: c.east !== false ? Roo.apply({
+            split:true,
+            initialSize: 200,
+            minSize: 175,
+            maxSize: 400,
+            titlebar: true,
+            collapsible: true,
+            animate: true,
+            margins:{left:0,right:5,bottom:5,top:5},
+            cmargins:{left:5,right:5,bottom:5,top:5}
+        }, c.east) : false,
+        center: Roo.apply({
+            tabPosition: 'top',
+            autoScroll:false,
+            closeOnTab: true,
+            titlebar:false,
+            margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
+        }, c.center)
     });
-    this.setHandleElId(Roo.id(hd));
-    this.setOuterHandleElId(Roo.id(hd2));
-    this.scroll = false;
-};
-Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
-    fly: Roo.Element.fly,
 
-    b4StartDrag : function(x, y){
-        this.view.headersDisabled = true;
-        this.proxy.setHeight(this.view.mainWrap.getHeight());
-        var w = this.cm.getColumnWidth(this.cellIndex);
-        var minw = Math.max(w-this.grid.minColumnWidth, 0);
-        this.resetConstraints();
-        this.setXConstraint(minw, 1000);
-        this.setYConstraint(0, 0);
-        this.minX = x - minw;
-        this.maxX = x + 1000;
-        this.startPos = x;
-        Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
-    },
+    this.el.addClass('x-reader');
 
+    this.beginUpdate();
 
-    handleMouseDown : function(e){
-        ev = Roo.EventObject.setEvent(e);
-        var t = this.fly(ev.getTarget());
-        if(t.hasClass("x-grid-split")){
-            this.cellIndex = this.view.getCellIndex(t.dom);
-            this.split = t.dom;
-            this.cm = this.grid.colModel;
-            if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
-                Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
-            }
-        }
-    },
+    var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
+        south: c.preview !== false ? Roo.apply({
+            split:true,
+            initialSize: 200,
+            minSize: 100,
+            autoScroll:true,
+            collapsible:true,
+            titlebar: true,
+            cmargins:{top:5,left:0, right:0, bottom:0}
+        }, c.preview) : false,
+        center: Roo.apply({
+            autoScroll:false,
+            titlebar:false,
+            minHeight:200
+        }, c.listView)
+    });
+    this.add('center', new Roo.NestedLayoutPanel(inner,
+            Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
 
-    endDrag : function(e){
-        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);
-    },
+    this.endUpdate();
 
-    autoOffset : function(){
-        this.setDelta(0,0);
-    }
-});/*
+    this.regions.preview = inner.getRegion('south');
+    this.regions.listView = inner.getRegion('center');
+};
+
+Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -57262,645 +61670,792 @@ Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
  * <script type="text/javascript">
  */
  
-// private
-// This is a support class used internally by the Grid components
-Roo.grid.GridDragZone = function(grid, config){
-    this.view = grid.getView();
-    Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
-    if(this.view.lockedBody){
-        this.setHandleElId(Roo.id(this.view.mainBody.dom));
-        this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
+/**
+ * @class Roo.grid.Grid
+ * @extends Roo.util.Observable
+ * This class represents the primary interface of a component based grid control.
+ * <br><br>Usage:<pre><code>
+ var grid = new Roo.grid.Grid("my-container-id", {
+     ds: myDataStore,
+     cm: myColModel,
+     selModel: mySelectionModel,
+     autoSizeColumns: true,
+     monitorWindowResize: false,
+     trackMouseOver: true
+ });
+ // set any options
+ grid.render();
+ * </code></pre>
+ * <b>Common Problems:</b><br/>
+ * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
+ * element will correct this<br/>
+ * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
+ * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
+ * are unpredictable.<br/>
+ * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
+ * grid to calculate dimensions/offsets.<br/>
+  * @constructor
+ * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
+ * The container MUST have some type of size defined for the grid to fill. The container will be
+ * automatically set to position relative if it isn't already.
+ * @param {Object} config A config object that sets properties on this grid.
+ */
+Roo.grid.Grid = function(container, config){
+       // initialize the container
+       this.container = Roo.get(container);
+       this.container.update("");
+       this.container.setStyle("overflow", "hidden");
+    this.container.addClass('x-grid-container');
+
+    this.id = this.container.id;
+
+    Roo.apply(this, config);
+    // check and correct shorthanded configs
+    if(this.ds){
+        this.dataSource = this.ds;
+        delete this.ds;
+    }
+    if(this.cm){
+        this.colModel = this.cm;
+        delete this.cm;
+    }
+    if(this.sm){
+        this.selModel = this.sm;
+        delete this.sm;
     }
-    this.scroll = false;
-    this.grid = grid;
-    this.ddel = document.createElement('div');
-    this.ddel.className = 'x-grid-dd-wrap';
-};
 
-Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
-    ddGroup : "GridDD",
+    if (this.selModel) {
+        this.selModel = Roo.factory(this.selModel, Roo.grid);
+        this.sm = this.selModel;
+        this.sm.xmodule = this.xmodule || false;
+    }
+    if (typeof(this.colModel.config) == 'undefined') {
+        this.colModel = new Roo.grid.ColumnModel(this.colModel);
+        this.cm = this.colModel;
+        this.cm.xmodule = this.xmodule || false;
+    }
+    if (this.dataSource) {
+        this.dataSource= Roo.factory(this.dataSource, Roo.data);
+        this.ds = this.dataSource;
+        this.ds.xmodule = this.xmodule || false;
+         
+    }
+    
+    
+    
+    if(this.width){
+        this.container.setWidth(this.width);
+    }
 
-    getDragData : function(e){
-        var t = Roo.lib.Event.getTarget(e);
-        var rowIndex = this.view.findRowIndex(t);
-        var sm = this.grid.selModel;
-            
-        //Roo.log(rowIndex);
-        
-        if (sm.getSelectedCell) {
-            // cell selection..
-            if (!sm.getSelectedCell()) {
-                return false;
-            }
-            if (rowIndex != sm.getSelectedCell()[0]) {
-                return false;
-            }
-        
-        }
-        
-        if(rowIndex !== false){
-            
-            // if editorgrid.. 
-            
-            
-            //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
-               
-            //if(!sm.isSelected(rowIndex) || e.hasModifier()){
-              //  
-            //}
-            if (e.hasModifier()){
-                sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
-            }
-            
-            Roo.log("getDragData");
-            
-            return {
-                grid: this.grid,
-                ddel: this.ddel,
-                rowIndex: rowIndex,
-                selections:sm.getSelections ? sm.getSelections() : (
-                    sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
-                )
-            };
-        }
-        return false;
-    },
-
-    onInitDrag : function(e){
-        var data = this.dragData;
-        this.ddel.innerHTML = this.grid.getDragDropText();
-        this.proxy.update(this.ddel);
-        // fire start drag?
-    },
-
-    afterRepair : function(){
-        this.dragging = false;
-    },
-
-    getRepairXY : function(e, data){
-        return false;
-    },
-
-    onEndDrag : function(data, e){
-        // fire end drag?
-    },
-
-    onValidDrop : function(dd, e, id){
-        // fire drag drop?
-        this.hideProxy();
-    },
-
-    beforeInvalidDrop : function(e, id){
-
-    }
-});/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-
-/**
- * @class Roo.grid.ColumnModel
- * @extends Roo.util.Observable
- * This is the default implementation of a ColumnModel used by the Grid. It defines
- * the columns in the grid.
- * <br>Usage:<br>
- <pre><code>
- var colModel = new Roo.grid.ColumnModel([
-       {header: "Ticker", width: 60, sortable: true, locked: true},
-       {header: "Company Name", width: 150, sortable: true},
-       {header: "Market Cap.", width: 100, sortable: true},
-       {header: "$ Sales", width: 100, sortable: true, renderer: money},
-       {header: "Employees", width: 100, sortable: true, resizable: false}
- ]);
- </code></pre>
- * <p>
- * The config options listed for this class are options which may appear in each
- * individual column definition.
- * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
- * @constructor
- * @param {Object} config An Array of column config objects. See this class's
- * config objects for details.
-*/
-Roo.grid.ColumnModel = function(config){
-       /**
-     * The config passed into the constructor
-     */
-    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;
+    if(this.height){
+        this.container.setHeight(this.height);
     }
+    /** @private */
+       this.addEvents({
+        // raw events
+        /**
+         * @event click
+         * The raw click event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "click" : true,
+        /**
+         * @event dblclick
+         * The raw dblclick event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "dblclick" : true,
+        /**
+         * @event contextmenu
+         * The raw contextmenu event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "contextmenu" : true,
+        /**
+         * @event mousedown
+         * The raw mousedown event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "mousedown" : true,
+        /**
+         * @event mouseup
+         * The raw mouseup event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "mouseup" : true,
+        /**
+         * @event mouseover
+         * The raw mouseover event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "mouseover" : true,
+        /**
+         * @event mouseout
+         * The raw mouseout event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "mouseout" : true,
+        /**
+         * @event keypress
+         * The raw keypress event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "keypress" : true,
+        /**
+         * @event keydown
+         * The raw keydown event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "keydown" : true,
 
-    /**
-     * The width of columns which have no width specified (defaults to 100)
-     * @type Number
-     */
-    this.defaultWidth = 100;
-
-    /**
-     * Default sortable of columns which have no sortable specified (defaults to false)
-     * @type Boolean
-     */
-    this.defaultSortable = false;
+        // custom events
 
-    this.addEvents({
         /**
-            * @event widthchange
-            * Fires when the width of a column changes.
-            * @param {ColumnModel} this
-            * @param {Number} columnIndex The column index
-            * @param {Number} newWidth The new width
-            */
-           "widthchange": true,
+         * @event cellclick
+         * Fires when a cell is clicked
+         * @param {Grid} this
+         * @param {Number} rowIndex
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "cellclick" : true,
         /**
-            * @event headerchange
-            * Fires when the text of a header changes.
-            * @param {ColumnModel} this
-            * @param {Number} columnIndex The column index
-            * @param {Number} newText The new header text
-            */
-           "headerchange": true,
+         * @event celldblclick
+         * Fires when a cell is double clicked
+         * @param {Grid} this
+         * @param {Number} rowIndex
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "celldblclick" : true,
         /**
-            * @event hiddenchange
-            * Fires when a column is hidden or "unhidden".
-            * @param {ColumnModel} this
-            * @param {Number} columnIndex The column index
-            * @param {Boolean} hidden true if hidden, false otherwise
-            */
-           "hiddenchange": true,
-           /**
-         * @event columnmoved
-         * Fires when a column is moved.
-         * @param {ColumnModel} this
+         * @event rowclick
+         * Fires when a row is clicked
+         * @param {Grid} this
+         * @param {Number} rowIndex
+         * @param {Roo.EventObject} e
+         */
+        "rowclick" : true,
+        /**
+         * @event rowdblclick
+         * Fires when a row is double clicked
+         * @param {Grid} this
+         * @param {Number} rowIndex
+         * @param {Roo.EventObject} e
+         */
+        "rowdblclick" : true,
+        /**
+         * @event headerclick
+         * Fires when a header is clicked
+         * @param {Grid} this
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "headerclick" : true,
+        /**
+         * @event headerdblclick
+         * Fires when a header cell is double clicked
+         * @param {Grid} this
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "headerdblclick" : true,
+        /**
+         * @event rowcontextmenu
+         * Fires when a row is right clicked
+         * @param {Grid} this
+         * @param {Number} rowIndex
+         * @param {Roo.EventObject} e
+         */
+        "rowcontextmenu" : true,
+        /**
+         * @event cellcontextmenu
+         * Fires when a cell is right clicked
+         * @param {Grid} this
+         * @param {Number} rowIndex
+         * @param {Number} cellIndex
+         * @param {Roo.EventObject} e
+         */
+         "cellcontextmenu" : true,
+        /**
+         * @event headercontextmenu
+         * Fires when a header is right clicked
+         * @param {Grid} this
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "headercontextmenu" : true,
+        /**
+         * @event bodyscroll
+         * Fires when the body element is scrolled
+         * @param {Number} scrollLeft
+         * @param {Number} scrollTop
+         */
+        "bodyscroll" : true,
+        /**
+         * @event columnresize
+         * Fires when the user resizes a column
+         * @param {Number} columnIndex
+         * @param {Number} newSize
+         */
+        "columnresize" : true,
+        /**
+         * @event columnmove
+         * Fires when the user moves a column
          * @param {Number} oldIndex
          * @param {Number} newIndex
          */
-        "columnmoved" : true,
+        "columnmove" : true,
         /**
-         * @event columlockchange
-         * Fires when a column's locked state is changed
-         * @param {ColumnModel} this
-         * @param {Number} colIndex
-         * @param {Boolean} locked true if locked
+         * @event startdrag
+         * Fires when row(s) start being dragged
+         * @param {Grid} this
+         * @param {Roo.GridDD} dd The drag drop object
+         * @param {event} e The raw browser event
          */
-        "columnlockchange" : true
+        "startdrag" : true,
+        /**
+         * @event enddrag
+         * Fires when a drag operation is complete
+         * @param {Grid} this
+         * @param {Roo.GridDD} dd The drag drop object
+         * @param {event} e The raw browser event
+         */
+        "enddrag" : true,
+        /**
+         * @event dragdrop
+         * Fires when dragged row(s) are dropped on a valid DD target
+         * @param {Grid} this
+         * @param {Roo.GridDD} dd The drag drop object
+         * @param {String} targetId The target drag drop object
+         * @param {event} e The raw browser event
+         */
+        "dragdrop" : true,
+        /**
+         * @event dragover
+         * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
+         * @param {Grid} this
+         * @param {Roo.GridDD} dd The drag drop object
+         * @param {String} targetId The target drag drop object
+         * @param {event} e The raw browser event
+         */
+        "dragover" : true,
+        /**
+         * @event dragenter
+         *  Fires when the dragged row(s) first cross another DD target while being dragged
+         * @param {Grid} this
+         * @param {Roo.GridDD} dd The drag drop object
+         * @param {String} targetId The target drag drop object
+         * @param {event} e The raw browser event
+         */
+        "dragenter" : true,
+        /**
+         * @event dragout
+         * Fires when the dragged row(s) leave another DD target while being dragged
+         * @param {Grid} this
+         * @param {Roo.GridDD} dd The drag drop object
+         * @param {String} targetId The target drag drop object
+         * @param {event} e The raw browser event
+         */
+        "dragout" : true,
+        /**
+         * @event rowclass
+         * Fires when a row is rendered, so you can change add a style to it.
+         * @param {GridView} gridview   The grid view
+         * @param {Object} rowcfg   contains record  rowIndex and rowClass - set rowClass to add a style.
+         */
+        'rowclass' : true,
+
+        /**
+         * @event render
+         * Fires when the grid is rendered
+         * @param {Grid} grid
+         */
+        'render' : true
     });
-    Roo.grid.ColumnModel.superclass.constructor.call(this);
+
+    Roo.grid.Grid.superclass.constructor.call(this);
 };
-Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
+Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
+    
     /**
-     * @cfg {String} header The header text to display in the Grid view.
+        * @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.data.Store} ds The data store for the grid
+        */
+       /**
+        * @cfg {Roo.Toolbar} toolbar a toolbar for buttons etc.
+        */
+        
+        /**
+        * @cfg {Roo.PagingToolbar} footer the paging toolbar
+        */
+       
+       /**
+     * @cfg {String} ddGroup - drag drop group.
      */
-    /**
-     * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
-     * {@link Roo.data.Record} definition from which to draw the column's value. If not
-     * specified, the column's index is used as an index into the Record's data Array.
+      /**
+     * @cfg {String} dragGroup - drag group (?? not sure if needed.)
      */
+
     /**
-     * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
-     * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
+     * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
      */
+    minColumnWidth : 25,
+
     /**
-     * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
-     * Defaults to the value of the {@link #defaultSortable} property.
-     * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
+     * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
+     * <b>on initial render.</b> It is more efficient to explicitly size the columns
+     * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option.  Default is false.
      */
+    autoSizeColumns : false,
+
     /**
-     * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
+     * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
      */
+    autoSizeHeaders : true,
+
     /**
-     * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
+     * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
      */
+    monitorWindowResize : true,
+
     /**
-     * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
+     * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
+     * rows measured to get a columns size. Default is 0 (all rows).
      */
+    maxRowsToMeasure : 0,
+
     /**
-     * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
+     * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
      */
+    trackMouseOver : true,
+
     /**
-     * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
-     * given the cell's data value. See {@link #setRenderer}. If not specified, the
-     * default renderer returns the escaped data value. If an object is returned (bootstrap only)
-     * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
-     */
-       /**
-     * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
-     */
+    * @cfg {Boolean} enableDrag  True to enable drag of rows. Default is false. (double check if this is needed?)
+    */
+      /**
+    * @cfg {Boolean} enableDrop  True to enable drop of elements. Default is false. (double check if this is needed?)
+    */
+    
     /**
-     * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
-     */
+    * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
+    */
+    enableDragDrop : false,
+    
     /**
-     * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc).  Defaults to undefined.
-     */
+    * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
+    */
+    enableColumnMove : true,
+    
     /**
-     * @cfg {String} cursor (Optional)
-     */
+    * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
+    */
+    enableColumnHide : true,
+    
     /**
-     * @cfg {String} tooltip (Optional)
-     */
+    * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
+    */
+    enableRowHeightSync : false,
+    
     /**
-     * @cfg {Number} xs (Optional)
-     */
+    * @cfg {Boolean} stripeRows True to stripe the rows.  Default is true.
+    */
+    stripeRows : true,
+    
     /**
-     * @cfg {Number} sm (Optional)
-     */
+    * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
+    */
+    autoHeight : false,
+
     /**
-     * @cfg {Number} md (Optional)
+     * @cfg {String} autoExpandColumn The id (or dataIndex) of a column in this grid that should expand to fill unused space. This id can not be 0. Default is false.
      */
+    autoExpandColumn : false,
+
     /**
-     * @cfg {Number} lg (Optional)
-     */
+    * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
+    * Default is 50.
+    */
+    autoExpandMin : 50,
+
     /**
-     * Returns the id of the column at the specified index.
-     * @param {Number} index The column index
-     * @return {String} the id
-     */
-    getColumnId : function(index){
-        return this.config[index].id;
-    },
+    * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
+    */
+    autoExpandMax : 1000,
 
     /**
-     * Returns the column for a specified id.
-     * @param {String} id The column id
-     * @return {Object} the column
-     */
-    getColumnById : function(id){
-        return this.lookup[id];
-    },
+    * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
+    */
+    view : null,
 
-    
     /**
-     * Returns the column for a specified dataIndex.
-     * @param {String} dataIndex The column dataIndex
-     * @return {Object|Boolean} the column or false if not found
-     */
-    getColumnByDataIndex: function(dataIndex){
-        var index = this.findColumnIndex(dataIndex);
-        return index > -1 ? this.config[index] : false;
-    },
-    
+    * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
+    */
+    loadMask : false,
     /**
-     * Returns the index for a specified column id.
-     * @param {String} id The column id
-     * @return {Number} the index, or -1 if not found
-     */
-    getIndexById : function(id){
-        for(var i = 0, len = this.config.length; i < len; i++){
-            if(this.config[i].id == id){
-                return i;
-            }
-        }
-        return -1;
-    },
+    * @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,
+
     /**
-     * Returns the index for a specified column dataIndex.
-     * @param {String} dataIndex The column dataIndex
-     * @return {Number} the index, or -1 if not found
-     */
+    * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
+    * of a fixed width. Default is false.
+    */
+    /**
+    * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
+    */
     
-    findColumnIndex : function(dataIndex){
-        for(var i = 0, len = this.config.length; i < len; i++){
-            if(this.config[i].dataIndex == dataIndex){
-                return i;
-            }
-        }
-        return -1;
-    },
     
+    /**
+    * @cfg {String} ddText Configures the text is the drag proxy (defaults to "%0 selected row(s)").
+    * %0 is replaced with the number of selected rows.
+    */
+    ddText : "{0} selected row{1}",
     
-    moveColumn : function(oldIndex, newIndex){
-        var c = this.config[oldIndex];
-        this.config.splice(oldIndex, 1);
-        this.config.splice(newIndex, 0, c);
-        this.dataMap = null;
-        this.fireEvent("columnmoved", this, oldIndex, newIndex);
-    },
-
-    isLocked : function(colIndex){
-        return this.config[colIndex].locked === true;
-    },
+    
+    /**
+     * Called once after all setup has been completed and the grid is ready to be rendered.
+     * @return {Roo.grid.Grid} this
+     */
+    render : function()
+    {
+        var c = this.container;
+        // try to detect autoHeight/width mode
+        if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
+           this.autoHeight = true;
+       }
+       var view = this.getView();
+        view.init(this);
 
-    setLocked : function(colIndex, value, suppressEvent){
-        if(this.isLocked(colIndex) == value){
-            return;
-        }
-        this.config[colIndex].locked = value;
-        if(!suppressEvent){
-            this.fireEvent("columnlockchange", this, colIndex, value);
+        c.on("click", this.onClick, this);
+        c.on("dblclick", this.onDblClick, this);
+        c.on("contextmenu", this.onContextMenu, this);
+        c.on("keydown", this.onKeyDown, this);
+        if (Roo.isTouch) {
+            c.on("touchstart", this.onTouchStart, this);
         }
-    },
 
-    getTotalLockedWidth : function(){
-        var totalWidth = 0;
-        for(var i = 0; i < this.config.length; i++){
-            if(this.isLocked(i) && !this.isHidden(i)){
-                this.totalWidth += this.getColumnWidth(i);
-            }
-        }
-        return totalWidth;
-    },
+        this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
 
-    getLockedCount : function(){
-        for(var i = 0, len = this.config.length; i < len; i++){
-            if(!this.isLocked(i)){
-                return i;
-            }
+        this.getSelectionModel().init(this);
+
+        view.render();
+
+        if(this.loadMask){
+            this.loadMask = new Roo.LoadMask(this.container,
+                    Roo.apply({store:this.dataSource}, this.loadMask));
         }
         
-        return this.config.length;
-    },
-
-    /**
-     * Returns the number of columns.
-     * @return {Number}
-     */
-    getColumnCount : function(visibleOnly){
-        if(visibleOnly === true){
-            var c = 0;
-            for(var i = 0, len = this.config.length; i < len; i++){
-                if(!this.isHidden(i)){
-                    c++;
-                }
-            }
-            return c;
+        
+        if (this.toolbar && this.toolbar.xtype) {
+            this.toolbar.container = this.getView().getHeaderPanel(true);
+            this.toolbar = new Roo.Toolbar(this.toolbar);
         }
-        return this.config.length;
-    },
-
-    /**
-     * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
-     * @param {Function} fn
-     * @param {Object} scope (optional)
-     * @return {Array} result
-     */
-    getColumnsBy : function(fn, scope){
-        var r = [];
-        for(var i = 0, len = this.config.length; i < len; i++){
-            var c = this.config[i];
-            if(fn.call(scope||this, c, i) === true){
-                r[r.length] = c;
-            }
+        if (this.footer && this.footer.xtype) {
+            this.footer.dataSource = this.getDataSource();
+            this.footer.container = this.getView().getFooterPanel(true);
+            this.footer = Roo.factory(this.footer, Roo);
         }
-        return r;
-    },
-
-    /**
-     * Returns true if the specified column is sortable.
-     * @param {Number} col The column index
-     * @return {Boolean}
-     */
-    isSortable : function(col){
-        if(typeof this.config[col].sortable == "undefined"){
-            return this.defaultSortable;
+        if (this.dropTarget && this.dropTarget.xtype) {
+            delete this.dropTarget.xtype;
+            this.dropTarget =  new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
         }
-        return this.config[col].sortable;
+        
+        
+        this.rendered = true;
+        this.fireEvent('render', this);
+        return this;
     },
 
     /**
-     * Returns the rendering (formatting) function defined for the column.
-     * @param {Number} col The column index.
-     * @return {Function} The function used to render the cell. See {@link #setRenderer}.
+     * Reconfigures the grid to use a different Store and Column Model.
+     * The View will be bound to the new objects and refreshed.
+     * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
+     * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
      */
-    getRenderer : function(col){
-        if(!this.config[col].renderer){
-            return Roo.grid.ColumnModel.defaultRenderer;
+    reconfigure : function(dataSource, colModel){
+        if(this.loadMask){
+            this.loadMask.destroy();
+            this.loadMask = new Roo.LoadMask(this.container,
+                    Roo.apply({store:dataSource}, this.loadMask));
         }
-        return this.config[col].renderer;
+        this.view.bind(dataSource, colModel);
+        this.dataSource = dataSource;
+        this.colModel = colModel;
+        this.view.refresh(true);
     },
-
     /**
-     * Sets the rendering (formatting) function for a column.
-     * @param {Number} col The column index
-     * @param {Function} fn The function to use to process the cell's raw data
-     * to return HTML markup for the grid view. The render function is called with
-     * the following parameters:<ul>
-     * <li>Data value.</li>
-     * <li>Cell metadata. An object in which you may set the following attributes:<ul>
-     * <li>css A CSS style string to apply to the table cell.</li>
-     * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
-     * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
-     * <li>Row index</li>
-     * <li>Column index</li>
-     * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
+     * addColumns
+     * Add's a column, default at the end..
+     
+     * @param {int} position to add (default end)
+     * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel} 
      */
-    setRenderer : function(col, fn){
-        this.config[col].renderer = fn;
+    addColumns : function(pos, ar)
+    {
+        
+        for (var i =0;i< ar.length;i++) {
+            var cfg = ar[i];
+            cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
+            this.cm.lookup[cfg.id] = cfg;
+        }
+        
+        
+        if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
+            pos = this.cm.config.length; //this.cm.config.push(cfg);
+        } 
+        pos = Math.max(0,pos);
+        ar.unshift(0);
+        ar.unshift(pos);
+        this.cm.config.splice.apply(this.cm.config, ar);
+        
+        
+        
+        this.view.generateRules(this.cm);
+        this.view.refresh(true);
+        
     },
-
-    /**
-     * Returns the width for the specified column.
-     * @param {Number} col The column index
-     * @return {Number}
-     */
-    getColumnWidth : function(col){
-        return this.config[col].width * 1 || this.defaultWidth;
+    
+    
+    
+    
+    // private
+    onKeyDown : function(e){
+        this.fireEvent("keydown", e);
     },
 
     /**
-     * Sets the width for a column.
-     * @param {Number} col The column index
-     * @param {Number} width The new width
+     * Destroy this grid.
+     * @param {Boolean} removeEl True to remove the element
      */
-    setColumnWidth : function(col, width, suppressEvent){
-        this.config[col].width = width;
-        this.totalWidth = null;
-        if(!suppressEvent){
-             this.fireEvent("widthchange", this, col, width);
+    destroy : function(removeEl, keepListeners){
+        if(this.loadMask){
+            this.loadMask.destroy();
+        }
+        var c = this.container;
+        c.removeAllListeners();
+        this.view.destroy();
+        this.colModel.purgeListeners();
+        if(!keepListeners){
+            this.purgeListeners();
+        }
+        c.update("");
+        if(removeEl === true){
+            c.remove();
         }
     },
 
-    /**
-     * Returns the total width of all columns.
-     * @param {Boolean} includeHidden True to include hidden column widths
-     * @return {Number}
-     */
-    getTotalWidth : function(includeHidden){
-        if(!this.totalWidth){
-            this.totalWidth = 0;
-            for(var i = 0, len = this.config.length; i < len; i++){
-                if(includeHidden || !this.isHidden(i)){
-                    this.totalWidth += this.getColumnWidth(i);
+    // private
+    processEvent : function(name, e){
+        // does this fire select???
+        //Roo.log('grid:processEvent '  + name);
+        
+        if (name != 'touchstart' ) {
+            this.fireEvent(name, e);    
+        }
+        
+        var t = e.getTarget();
+        var v = this.view;
+        var header = v.findHeaderIndex(t);
+        if(header !== false){
+            var ename = name == 'touchstart' ? 'click' : name;
+             
+            this.fireEvent("header" + ename, this, header, e);
+        }else{
+            var row = v.findRowIndex(t);
+            var cell = v.findCellIndex(t);
+            if (name == 'touchstart') {
+                // first touch is always a click.
+                // hopefull this happens after selection is updated.?
+                name = false;
+                
+                if (typeof(this.selModel.getSelectedCell) != 'undefined') {
+                    var cs = this.selModel.getSelectedCell();
+                    if (row == cs[0] && cell == cs[1]){
+                        name = 'dblclick';
+                    }
+                }
+                if (typeof(this.selModel.getSelections) != 'undefined') {
+                    var cs = this.selModel.getSelections();
+                    var ds = this.dataSource;
+                    if (cs.length == 1 && ds.getAt(row) == cs[0]){
+                        name = 'dblclick';
+                    }
+                }
+                if (!name) {
+                    return;
+                }
+            }
+            
+            
+            if(row !== false){
+                this.fireEvent("row" + name, this, row, e);
+                if(cell !== false){
+                    this.fireEvent("cell" + name, this, row, cell, e);
                 }
             }
         }
-        return this.totalWidth;
     },
 
-    /**
-     * Returns the header for the specified column.
-     * @param {Number} col The column index
-     * @return {String}
-     */
-    getColumnHeader : function(col){
-        return this.config[col].header;
+    // private
+    onClick : function(e){
+        this.processEvent("click", e);
     },
-
-    /**
-     * Sets the header for a column.
-     * @param {Number} col The column index
-     * @param {String} header The new header
-     */
-    setColumnHeader : function(col, header){
-        this.config[col].header = header;
-        this.fireEvent("headerchange", this, col, header);
+   // private
+    onTouchStart : function(e){
+        this.processEvent("touchstart", e);
     },
 
-    /**
-     * Returns the tooltip for the specified column.
-     * @param {Number} col The column index
-     * @return {String}
-     */
-    getColumnTooltip : function(col){
-            return this.config[col].tooltip;
-    },
-    /**
-     * Sets the tooltip for a column.
-     * @param {Number} col The column index
-     * @param {String} tooltip The new tooltip
-     */
-    setColumnTooltip : function(col, tooltip){
-            this.config[col].tooltip = tooltip;
+    // private
+    onContextMenu : function(e, t){
+        this.processEvent("contextmenu", e);
     },
 
-    /**
-     * Returns the dataIndex for the specified column.
-     * @param {Number} col The column index
-     * @return {Number}
-     */
-    getDataIndex : function(col){
-        return this.config[col].dataIndex;
+    // private
+    onDblClick : function(e){
+        this.processEvent("dblclick", e);
     },
 
-    /**
-     * Sets the dataIndex for a column.
-     * @param {Number} col The column index
-     * @param {Number} dataIndex The new dataIndex
-     */
-    setDataIndex : function(col, dataIndex){
-        this.config[col].dataIndex = dataIndex;
+    // private
+    walkCells : function(row, col, step, fn, scope){
+        var cm = this.colModel, clen = cm.getColumnCount();
+        var ds = this.dataSource, rlen = ds.getCount(), first = true;
+        if(step < 0){
+            if(col < 0){
+                row--;
+                first = false;
+            }
+            while(row >= 0){
+                if(!first){
+                    col = clen-1;
+                }
+                first = false;
+                while(col >= 0){
+                    if(fn.call(scope || this, row, col, cm) === true){
+                        return [row, col];
+                    }
+                    col--;
+                }
+                row--;
+            }
+        } else {
+            if(col >= clen){
+                row++;
+                first = false;
+            }
+            while(row < rlen){
+                if(!first){
+                    col = 0;
+                }
+                first = false;
+                while(col < clen){
+                    if(fn.call(scope || this, row, col, cm) === true){
+                        return [row, col];
+                    }
+                    col++;
+                }
+                row++;
+            }
+        }
+        return null;
     },
 
-    
-    
-    /**
-     * Returns true if the cell is editable.
-     * @param {Number} colIndex The column index
-     * @param {Number} rowIndex The row index - this is nto actually used..?
-     * @return {Boolean}
-     */
-    isCellEditable : function(colIndex, rowIndex){
-        return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
+    // private
+    getSelections : function(){
+        return this.selModel.getSelections();
     },
 
     /**
-     * Returns the editor defined for the cell/column.
-     * return false or null to disable editing.
-     * @param {Number} colIndex The column index
-     * @param {Number} rowIndex The row index
-     * @return {Object}
+     * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
+     * but if manual update is required this method will initiate it.
      */
-    getCellEditor : function(colIndex, rowIndex){
-        return this.config[colIndex].editor;
+    autoSize : function(){
+        if(this.rendered){
+            this.view.layout();
+            if(this.view.adjustForScroll){
+                this.view.adjustForScroll();
+            }
+        }
     },
 
     /**
-     * Sets if a column is editable.
-     * @param {Number} col The column index
-     * @param {Boolean} editable True if the column is editable
+     * Returns the grid's underlying element.
+     * @return {Element} The element
      */
-    setEditable : function(col, editable){
-        this.config[col].editable = editable;
+    getGridEl : function(){
+        return this.container;
     },
 
+    // private for compatibility, overridden by editor grid
+    stopEditing : function(){},
 
     /**
-     * Returns true if the column is hidden.
-     * @param {Number} colIndex The column index
-     * @return {Boolean}
+     * Returns the grid's SelectionModel.
+     * @return {SelectionModel}
      */
-    isHidden : function(colIndex){
-        return this.config[colIndex].hidden;
+    getSelectionModel : function(){
+        if(!this.selModel){
+            this.selModel = new Roo.grid.RowSelectionModel();
+        }
+        return this.selModel;
     },
 
-
     /**
-     * Returns true if the column width cannot be changed
+     * Returns the grid's DataSource.
+     * @return {DataSource}
      */
-    isFixed : function(colIndex){
-        return this.config[colIndex].fixed;
+    getDataSource : function(){
+        return this.dataSource;
     },
 
     /**
-     * Returns true if the column can be resized
-     * @return {Boolean}
+     * Returns the grid's ColumnModel.
+     * @return {ColumnModel}
      */
-    isResizable : function(colIndex){
-        return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
+    getColumnModel : function(){
+        return this.colModel;
     },
+
     /**
-     * Sets if a column is hidden.
-     * @param {Number} colIndex The column index
-     * @param {Boolean} hidden True if the column is hidden
+     * Returns the grid's GridView object.
+     * @return {GridView}
      */
-    setHidden : function(colIndex, hidden){
-        this.config[colIndex].hidden = hidden;
-        this.totalWidth = null;
-        this.fireEvent("hiddenchange", this, colIndex, hidden);
+    getView : function(){
+        if(!this.view){
+            this.view = new Roo.grid.GridView(this.viewConfig);
+           this.relayEvents(this.view, [
+               "beforerowremoved", "beforerowsinserted",
+               "beforerefresh", "rowremoved",
+               "rowsinserted", "rowupdated" ,"refresh"
+           ]);
+        }
+        return this.view;
     },
-
     /**
-     * Sets the editor for a column.
-     * @param {Number} col The column index
-     * @param {Object} editor The editor object
+     * Called to get grid's drag proxy text, by default returns this.ddText.
+     * Override this to put something different in the dragged text.
+     * @return {String}
      */
-    setEditor : function(col, editor){
-        this.config[col].editor = editor;
+    getDragDropText : function(){
+        var count = this.selModel.getCount();
+        return String.format(this.ddText, count, count == 1 ? '' : 's');
     }
 });
-
-Roo.grid.ColumnModel.defaultRenderer = function(value)
-{
-    if(typeof value == "object") {
-        return value;
-    }
-       if(typeof value == "string" && value.length < 1){
-           return "&#160;";
-       }
-    
-       return String.format("{0}", value);
-};
-
-// Alias for backwards compatibility
-Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
 /*
  * Based on:
  * Ext JS Library 1.1.1
@@ -57911,46 +62466,100 @@ Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
  * Fork - LGPL
  * <script type="text/javascript">
  */
-
-/**
- * @class Roo.grid.AbstractSelectionModel
+ /**
+ * @class Roo.grid.AbstractGridView
  * @extends Roo.util.Observable
- * Abstract base class for grid SelectionModels.  It provides the interface that should be
- * implemented by descendant classes.  This class should not be directly instantiated.
+ * @abstract
+ * Abstract base class for grid Views
  * @constructor
  */
-Roo.grid.AbstractSelectionModel = function(){
-    this.locked = false;
-    Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
+Roo.grid.AbstractGridView = function(){
+       this.grid = null;
+       
+       this.events = {
+           "beforerowremoved" : true,
+           "beforerowsinserted" : true,
+           "beforerefresh" : true,
+           "rowremoved" : true,
+           "rowsinserted" : true,
+           "rowupdated" : true,
+           "refresh" : true
+       };
+    Roo.grid.AbstractGridView.superclass.constructor.call(this);
 };
 
-Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable,  {
-    /** @ignore Called by the grid automatically. Do not call directly. */
-    init : function(grid){
+Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
+    rowClass : "x-grid-row",
+    cellClass : "x-grid-cell",
+    tdClass : "x-grid-td",
+    hdClass : "x-grid-hd",
+    splitClass : "x-grid-hd-split",
+    
+    init: function(grid){
         this.grid = grid;
-        this.initEvents();
+               var cid = this.grid.getGridEl().id;
+        this.colSelector = "#" + cid + " ." + this.cellClass + "-";
+        this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
+        this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
+        this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
+       },
+       
+    getColumnRenderers : function(){
+       var renderers = [];
+       var cm = this.grid.colModel;
+        var colCount = cm.getColumnCount();
+        for(var i = 0; i < colCount; i++){
+            renderers[i] = cm.getRenderer(i);
+        }
+        return renderers;
     },
-
-    /**
-     * Locks the selections.
-     */
-    lock : function(){
-        this.locked = true;
+    
+    getColumnIds : function(){
+       var ids = [];
+       var cm = this.grid.colModel;
+        var colCount = cm.getColumnCount();
+        for(var i = 0; i < colCount; i++){
+            ids[i] = cm.getColumnId(i);
+        }
+        return ids;
     },
-
-    /**
-     * Unlocks the selections.
-     */
-    unlock : function(){
-        this.locked = false;
+    
+    getDataIndexes : function(){
+       if(!this.indexMap){
+            this.indexMap = this.buildIndexMap();
+        }
+        return this.indexMap.colToData;
     },
-
+    
+    getColumnIndexByDataIndex : function(dataIndex){
+        if(!this.indexMap){
+            this.indexMap = this.buildIndexMap();
+        }
+       return this.indexMap.dataToCol[dataIndex];
+    },
+    
     /**
-     * Returns true if the selections are locked.
-     * @return {Boolean}
+     * Set a css style for a column dynamically. 
+     * @param {Number} colIndex The index of the column
+     * @param {String} name The css property name
+     * @param {String} value The css value
      */
-    isLocked : function(){
-        return this.locked;
+    setCSSStyle : function(colIndex, name, value){
+        var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
+        Roo.util.CSS.updateRule(selector, name, value);
+    },
+    
+    generateRules : function(cm){
+        var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
+        Roo.util.CSS.removeStyleSheet(rulesId);
+        for(var i = 0, len = cm.getColumnCount(); i < len; i++){
+            var cid = cm.getColumnId(i);
+            ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
+                         this.tdSelector, cid, " {\n}\n",
+                         this.hdSelector, cid, " {\n}\n",
+                         this.splitSelector, cid, " {\n}\n");
+        }
+        return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
     }
 });/*
  * Based on:
@@ -57962,1227 +62571,4073 @@ Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable,  {
  * Fork - LGPL
  * <script type="text/javascript">
  */
-/**
- * @extends Roo.grid.AbstractSelectionModel
- * @class Roo.grid.RowSelectionModel
- * The default SelectionModel used by {@link Roo.grid.Grid}.
- * It supports multiple selections and keyboard selection/navigation. 
- * @constructor
- * @param {Object} config
- */
-Roo.grid.RowSelectionModel = function(config){
-    Roo.apply(this, config);
-    this.selections = new Roo.util.MixedCollection(false, function(o){
-        return o.id;
-    });
-
-    this.last = false;
-    this.lastActive = false;
 
-    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
-            */
-        "rowdeselect" : true
-    });
-    Roo.grid.RowSelectionModel.superclass.constructor.call(this);
-    this.locked = false;
+// private
+// This is a support class used internally by the Grid components
+Roo.grid.HeaderDragZone = function(grid, hd, hd2){
+    this.grid = grid;
+    this.view = grid.getView();
+    this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
+    Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
+    if(hd2){
+        this.setHandleElId(Roo.id(hd));
+        this.setOuterHandleElId(Roo.id(hd2));
+    }
+    this.scroll = false;
 };
-
-Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
-    /**
-     * @cfg {Boolean} singleSelect
-     * True to allow selection of only one row at a time (defaults to false)
-     */
-    singleSelect : false,
-
-    // private
-    initEvents : function(){
-
-        if(!this.grid.enableDragDrop && !this.grid.enableDrag){
-            this.grid.on("mousedown", this.handleMouseDown, this);
-        }else{ // allow click to work like normal
-            this.grid.on("rowclick", this.handleDragableRowClick, this);
+Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
+    maxDragWidth: 120,
+    getDragData : function(e){
+        var t = Roo.lib.Event.getTarget(e);
+        var h = this.view.findHeaderCell(t);
+        if(h){
+            return {ddel: h.firstChild, header:h};
         }
-
-        this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
-            "up" : function(e){
-                if(!e.shiftKey){
-                    this.selectPrevious(e.shiftKey);
-                }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);
-                    if(last !== false){
-                        this.last = last;
-                    }
-                }else{
-                    this.selectFirstRow();
-                }
-                this.fireEvent("afterselectionchange", this);
-            },
-            "down" : function(e){
-                if(!e.shiftKey){
-                    this.selectNext(e.shiftKey);
-                }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);
-                    if(last !== false){
-                        this.last = last;
-                    }
-                }else{
-                    this.selectFirstRow();
-                }
-                this.fireEvent("afterselectionchange", this);
-            },
-            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);
+        return false;
     },
 
-    // private
-    onRefresh : function(){
-        var ds = this.grid.dataSource, i, v = this.grid.view;
-        var s = this.selections;
-        s.each(function(r){
-            if((i = ds.indexOfId(r.id)) != -1){
-                v.onRowSelect(i);
-                s.add(ds.getAt(i)); // updating the selection relate data
-            }else{
-                s.remove(r);
-            }
-        });
+    onInitDrag : function(e){
+        this.view.headersDisabled = true;
+        var clone = this.dragData.ddel.cloneNode(true);
+        clone.id = Roo.id();
+        clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
+        this.proxy.update(clone);
+        return true;
     },
 
-    // private
-    onRemove : function(v, index, r){
-        this.selections.remove(r);
+    afterValidDrop : function(){
+        var v = this.view;
+        setTimeout(function(){
+            v.headersDisabled = false;
+        }, 50);
     },
 
-    // private
-    onRowUpdated : function(v, index, r){
-        if(this.isSelected(r)){
-            v.onRowSelect(index);
-        }
-    },
+    afterInvalidDrop : function(){
+        var v = this.view;
+        setTimeout(function(){
+            v.headersDisabled = false;
+        }, 50);
+    }
+});
+/*
+ * 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">
+ */
+// private
+// This is a support class used internally by the Grid components
+Roo.grid.HeaderDropZone = function(grid, hd, hd2){
+    this.grid = grid;
+    this.view = grid.getView();
+    // split the proxies so they don't interfere with mouse events
+    this.proxyTop = Roo.DomHelper.append(document.body, {
+        cls:"col-move-top", html:"&#160;"
+    }, true);
+    this.proxyBottom = Roo.DomHelper.append(document.body, {
+        cls:"col-move-bottom", html:"&#160;"
+    }, true);
+    this.proxyTop.hide = this.proxyBottom.hide = function(){
+        this.setLeftTop(-100,-100);
+        this.setStyle("visibility", "hidden");
+    };
+    this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
+    // temporarily disabled
+    //Roo.dd.ScrollManager.register(this.view.scroller.dom);
+    Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
+};
+Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
+    proxyOffsets : [-4, -9],
+    fly: Roo.Element.fly,
 
-    /**
-     * Select records.
-     * @param {Array} records The records to select
-     * @param {Boolean} keepExisting (optional) True to keep existing selections
-     */
-    selectRecords : function(records, keepExisting){
-        if(!keepExisting){
-            this.clearSelections();
-        }
-        var ds = this.grid.dataSource;
-        for(var i = 0, len = records.length; i < len; i++){
-            this.selectRow(ds.indexOf(records[i]), true);
+    getTargetFromEvent : function(e){
+        var t = Roo.lib.Event.getTarget(e);
+        var cindex = this.view.findCellIndex(t);
+        if(cindex !== false){
+            return this.view.getHeaderCell(cindex);
         }
+        return null;
     },
 
-    /**
-     * Gets the number of selected rows.
-     * @return {Number}
-     */
-    getCount : function(){
-        return this.selections.length;
-    },
-
-    /**
-     * Selects the first row in the grid.
-     */
-    selectFirstRow : function(){
-        this.selectRow(0);
-    },
-
-    /**
-     * Select the last row.
-     * @param {Boolean} keepExisting (optional) True to keep existing selections
-     */
-    selectLastRow : function(keepExisting){
-        this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
-    },
-
-    /**
-     * Selects the row immediately following the last selected row.
-     * @param {Boolean} keepExisting (optional) True to keep existing selections
-     */
-    selectNext : function(keepExisting){
-        if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
-            this.selectRow(this.last+1, keepExisting);
-            this.grid.getView().focusRow(this.last);
+    nextVisible : function(h){
+        var v = this.view, cm = this.grid.colModel;
+        h = h.nextSibling;
+        while(h){
+            if(!cm.isHidden(v.getCellIndex(h))){
+                return h;
+            }
+            h = h.nextSibling;
         }
+        return null;
     },
 
-    /**
-     * Selects the row that precedes the last selected row.
-     * @param {Boolean} keepExisting (optional) True to keep existing selections
-     */
-    selectPrevious : function(keepExisting){
-        if(this.last){
-            this.selectRow(this.last-1, keepExisting);
-            this.grid.getView().focusRow(this.last);
+    prevVisible : function(h){
+        var v = this.view, cm = this.grid.colModel;
+        h = h.prevSibling;
+        while(h){
+            if(!cm.isHidden(v.getCellIndex(h))){
+                return h;
+            }
+            h = h.prevSibling;
         }
+        return null;
     },
 
-    /**
-     * Returns the selected records
-     * @return {Array} Array of selected records
-     */
-    getSelections : function(){
-        return [].concat(this.selections.items);
-    },
+    positionIndicator : function(h, n, e){
+        var x = Roo.lib.Event.getPageX(e);
+        var r = Roo.lib.Dom.getRegion(n.firstChild);
+        var px, pt, py = r.top + this.proxyOffsets[1];
+        if((r.right - x) <= (r.right-r.left)/2){
+            px = r.right+this.view.borderWidth;
+            pt = "after";
+        }else{
+            px = r.left;
+            pt = "before";
+        }
+        var oldIndex = this.view.getCellIndex(h);
+        var newIndex = this.view.getCellIndex(n);
 
-    /**
-     * Returns the first selected record.
-     * @return {Record}
-     */
-    getSelected : function(){
-        return this.selections.itemAt(0);
-    },
+        if(this.grid.colModel.isFixed(newIndex)){
+            return false;
+        }
 
+        var locked = this.grid.colModel.isLocked(newIndex);
 
-    /**
-     * Clears all selections.
-     */
-    clearSelections : function(fast){
-        if(this.locked) {
-            return;
+        if(pt == "after"){
+            newIndex++;
         }
-        if(fast !== true){
-            var ds = this.grid.dataSource;
-            var s = this.selections;
-            s.each(function(r){
-                this.deselectRow(ds.indexOfId(r.id));
-            }, this);
-            s.clear();
-        }else{
-            this.selections.clear();
+        if(oldIndex < newIndex){
+            newIndex--;
         }
-        this.last = false;
-    },
-
-
-    /**
-     * Selects all rows.
-     */
-    selectAll : function(){
-        if(this.locked) {
-            return;
+        if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
+            return false;
         }
-        this.selections.clear();
-        for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
-            this.selectRow(i, true);
+        px +=  this.proxyOffsets[0];
+        this.proxyTop.setLeftTop(px, py);
+        this.proxyTop.show();
+        if(!this.bottomOffset){
+            this.bottomOffset = this.view.mainHd.getHeight();
         }
+        this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
+        this.proxyBottom.show();
+        return pt;
     },
 
-    /**
-     * Returns True if there is a selection.
-     * @return {Boolean}
-     */
-    hasSelection : function(){
-        return this.selections.length > 0;
+    onNodeEnter : function(n, dd, e, data){
+        if(data.header != n){
+            this.positionIndicator(data.header, n, e);
+        }
     },
 
-    /**
-     * Returns True if the specified row is selected.
-     * @param {Number/Record} record The record or index of the record to check
-     * @return {Boolean}
-     */
-    isSelected : function(index){
-        var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
-        return (r && this.selections.key(r.id) ? true : false);
+    onNodeOver : function(n, dd, e, data){
+        var result = false;
+        if(data.header != n){
+            result = this.positionIndicator(data.header, n, e);
+        }
+        if(!result){
+            this.proxyTop.hide();
+            this.proxyBottom.hide();
+        }
+        return result ? this.dropAllowed : this.dropNotAllowed;
     },
 
-    /**
-     * Returns True if the specified record id is selected.
-     * @param {String} id The id of record to check
-     * @return {Boolean}
-     */
-    isIdSelected : function(id){
-        return (this.selections.key(id) ? true : false);
+    onNodeOut : function(n, dd, e, data){
+        this.proxyTop.hide();
+        this.proxyBottom.hide();
     },
 
-    // private
-    handleMouseDown : function(e, t){
-        var view = this.grid.getView(), rowIndex;
-        if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
-            return;
-        };
-        if(e.shiftKey && this.last !== false){
-            var last = this.last;
-            this.selectRange(last, rowIndex, e.ctrlKey);
-            this.last = last; // reset the last
-            view.focusRow(rowIndex);
-        }else{
-            var isSelected = this.isSelected(rowIndex);
-            if(e.button !== 0 && isSelected){
-                view.focusRow(rowIndex);
-            }else if(e.ctrlKey && isSelected){
-                this.deselectRow(rowIndex);
-            }else if(!isSelected){
-                this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
-                view.focusRow(rowIndex);
+    onNodeDrop : function(n, dd, e, data){
+        var h = data.header;
+        if(h != n){
+            var cm = this.grid.colModel;
+            var x = Roo.lib.Event.getPageX(e);
+            var r = Roo.lib.Dom.getRegion(n.firstChild);
+            var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
+            var oldIndex = this.view.getCellIndex(h);
+            var newIndex = this.view.getCellIndex(n);
+            var locked = cm.isLocked(newIndex);
+            if(pt == "after"){
+                newIndex++;
             }
+            if(oldIndex < newIndex){
+                newIndex--;
+            }
+            if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
+                return false;
+            }
+            cm.setLocked(oldIndex, locked, true);
+            cm.moveColumn(oldIndex, newIndex);
+            this.grid.fireEvent("columnmove", oldIndex, newIndex);
+            return true;
         }
-        this.fireEvent("afterselectionchange", this);
-    },
-    // private
-    handleDragableRowClick :  function(grid, rowIndex, e) 
-    {
-        if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
-            this.selectRow(rowIndex, false);
-            grid.view.focusRow(rowIndex);
-             this.fireEvent("afterselectionchange", this);
-        }
-    },
+        return false;
+    }
+});
+/*
+ * 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.grid.GridView
+ * @extends Roo.util.Observable
+ *
+ * @constructor
+ * @param {Object} config
+ */
+Roo.grid.GridView = function(config){
+    Roo.grid.GridView.superclass.constructor.call(this);
+    this.el = null;
+
+    Roo.apply(this, config);
+};
+
+Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
+
+    unselectable :  'unselectable="on"',
+    unselectableCls :  'x-unselectable',
     
-    /**
-     * Selects multiple rows.
-     * @param {Array} rows Array of the indexes of the row to select
-     * @param {Boolean} keepExisting (optional) True to keep existing selections
-     */
-    selectRows : function(rows, keepExisting){
-        if(!keepExisting){
-            this.clearSelections();
+    
+    rowClass : "x-grid-row",
+
+    cellClass : "x-grid-col",
+
+    tdClass : "x-grid-td",
+
+    hdClass : "x-grid-hd",
+
+    splitClass : "x-grid-split",
+
+    sortClasses : ["sort-asc", "sort-desc"],
+
+    enableMoveAnim : false,
+
+    hlColor: "C3DAF9",
+
+    dh : Roo.DomHelper,
+
+    fly : Roo.Element.fly,
+
+    css : Roo.util.CSS,
+
+    borderWidth: 1,
+
+    splitOffset: 3,
+
+    scrollIncrement : 22,
+
+    cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
+
+    findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
+
+    bind : function(ds, cm){
+        if(this.ds){
+            this.ds.un("load", this.onLoad, this);
+            this.ds.un("datachanged", this.onDataChange, this);
+            this.ds.un("add", this.onAdd, this);
+            this.ds.un("remove", this.onRemove, this);
+            this.ds.un("update", this.onUpdate, this);
+            this.ds.un("clear", this.onClear, this);
         }
-        for(var i = 0, len = rows.length; i < len; i++){
-            this.selectRow(rows[i], true);
+        if(ds){
+            ds.on("load", this.onLoad, this);
+            ds.on("datachanged", this.onDataChange, this);
+            ds.on("add", this.onAdd, this);
+            ds.on("remove", this.onRemove, this);
+            ds.on("update", this.onUpdate, this);
+            ds.on("clear", this.onClear, this);
         }
-    },
+        this.ds = ds;
 
-    /**
-     * Selects a range of rows. All rows in between startRow and endRow are also selected.
-     * @param {Number} startRow The index of the first row in the range
-     * @param {Number} endRow The index of the last row in the range
-     * @param {Boolean} keepExisting (optional) True to retain existing selections
-     */
-    selectRange : function(startRow, endRow, keepExisting){
-        if(this.locked) {
-            return;
-        }
-        if(!keepExisting){
-            this.clearSelections();
+        if(this.cm){
+            this.cm.un("widthchange", this.onColWidthChange, this);
+            this.cm.un("headerchange", this.onHeaderChange, this);
+            this.cm.un("hiddenchange", this.onHiddenChange, this);
+            this.cm.un("columnmoved", this.onColumnMove, this);
+            this.cm.un("columnlockchange", this.onColumnLock, this);
         }
-        if(startRow <= endRow){
-            for(var i = startRow; i <= endRow; i++){
-                this.selectRow(i, true);
-            }
-        }else{
-            for(var i = startRow; i >= endRow; i--){
-                this.selectRow(i, true);
-            }
+        if(cm){
+            this.generateRules(cm);
+            cm.on("widthchange", this.onColWidthChange, this);
+            cm.on("headerchange", this.onHeaderChange, this);
+            cm.on("hiddenchange", this.onHiddenChange, this);
+            cm.on("columnmoved", this.onColumnMove, this);
+            cm.on("columnlockchange", this.onColumnLock, this);
         }
+        this.cm = cm;
     },
 
-    /**
-     * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
-     * @param {Number} startRow The index of the first row in the range
-     * @param {Number} endRow The index of the last row in the range
-     */
-    deselectRange : function(startRow, endRow, preventViewNotify){
-        if(this.locked) {
-            return;
-        }
-        for(var i = startRow; i <= endRow; i++){
-            this.deselectRow(i, preventViewNotify);
+    init: function(grid){
+        Roo.grid.GridView.superclass.init.call(this, grid);
+
+        this.bind(grid.dataSource, grid.colModel);
+
+        grid.on("headerclick", this.handleHeaderClick, this);
+
+        if(grid.trackMouseOver){
+            grid.on("mouseover", this.onRowOver, this);
+            grid.on("mouseout", this.onRowOut, this);
         }
-    },
+        grid.cancelTextSelection = function(){};
+        this.gridId = grid.id;
 
-    /**
-     * Selects a row.
-     * @param {Number} row The index of the row to select
-     * @param {Boolean} keepExisting (optional) True to keep existing selections
-     */
-    selectRow : function(index, keepExisting, preventViewNotify){
-        if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
-            return;
+        var tpls = this.templates || {};
+
+        if(!tpls.master){
+            tpls.master = new Roo.Template(
+               '<div class="x-grid" hidefocus="true">',
+                '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
+                  '<div class="x-grid-topbar"></div>',
+                  '<div class="x-grid-scroller"><div></div></div>',
+                  '<div class="x-grid-locked">',
+                      '<div class="x-grid-header">{lockedHeader}</div>',
+                      '<div class="x-grid-body">{lockedBody}</div>',
+                  "</div>",
+                  '<div class="x-grid-viewport">',
+                      '<div class="x-grid-header">{header}</div>',
+                      '<div class="x-grid-body">{body}</div>',
+                  "</div>",
+                  '<div class="x-grid-bottombar"></div>',
+                 
+                  '<div class="x-grid-resize-proxy">&#160;</div>',
+               "</div>"
+            );
+            tpls.master.disableformats = true;
         }
-        if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
-            if(!keepExisting || this.singleSelect){
-                this.clearSelections();
-            }
-            var r = this.grid.dataSource.getAt(index);
-            this.selections.add(r);
-            this.last = this.lastActive = index;
-            if(!preventViewNotify){
-                this.grid.getView().onRowSelect(index);
-            }
-            this.fireEvent("rowselect", this, index, r);
-            this.fireEvent("selectionchange", this);
+
+        if(!tpls.header){
+            tpls.header = new Roo.Template(
+               '<table border="0" cellspacing="0" cellpadding="0">',
+               '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
+               "</table>{splits}"
+            );
+            tpls.header.disableformats = true;
         }
-    },
+        tpls.header.compile();
 
-    /**
-     * Deselects a row.
-     * @param {Number} row The index of the row to deselect
-     */
-    deselectRow : function(index, preventViewNotify){
-        if(this.locked) {
-            return;
+        if(!tpls.hcell){
+            tpls.hcell = new Roo.Template(
+                '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
+                '<div class="x-grid-hd-text ' + this.unselectableCls +  '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
+                "</div></td>"
+             );
+             tpls.hcell.disableFormats = true;
         }
-        if(this.last == index){
-            this.last = false;
+        tpls.hcell.compile();
+
+        if(!tpls.hsplit){
+            tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
+                                            this.unselectableCls +  '" ' + this.unselectable +'>&#160;</div>');
+            tpls.hsplit.disableFormats = true;
         }
-        if(this.lastActive == index){
-            this.lastActive = false;
+        tpls.hsplit.compile();
+
+        if(!tpls.body){
+            tpls.body = new Roo.Template(
+               '<table border="0" cellspacing="0" cellpadding="0">',
+               "<tbody>{rows}</tbody>",
+               "</table>"
+            );
+            tpls.body.disableFormats = true;
         }
-        var r = this.grid.dataSource.getAt(index);
-        this.selections.remove(r);
-        if(!preventViewNotify){
-            this.grid.getView().onRowDeselect(index);
+        tpls.body.compile();
+
+        if(!tpls.row){
+            tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
+            tpls.row.disableFormats = true;
         }
-        this.fireEvent("rowdeselect", this, index);
-        this.fireEvent("selectionchange", this);
-    },
+        tpls.row.compile();
 
-    // private
-    restoreLast : function(){
-        if(this._last){
-            this.last = this._last;
+        if(!tpls.cell){
+            tpls.cell = new Roo.Template(
+                '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
+                '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
+                    this.unselectableCls +  '" ' + this.unselectable +'" {attr}>{value}</div></div>',
+                "</td>"
+            );
+            tpls.cell.disableFormats = true;
         }
-    },
+        tpls.cell.compile();
 
-    // private
-    acceptsNav : function(row, col, cm){
-        return !cm.isHidden(col) && cm.isCellEditable(col, row);
+        this.templates = tpls;
     },
 
-    // private
-    onEditorKey : function(field, e){
-        var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
-        if(k == e.TAB){
-            e.stopEvent();
-            ed.completeEdit();
-            if(e.shiftKey){
-                newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
-            }else{
-                newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
-            }
-        }else if(k == e.ENTER && !e.ctrlKey){
-            e.stopEvent();
-            ed.completeEdit();
-            if(e.shiftKey){
-                newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
-            }else{
-                newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
-            }
-        }else if(k == e.ESC){
-            ed.cancelEdit();
-        }
-        if(newCell){
-            g.startEditing(newCell[0], newCell[1]);
-        }
-    }
-});/*
- * 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.grid.CellSelectionModel
- * @extends Roo.grid.AbstractSelectionModel
- * This class provides the basic implementation for cell selection in a grid.
- * @constructor
- * @param {Object} config The object containing the configuration of this model.
- * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
- */
-Roo.grid.CellSelectionModel = function(config){
-    Roo.apply(this, config);
+    // remap these for backwards compat
+    onColWidthChange : function(){
+        this.updateColumns.apply(this, arguments);
+    },
+    onHeaderChange : function(){
+        this.updateHeaders.apply(this, arguments);
+    }, 
+    onHiddenChange : function(){
+        this.handleHiddenChange.apply(this, arguments);
+    },
+    onColumnMove : function(){
+        this.handleColumnMove.apply(this, arguments);
+    },
+    onColumnLock : function(){
+        this.handleLockChange.apply(this, arguments);
+    },
 
-    this.selection = null;
+    onDataChange : function(){
+        this.refresh();
+        this.updateHeaderSortState();
+    },
 
-    this.addEvents({
-        /**
-            * @event beforerowselect
-            * Fires before a cell is selected.
-            * @param {SelectionModel} this
-            * @param {Number} rowIndex The selected row index
-            * @param {Number} colIndex The selected cell index
-            */
-           "beforecellselect" : true,
-        /**
-            * @event cellselect
-            * Fires when a cell is selected.
-            * @param {SelectionModel} this
-            * @param {Number} rowIndex The selected row index
-            * @param {Number} colIndex The selected cell index
-            */
-           "cellselect" : true,
-        /**
-            * @event selectionchange
-            * Fires when the active selection changes.
-            * @param {SelectionModel} this
-            * @param {Object} selection null for no selection or an object (o) with two properties
-               <ul>
-               <li>o.record: the record object for the row the selection is in</li>
-               <li>o.cell: An array of [rowIndex, columnIndex]</li>
-               </ul>
-            */
-           "selectionchange" : true,
-        /**
-            * @event tabend
-            * Fires when the tab (or enter) was pressed on the last editable cell
-            * You can use this to trigger add new row.
-            * @param {SelectionModel} this
-            */
-           "tabend" : true,
-         /**
-            * @event beforeeditnext
-            * Fires before the next editable sell is made active
-            * You can use this to skip to another cell or fire the tabend
-            *    if you set cell to false
-            * @param {Object} eventdata object : { cell : [ row, col ] } 
-            */
-           "beforeeditnext" : true
-    });
-    Roo.grid.CellSelectionModel.superclass.constructor.call(this);
-};
+    onClear : function(){
+        this.refresh();
+    },
 
-Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel,  {
-    
-    enter_is_tab: false,
+    onUpdate : function(ds, record){
+        this.refreshRow(record);
+    },
 
-    /** @ignore */
-    initEvents : function(){
-        this.grid.on("mousedown", this.handleMouseDown, this);
-        this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
-        var view = this.grid.view;
-        view.on("refresh", this.onViewChange, this);
-        view.on("rowupdated", this.onRowUpdated, this);
-        view.on("beforerowremoved", this.clearSelections, this);
-        view.on("beforerowsinserted", this.clearSelections, this);
-        if(this.grid.isEditor){
-            this.grid.on("beforeedit", this.beforeEdit,  this);
+    refreshRow : function(record){
+        var ds = this.ds, index;
+        if(typeof record == 'number'){
+            index = record;
+            record = ds.getAt(index);
+        }else{
+            index = ds.indexOf(record);
         }
+        this.insertRows(ds, index, index, true);
+        this.onRemove(ds, record, index+1, true);
+        this.syncRowHeights(index, index);
+        this.layout();
+        this.fireEvent("rowupdated", this, index, record);
     },
 
-       //private
-    beforeEdit : function(e){
-        this.select(e.row, e.column, false, true, e.record);
+    onAdd : function(ds, records, index){
+        this.insertRows(ds, index, index + (records.length-1));
     },
 
-       //private
-    onRowUpdated : function(v, index, r){
-        if(this.selection && this.selection.record == r){
-            v.onCellSelect(index, this.selection.cell[1]);
+    onRemove : function(ds, record, index, isUpdate){
+        if(isUpdate !== true){
+            this.fireEvent("beforerowremoved", this, index, record);
+        }
+        var bt = this.getBodyTable(), lt = this.getLockedTable();
+        if(bt.rows[index]){
+            bt.firstChild.removeChild(bt.rows[index]);
+        }
+        if(lt.rows[index]){
+            lt.firstChild.removeChild(lt.rows[index]);
+        }
+        if(isUpdate !== true){
+            this.stripeRows(index);
+            this.syncRowHeights(index, index);
+            this.layout();
+            this.fireEvent("rowremoved", this, index, record);
         }
     },
 
-       //private
-    onViewChange : function(){
-        this.clearSelections(true);
-    },
-
-       /**
-        * Returns the currently selected cell,.
-        * @return {Array} The selected cell (row, column) or null if none selected.
-        */
-    getSelectedCell : function(){
-        return this.selection ? this.selection.cell : null;
+    onLoad : function(){
+        this.scrollToTop();
     },
 
     /**
-     * Clears all selections.
-     * @param {Boolean} true to prevent the gridview from being notified about the change.
+     * Scrolls the grid to the top
      */
-    clearSelections : function(preventNotify){
-        var s = this.selection;
-        if(s){
-            if(preventNotify !== true){
-                this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
-            }
-            this.selection = null;
-            this.fireEvent("selectionchange", this, null);
+    scrollToTop : function(){
+        if(this.scroller){
+            this.scroller.dom.scrollTop = 0;
+            this.syncScroll();
         }
     },
 
     /**
-     * Returns true if there is a selection.
-     * @return {Boolean}
+     * Gets a panel in the header of the grid that can be used for toolbars etc.
+     * After modifying the contents of this panel a call to grid.autoSize() may be
+     * required to register any changes in size.
+     * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
+     * @return Roo.Element
      */
-    hasSelection : function(){
-        return this.selection ? true : false;
-    },
-
-    /** @ignore */
-    handleMouseDown : function(e, t){
-        var v = this.grid.getView();
-        if(this.isLocked()){
-            return;
-        };
-        var row = v.findRowIndex(t);
-        var cell = v.findCellIndex(t);
-        if(row !== false && cell !== false){
-            this.select(row, cell);
+    getHeaderPanel : function(doShow){
+        if(doShow){
+            this.headerPanel.show();
         }
+        return this.headerPanel;
     },
 
     /**
-     * Selects a cell.
-     * @param {Number} rowIndex
-     * @param {Number} collIndex
+     * Gets a panel in the footer of the grid that can be used for toolbars etc.
+     * After modifying the contents of this panel a call to grid.autoSize() may be
+     * required to register any changes in size.
+     * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
+     * @return Roo.Element
      */
-    select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
-        if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
-            this.clearSelections();
-            r = r || this.grid.dataSource.getAt(rowIndex);
-            this.selection = {
-                record : r,
-                cell : [rowIndex, colIndex]
-            };
-            if(!preventViewNotify){
-                var v = this.grid.getView();
-                v.onCellSelect(rowIndex, colIndex);
-                if(preventFocus !== true){
-                    v.focusCell(rowIndex, colIndex);
-                }
-            }
-            this.fireEvent("cellselect", this, rowIndex, colIndex);
-            this.fireEvent("selectionchange", this, this.selection);
+    getFooterPanel : function(doShow){
+        if(doShow){
+            this.footerPanel.show();
         }
+        return this.footerPanel;
     },
 
-       //private
-    isSelectable : function(rowIndex, colIndex, cm){
-        return !cm.isHidden(colIndex);
+    initElements : function(){
+        var E = Roo.Element;
+        var el = this.grid.getGridEl().dom.firstChild;
+        var cs = el.childNodes;
+
+        this.el = new E(el);
+        
+         this.focusEl = new E(el.firstChild);
+        this.focusEl.swallowEvent("click", true);
+        
+        this.headerPanel = new E(cs[1]);
+        this.headerPanel.enableDisplayMode("block");
+
+        this.scroller = new E(cs[2]);
+        this.scrollSizer = new E(this.scroller.dom.firstChild);
+
+        this.lockedWrap = new E(cs[3]);
+        this.lockedHd = new E(this.lockedWrap.dom.firstChild);
+        this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
+
+        this.mainWrap = new E(cs[4]);
+        this.mainHd = new E(this.mainWrap.dom.firstChild);
+        this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
+
+        this.footerPanel = new E(cs[5]);
+        this.footerPanel.enableDisplayMode("block");
+
+        this.resizeProxy = new E(cs[6]);
+
+        this.headerSelector = String.format(
+           '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
+           this.lockedHd.id, this.mainHd.id
+        );
+
+        this.splitterSelector = String.format(
+           '#{0} div.x-grid-split, #{1} div.x-grid-split',
+           this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
+        );
+    },
+    idToCssName : function(s)
+    {
+        return s.replace(/[^a-z0-9]+/ig, '-');
     },
 
-    /** @ignore */
-    handleKeyDown : function(e){
-        //Roo.log('Cell Sel Model handleKeyDown');
-        if(!e.isNavKeyPress()){
-            return;
-        }
-        var g = this.grid, s = this.selection;
-        if(!s){
-            e.stopEvent();
-            var cell = g.walkCells(0, 0, 1, this.isSelectable,  this);
-            if(cell){
-                this.select(cell[0], cell[1]);
-            }
-            return;
-        }
-        var sm = this;
-        var walk = function(row, col, step){
-            return g.walkCells(row, col, step, sm.isSelectable,  sm);
-        };
-        var k = e.getKey(), r = s.cell[0], c = s.cell[1];
-        var newCell;
+    getHeaderCell : function(index){
+        return Roo.DomQuery.select(this.headerSelector)[index];
+    },
 
-      
+    getHeaderCellMeasure : function(index){
+        return this.getHeaderCell(index).firstChild;
+    },
 
-        switch(k){
-            case e.TAB:
-                // handled by onEditorKey
-                if (g.isEditor && g.editing) {
-                    return;
-                }
-                if(e.shiftKey) {
-                    newCell = walk(r, c-1, -1);
-                } else {
-                    newCell = walk(r, c+1, 1);
-                }
-                break;
-            
-            case e.DOWN:
-               newCell = walk(r+1, c, 1);
-                break;
-            
-            case e.UP:
-                newCell = walk(r-1, c, -1);
-                break;
-            
-            case e.RIGHT:
-                newCell = walk(r, c+1, 1);
-                break;
-            
-            case e.LEFT:
-                newCell = walk(r, c-1, -1);
-                break;
-            
-            case e.ENTER:
-                
-                if(g.isEditor && !g.editing){
-                   g.startEditing(r, c);
-                   e.stopEvent();
-                   return;
-                }
-                
-                
-             break;
-        };
-        if(newCell){
-            this.select(newCell[0], newCell[1]);
-            e.stopEvent();
-            
-        }
+    getHeaderCellText : function(index){
+        return this.getHeaderCell(index).firstChild.firstChild;
     },
 
-    acceptsNav : function(row, col, cm){
-        return !cm.isHidden(col) && cm.isCellEditable(col, row);
+    getLockedTable : function(){
+        return this.lockedBody.dom.firstChild;
+    },
+
+    getBodyTable : function(){
+        return this.mainBody.dom.firstChild;
+    },
+
+    getLockedRow : function(index){
+        return this.getLockedTable().rows[index];
+    },
+
+    getRow : function(index){
+        return this.getBodyTable().rows[index];
+    },
+
+    getRowComposite : function(index){
+        if(!this.rowEl){
+            this.rowEl = new Roo.CompositeElementLite();
+        }
+        var els = [], lrow, mrow;
+        if(lrow = this.getLockedRow(index)){
+            els.push(lrow);
+        }
+        if(mrow = this.getRow(index)){
+            els.push(mrow);
+        }
+        this.rowEl.elements = els;
+        return this.rowEl;
     },
     /**
-     * Selects a cell.
-     * @param {Number} field (not used) - as it's normally used as a listener
-     * @param {Number} e - event - fake it by using
-     *
-     * var e = Roo.EventObjectImpl.prototype;
-     * e.keyCode = e.TAB
-     *
+     * Gets the 'td' of the cell
+     * 
+     * @param {Integer} rowIndex row to select
+     * @param {Integer} colIndex column to select
      * 
+     * @return {Object} 
      */
-    onEditorKey : function(field, e){
-        
-        var k = e.getKey(),
-            newCell,
-            g = this.grid,
-            ed = g.activeEditor,
-            forward = false;
-        ///Roo.log('onEditorKey' + k);
-        
-        
-        if (this.enter_is_tab && k == e.ENTER) {
-            k = e.TAB;
-        }
-        
-        if(k == e.TAB){
-            if(e.shiftKey){
-                newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
-            }else{
-                newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
-                forward = true;
-            }
-            
-            e.stopEvent();
-            
-        } else if(k == e.ENTER &&  !e.ctrlKey){
-            ed.completeEdit();
-            e.stopEvent();
-            newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
-        
-               } else if(k == e.ESC){
-            ed.cancelEdit();
+    getCell : function(rowIndex, colIndex){
+        var locked = this.cm.getLockedCount();
+        var source;
+        if(colIndex < locked){
+            source = this.lockedBody.dom.firstChild;
+        }else{
+            source = this.mainBody.dom.firstChild;
+            colIndex -= locked;
         }
-               
-        if (newCell) {
-            var ecall = { cell : newCell, forward : forward };
-            this.fireEvent('beforeeditnext', ecall );
-            newCell = ecall.cell;
-                       forward = ecall.forward;
+        return source.rows[rowIndex].childNodes[colIndex];
+    },
+
+    getCellText : function(rowIndex, colIndex){
+        return this.getCell(rowIndex, colIndex).firstChild.firstChild;
+    },
+
+    getCellBox : function(cell){
+        var b = this.fly(cell).getBox();
+        if(Roo.isOpera){ // opera fails to report the Y
+            b.y = cell.offsetTop + this.mainBody.getY();
         }
-               
-        if(newCell){
-            //Roo.log('next cell after edit');
-            g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
-        } else if (forward) {
-            // tabbed past last
-            this.fireEvent.defer(100, this, ['tabend',this]);
+        return b;
+    },
+
+    getCellIndex : function(cell){
+        var id = String(cell.className).match(this.cellRE);
+        if(id){
+            return parseInt(id[1], 10);
         }
-    }
-});/*
- * 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.grid.EditorGrid
- * @extends Roo.grid.Grid
- * Class for creating and editable grid.
- * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered - 
- * The container MUST have some type of size defined for the grid to fill. The container will be 
- * automatically set to position relative if it isn't already.
- * @param {Object} dataSource The data model to bind to
- * @param {Object} colModel The column model with info about this grid's columns
- */
-Roo.grid.EditorGrid = function(container, config){
-    Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
-    this.getGridEl().addClass("xedit-grid");
+        return 0;
+    },
 
-    if(!this.selModel){
-        this.selModel = new Roo.grid.CellSelectionModel();
-    }
+    findHeaderIndex : function(n){
+        var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
+        return r ? this.getCellIndex(r) : false;
+    },
 
-    this.activeEditor = null;
+    findHeaderCell : function(n){
+        var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
+        return r ? r : false;
+    },
 
-       this.addEvents({
-           /**
-            * @event beforeedit
-            * Fires before cell editing is triggered. The edit event object has the following properties <br />
-            * <ul style="padding:5px;padding-left:16px;">
-            * <li>grid - This grid</li>
-            * <li>record - The record being edited</li>
-            * <li>field - The field name being edited</li>
-            * <li>value - The value for the field being edited.</li>
-            * <li>row - The grid row index</li>
-            * <li>column - The grid column index</li>
-            * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
-            * </ul>
-            * @param {Object} e An edit event (see above for description)
-            */
-           "beforeedit" : true,
-           /**
-            * @event afteredit
-            * Fires after a cell is edited. <br />
-            * <ul style="padding:5px;padding-left:16px;">
-            * <li>grid - This grid</li>
-            * <li>record - The record being edited</li>
-            * <li>field - The field name being edited</li>
-            * <li>value - The value being set</li>
-            * <li>originalValue - The original value for the field, before the edit.</li>
-            * <li>row - The grid row index</li>
-            * <li>column - The grid column index</li>
-            * </ul>
-            * @param {Object} e An edit event (see above for description)
-            */
-           "afteredit" : true,
-           /**
-            * @event validateedit
-            * Fires after a cell is edited, but before the value is set in the record. 
-         * You can use this to modify the value being set in the field, Return false
-            * to cancel the change. The edit event object has the following properties <br />
-            * <ul style="padding:5px;padding-left:16px;">
-         * <li>editor - This editor</li>
-            * <li>grid - This grid</li>
-            * <li>record - The record being edited</li>
-            * <li>field - The field name being edited</li>
-            * <li>value - The value being set</li>
-            * <li>originalValue - The original value for the field, before the edit.</li>
-            * <li>row - The grid row index</li>
-            * <li>column - The grid column index</li>
-            * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
-            * </ul>
-            * @param {Object} e An edit event (see above for description)
-            */
-           "validateedit" : true
-       });
-    this.on("bodyscroll", this.stopEditing,  this);
-    this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick,  this);
-};
+    findRowIndex : function(n){
+        if(!n){
+            return false;
+        }
+        var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
+        return r ? r.rowIndex : false;
+    },
 
-Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
-    /**
-     * @cfg {Number} clicksToEdit
-     * The number of clicks on a cell required to display the cell's editor (defaults to 2)
-     */
-    clicksToEdit: 2,
+    findCellIndex : function(node){
+        var stop = this.el.dom;
+        while(node && node != stop){
+            if(this.findRE.test(node.className)){
+                return this.getCellIndex(node);
+            }
+            node = node.parentNode;
+        }
+        return false;
+    },
 
-    // private
-    isEditor : true,
-    // private
-    trackMouseOver: false, // causes very odd FF errors
+    getColumnId : function(index){
+        return this.cm.getColumnId(index);
+    },
 
-    onCellDblClick : function(g, row, col){
-        this.startEditing(row, col);
+    getSplitters : function()
+    {
+        if(this.splitterSelector){
+           return Roo.DomQuery.select(this.splitterSelector);
+        }else{
+            return null;
+      }
     },
 
-    onEditComplete : function(ed, value, startValue){
-        this.editing = false;
-        this.activeEditor = null;
-        ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
-        var r = ed.record;
-        var field = this.colModel.getDataIndex(ed.col);
-        var e = {
-            grid: this,
-            record: r,
-            field: field,
-            originalValue: startValue,
-            value: value,
-            row: ed.row,
-            column: ed.col,
-            cancel:false,
-            editor: ed
-        };
-        var cell = Roo.get(this.view.getCell(ed.row,ed.col));
-        cell.show();
-          
-        if(String(value) !== String(startValue)){
-            
-            if(this.fireEvent("validateedit", e) !== false && !e.cancel){
-                r.set(field, e.value);
-                // if we are dealing with a combo box..
-                // then we also set the 'name' colum to be the displayField
-                if (ed.field.displayField && ed.field.name) {
-                    r.set(ed.field.name, ed.field.el.dom.value);
-                }
-                
-                delete e.cancel; //?? why!!!
-                this.fireEvent("afteredit", e);
-            }
-        } else {
-            this.fireEvent("afteredit", e); // always fire it!
+    getSplitter : function(index){
+        return this.getSplitters()[index];
+    },
+
+    onRowOver : function(e, t){
+        var row;
+        if((row = this.findRowIndex(t)) !== false){
+            this.getRowComposite(row).addClass("x-grid-row-over");
         }
-        this.view.focusCell(ed.row, ed.col);
     },
 
-    /**
-     * Starts editing the specified for the specified row/column
-     * @param {Number} rowIndex
-     * @param {Number} colIndex
-     */
-    startEditing : function(row, col){
-        this.stopEditing();
-        if(this.colModel.isCellEditable(col, row)){
-            this.view.ensureVisible(row, col, true);
-          
-            var r = this.dataSource.getAt(row);
-            var field = this.colModel.getDataIndex(col);
-            var cell = Roo.get(this.view.getCell(row,col));
-            var e = {
-                grid: this,
-                record: r,
-                field: field,
-                value: r.data[field],
-                row: row,
-                column: col,
-                cancel:false 
-            };
-            if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
-                this.editing = true;
-                var ed = this.colModel.getCellEditor(col, row);
-                
-                if (!ed) {
-                    return;
-                }
-                if(!ed.rendered){
-                    ed.render(ed.parentEl || document.body);
-                }
-                ed.field.reset();
-               
-                cell.hide();
-                
-                (function(){ // complex but required for focus issues in safari, ie and opera
-                    ed.row = row;
-                    ed.col = col;
-                    ed.record = r;
-                    ed.on("complete",   this.onEditComplete,        this,       {single: true});
-                    ed.on("specialkey", this.selModel.onEditorKey,  this.selModel);
-                    this.activeEditor = ed;
-                    var v = r.data[field];
-                    ed.startEdit(this.view.getCell(row, col), v);
-                    // combo's with 'displayField and name set
-                    if (ed.field.displayField && ed.field.name) {
-                        ed.field.el.dom.value = r.data[ed.field.name];
-                    }
-                    
-                    
-                }).defer(50, this);
+    onRowOut : function(e, t){
+        var row;
+        if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
+            this.getRowComposite(row).removeClass("x-grid-row-over");
+        }
+    },
+
+    renderHeaders : function(){
+        var cm = this.cm;
+        var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
+        var cb = [], lb = [], sb = [], lsb = [], p = {};
+        for(var i = 0, len = cm.getColumnCount(); i < len; i++){
+            p.cellId = "x-grid-hd-0-" + i;
+            p.splitId = "x-grid-csplit-0-" + i;
+            p.id = cm.getColumnId(i);
+            p.value = cm.getColumnHeader(i) || "";
+            p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</)  ? '' :  p.value  || "";
+            p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
+            if(!cm.isLocked(i)){
+                cb[cb.length] = ct.apply(p);
+                sb[sb.length] = st.apply(p);
+            }else{
+                lb[lb.length] = ct.apply(p);
+                lsb[lsb.length] = st.apply(p);
             }
         }
+        return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
+                ht.apply({cells: cb.join(""), splits:sb.join("")})];
     },
-        
+
+    updateHeaders : function(){
+        var html = this.renderHeaders();
+        this.lockedHd.update(html[0]);
+        this.mainHd.update(html[1]);
+    },
+
     /**
-     * Stops any active editing
+     * Focuses the specified row.
+     * @param {Number} row The row index
      */
-    stopEditing : function(){
-        if(this.activeEditor){
-            this.activeEditor.completeEdit();
-        }
-        this.activeEditor = null;
+    focusRow : function(row)
+    {
+        //Roo.log('GridView.focusRow');
+        var x = this.scroller.dom.scrollLeft;
+        this.focusCell(row, 0, false);
+        this.scroller.dom.scrollLeft = x;
     },
-       
-        /**
-     * Called to get grid's drag proxy text, by default returns this.ddText.
-     * @return {String}
-     */
-    getDragDropText : function(){
-        var count = this.selModel.getSelectedCell() ? 1 : 0;
-        return String.format(this.ddText, count, count == 1 ? '' : 's');
-    }
-       
-});/*
- * 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">
- */
-
-// private - not really -- you end up using it !
-// This is a support class used internally by the Grid components
 
-/**
- * @class Roo.grid.GridEditor
- * @extends Roo.Editor
- * Class for creating and editable grid elements.
- * @param {Object} config any settings (must include field)
- */
-Roo.grid.GridEditor = function(field, config){
-    if (!config && field.field) {
-        config = field;
-        field = Roo.factory(config.field, Roo.form);
-    }
-    Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
-    field.monitorTab = false;
-};
-
-Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
-    
     /**
-     * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
+     * Focuses the specified cell.
+     * @param {Number} row The row index
+     * @param {Number} col The column index
+     * @param {Boolean} hscroll false to disable horizontal scrolling
      */
-    
-    alignment: "tl-tl",
-    autoSize: "width",
-    hideEl : false,
-    cls: "x-small-editor x-grid-editor",
-    shim:false,
-    shadow:"frame"
-});/*
- * 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">
- */
-  
-
-  
-Roo.grid.PropertyRecord = Roo.data.Record.create([
-    {name:'name',type:'string'},  'value'
-]);
+    focusCell : function(row, col, hscroll)
+    {
+        //Roo.log('GridView.focusCell');
+        var el = this.ensureVisible(row, col, hscroll);
+        this.focusEl.alignTo(el, "tl-tl");
+        if(Roo.isGecko){
+            this.focusEl.focus();
+        }else{
+            this.focusEl.focus.defer(1, this.focusEl);
+        }
+    },
 
+    /**
+     * Scrolls the specified cell into view
+     * @param {Number} row The row index
+     * @param {Number} col The column index
+     * @param {Boolean} hscroll false to disable horizontal scrolling
+     */
+    ensureVisible : function(row, col, hscroll)
+    {
+        //Roo.log('GridView.ensureVisible,' + row + ',' + col);
+        //return null; //disable for testing.
+        if(typeof row != "number"){
+            row = row.rowIndex;
+        }
+        if(row < 0 && row >= this.ds.getCount()){
+            return  null;
+        }
+        col = (col !== undefined ? col : 0);
+        var cm = this.grid.colModel;
+        while(cm.isHidden(col)){
+            col++;
+        }
 
-Roo.grid.PropertyStore = function(grid, source){
-    this.grid = grid;
-    this.store = new Roo.data.Store({
-        recordType : Roo.grid.PropertyRecord
-    });
-    this.store.on('update', this.onUpdate,  this);
-    if(source){
-        this.setSource(source);
-    }
-    Roo.grid.PropertyStore.superclass.constructor.call(this);
-};
+        var el = this.getCell(row, col);
+        if(!el){
+            return null;
+        }
+        var c = this.scroller.dom;
 
+        var ctop = parseInt(el.offsetTop, 10);
+        var cleft = parseInt(el.offsetLeft, 10);
+        var cbot = ctop + el.offsetHeight;
+        var cright = cleft + el.offsetWidth;
+        
+        var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
+        var stop = parseInt(c.scrollTop, 10);
+        var sleft = parseInt(c.scrollLeft, 10);
+        var sbot = stop + ch;
+        var sright = sleft + c.clientWidth;
+        /*
+        Roo.log('GridView.ensureVisible:' +
+                ' ctop:' + ctop +
+                ' c.clientHeight:' + c.clientHeight +
+                ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
+                ' stop:' + stop +
+                ' cbot:' + cbot +
+                ' sbot:' + sbot +
+                ' ch:' + ch  
+                );
+        */
+        if(ctop < stop){
+            c.scrollTop = ctop;
+            //Roo.log("set scrolltop to ctop DISABLE?");
+        }else if(cbot > sbot){
+            //Roo.log("set scrolltop to cbot-ch");
+            c.scrollTop = cbot-ch;
+        }
+        
+        if(hscroll !== false){
+            if(cleft < sleft){
+                c.scrollLeft = cleft;
+            }else if(cright > sright){
+                c.scrollLeft = cright-c.clientWidth;
+            }
+        }
+         
+        return el;
+    },
 
+    updateColumns : function(){
+        this.grid.stopEditing();
+        var cm = this.grid.colModel, colIds = this.getColumnIds();
+        //var totalWidth = cm.getTotalWidth();
+        var pos = 0;
+        for(var i = 0, len = cm.getColumnCount(); i < len; i++){
+            //if(cm.isHidden(i)) continue;
+            var w = cm.getColumnWidth(i);
+            this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
+            this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
+        }
+        this.updateSplitters();
+    },
 
-Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
-    setSource : function(o){
-        this.source = o;
-        this.store.removeAll();
-        var data = [];
-        for(var k in o){
-            if(this.isEditableValue(o[k])){
-                data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
+    generateRules : function(cm){
+        var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
+        Roo.util.CSS.removeStyleSheet(rulesId);
+        for(var i = 0, len = cm.getColumnCount(); i < len; i++){
+            var cid = cm.getColumnId(i);
+            var align = '';
+            if(cm.config[i].align){
+                align = 'text-align:'+cm.config[i].align+';';
             }
+            var hidden = '';
+            if(cm.isHidden(i)){
+                hidden = 'display:none;';
+            }
+            var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
+            ruleBuf.push(
+                    this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
+                    this.hdSelector, cid, " {\n", align, width, "}\n",
+                    this.tdSelector, cid, " {\n",hidden,"\n}\n",
+                    this.splitSelector, cid, " {\n", hidden , "\n}\n");
         }
-        this.store.loadRecords({records: data}, {}, true);
+        return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
     },
 
-    onUpdate : function(ds, record, type){
-        if(type == Roo.data.Record.EDIT){
-            var v = record.data['value'];
-            var oldValue = record.modified['value'];
-            if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
-                this.source[record.id] = v;
-                record.commit();
-                this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
-            }else{
-                record.reject();
+    updateSplitters : function(){
+        var cm = this.cm, s = this.getSplitters();
+        if(s){ // splitters not created yet
+            var pos = 0, locked = true;
+            for(var i = 0, len = cm.getColumnCount(); i < len; i++){
+                if(cm.isHidden(i)) {
+                    continue;
+                }
+                var w = cm.getColumnWidth(i); // make sure it's a number
+                if(!cm.isLocked(i) && locked){
+                    pos = 0;
+                    locked = false;
+                }
+                pos += w;
+                s[i].style.left = (pos-this.splitOffset) + "px";
             }
         }
     },
 
-    getProperty : function(row){
-       return this.store.getAt(row);
+    handleHiddenChange : function(colModel, colIndex, hidden){
+        if(hidden){
+            this.hideColumn(colIndex);
+        }else{
+            this.unhideColumn(colIndex);
+        }
     },
 
-    isEditableValue: function(val){
-        if(val && val instanceof Date){
-            return true;
-        }else if(typeof val == 'object' || typeof val == 'function'){
-            return false;
+    hideColumn : function(colIndex){
+        var cid = this.getColumnId(colIndex);
+        this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
+        this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
+        if(Roo.isSafari){
+            this.updateHeaders();
         }
-        return true;
+        this.updateSplitters();
+        this.layout();
     },
 
-    setValue : function(prop, value){
-        this.source[prop] = value;
-        this.store.getById(prop).set('value', value);
-    },
+    unhideColumn : function(colIndex){
+        var cid = this.getColumnId(colIndex);
+        this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
+        this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
 
-    getSource : function(){
-        return this.source;
-    }
-});
+        if(Roo.isSafari){
+            this.updateHeaders();
+        }
+        this.updateSplitters();
+        this.layout();
+    },
 
-Roo.grid.PropertyColumnModel = function(grid, store){
-    this.grid = grid;
-    var g = Roo.grid;
-    g.PropertyColumnModel.superclass.constructor.call(this, [
-        {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
-        {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
-    ]);
-    this.store = store;
-    this.bselect = Roo.DomHelper.append(document.body, {
-        tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
-            {tag: 'option', value: 'true', html: 'true'},
-            {tag: 'option', value: 'false', html: 'false'}
-        ]
-    });
-    Roo.id(this.bselect);
-    var f = Roo.form;
-    this.editors = {
-        'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
-        'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
-        'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
-        'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
-        'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
-    };
-    this.renderCellDelegate = this.renderCell.createDelegate(this);
-    this.renderPropDelegate = this.renderProp.createDelegate(this);
-};
+    insertRows : function(dm, firstRow, lastRow, isUpdate){
+        if(firstRow == 0 && lastRow == dm.getCount()-1){
+            this.refresh();
+        }else{
+            if(!isUpdate){
+                this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
+            }
+            var s = this.getScrollState();
+            var markup = this.renderRows(firstRow, lastRow);
+            this.bufferRows(markup[0], this.getLockedTable(), firstRow);
+            this.bufferRows(markup[1], this.getBodyTable(), firstRow);
+            this.restoreScroll(s);
+            if(!isUpdate){
+                this.fireEvent("rowsinserted", this, firstRow, lastRow);
+                this.syncRowHeights(firstRow, lastRow);
+                this.stripeRows(firstRow);
+                this.layout();
+            }
+        }
+    },
 
-Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
-    
-    
-    nameText : 'Name',
-    valueText : 'Value',
-    
-    dateFormat : 'm/j/Y',
-    
-    
-    renderDate : function(dateVal){
-        return dateVal.dateFormat(this.dateFormat);
+    bufferRows : function(markup, target, index){
+        var before = null, trows = target.rows, tbody = target.tBodies[0];
+        if(index < trows.length){
+            before = trows[index];
+        }
+        var b = document.createElement("div");
+        b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
+        var rows = b.firstChild.rows;
+        for(var i = 0, len = rows.length; i < len; i++){
+            if(before){
+                tbody.insertBefore(rows[0], before);
+            }else{
+                tbody.appendChild(rows[0]);
+            }
+        }
+        b.innerHTML = "";
+        b = null;
     },
 
-    renderBool : function(bVal){
-        return bVal ? 'true' : 'false';
+    deleteRows : function(dm, firstRow, lastRow){
+        if(dm.getRowCount()<1){
+            this.fireEvent("beforerefresh", this);
+            this.mainBody.update("");
+            this.lockedBody.update("");
+            this.fireEvent("refresh", this);
+        }else{
+            this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
+            var bt = this.getBodyTable();
+            var tbody = bt.firstChild;
+            var rows = bt.rows;
+            for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
+                tbody.removeChild(rows[firstRow]);
+            }
+            this.stripeRows(firstRow);
+            this.fireEvent("rowsdeleted", this, firstRow, lastRow);
+        }
     },
 
-    isCellEditable : function(colIndex, rowIndex){
-        return colIndex == 1;
+    updateRows : function(dataSource, firstRow, lastRow){
+        var s = this.getScrollState();
+        this.refresh();
+        this.restoreScroll(s);
     },
 
-    getRenderer : function(col){
-        return col == 1 ?
-            this.renderCellDelegate : this.renderPropDelegate;
+    handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
+        if(!noRefresh){
+           this.refresh();
+        }
+        this.updateHeaderSortState();
     },
 
-    renderProp : function(v){
-        return this.getPropertyName(v);
+    getScrollState : function(){
+        
+        var sb = this.scroller.dom;
+        return {left: sb.scrollLeft, top: sb.scrollTop};
     },
 
-    renderCell : function(val){
-        var rv = val;
-        if(val instanceof Date){
-            rv = this.renderDate(val);
-        }else if(typeof val == 'boolean'){
-            rv = this.renderBool(val);
+    stripeRows : function(startRow){
+        if(!this.grid.stripeRows || this.ds.getCount() < 1){
+            return;
+        }
+        startRow = startRow || 0;
+        var rows = this.getBodyTable().rows;
+        var lrows = this.getLockedTable().rows;
+        var cls = ' x-grid-row-alt ';
+        for(var i = startRow, len = rows.length; i < len; i++){
+            var row = rows[i], lrow = lrows[i];
+            var isAlt = ((i+1) % 2 == 0);
+            var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
+            if(isAlt == hasAlt){
+                continue;
+            }
+            if(isAlt){
+                row.className += " x-grid-row-alt";
+            }else{
+                row.className = row.className.replace("x-grid-row-alt", "");
+            }
+            if(lrow){
+                lrow.className = row.className;
+            }
         }
-        return Roo.util.Format.htmlEncode(rv);
     },
 
-    getPropertyName : function(name){
-        var pn = this.grid.propertyNames;
-        return pn && pn[name] ? pn[name] : name;
+    restoreScroll : function(state){
+        //Roo.log('GridView.restoreScroll');
+        var sb = this.scroller.dom;
+        sb.scrollLeft = state.left;
+        sb.scrollTop = state.top;
+        this.syncScroll();
     },
 
-    getCellEditor : function(colIndex, rowIndex){
-        var p = this.store.getProperty(rowIndex);
-        var n = p.data['name'], val = p.data['value'];
-        
-        if(typeof(this.grid.customEditors[n]) == 'string'){
-            return this.editors[this.grid.customEditors[n]];
-        }
-        if(typeof(this.grid.customEditors[n]) != 'undefined'){
-            return this.grid.customEditors[n];
+    syncScroll : function(){
+        //Roo.log('GridView.syncScroll');
+        var sb = this.scroller.dom;
+        var sh = this.mainHd.dom;
+        var bs = this.mainBody.dom;
+        var lv = this.lockedBody.dom;
+        sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
+        lv.scrollTop = bs.scrollTop = sb.scrollTop;
+    },
+
+    handleScroll : function(e){
+        this.syncScroll();
+        var sb = this.scroller.dom;
+        this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
+        e.stopEvent();
+    },
+
+    handleWheel : function(e){
+        var d = e.getWheelDelta();
+        this.scroller.dom.scrollTop -= d*22;
+        // set this here to prevent jumpy scrolling on large tables
+        this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
+        e.stopEvent();
+    },
+
+    renderRows : function(startRow, endRow){
+        // pull in all the crap needed to render rows
+        var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
+        var colCount = cm.getColumnCount();
+
+        if(ds.getCount() < 1){
+            return ["", ""];
         }
-        if(val instanceof Date){
-            return this.editors['date'];
-        }else if(typeof val == 'number'){
-            return this.editors['number'];
-        }else if(typeof val == 'boolean'){
-            return this.editors['boolean'];
-        }else{
-            return this.editors['string'];
+
+        // build a map for all the columns
+        var cs = [];
+        for(var i = 0; i < colCount; i++){
+            var name = cm.getDataIndex(i);
+            cs[i] = {
+                name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
+                renderer : cm.getRenderer(i),
+                id : cm.getColumnId(i),
+                locked : cm.isLocked(i),
+                has_editor : cm.isCellEditable(i)
+            };
         }
-    }
-});
 
-/**
- * @class Roo.grid.PropertyGrid
- * @extends Roo.grid.EditorGrid
- * This class represents the  interface of a component based property grid control.
- * <br><br>Usage:<pre><code>
- var grid = new Roo.grid.PropertyGrid("my-container-id", {
-      
- });
- // set any options
- grid.render();
- * </code></pre>
-  
- * @constructor
- * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
- * The container MUST have some type of size defined for the grid to fill. The container will be
- * automatically set to position relative if it isn't already.
- * @param {Object} config A config object that sets properties on this grid.
- */
-Roo.grid.PropertyGrid = function(container, config){
-    config = config || {};
-    var store = new Roo.grid.PropertyStore(this);
-    this.store = store;
-    var cm = new Roo.grid.PropertyColumnModel(this, store);
-    store.store.sort('name', 'ASC');
-    Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
-        ds: store.store,
-        cm: cm,
-        enableColLock:false,
+        startRow = startRow || 0;
+        endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
+
+        // records to render
+        var rs = ds.getRange(startRow, endRow);
+
+        return this.doRender(cs, rs, ds, startRow, colCount, stripe);
+    },
+
+    // As much as I hate to duplicate code, this was branched because FireFox really hates
+    // [].join("") on strings. The performance difference was substantial enough to
+    // branch this function
+    doRender : Roo.isGecko ?
+            function(cs, rs, ds, startRow, colCount, stripe){
+                var ts = this.templates, ct = ts.cell, rt = ts.row;
+                // buffers
+                var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
+                
+                var hasListener = this.grid.hasListener('rowclass');
+                var rowcfg = {};
+                for(var j = 0, len = rs.length; j < len; j++){
+                    r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
+                    for(var i = 0; i < colCount; i++){
+                        c = cs[i];
+                        p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
+                        p.id = c.id;
+                        p.css = p.attr = "";
+                        p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
+                        if(p.value == undefined || p.value === "") {
+                            p.value = "&#160;";
+                        }
+                        if(c.has_editor){
+                            p.css += ' x-grid-editable-cell';
+                        }
+                        if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
+                            p.css +=  ' x-grid-dirty-cell';
+                        }
+                        var markup = ct.apply(p);
+                        if(!c.locked){
+                            cb+= markup;
+                        }else{
+                            lcb+= markup;
+                        }
+                    }
+                    var alt = [];
+                    if(stripe && ((rowIndex+1) % 2 == 0)){
+                        alt.push("x-grid-row-alt")
+                    }
+                    if(r.dirty){
+                        alt.push(  " x-grid-dirty-row");
+                    }
+                    rp.cells = lcb;
+                    if(this.getRowClass){
+                        alt.push(this.getRowClass(r, rowIndex));
+                    }
+                    if (hasListener) {
+                        rowcfg = {
+                             
+                            record: r,
+                            rowIndex : rowIndex,
+                            rowClass : ''
+                        };
+                        this.grid.fireEvent('rowclass', this, rowcfg);
+                        alt.push(rowcfg.rowClass);
+                    }
+                    rp.alt = alt.join(" ");
+                    lbuf+= rt.apply(rp);
+                    rp.cells = cb;
+                    buf+=  rt.apply(rp);
+                }
+                return [lbuf, buf];
+            } :
+            function(cs, rs, ds, startRow, colCount, stripe){
+                var ts = this.templates, ct = ts.cell, rt = ts.row;
+                // buffers
+                var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
+                var hasListener = this.grid.hasListener('rowclass');
+                var rowcfg = {};
+                for(var j = 0, len = rs.length; j < len; j++){
+                    r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
+                    for(var i = 0; i < colCount; i++){
+                        c = cs[i];
+                        p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
+                        p.id = c.id;
+                        p.css = p.attr = "";
+                        p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
+                        if(p.value == undefined || p.value === "") {
+                            p.value = "&#160;";
+                        }
+                        //Roo.log(c);
+                         if(c.has_editor){
+                            p.css += ' x-grid-editable-cell';
+                        }
+                        if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
+                            p.css += ' x-grid-dirty-cell' 
+                        }
+                        
+                        var markup = ct.apply(p);
+                        if(!c.locked){
+                            cb[cb.length] = markup;
+                        }else{
+                            lcb[lcb.length] = markup;
+                        }
+                    }
+                    var alt = [];
+                    if(stripe && ((rowIndex+1) % 2 == 0)){
+                        alt.push( "x-grid-row-alt");
+                    }
+                    if(r.dirty){
+                        alt.push(" x-grid-dirty-row");
+                    }
+                    rp.cells = lcb;
+                    if(this.getRowClass){
+                        alt.push( this.getRowClass(r, rowIndex));
+                    }
+                    if (hasListener) {
+                        rowcfg = {
+                             
+                            record: r,
+                            rowIndex : rowIndex,
+                            rowClass : ''
+                        };
+                        this.grid.fireEvent('rowclass', this, rowcfg);
+                        alt.push(rowcfg.rowClass);
+                    }
+                    
+                    rp.alt = alt.join(" ");
+                    rp.cells = lcb.join("");
+                    lbuf[lbuf.length] = rt.apply(rp);
+                    rp.cells = cb.join("");
+                    buf[buf.length] =  rt.apply(rp);
+                }
+                return [lbuf.join(""), buf.join("")];
+            },
+
+    renderBody : function(){
+        var markup = this.renderRows();
+        var bt = this.templates.body;
+        return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
+    },
+
+    /**
+     * Refreshes the grid
+     * @param {Boolean} headersToo
+     */
+    refresh : function(headersToo){
+        this.fireEvent("beforerefresh", this);
+        this.grid.stopEditing();
+        var result = this.renderBody();
+        this.lockedBody.update(result[0]);
+        this.mainBody.update(result[1]);
+        if(headersToo === true){
+            this.updateHeaders();
+            this.updateColumns();
+            this.updateSplitters();
+            this.updateHeaderSortState();
+        }
+        this.syncRowHeights();
+        this.layout();
+        this.fireEvent("refresh", this);
+    },
+
+    handleColumnMove : function(cm, oldIndex, newIndex){
+        this.indexMap = null;
+        var s = this.getScrollState();
+        this.refresh(true);
+        this.restoreScroll(s);
+        this.afterMove(newIndex);
+    },
+
+    afterMove : function(colIndex){
+        if(this.enableMoveAnim && Roo.enableFx){
+            this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
+        }
+        // if multisort - fix sortOrder, and reload..
+        if (this.grid.dataSource.multiSort) {
+            // the we can call sort again..
+            var dm = this.grid.dataSource;
+            var cm = this.grid.colModel;
+            var so = [];
+            for(var i = 0; i < cm.config.length; i++ ) {
+                
+                if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
+                    continue; // dont' bother, it's not in sort list or being set.
+                }
+                
+                so.push(cm.config[i].dataIndex);
+            };
+            dm.sortOrder = so;
+            dm.load(dm.lastOptions);
+            
+            
+        }
+        
+    },
+
+    updateCell : function(dm, rowIndex, dataIndex){
+        var colIndex = this.getColumnIndexByDataIndex(dataIndex);
+        if(typeof colIndex == "undefined"){ // not present in grid
+            return;
+        }
+        var cm = this.grid.colModel;
+        var cell = this.getCell(rowIndex, colIndex);
+        var cellText = this.getCellText(rowIndex, colIndex);
+
+        var p = {
+            cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
+            id : cm.getColumnId(colIndex),
+            css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
+        };
+        var renderer = cm.getRenderer(colIndex);
+        var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
+        if(typeof val == "undefined" || val === "") {
+            val = "&#160;";
+        }
+        cellText.innerHTML = val;
+        cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
+        this.syncRowHeights(rowIndex, rowIndex);
+    },
+
+    calcColumnWidth : function(colIndex, maxRowsToMeasure){
+        var maxWidth = 0;
+        if(this.grid.autoSizeHeaders){
+            var h = this.getHeaderCellMeasure(colIndex);
+            maxWidth = Math.max(maxWidth, h.scrollWidth);
+        }
+        var tb, index;
+        if(this.cm.isLocked(colIndex)){
+            tb = this.getLockedTable();
+            index = colIndex;
+        }else{
+            tb = this.getBodyTable();
+            index = colIndex - this.cm.getLockedCount();
+        }
+        if(tb && tb.rows){
+            var rows = tb.rows;
+            var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
+            for(var i = 0; i < stopIndex; i++){
+                var cell = rows[i].childNodes[index].firstChild;
+                maxWidth = Math.max(maxWidth, cell.scrollWidth);
+            }
+        }
+        return maxWidth + /*margin for error in IE*/ 5;
+    },
+    /**
+     * Autofit a column to its content.
+     * @param {Number} colIndex
+     * @param {Boolean} forceMinSize true to force the column to go smaller if possible
+     */
+     autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
+         if(this.cm.isHidden(colIndex)){
+             return; // can't calc a hidden column
+         }
+        if(forceMinSize){
+            var cid = this.cm.getColumnId(colIndex);
+            this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
+           if(this.grid.autoSizeHeaders){
+               this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
+           }
+        }
+        var newWidth = this.calcColumnWidth(colIndex);
+        this.cm.setColumnWidth(colIndex,
+            Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
+        if(!suppressEvent){
+            this.grid.fireEvent("columnresize", colIndex, newWidth);
+        }
+    },
+
+    /**
+     * Autofits all columns to their content and then expands to fit any extra space in the grid
+     */
+     autoSizeColumns : function(){
+        var cm = this.grid.colModel;
+        var colCount = cm.getColumnCount();
+        for(var i = 0; i < colCount; i++){
+            this.autoSizeColumn(i, true, true);
+        }
+        if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
+            this.fitColumns();
+        }else{
+            this.updateColumns();
+            this.layout();
+        }
+    },
+
+    /**
+     * Autofits all columns to the grid's width proportionate with their current size
+     * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
+     */
+    fitColumns : function(reserveScrollSpace){
+        var cm = this.grid.colModel;
+        var colCount = cm.getColumnCount();
+        var cols = [];
+        var width = 0;
+        var i, w;
+        for (i = 0; i < colCount; i++){
+            if(!cm.isHidden(i) && !cm.isFixed(i)){
+                w = cm.getColumnWidth(i);
+                cols.push(i);
+                cols.push(w);
+                width += w;
+            }
+        }
+        var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
+        if(reserveScrollSpace){
+            avail -= 17;
+        }
+        var frac = (avail - cm.getTotalWidth())/width;
+        while (cols.length){
+            w = cols.pop();
+            i = cols.pop();
+            cm.setColumnWidth(i, Math.floor(w + w*frac), true);
+        }
+        this.updateColumns();
+        this.layout();
+    },
+
+    onRowSelect : function(rowIndex){
+        var row = this.getRowComposite(rowIndex);
+        row.addClass("x-grid-row-selected");
+    },
+
+    onRowDeselect : function(rowIndex){
+        var row = this.getRowComposite(rowIndex);
+        row.removeClass("x-grid-row-selected");
+    },
+
+    onCellSelect : function(row, col){
+        var cell = this.getCell(row, col);
+        if(cell){
+            Roo.fly(cell).addClass("x-grid-cell-selected");
+        }
+    },
+
+    onCellDeselect : function(row, col){
+        var cell = this.getCell(row, col);
+        if(cell){
+            Roo.fly(cell).removeClass("x-grid-cell-selected");
+        }
+    },
+
+    updateHeaderSortState : function(){
+        
+        // sort state can be single { field: xxx, direction : yyy}
+        // or   { xxx=>ASC , yyy : DESC ..... }
+        
+        var mstate = {};
+        if (!this.ds.multiSort) { 
+            var state = this.ds.getSortState();
+            if(!state){
+                return;
+            }
+            mstate[state.field] = state.direction;
+            // FIXME... - this is not used here.. but might be elsewhere..
+            this.sortState = state;
+            
+        } else {
+            mstate = this.ds.sortToggle;
+        }
+        //remove existing sort classes..
+        
+        var sc = this.sortClasses;
+        var hds = this.el.select(this.headerSelector).removeClass(sc);
+        
+        for(var f in mstate) {
+        
+            var sortColumn = this.cm.findColumnIndex(f);
+            
+            if(sortColumn != -1){
+                var sortDir = mstate[f];        
+                hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
+            }
+        }
+        
+         
+        
+    },
+
+
+    handleHeaderClick : function(g, index,e){
+        
+        Roo.log("header click");
+        
+        if (Roo.isTouch) {
+            // touch events on header are handled by context
+            this.handleHdCtx(g,index,e);
+            return;
+        }
+        
+        
+        if(this.headersDisabled){
+            return;
+        }
+        var dm = g.dataSource, cm = g.colModel;
+        if(!cm.isSortable(index)){
+            return;
+        }
+        g.stopEditing();
+        
+        if (dm.multiSort) {
+            // update the sortOrder
+            var so = [];
+            for(var i = 0; i < cm.config.length; i++ ) {
+                
+                if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
+                    continue; // dont' bother, it's not in sort list or being set.
+                }
+                
+                so.push(cm.config[i].dataIndex);
+            };
+            dm.sortOrder = so;
+        }
+        
+        
+        dm.sort(cm.getDataIndex(index));
+    },
+
+
+    destroy : function(){
+        if(this.colMenu){
+            this.colMenu.removeAll();
+            Roo.menu.MenuMgr.unregister(this.colMenu);
+            this.colMenu.getEl().remove();
+            delete this.colMenu;
+        }
+        if(this.hmenu){
+            this.hmenu.removeAll();
+            Roo.menu.MenuMgr.unregister(this.hmenu);
+            this.hmenu.getEl().remove();
+            delete this.hmenu;
+        }
+        if(this.grid.enableColumnMove){
+            var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
+            if(dds){
+                for(var dd in dds){
+                    if(!dds[dd].config.isTarget && dds[dd].dragElId){
+                        var elid = dds[dd].dragElId;
+                        dds[dd].unreg();
+                        Roo.get(elid).remove();
+                    } else if(dds[dd].config.isTarget){
+                        dds[dd].proxyTop.remove();
+                        dds[dd].proxyBottom.remove();
+                        dds[dd].unreg();
+                    }
+                    if(Roo.dd.DDM.locationCache[dd]){
+                        delete Roo.dd.DDM.locationCache[dd];
+                    }
+                }
+                delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
+            }
+        }
+        Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
+        this.bind(null, null);
+        Roo.EventManager.removeResizeListener(this.onWindowResize, this);
+    },
+
+    handleLockChange : function(){
+        this.refresh(true);
+    },
+
+    onDenyColumnLock : function(){
+
+    },
+
+    onDenyColumnHide : function(){
+
+    },
+
+    handleHdMenuClick : function(item){
+        var index = this.hdCtxIndex;
+        var cm = this.cm, ds = this.ds;
+        switch(item.id){
+            case "asc":
+                ds.sort(cm.getDataIndex(index), "ASC");
+                break;
+            case "desc":
+                ds.sort(cm.getDataIndex(index), "DESC");
+                break;
+            case "lock":
+                var lc = cm.getLockedCount();
+                if(cm.getColumnCount(true) <= lc+1){
+                    this.onDenyColumnLock();
+                    return;
+                }
+                if(lc != index){
+                    cm.setLocked(index, true, true);
+                    cm.moveColumn(index, lc);
+                    this.grid.fireEvent("columnmove", index, lc);
+                }else{
+                    cm.setLocked(index, true);
+                }
+            break;
+            case "unlock":
+                var lc = cm.getLockedCount();
+                if((lc-1) != index){
+                    cm.setLocked(index, false, true);
+                    cm.moveColumn(index, lc-1);
+                    this.grid.fireEvent("columnmove", index, lc-1);
+                }else{
+                    cm.setLocked(index, false);
+                }
+            break;
+            case 'wider': // used to expand cols on touch..
+            case 'narrow':
+                var cw = cm.getColumnWidth(index);
+                cw += (item.id == 'wider' ? 1 : -1) * 50;
+                cw = Math.max(0, cw);
+                cw = Math.min(cw,4000);
+                cm.setColumnWidth(index, cw);
+                break;
+                
+            default:
+                index = cm.getIndexById(item.id.substr(4));
+                if(index != -1){
+                    if(item.checked && cm.getColumnCount(true) <= 1){
+                        this.onDenyColumnHide();
+                        return false;
+                    }
+                    cm.setHidden(index, item.checked);
+                }
+        }
+        return true;
+    },
+
+    beforeColMenuShow : function(){
+        var cm = this.cm,  colCount = cm.getColumnCount();
+        this.colMenu.removeAll();
+        
+        var items = [];
+        for(var i = 0; i < colCount; i++){
+            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]));
+        }
+    },
+
+    handleHdCtx : function(g, index, e){
+        e.stopEvent();
+        var hd = this.getHeaderCell(index);
+        this.hdCtxIndex = index;
+        var ms = this.hmenu.items, cm = this.cm;
+        ms.get("asc").setDisabled(!cm.isSortable(index));
+        ms.get("desc").setDisabled(!cm.isSortable(index));
+        if(this.grid.enableColLock !== false){
+            ms.get("lock").setDisabled(cm.isLocked(index));
+            ms.get("unlock").setDisabled(!cm.isLocked(index));
+        }
+        this.hmenu.show(hd, "tl-bl");
+    },
+
+    handleHdOver : function(e){
+        var hd = this.findHeaderCell(e.getTarget());
+        if(hd && !this.headersDisabled){
+            if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
+               this.fly(hd).addClass("x-grid-hd-over");
+            }
+        }
+    },
+
+    handleHdOut : function(e){
+        var hd = this.findHeaderCell(e.getTarget());
+        if(hd){
+            this.fly(hd).removeClass("x-grid-hd-over");
+        }
+    },
+
+    handleSplitDblClick : function(e, t){
+        var i = this.getCellIndex(t);
+        if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
+            this.autoSizeColumn(i, true);
+            this.layout();
+        }
+    },
+
+    render : function(){
+
+        var cm = this.cm;
+        var colCount = cm.getColumnCount();
+
+        if(this.grid.monitorWindowResize === true){
+            Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
+        }
+        var header = this.renderHeaders();
+        var body = this.templates.body.apply({rows:""});
+        var html = this.templates.master.apply({
+            lockedBody: body,
+            body: body,
+            lockedHeader: header[0],
+            header: header[1]
+        });
+
+        //this.updateColumns();
+
+        this.grid.getGridEl().dom.innerHTML = html;
+
+        this.initElements();
+        
+        // a kludge to fix the random scolling effect in webkit
+        this.el.on("scroll", function() {
+            this.el.dom.scrollTop=0; // hopefully not recursive..
+        },this);
+
+        this.scroller.on("scroll", this.handleScroll, this);
+        this.lockedBody.on("mousewheel", this.handleWheel, this);
+        this.mainBody.on("mousewheel", this.handleWheel, this);
+
+        this.mainHd.on("mouseover", this.handleHdOver, this);
+        this.mainHd.on("mouseout", this.handleHdOut, this);
+        this.mainHd.on("dblclick", this.handleSplitDblClick, this,
+                {delegate: "."+this.splitClass});
+
+        this.lockedHd.on("mouseover", this.handleHdOver, this);
+        this.lockedHd.on("mouseout", this.handleHdOut, this);
+        this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
+                {delegate: "."+this.splitClass});
+
+        if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
+            new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
+        }
+
+        this.updateSplitters();
+
+        if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
+            new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
+            new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
+        }
+
+        if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
+            this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
+            this.hmenu.add(
+                {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
+                {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
+            );
+            if(this.grid.enableColLock !== false){
+                this.hmenu.add('-',
+                    {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
+                    {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
+                );
+            }
+            if (Roo.isTouch) {
+                 this.hmenu.add('-',
+                    {id:"wider", text: this.columnsWiderText},
+                    {id:"narrow", text: this.columnsNarrowText }
+                );
+                
+                 
+            }
+            
+            if(this.grid.enableColumnHide !== false){
+
+                this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
+                this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
+                this.colMenu.on("itemclick", this.handleHdMenuClick, this);
+
+                this.hmenu.add('-',
+                    {id:"columns", text: this.columnsText, menu: this.colMenu}
+                );
+            }
+            this.hmenu.on("itemclick", this.handleHdMenuClick, this);
+
+            this.grid.on("headercontextmenu", this.handleHdCtx, this);
+        }
+
+        if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
+            this.dd = new Roo.grid.GridDragZone(this.grid, {
+                ddGroup : this.grid.ddGroup || 'GridDD'
+            });
+            
+        }
+
+        /*
+        for(var i = 0; i < colCount; i++){
+            if(cm.isHidden(i)){
+                this.hideColumn(i);
+            }
+            if(cm.config[i].align){
+                this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
+                this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
+            }
+        }*/
+        
+        this.updateHeaderSortState();
+
+        this.beforeInitialResize();
+        this.layout(true);
+
+        // two part rendering gives faster view to the user
+        this.renderPhase2.defer(1, this);
+    },
+
+    renderPhase2 : function(){
+        // render the rows now
+        this.refresh();
+        if(this.grid.autoSizeColumns){
+            this.autoSizeColumns();
+        }
+    },
+
+    beforeInitialResize : function(){
+
+    },
+
+    onColumnSplitterMoved : function(i, w){
+        this.userResized = true;
+        var cm = this.grid.colModel;
+        cm.setColumnWidth(i, w, true);
+        var cid = cm.getColumnId(i);
+        this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
+        this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
+        this.updateSplitters();
+        this.layout();
+        this.grid.fireEvent("columnresize", i, w);
+    },
+
+    syncRowHeights : function(startIndex, endIndex){
+        if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
+            startIndex = startIndex || 0;
+            var mrows = this.getBodyTable().rows;
+            var lrows = this.getLockedTable().rows;
+            var len = mrows.length-1;
+            endIndex = Math.min(endIndex || len, len);
+            for(var i = startIndex; i <= endIndex; i++){
+                var m = mrows[i], l = lrows[i];
+                var h = Math.max(m.offsetHeight, l.offsetHeight);
+                m.style.height = l.style.height = h + "px";
+            }
+        }
+    },
+
+    layout : function(initialRender, is2ndPass)
+    {
+        var g = this.grid;
+        var auto = g.autoHeight;
+        var scrollOffset = 16;
+        var c = g.getGridEl(), cm = this.cm,
+                expandCol = g.autoExpandColumn,
+                gv = this;
+        //c.beginMeasure();
+
+        if(!c.dom.offsetWidth){ // display:none?
+            if(initialRender){
+                this.lockedWrap.show();
+                this.mainWrap.show();
+            }
+            return;
+        }
+
+        var hasLock = this.cm.isLocked(0);
+
+        var tbh = this.headerPanel.getHeight();
+        var bbh = this.footerPanel.getHeight();
+
+        if(auto){
+            var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
+            var newHeight = ch + c.getBorderWidth("tb");
+            if(g.maxHeight){
+                newHeight = Math.min(g.maxHeight, newHeight);
+            }
+            c.setHeight(newHeight);
+        }
+
+        if(g.autoWidth){
+            c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
+        }
+
+        var s = this.scroller;
+
+        var csize = c.getSize(true);
+
+        this.el.setSize(csize.width, csize.height);
+
+        this.headerPanel.setWidth(csize.width);
+        this.footerPanel.setWidth(csize.width);
+
+        var hdHeight = this.mainHd.getHeight();
+        var vw = csize.width;
+        var vh = csize.height - (tbh + bbh);
+
+        s.setSize(vw, vh);
+
+        var bt = this.getBodyTable();
+        
+        if(cm.getLockedCount() == cm.config.length){
+            bt = this.getLockedTable();
+        }
+        
+        var ltWidth = hasLock ?
+                      Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
+
+        var scrollHeight = bt.offsetHeight;
+        var scrollWidth = ltWidth + bt.offsetWidth;
+        var vscroll = false, hscroll = false;
+
+        this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
+
+        var lw = this.lockedWrap, mw = this.mainWrap;
+        var lb = this.lockedBody, mb = this.mainBody;
+
+        setTimeout(function(){
+            var t = s.dom.offsetTop;
+            var w = s.dom.clientWidth,
+                h = s.dom.clientHeight;
+
+            lw.setTop(t);
+            lw.setSize(ltWidth, h);
+
+            mw.setLeftTop(ltWidth, t);
+            mw.setSize(w-ltWidth, h);
+
+            lb.setHeight(h-hdHeight);
+            mb.setHeight(h-hdHeight);
+
+            if(is2ndPass !== true && !gv.userResized && expandCol){
+                // high speed resize without full column calculation
+                
+                var ci = cm.getIndexById(expandCol);
+                if (ci < 0) {
+                    ci = cm.findColumnIndex(expandCol);
+                }
+                ci = Math.max(0, ci); // make sure it's got at least the first col.
+                var expandId = cm.getColumnId(ci);
+                var  tw = cm.getTotalWidth(false);
+                var currentWidth = cm.getColumnWidth(ci);
+                var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
+                if(currentWidth != cw){
+                    cm.setColumnWidth(ci, cw, true);
+                    gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
+                    gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
+                    gv.updateSplitters();
+                    gv.layout(false, true);
+                }
+            }
+
+            if(initialRender){
+                lw.show();
+                mw.show();
+            }
+            //c.endMeasure();
+        }, 10);
+    },
+
+    onWindowResize : function(){
+        if(!this.grid.monitorWindowResize || this.grid.autoHeight){
+            return;
+        }
+        this.layout();
+    },
+
+    appendFooter : function(parentEl){
+        return null;
+    },
+
+    sortAscText : "Sort Ascending",
+    sortDescText : "Sort Descending",
+    lockText : "Lock Column",
+    unlockText : "Unlock Column",
+    columnsText : "Columns",
+    columnsWiderText : "Wider",
+    columnsNarrowText : "Thinner"
+});
+
+
+Roo.grid.GridView.ColumnDragZone = function(grid, hd){
+    Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
+    this.proxy.el.addClass('x-grid3-col-dd');
+};
+
+Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
+    handleMouseDown : function(e){
+
+    },
+
+    callHandleMouseDown : function(e){
+        Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
+    }
+});
+/*
+ * 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">
+ */
+ /**
+ * @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, // ID
+        "gridSplitters" + this.grid.getGridEl().id, // SGROUP
+        {  // CONFIG
+            dragElId : Roo.id(this.proxy.dom),
+            resizeFrame:false
+        }
+    );
+    
+    this.setHandleElId(Roo.id(hd));
+    if (hd2 !== false) {
+        this.setOuterHandleElId(Roo.id(hd2));
+    }
+    
+    this.scroll = false;
+};
+Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
+    fly: Roo.Element.fly,
+
+    b4StartDrag : function(x, y){
+        this.view.headersDisabled = true;
+        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);
+        this.setYConstraint(0, 0);
+        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);
+    },
+
+
+    handleMouseDown : function(e){
+        ev = Roo.EventObject.setEvent(e);
+        var t = this.fly(ev.getTarget());
+        if(t.hasClass("x-grid-split")){
+            this.cellIndex = this.view.getCellIndex(t.dom);
+            this.split = t.dom;
+            this.cm = this.grid.colModel;
+            if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
+                Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
+            }
+        }
+    },
+
+    endDrag : function(e){
+        this.view.headersDisabled = false;
+        var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
+        var diff = endX - this.startPos;
+        // 
+        var w = this.cm.getColumnWidth(this.cellIndex);
+        if (!this.view.mainWrap) {
+            w = 0;
+        }
+        this.view.onColumnSplitterMoved(this.cellIndex, w+diff);
+    },
+
+    autoOffset : function(){
+        this.setDelta(0,0);
+    }
+});/*
+ * 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">
+ */
+// private
+// This is a support class used internally by the Grid components
+Roo.grid.GridDragZone = function(grid, config){
+    this.view = grid.getView();
+    Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
+    if(this.view.lockedBody){
+        this.setHandleElId(Roo.id(this.view.mainBody.dom));
+        this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
+    }
+    this.scroll = false;
+    this.grid = grid;
+    this.ddel = document.createElement('div');
+    this.ddel.className = 'x-grid-dd-wrap';
+};
+
+Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
+    ddGroup : "GridDD",
+
+    getDragData : function(e){
+        var t = Roo.lib.Event.getTarget(e);
+        var rowIndex = this.view.findRowIndex(t);
+        var sm = this.grid.selModel;
+            
+        //Roo.log(rowIndex);
+        
+        if (sm.getSelectedCell) {
+            // cell selection..
+            if (!sm.getSelectedCell()) {
+                return false;
+            }
+            if (rowIndex != sm.getSelectedCell()[0]) {
+                return false;
+            }
+        
+        }
+        if (sm.getSelections && sm.getSelections().length < 1) {
+            return false;
+        }
+        
+        
+        // before it used to all dragging of unseleted... - now we dont do that.
+        if(rowIndex !== false){
+            
+            // if editorgrid.. 
+            
+            
+            //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
+               
+            //if(!sm.isSelected(rowIndex) || e.hasModifier()){
+              //  
+            //}
+            if (e.hasModifier()){
+                sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
+            }
+            
+            Roo.log("getDragData");
+            
+            return {
+                grid: this.grid,
+                ddel: this.ddel,
+                rowIndex: rowIndex,
+                selections: sm.getSelections ? sm.getSelections() : (
+                    sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : [])
+            };
+        }
+        return false;
+    },
+    
+    
+    onInitDrag : function(e){
+        var data = this.dragData;
+        this.ddel.innerHTML = this.grid.getDragDropText();
+        this.proxy.update(this.ddel);
+        // fire start drag?
+    },
+
+    afterRepair : function(){
+        this.dragging = false;
+    },
+
+    getRepairXY : function(e, data){
+        return false;
+    },
+
+    onEndDrag : function(data, e){
+        // fire end drag?
+    },
+
+    onValidDrop : function(dd, e, id){
+        // fire drag drop?
+        this.hideProxy();
+    },
+
+    beforeInvalidDrop : function(e, id){
+
+    }
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+
+/**
+ * @class Roo.grid.ColumnModel
+ * @extends Roo.util.Observable
+ * This is the default implementation of a ColumnModel used by the Grid. It defines
+ * the columns in the grid.
+ * <br>Usage:<br>
+ <pre><code>
+ var colModel = new Roo.grid.ColumnModel([
+       {header: "Ticker", width: 60, sortable: true, locked: true},
+       {header: "Company Name", width: 150, sortable: true},
+       {header: "Market Cap.", width: 100, sortable: true},
+       {header: "$ Sales", width: 100, sortable: true, renderer: money},
+       {header: "Employees", width: 100, sortable: true, resizable: false}
+ ]);
+ </code></pre>
+ * <p>
+ * The config options listed for this class are options which may appear in each
+ * individual column definition.
+ * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
+ * @constructor
+ * @param {Object} config An Array of column config objects. See this class's
+ * config objects for details.
+*/
+Roo.grid.ColumnModel = function(config){
+       /**
+     * The config passed into the constructor
+     */
+    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++){
+       this.addColumn(config[i]);
+       
+    }
+
+    /**
+     * The width of columns which have no width specified (defaults to 100)
+     * @type Number
+     */
+    this.defaultWidth = 100;
+
+    /**
+     * Default sortable of columns which have no sortable specified (defaults to false)
+     * @type Boolean
+     */
+    this.defaultSortable = false;
+
+    this.addEvents({
+        /**
+            * @event widthchange
+            * Fires when the width of a column changes.
+            * @param {ColumnModel} this
+            * @param {Number} columnIndex The column index
+            * @param {Number} newWidth The new width
+            */
+           "widthchange": true,
+        /**
+            * @event headerchange
+            * Fires when the text of a header changes.
+            * @param {ColumnModel} this
+            * @param {Number} columnIndex The column index
+            * @param {Number} newText The new header text
+            */
+           "headerchange": true,
+        /**
+            * @event hiddenchange
+            * Fires when a column is hidden or "unhidden".
+            * @param {ColumnModel} this
+            * @param {Number} columnIndex The column index
+            * @param {Boolean} hidden true if hidden, false otherwise
+            */
+           "hiddenchange": true,
+           /**
+         * @event columnmoved
+         * Fires when a column is moved.
+         * @param {ColumnModel} this
+         * @param {Number} oldIndex
+         * @param {Number} newIndex
+         */
+        "columnmoved" : true,
+        /**
+         * @event columlockchange
+         * Fires when a column's locked state is changed
+         * @param {ColumnModel} this
+         * @param {Number} colIndex
+         * @param {Boolean} locked true if locked
+         */
+        "columnlockchange" : true
+    });
+    Roo.grid.ColumnModel.superclass.constructor.call(this);
+};
+Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
+    /**
+     * @cfg {String} header [required] 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  The name of the field in the grid's {@link Roo.data.Store}'s
+     * {@link Roo.data.Record} definition from which to draw the column's value. If not
+     * specified, the column's index is used as an index into the Record's data Array.
+     */
+    /**
+     * @cfg {Number} width  The initial width in pixels of the column. Using this
+     * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
+     */
+    /**
+     * @cfg {Boolean} sortable True if sorting is to be allowed on this column.
+     * Defaults to the value of the {@link #defaultSortable} property.
+     * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
+     */
+    /**
+     * @cfg {Boolean} locked  True to lock the column in place while scrolling the Grid.  Defaults to false.
+     */
+    /**
+     * @cfg {Boolean} fixed  True if the column width cannot be changed.  Defaults to false.
+     */
+    /**
+     * @cfg {Boolean} resizable  False to disable column resizing. Defaults to true.
+     */
+    /**
+     * @cfg {Boolean} hidden  True to hide the column. Defaults to false.
+     */
+    /**
+     * @cfg {Function} renderer A function used to generate HTML markup for a cell
+     * given the cell's data value. See {@link #setRenderer}. If not specified, the
+     * default renderer returns the escaped data value. If an object is returned (bootstrap only)
+     * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
+     */
+       /**
+     * @cfg {Roo.grid.GridEditor} editor  For grid editors - returns the grid editor 
+     */
+    /**
+     * @cfg {String} align (left|right) Set the CSS text-align property of the column.  Defaults to undefined (left).
+     */
+    /**
+     * @cfg {String} valign (top|bottom|middle) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc).  Defaults to undefined (middle)
+     */
+    /**
+     * @cfg {String} cursor ( auto|default|none|context-menu|help|pointer|progress|wait|cell|crosshair|text|vertical-text|alias|copy|move|no-drop|not-allowed|e-resize|n-resize|ne-resize|nw-resize|s-resize|se-resize|sw-resize|w-resize|ew-resize|ns-resize|nesw-resize|nwse-resize|col-resize|row-resize|all-scroll|zoom-in|zoom-out|grab|grabbing)
+     */
+    /**
+     * @cfg {String} tooltip mouse over tooltip text
+     */
+    /**
+     * @cfg {Number} xs  can be '0' for hidden at this size (number less than 12)
+     */
+    /**
+     * @cfg {Number} sm can be '0' for hidden at this size (number less than 12)
+     */
+    /**
+     * @cfg {Number} md can be '0' for hidden at this size (number less than 12)
+     */
+    /**
+     * @cfg {Number} lg   can be '0' for hidden at this size (number less than 12)
+     */
+       /**
+     * @cfg {Number} xl   can be '0' for hidden at this size (number less than 12)
+     */
+    /**
+     * Returns the id of the column at the specified index.
+     * @param {Number} index The column index
+     * @return {String} the id
+     */
+    getColumnId : function(index){
+        return this.config[index].id;
+    },
+
+    /**
+     * Returns the column for a specified id.
+     * @param {String} id The column id
+     * @return {Object} the column
+     */
+    getColumnById : function(id){
+        return this.lookup[id];
+    },
+
+    
+    /**
+     * Returns the column Object for a specified dataIndex.
+     * @param {String} dataIndex The column dataIndex
+     * @return {Object|Boolean} the column or false if not found
+     */
+    getColumnByDataIndex: function(dataIndex){
+        var index = this.findColumnIndex(dataIndex);
+        return index > -1 ? this.config[index] : false;
+    },
+    
+    /**
+     * Returns the index for a specified column id.
+     * @param {String} id The column id
+     * @return {Number} the index, or -1 if not found
+     */
+    getIndexById : function(id){
+        for(var i = 0, len = this.config.length; i < len; i++){
+            if(this.config[i].id == id){
+                return i;
+            }
+        }
+        return -1;
+    },
+    
+    /**
+     * Returns the index for a specified column dataIndex.
+     * @param {String} dataIndex The column dataIndex
+     * @return {Number} the index, or -1 if not found
+     */
+    
+    findColumnIndex : function(dataIndex){
+        for(var i = 0, len = this.config.length; i < len; i++){
+            if(this.config[i].dataIndex == dataIndex){
+                return i;
+            }
+        }
+        return -1;
+    },
+    
+    
+    moveColumn : function(oldIndex, newIndex){
+        var c = this.config[oldIndex];
+        this.config.splice(oldIndex, 1);
+        this.config.splice(newIndex, 0, c);
+        this.dataMap = null;
+        this.fireEvent("columnmoved", this, oldIndex, newIndex);
+    },
+
+    isLocked : function(colIndex){
+        return this.config[colIndex].locked === true;
+    },
+
+    setLocked : function(colIndex, value, suppressEvent){
+        if(this.isLocked(colIndex) == value){
+            return;
+        }
+        this.config[colIndex].locked = value;
+        if(!suppressEvent){
+            this.fireEvent("columnlockchange", this, colIndex, value);
+        }
+    },
+
+    getTotalLockedWidth : function(){
+        var totalWidth = 0;
+        for(var i = 0; i < this.config.length; i++){
+            if(this.isLocked(i) && !this.isHidden(i)){
+                this.totalWidth += this.getColumnWidth(i);
+            }
+        }
+        return totalWidth;
+    },
+
+    getLockedCount : function(){
+        for(var i = 0, len = this.config.length; i < len; i++){
+            if(!this.isLocked(i)){
+                return i;
+            }
+        }
+        
+        return this.config.length;
+    },
+
+    /**
+     * Returns the number of columns.
+     * @return {Number}
+     */
+    getColumnCount : function(visibleOnly){
+        if(visibleOnly === true){
+            var c = 0;
+            for(var i = 0, len = this.config.length; i < len; i++){
+                if(!this.isHidden(i)){
+                    c++;
+                }
+            }
+            return c;
+        }
+        return this.config.length;
+    },
+
+    /**
+     * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
+     * @param {Function} fn
+     * @param {Object} scope (optional)
+     * @return {Array} result
+     */
+    getColumnsBy : function(fn, scope){
+        var r = [];
+        for(var i = 0, len = this.config.length; i < len; i++){
+            var c = this.config[i];
+            if(fn.call(scope||this, c, i) === true){
+                r[r.length] = c;
+            }
+        }
+        return r;
+    },
+
+    /**
+     * Returns true if the specified column is sortable.
+     * @param {Number} col The column index
+     * @return {Boolean}
+     */
+    isSortable : function(col){
+        if(typeof this.config[col].sortable == "undefined"){
+            return this.defaultSortable;
+        }
+        return this.config[col].sortable;
+    },
+
+    /**
+     * Returns the rendering (formatting) function defined for the column.
+     * @param {Number} col The column index.
+     * @return {Function} The function used to render the cell. See {@link #setRenderer}.
+     */
+    getRenderer : function(col){
+        if(!this.config[col].renderer){
+            return Roo.grid.ColumnModel.defaultRenderer;
+        }
+        return this.config[col].renderer;
+    },
+
+    /**
+     * Sets the rendering (formatting) function for a column.
+     * @param {Number} col The column index
+     * @param {Function} fn The function to use to process the cell's raw data
+     * to return HTML markup for the grid view. The render function is called with
+     * the following parameters:<ul>
+     * <li>Data value.</li>
+     * <li>Cell metadata. An object in which you may set the following attributes:<ul>
+     * <li>css A CSS style string to apply to the table cell.</li>
+     * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
+     * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
+     * <li>Row index</li>
+     * <li>Column index</li>
+     * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
+     */
+    setRenderer : function(col, fn){
+        this.config[col].renderer = fn;
+    },
+
+    /**
+     * 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, 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;
+               
+    },
+
+    /**
+     * Sets the width for a column.
+     * @param {Number} col The column index
+     * @param {Number} width The new width
+     */
+    setColumnWidth : function(col, width, suppressEvent){
+        this.config[col].width = width;
+        this.totalWidth = null;
+        if(!suppressEvent){
+             this.fireEvent("widthchange", this, col, width);
+        }
+    },
+
+    /**
+     * Returns the total width of all columns.
+     * @param {Boolean} includeHidden True to include hidden column widths
+     * @return {Number}
+     */
+    getTotalWidth : function(includeHidden){
+        if(!this.totalWidth){
+            this.totalWidth = 0;
+            for(var i = 0, len = this.config.length; i < len; i++){
+                if(includeHidden || !this.isHidden(i)){
+                    this.totalWidth += this.getColumnWidth(i);
+                }
+            }
+        }
+        return this.totalWidth;
+    },
+
+    /**
+     * Returns the header for the specified column.
+     * @param {Number} col The column index
+     * @return {String}
+     */
+    getColumnHeader : function(col){
+        return this.config[col].header;
+    },
+
+    /**
+     * Sets the header for a column.
+     * @param {Number} col The column index
+     * @param {String} header The new header
+     */
+    setColumnHeader : function(col, header){
+        this.config[col].header = header;
+        this.fireEvent("headerchange", this, col, header);
+    },
+
+    /**
+     * Returns the tooltip for the specified column.
+     * @param {Number} col The column index
+     * @return {String}
+     */
+    getColumnTooltip : function(col){
+            return this.config[col].tooltip;
+    },
+    /**
+     * Sets the tooltip for a column.
+     * @param {Number} col The column index
+     * @param {String} tooltip The new tooltip
+     */
+    setColumnTooltip : function(col, tooltip){
+            this.config[col].tooltip = tooltip;
+    },
+
+    /**
+     * Returns the dataIndex for the specified column.
+     * @param {Number} col The column index
+     * @return {Number}
+     */
+    getDataIndex : function(col){
+        return this.config[col].dataIndex;
+    },
+
+    /**
+     * Sets the dataIndex for a column.
+     * @param {Number} col The column index
+     * @param {Number} dataIndex The new dataIndex
+     */
+    setDataIndex : function(col, dataIndex){
+        this.config[col].dataIndex = dataIndex;
+    },
+
+    
+    
+    /**
+     * Returns true if the cell is editable.
+     * @param {Number} colIndex The column index
+     * @param {Number} rowIndex The row index - this is nto actually used..?
+     * @return {Boolean}
+     */
+    isCellEditable : function(colIndex, rowIndex){
+        return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
+    },
+
+    /**
+     * Returns the editor defined for the cell/column.
+     * return false or null to disable editing.
+     * @param {Number} colIndex The column index
+     * @param {Number} rowIndex The row index
+     * @return {Object}
+     */
+    getCellEditor : function(colIndex, rowIndex){
+        return this.config[colIndex].editor;
+    },
+
+    /**
+     * Sets if a column is editable.
+     * @param {Number} col The column index
+     * @param {Boolean} editable True if the column is editable
+     */
+    setEditable : function(col, editable){
+        this.config[col].editable = editable;
+    },
+
+
+    /**
+     * Returns true if the column is hidden.
+     * @param {Number} colIndex The column index
+     * @return {Boolean}
+     */
+    isHidden : function(colIndex){
+        return this.config[colIndex].hidden;
+    },
+
+
+    /**
+     * Returns true if the column width cannot be changed
+     */
+    isFixed : function(colIndex){
+        return this.config[colIndex].fixed;
+    },
+
+    /**
+     * Returns true if the column can be resized
+     * @return {Boolean}
+     */
+    isResizable : function(colIndex){
+        return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
+    },
+    /**
+     * Sets if a column is hidden.
+     * @param {Number} colIndex The column index
+     * @param {Boolean} hidden True if the column is hidden
+     */
+    setHidden : function(colIndex, hidden){
+        this.config[colIndex].hidden = hidden;
+        this.totalWidth = null;
+        this.fireEvent("hiddenchange", this, colIndex, hidden);
+    },
+
+    /**
+     * Sets the editor for a column.
+     * @param {Number} col The column index
+     * @param {Object} editor The editor object
+     */
+    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)
+{
+    if(typeof value == "object") {
+        return value;
+    }
+       if(typeof value == "string" && value.length < 1){
+           return "&#160;";
+       }
+    
+       return String.format("{0}", value);
+};
+
+// Alias for backwards compatibility
+Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
+/*
+ * 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.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
+ */
+Roo.grid.AbstractSelectionModel = function(){
+    this.locked = false;
+    Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
+};
+
+Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable,  {
+    /** @ignore Called by the grid automatically. Do not call directly. */
+    init : function(grid){
+        this.grid = grid;
+        this.initEvents();
+    },
+
+    /**
+     * Locks the selections.
+     */
+    lock : function(){
+        this.locked = true;
+    },
+
+    /**
+     * Unlocks the selections.
+     */
+    unlock : function(){
+        this.locked = false;
+    },
+
+    /**
+     * Returns true if the selections are locked.
+     * @return {Boolean}
+     */
+    isLocked : function(){
+        return this.locked;
+    }
+});/*
+ * 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">
+ */
+/**
+ * @extends Roo.grid.AbstractSelectionModel
+ * @class Roo.grid.RowSelectionModel
+ * The default SelectionModel used by {@link Roo.grid.Grid}.
+ * It supports multiple selections and keyboard selection/navigation. 
+ * @constructor
+ * @param {Object} config
+ */
+Roo.grid.RowSelectionModel = function(config){
+    Roo.apply(this, config);
+    this.selections = new Roo.util.MixedCollection(false, function(o){
+        return o.id;
+    });
+
+    this.last = false;
+    this.lastActive = false;
+
+    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
+        */
+        "rowdeselect" : true
+    });
+    Roo.grid.RowSelectionModel.superclass.constructor.call(this);
+    this.locked = false;
+};
+
+Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
+    /**
+     * @cfg {Boolean} singleSelect
+     * True to allow selection of only one row at a time (defaults to false)
+     */
+    singleSelect : false,
+
+    // private
+    initEvents : function(){
+
+        if(!this.grid.enableDragDrop && !this.grid.enableDrag){
+            this.grid.on("mousedown", this.handleMouseDown, this);
+        }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){
+                    this.selectPrevious(e.shiftKey);
+                }else if(this.last !== false && this.lastActive !== false){
+                    var last = this.last;
+                    this.selectRange(this.last,  this.lastActive-1);
+                    view.focusRow(this.lastActive);
+                    if(last !== false){
+                        this.last = last;
+                    }
+                }else{
+                    this.selectFirstRow();
+                }
+                this.fireEvent("afterselectionchange", this);
+            },
+            "down" : function(e){
+                if(!e.shiftKey){
+                    this.selectNext(e.shiftKey);
+                }else if(this.last !== false && this.lastActive !== false){
+                    var last = this.last;
+                    this.selectRange(this.last,  this.lastActive+1);
+                    view.focusRow(this.lastActive);
+                    if(last !== false){
+                        this.last = last;
+                    }
+                }else{
+                    this.selectFirstRow();
+                }
+                this.fireEvent("afterselectionchange", this);
+            },
+            scope: this
+        });
+
+         
+        view.on("refresh", this.onRefresh, this);
+        view.on("rowupdated", this.onRowUpdated, this);
+        view.on("rowremoved", this.onRemove, this);
+    },
+
+    // private
+    onRefresh : function(){
+        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){
+                v.onRowSelect(i);
+                s.add(ds.getAt(i)); // updating the selection relate data
+            }else{
+                s.remove(r);
+            }
+        });
+    },
+
+    // private
+    onRemove : function(v, index, r){
+        this.selections.remove(r);
+    },
+
+    // private
+    onRowUpdated : function(v, index, r){
+        if(this.isSelected(r)){
+            v.onRowSelect(index);
+        }
+    },
+
+    /**
+     * Select records.
+     * @param {Array} records The records to select
+     * @param {Boolean} keepExisting (optional) True to keep existing selections
+     */
+    selectRecords : function(records, keepExisting){
+        if(!keepExisting){
+            this.clearSelections();
+        }
+        var ds = this.grid.ds;
+        for(var i = 0, len = records.length; i < len; i++){
+            this.selectRow(ds.indexOf(records[i]), true);
+        }
+    },
+
+    /**
+     * Gets the number of selected rows.
+     * @return {Number}
+     */
+    getCount : function(){
+        return this.selections.length;
+    },
+
+    /**
+     * Selects the first row in the grid.
+     */
+    selectFirstRow : function(){
+        this.selectRow(0);
+    },
+
+    /**
+     * Select the last row.
+     * @param {Boolean} keepExisting (optional) True to keep existing selections
+     */
+    selectLastRow : function(keepExisting){
+        this.selectRow(this.grid.ds.getCount() - 1, keepExisting);
+    },
+
+    /**
+     * Selects the row immediately following the last selected row.
+     * @param {Boolean} keepExisting (optional) True to keep existing selections
+     */
+    selectNext : function(keepExisting){
+        if(this.last !== false && (this.last+1) < this.grid.ds.getCount()){
+            this.selectRow(this.last+1, keepExisting);
+            var view = this.grid.view ? this.grid.view : this.grid;
+            view.focusRow(this.last);
+        }
+    },
+
+    /**
+     * Selects the row that precedes the last selected row.
+     * @param {Boolean} keepExisting (optional) True to keep existing selections
+     */
+    selectPrevious : function(keepExisting){
+        if(this.last){
+            this.selectRow(this.last-1, keepExisting);
+            var view = this.grid.view ? this.grid.view : this.grid;
+            view.focusRow(this.last);
+        }
+    },
+
+    /**
+     * Returns the selected records
+     * @return {Array} Array of selected records
+     */
+    getSelections : function(){
+        return [].concat(this.selections.items);
+    },
+
+    /**
+     * Returns the first selected record.
+     * @return {Record}
+     */
+    getSelected : function(){
+        return this.selections.itemAt(0);
+    },
+
+
+    /**
+     * Clears all selections.
+     */
+    clearSelections : function(fast){
+        if(this.locked) {
+            return;
+        }
+        if(fast !== true){
+            var ds = this.grid.ds;
+            var s = this.selections;
+            s.each(function(r){
+                this.deselectRow(ds.indexOfId(r.id));
+            }, this);
+            s.clear();
+        }else{
+            this.selections.clear();
+        }
+        this.last = false;
+    },
+
+
+    /**
+     * Selects all rows.
+     */
+    selectAll : function(){
+        if(this.locked) {
+            return;
+        }
+        this.selections.clear();
+        for(var i = 0, len = this.grid.ds.getCount(); i < len; i++){
+            this.selectRow(i, true);
+        }
+    },
+
+    /**
+     * Returns True if there is a selection.
+     * @return {Boolean}
+     */
+    hasSelection : function(){
+        return this.selections.length > 0;
+    },
+
+    /**
+     * Returns True if the specified row is selected.
+     * @param {Number/Record} record The record or index of the record to check
+     * @return {Boolean}
+     */
+    isSelected : function(index){
+        var r = typeof index == "number" ? this.grid.ds.getAt(index) : index;
+        return (r && this.selections.key(r.id) ? true : false);
+    },
+
+    /**
+     * Returns True if the specified record id is selected.
+     * @param {String} id The id of record to check
+     * @return {Boolean}
+     */
+    isIdSelected : function(id){
+        return (this.selections.key(id) ? true : false);
+    },
+
+    // private
+    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;
+        };
+        if(e.shiftKey && this.last !== false){
+            var last = this.last;
+            this.selectRange(last, rowIndex, e.ctrlKey);
+            this.last = last; // reset the last
+            view.focusRow(rowIndex);
+        }else{
+            var isSelected = this.isSelected(rowIndex);
+            if(e.button !== 0 && isSelected){
+                view.focusRow(rowIndex);
+            }else if(e.ctrlKey && isSelected){
+                this.deselectRow(rowIndex);
+            }else if(!isSelected){
+                this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
+                view.focusRow(rowIndex);
+            }
+        }
+        this.fireEvent("afterselectionchange", this);
+    },
+    // private
+    handleDragableRowClick :  function(grid, rowIndex, e) 
+    {
+        if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
+            this.selectRow(rowIndex, false);
+            var view = this.grid.view ? this.grid.view : this.grid;
+            view.focusRow(rowIndex);
+             this.fireEvent("afterselectionchange", this);
+        }
+    },
+    
+    /**
+     * Selects multiple rows.
+     * @param {Array} rows Array of the indexes of the row to select
+     * @param {Boolean} keepExisting (optional) True to keep existing selections
+     */
+    selectRows : function(rows, keepExisting){
+        if(!keepExisting){
+            this.clearSelections();
+        }
+        for(var i = 0, len = rows.length; i < len; i++){
+            this.selectRow(rows[i], true);
+        }
+    },
+
+    /**
+     * Selects a range of rows. All rows in between startRow and endRow are also selected.
+     * @param {Number} startRow The index of the first row in the range
+     * @param {Number} endRow The index of the last row in the range
+     * @param {Boolean} keepExisting (optional) True to retain existing selections
+     */
+    selectRange : function(startRow, endRow, keepExisting){
+        if(this.locked) {
+            return;
+        }
+        if(!keepExisting){
+            this.clearSelections();
+        }
+        if(startRow <= endRow){
+            for(var i = startRow; i <= endRow; i++){
+                this.selectRow(i, true);
+            }
+        }else{
+            for(var i = startRow; i >= endRow; i--){
+                this.selectRow(i, true);
+            }
+        }
+    },
+
+    /**
+     * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
+     * @param {Number} startRow The index of the first row in the range
+     * @param {Number} endRow The index of the last row in the range
+     */
+    deselectRange : function(startRow, endRow, preventViewNotify){
+        if(this.locked) {
+            return;
+        }
+        for(var i = startRow; i <= endRow; i++){
+            this.deselectRow(i, preventViewNotify);
+        }
+    },
+
+    /**
+     * Selects a row.
+     * @param {Number} row The index of the row to select
+     * @param {Boolean} keepExisting (optional) True to keep existing selections
+     */
+    selectRow : function(index, keepExisting, preventViewNotify){
+        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.ds.getAt(index);
+            this.selections.add(r);
+            this.last = this.lastActive = index;
+            if(!preventViewNotify){
+                var view = this.grid.view ? this.grid.view : this.grid;
+                view.onRowSelect(index);
+            }
+            this.fireEvent("rowselect", this, index, r);
+            this.fireEvent("selectionchange", this);
+        }
+    },
+
+    /**
+     * Deselects a row.
+     * @param {Number} row The index of the row to deselect
+     */
+    deselectRow : function(index, preventViewNotify){
+        if(this.locked) {
+            return;
+        }
+        if(this.last == index){
+            this.last = false;
+        }
+        if(this.lastActive == index){
+            this.lastActive = false;
+        }
+        var r = this.grid.ds.getAt(index);
+        this.selections.remove(r);
+        if(!preventViewNotify){
+            var view = this.grid.view ? this.grid.view : this.grid;
+            view.onRowDeselect(index);
+        }
+        this.fireEvent("rowdeselect", this, index);
+        this.fireEvent("selectionchange", this);
+    },
+
+    // private
+    restoreLast : function(){
+        if(this._last){
+            this.last = this._last;
+        }
+    },
+
+    // private
+    acceptsNav : function(row, col, cm){
+        return !cm.isHidden(col) && cm.isCellEditable(col, row);
+    },
+
+    // private
+    onEditorKey : function(field, e){
+        var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
+        if(k == e.TAB){
+            e.stopEvent();
+            ed.completeEdit();
+            if(e.shiftKey){
+                newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
+            }else{
+                newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
+            }
+        }else if(k == e.ENTER && !e.ctrlKey){
+            e.stopEvent();
+            ed.completeEdit();
+            if(e.shiftKey){
+                newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
+            }else{
+                newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
+            }
+        }else if(k == e.ESC){
+            ed.cancelEdit();
+        }
+        if(newCell){
+            g.startEditing(newCell[0], newCell[1]);
+        }
+    }
+});/*
+ * 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.grid.CellSelectionModel
+ * @extends Roo.grid.AbstractSelectionModel
+ * This class provides the basic implementation for cell selection in a grid.
+ * @constructor
+ * @param {Object} config The object containing the configuration of this model.
+ * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
+ */
+Roo.grid.CellSelectionModel = function(config){
+    Roo.apply(this, config);
+
+    this.selection = null;
+
+    this.addEvents({
+        /**
+            * @event beforerowselect
+            * Fires before a cell is selected.
+            * @param {SelectionModel} this
+            * @param {Number} rowIndex The selected row index
+            * @param {Number} colIndex The selected cell index
+            */
+           "beforecellselect" : true,
+        /**
+            * @event cellselect
+            * Fires when a cell is selected.
+            * @param {SelectionModel} this
+            * @param {Number} rowIndex The selected row index
+            * @param {Number} colIndex The selected cell index
+            */
+           "cellselect" : true,
+        /**
+            * @event selectionchange
+            * Fires when the active selection changes.
+            * @param {SelectionModel} this
+            * @param {Object} selection null for no selection or an object (o) with two properties
+               <ul>
+               <li>o.record: the record object for the row the selection is in</li>
+               <li>o.cell: An array of [rowIndex, columnIndex]</li>
+               </ul>
+            */
+           "selectionchange" : true,
+        /**
+            * @event tabend
+            * Fires when the tab (or enter) was pressed on the last editable cell
+            * You can use this to trigger add new row.
+            * @param {SelectionModel} this
+            */
+           "tabend" : true,
+         /**
+            * @event beforeeditnext
+            * Fires before the next editable sell is made active
+            * You can use this to skip to another cell or fire the tabend
+            *    if you set cell to false
+            * @param {Object} eventdata object : { cell : [ row, col ] } 
+            */
+           "beforeeditnext" : true
+    });
+    Roo.grid.CellSelectionModel.superclass.constructor.call(this);
+};
+
+Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel,  {
+    
+    enter_is_tab: false,
+
+    /** @ignore */
+    initEvents : function(){
+        this.grid.on("mousedown", this.handleMouseDown, this);
+        this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
+        var view = this.grid.view;
+        view.on("refresh", this.onViewChange, this);
+        view.on("rowupdated", this.onRowUpdated, this);
+        view.on("beforerowremoved", this.clearSelections, this);
+        view.on("beforerowsinserted", this.clearSelections, this);
+        if(this.grid.isEditor){
+            this.grid.on("beforeedit", this.beforeEdit,  this);
+        }
+    },
+
+       //private
+    beforeEdit : function(e){
+        this.select(e.row, e.column, false, true, e.record);
+    },
+
+       //private
+    onRowUpdated : function(v, index, r){
+        if(this.selection && this.selection.record == r){
+            v.onCellSelect(index, this.selection.cell[1]);
+        }
+    },
+
+       //private
+    onViewChange : function(){
+        this.clearSelections(true);
+    },
+
+       /**
+        * Returns the currently selected cell,.
+        * @return {Array} The selected cell (row, column) or null if none selected.
+        */
+    getSelectedCell : function(){
+        return this.selection ? this.selection.cell : null;
+    },
+
+    /**
+     * Clears all selections.
+     * @param {Boolean} true to prevent the gridview from being notified about the change.
+     */
+    clearSelections : function(preventNotify){
+        var s = this.selection;
+        if(s){
+            if(preventNotify !== true){
+                this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
+            }
+            this.selection = null;
+            this.fireEvent("selectionchange", this, null);
+        }
+    },
+
+    /**
+     * Returns true if there is a selection.
+     * @return {Boolean}
+     */
+    hasSelection : function(){
+        return this.selection ? true : false;
+    },
+
+    /** @ignore */
+    handleMouseDown : function(e, t){
+        var v = this.grid.getView();
+        if(this.isLocked()){
+            return;
+        };
+        var row = v.findRowIndex(t);
+        var cell = v.findCellIndex(t);
+        if(row !== false && cell !== false){
+            this.select(row, cell);
+        }
+    },
+
+    /**
+     * Selects a cell.
+     * @param {Number} rowIndex
+     * @param {Number} collIndex
+     */
+    select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
+        if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
+            this.clearSelections();
+            r = r || this.grid.dataSource.getAt(rowIndex);
+            this.selection = {
+                record : r,
+                cell : [rowIndex, colIndex]
+            };
+            if(!preventViewNotify){
+                var v = this.grid.getView();
+                v.onCellSelect(rowIndex, colIndex);
+                if(preventFocus !== true){
+                    v.focusCell(rowIndex, colIndex);
+                }
+            }
+            this.fireEvent("cellselect", this, rowIndex, colIndex);
+            this.fireEvent("selectionchange", this, this.selection);
+        }
+    },
+
+       //private
+    isSelectable : function(rowIndex, colIndex, cm){
+        return !cm.isHidden(colIndex);
+    },
+
+    /** @ignore */
+    handleKeyDown : function(e){
+        //Roo.log('Cell Sel Model handleKeyDown');
+        if(!e.isNavKeyPress()){
+            return;
+        }
+        var g = this.grid, s = this.selection;
+        if(!s){
+            e.stopEvent();
+            var cell = g.walkCells(0, 0, 1, this.isSelectable,  this);
+            if(cell){
+                this.select(cell[0], cell[1]);
+            }
+            return;
+        }
+        var sm = this;
+        var walk = function(row, col, step){
+            return g.walkCells(row, col, step, sm.isSelectable,  sm);
+        };
+        var k = e.getKey(), r = s.cell[0], c = s.cell[1];
+        var newCell;
+
+      
+
+        switch(k){
+            case e.TAB:
+                // handled by onEditorKey
+                if (g.isEditor && g.editing) {
+                    return;
+                }
+                if(e.shiftKey) {
+                    newCell = walk(r, c-1, -1);
+                } else {
+                    newCell = walk(r, c+1, 1);
+                }
+                break;
+            
+            case e.DOWN:
+               newCell = walk(r+1, c, 1);
+                break;
+            
+            case e.UP:
+                newCell = walk(r-1, c, -1);
+                break;
+            
+            case e.RIGHT:
+                newCell = walk(r, c+1, 1);
+                break;
+            
+            case e.LEFT:
+                newCell = walk(r, c-1, -1);
+                break;
+            
+            case e.ENTER:
+                
+                if(g.isEditor && !g.editing){
+                   g.startEditing(r, c);
+                   e.stopEvent();
+                   return;
+                }
+                
+                
+             break;
+        };
+        if(newCell){
+            this.select(newCell[0], newCell[1]);
+            e.stopEvent();
+            
+        }
+    },
+
+    acceptsNav : function(row, col, cm){
+        return !cm.isHidden(col) && cm.isCellEditable(col, row);
+    },
+    /**
+     * Selects a cell.
+     * @param {Number} field (not used) - as it's normally used as a listener
+     * @param {Number} e - event - fake it by using
+     *
+     * var e = Roo.EventObjectImpl.prototype;
+     * e.keyCode = e.TAB
+     *
+     * 
+     */
+    onEditorKey : function(field, e){
+        
+        var k = e.getKey(),
+            newCell,
+            g = this.grid,
+            ed = g.activeEditor,
+            forward = false;
+        ///Roo.log('onEditorKey' + k);
+        
+        
+        if (this.enter_is_tab && k == e.ENTER) {
+            k = e.TAB;
+        }
+        
+        if(k == e.TAB){
+            if(e.shiftKey){
+                newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
+            }else{
+                newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
+                forward = true;
+            }
+            
+            e.stopEvent();
+            
+        } else if(k == e.ENTER &&  !e.ctrlKey){
+            ed.completeEdit();
+            e.stopEvent();
+            newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
+        
+               } else if(k == e.ESC){
+            ed.cancelEdit();
+        }
+               
+        if (newCell) {
+            var ecall = { cell : newCell, forward : forward };
+            this.fireEvent('beforeeditnext', ecall );
+            newCell = ecall.cell;
+                       forward = ecall.forward;
+        }
+               
+        if(newCell){
+            //Roo.log('next cell after edit');
+            g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
+        } else if (forward) {
+            // tabbed past last
+            this.fireEvent.defer(100, this, ['tabend',this]);
+        }
+    }
+});/*
+ * 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.grid.EditorGrid
+ * @extends Roo.grid.Grid
+ * Class for creating and editable grid.
+ * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered - 
+ * The container MUST have some type of size defined for the grid to fill. The container will be 
+ * automatically set to position relative if it isn't already.
+ * @param {Object} dataSource The data model to bind to
+ * @param {Object} colModel The column model with info about this grid's columns
+ */
+Roo.grid.EditorGrid = function(container, config){
+    Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
+    this.getGridEl().addClass("xedit-grid");
+
+    if(!this.selModel){
+        this.selModel = new Roo.grid.CellSelectionModel();
+    }
+
+    this.activeEditor = null;
+
+       this.addEvents({
+           /**
+            * @event beforeedit
+            * Fires before cell editing is triggered. The edit event object has the following properties <br />
+            * <ul style="padding:5px;padding-left:16px;">
+            * <li>grid - This grid</li>
+            * <li>record - The record being edited</li>
+            * <li>field - The field name being edited</li>
+            * <li>value - The value for the field being edited.</li>
+            * <li>row - The grid row index</li>
+            * <li>column - The grid column index</li>
+            * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
+            * </ul>
+            * @param {Object} e An edit event (see above for description)
+            */
+           "beforeedit" : true,
+           /**
+            * @event afteredit
+            * Fires after a cell is edited. <br />
+            * <ul style="padding:5px;padding-left:16px;">
+            * <li>grid - This grid</li>
+            * <li>record - The record being edited</li>
+            * <li>field - The field name being edited</li>
+            * <li>value - The value being set</li>
+            * <li>originalValue - The original value for the field, before the edit.</li>
+            * <li>row - The grid row index</li>
+            * <li>column - The grid column index</li>
+            * </ul>
+            * @param {Object} e An edit event (see above for description)
+            */
+           "afteredit" : true,
+           /**
+            * @event validateedit
+            * Fires after a cell is edited, but before the value is set in the record. 
+         * You can use this to modify the value being set in the field, Return false
+            * to cancel the change. The edit event object has the following properties <br />
+            * <ul style="padding:5px;padding-left:16px;">
+         * <li>editor - This editor</li>
+            * <li>grid - This grid</li>
+            * <li>record - The record being edited</li>
+            * <li>field - The field name being edited</li>
+            * <li>value - The value being set</li>
+            * <li>originalValue - The original value for the field, before the edit.</li>
+            * <li>row - The grid row index</li>
+            * <li>column - The grid column index</li>
+            * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
+            * </ul>
+            * @param {Object} e An edit event (see above for description)
+            */
+           "validateedit" : true
+       });
+    this.on("bodyscroll", this.stopEditing,  this);
+    this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick,  this);
+};
+
+Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
+    /**
+     * @cfg {Number} clicksToEdit
+     * The number of clicks on a cell required to display the cell's editor (defaults to 2)
+     */
+    clicksToEdit: 2,
+
+    // private
+    isEditor : true,
+    // private
+    trackMouseOver: false, // causes very odd FF errors
+
+    onCellDblClick : function(g, row, col){
+        this.startEditing(row, col);
+    },
+
+    onEditComplete : function(ed, value, startValue){
+        this.editing = false;
+        this.activeEditor = null;
+        ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
+        var r = ed.record;
+        var field = this.colModel.getDataIndex(ed.col);
+        var e = {
+            grid: this,
+            record: r,
+            field: field,
+            originalValue: startValue,
+            value: value,
+            row: ed.row,
+            column: ed.col,
+            cancel:false,
+            editor: ed
+        };
+        var cell = Roo.get(this.view.getCell(ed.row,ed.col));
+        cell.show();
+          
+        if(String(value) !== String(startValue)){
+            
+            if(this.fireEvent("validateedit", e) !== false && !e.cancel){
+                r.set(field, e.value);
+                // if we are dealing with a combo box..
+                // then we also set the 'name' colum to be the displayField
+                if (ed.field.displayField && ed.field.name) {
+                    r.set(ed.field.name, ed.field.el.dom.value);
+                }
+                
+                delete e.cancel; //?? why!!!
+                this.fireEvent("afteredit", e);
+            }
+        } else {
+            this.fireEvent("afteredit", e); // always fire it!
+        }
+        this.view.focusCell(ed.row, ed.col);
+    },
+
+    /**
+     * Starts editing the specified for the specified row/column
+     * @param {Number} rowIndex
+     * @param {Number} colIndex
+     */
+    startEditing : function(row, col){
+        this.stopEditing();
+        if(this.colModel.isCellEditable(col, row)){
+            this.view.ensureVisible(row, col, true);
+          
+            var r = this.dataSource.getAt(row);
+            var field = this.colModel.getDataIndex(col);
+            var cell = Roo.get(this.view.getCell(row,col));
+            var e = {
+                grid: this,
+                record: r,
+                field: field,
+                value: r.data[field],
+                row: row,
+                column: col,
+                cancel:false 
+            };
+            if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
+                this.editing = true;
+                var ed = this.colModel.getCellEditor(col, row);
+                
+                if (!ed) {
+                    return;
+                }
+                if(!ed.rendered){
+                    ed.render(ed.parentEl || document.body);
+                }
+                ed.field.reset();
+               
+                cell.hide();
+                
+                (function(){ // complex but required for focus issues in safari, ie and opera
+                    ed.row = row;
+                    ed.col = col;
+                    ed.record = r;
+                    ed.on("complete",   this.onEditComplete,        this,       {single: true});
+                    ed.on("specialkey", this.selModel.onEditorKey,  this.selModel);
+                    this.activeEditor = ed;
+                    var v = r.data[field];
+                    ed.startEdit(this.view.getCell(row, col), v);
+                    // combo's with 'displayField and name set
+                    if (ed.field.displayField && ed.field.name) {
+                        ed.field.el.dom.value = r.data[ed.field.name];
+                    }
+                    
+                    
+                }).defer(50, this);
+            }
+        }
+    },
+        
+    /**
+     * Stops any active editing
+     */
+    stopEditing : function(){
+        if(this.activeEditor){
+            this.activeEditor.completeEdit();
+        }
+        this.activeEditor = null;
+    },
+       
+        /**
+     * Called to get grid's drag proxy text, by default returns this.ddText.
+     * @return {String}
+     */
+    getDragDropText : function(){
+        var count = this.selModel.getSelectedCell() ? 1 : 0;
+        return String.format(this.ddText, count, count == 1 ? '' : 's');
+    }
+       
+});/*
+ * 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">
+ */
+
+// private - not really -- you end up using it !
+// This is a support class used internally by the Grid components
+
+/**
+ * @class Roo.grid.GridEditor
+ * @extends Roo.Editor
+ * Class for creating and editable grid elements.
+ * @param {Object} config any settings (must include field)
+ */
+Roo.grid.GridEditor = function(field, config){
+    if (!config && field.field) {
+        config = field;
+        field = Roo.factory(config.field, Roo.form);
+    }
+    Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
+    field.monitorTab = false;
+};
+
+Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
+    
+    /**
+     * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
+     */
+    
+    alignment: "tl-tl",
+    autoSize: "width",
+    hideEl : false,
+    cls: "x-small-editor x-grid-editor",
+    shim:false,
+    shadow:"frame"
+});/*
+ * 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">
+ */
+  
+
+  
+Roo.grid.PropertyRecord = Roo.data.Record.create([
+    {name:'name',type:'string'},  'value'
+]);
+
+
+Roo.grid.PropertyStore = function(grid, source){
+    this.grid = grid;
+    this.store = new Roo.data.Store({
+        recordType : Roo.grid.PropertyRecord
+    });
+    this.store.on('update', this.onUpdate,  this);
+    if(source){
+        this.setSource(source);
+    }
+    Roo.grid.PropertyStore.superclass.constructor.call(this);
+};
+
+
+
+Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
+    setSource : function(o){
+        this.source = o;
+        this.store.removeAll();
+        var data = [];
+        for(var k in o){
+            if(this.isEditableValue(o[k])){
+                data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
+            }
+        }
+        this.store.loadRecords({records: data}, {}, true);
+    },
+
+    onUpdate : function(ds, record, type){
+        if(type == Roo.data.Record.EDIT){
+            var v = record.data['value'];
+            var oldValue = record.modified['value'];
+            if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
+                this.source[record.id] = v;
+                record.commit();
+                this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
+            }else{
+                record.reject();
+            }
+        }
+    },
+
+    getProperty : function(row){
+       return this.store.getAt(row);
+    },
+
+    isEditableValue: function(val){
+        if(val && val instanceof Date){
+            return true;
+        }else if(typeof val == 'object' || typeof val == 'function'){
+            return false;
+        }
+        return true;
+    },
+
+    setValue : function(prop, value){
+        this.source[prop] = value;
+        this.store.getById(prop).set('value', value);
+    },
+
+    getSource : function(){
+        return this.source;
+    }
+});
+
+Roo.grid.PropertyColumnModel = function(grid, store){
+    this.grid = grid;
+    var g = Roo.grid;
+    g.PropertyColumnModel.superclass.constructor.call(this, [
+        {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
+        {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
+    ]);
+    this.store = store;
+    this.bselect = Roo.DomHelper.append(document.body, {
+        tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
+            {tag: 'option', value: 'true', html: 'true'},
+            {tag: 'option', value: 'false', html: 'false'}
+        ]
+    });
+    Roo.id(this.bselect);
+    var f = Roo.form;
+    this.editors = {
+        'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
+        'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
+        'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
+        'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
+        'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
+    };
+    this.renderCellDelegate = this.renderCell.createDelegate(this);
+    this.renderPropDelegate = this.renderProp.createDelegate(this);
+};
+
+Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
+    
+    
+    nameText : 'Name',
+    valueText : 'Value',
+    
+    dateFormat : 'm/j/Y',
+    
+    
+    renderDate : function(dateVal){
+        return dateVal.dateFormat(this.dateFormat);
+    },
+
+    renderBool : function(bVal){
+        return bVal ? 'true' : 'false';
+    },
+
+    isCellEditable : function(colIndex, rowIndex){
+        return colIndex == 1;
+    },
+
+    getRenderer : function(col){
+        return col == 1 ?
+            this.renderCellDelegate : this.renderPropDelegate;
+    },
+
+    renderProp : function(v){
+        return this.getPropertyName(v);
+    },
+
+    renderCell : function(val){
+        var rv = val;
+        if(val instanceof Date){
+            rv = this.renderDate(val);
+        }else if(typeof val == 'boolean'){
+            rv = this.renderBool(val);
+        }
+        return Roo.util.Format.htmlEncode(rv);
+    },
+
+    getPropertyName : function(name){
+        var pn = this.grid.propertyNames;
+        return pn && pn[name] ? pn[name] : name;
+    },
+
+    getCellEditor : function(colIndex, rowIndex){
+        var p = this.store.getProperty(rowIndex);
+        var n = p.data['name'], val = p.data['value'];
+        
+        if(typeof(this.grid.customEditors[n]) == 'string'){
+            return this.editors[this.grid.customEditors[n]];
+        }
+        if(typeof(this.grid.customEditors[n]) != 'undefined'){
+            return this.grid.customEditors[n];
+        }
+        if(val instanceof Date){
+            return this.editors['date'];
+        }else if(typeof val == 'number'){
+            return this.editors['number'];
+        }else if(typeof val == 'boolean'){
+            return this.editors['boolean'];
+        }else{
+            return this.editors['string'];
+        }
+    }
+});
+
+/**
+ * @class Roo.grid.PropertyGrid
+ * @extends Roo.grid.EditorGrid
+ * This class represents the  interface of a component based property grid control.
+ * <br><br>Usage:<pre><code>
+ var grid = new Roo.grid.PropertyGrid("my-container-id", {
+      
+ });
+ // set any options
+ grid.render();
+ * </code></pre>
+  
+ * @constructor
+ * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
+ * The container MUST have some type of size defined for the grid to fill. The container will be
+ * automatically set to position relative if it isn't already.
+ * @param {Object} config A config object that sets properties on this grid.
+ */
+Roo.grid.PropertyGrid = function(container, config){
+    config = config || {};
+    var store = new Roo.grid.PropertyStore(this);
+    this.store = store;
+    var cm = new Roo.grid.PropertyColumnModel(this, store);
+    store.store.sort('name', 'ASC');
+    Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
+        ds: store.store,
+        cm: cm,
+        enableColLock:false,
         enableColumnMove:false,
         stripeRows:false,
         trackMouseOver: false,
@@ -59213,1766 +66668,3661 @@ Roo.grid.PropertyGrid = function(container, config){
     });
     this.customEditors = this.customEditors || {};
 };
-Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
-    
-     /**
-     * @cfg {Object} customEditors map of colnames=> custom editors.
-     * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
-     * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
-     * false disables editing of the field.
-        */
+Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
+    
+     /**
+     * @cfg {Object} customEditors map of colnames=> custom editors.
+     * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
+     * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
+     * false disables editing of the field.
+        */
+    
+      /**
+     * @cfg {Object} propertyNames map of property Names to their displayed value
+        */
+    
+    render : function(){
+        Roo.grid.PropertyGrid.superclass.render.call(this);
+        this.autoSize.defer(100, this);
+    },
+
+    autoSize : function(){
+        Roo.grid.PropertyGrid.superclass.autoSize.call(this);
+        if(this.view){
+            this.view.fitColumns();
+        }
+    },
+
+    onColumnResize : function(){
+        this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
+        this.autoSize();
+    },
+    /**
+     * Sets the data for the Grid
+     * accepts a Key => Value object of all the elements avaiable.
+     * @param {Object} data  to appear in grid.
+     */
+    setSource : function(source){
+        this.store.setSource(source);
+        //this.autoSize();
+    },
+    /**
+     * Gets all the data from the grid.
+     * @return {Object} data  data stored in grid
+     */
+    getSource : function(){
+        return this.store.getSource();
+    }
+});/*
+  
+ * Licence LGPL
+ */
+/**
+ * @class Roo.grid.Calendar
+ * @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", {
+     ds: myDataStore,
+     cm: myColModel,
+     selModel: mySelectionModel,
+     autoSizeColumns: true,
+     monitorWindowResize: false,
+     trackMouseOver: true
+     eventstore : real data store..
+ });
+ // set any options
+ grid.render();
+  
+  * @constructor
+ * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
+ * The container MUST have some type of size defined for the grid to fill. The container will be
+ * automatically set to position relative if it isn't already.
+ * @param {Object} config A config object that sets properties on this grid.
+ */
+Roo.grid.Calendar = function(container, config){
+       // initialize the container
+       this.container = Roo.get(container);
+       this.container.update("");
+       this.container.setStyle("overflow", "hidden");
+    this.container.addClass('x-grid-container');
+
+    this.id = this.container.id;
+
+    Roo.apply(this, config);
+    // check and correct shorthanded configs
+    
+    var rows = [];
+    var d =1;
+    for (var r = 0;r < 6;r++) {
+        
+        rows[r]=[];
+        for (var c =0;c < 7;c++) {
+            rows[r][c]= '';
+        }
+    }
+    if (this.eventStore) {
+        this.eventStore= Roo.factory(this.eventStore, Roo.data);
+        this.eventStore.on('load',this.onLoad, this);
+        this.eventStore.on('beforeload',this.clearEvents, this);
+         
+    }
+    
+    this.dataSource = new Roo.data.Store({
+            proxy: new Roo.data.MemoryProxy(rows),
+            reader: new Roo.data.ArrayReader({}, [
+                   'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
+    });
+
+    this.dataSource.load();
+    this.ds = this.dataSource;
+    this.ds.xmodule = this.xmodule || false;
+    
+    
+    var cellRender = function(v,x,r)
+    {
+        return String.format(
+            '<div class="fc-day  fc-widget-content"><div>' +
+                '<div class="fc-event-container"></div>' +
+                '<div class="fc-day-number">{0}</div>'+
+                
+                '<div class="fc-day-content"><div style="position:relative"></div></div>' +
+            '</div></div>', v);
+    
+    }
+    
+    
+    this.colModel = new Roo.grid.ColumnModel( [
+        {
+            xtype: 'ColumnModel',
+            xns: Roo.grid,
+            dataIndex : 'weekday0',
+            header : 'Sunday',
+            renderer : cellRender
+        },
+        {
+            xtype: 'ColumnModel',
+            xns: Roo.grid,
+            dataIndex : 'weekday1',
+            header : 'Monday',
+            renderer : cellRender
+        },
+        {
+            xtype: 'ColumnModel',
+            xns: Roo.grid,
+            dataIndex : 'weekday2',
+            header : 'Tuesday',
+            renderer : cellRender
+        },
+        {
+            xtype: 'ColumnModel',
+            xns: Roo.grid,
+            dataIndex : 'weekday3',
+            header : 'Wednesday',
+            renderer : cellRender
+        },
+        {
+            xtype: 'ColumnModel',
+            xns: Roo.grid,
+            dataIndex : 'weekday4',
+            header : 'Thursday',
+            renderer : cellRender
+        },
+        {
+            xtype: 'ColumnModel',
+            xns: Roo.grid,
+            dataIndex : 'weekday5',
+            header : 'Friday',
+            renderer : cellRender
+        },
+        {
+            xtype: 'ColumnModel',
+            xns: Roo.grid,
+            dataIndex : 'weekday6',
+            header : 'Saturday',
+            renderer : cellRender
+        }
+    ]);
+    this.cm = this.colModel;
+    this.cm.xmodule = this.xmodule || false;
+        
+          
+    //this.selModel = new Roo.grid.CellSelectionModel();
+    //this.sm = this.selModel;
+    //this.selModel.init(this);
+    
+    
+    if(this.width){
+        this.container.setWidth(this.width);
+    }
+
+    if(this.height){
+        this.container.setHeight(this.height);
+    }
+    /** @private */
+       this.addEvents({
+        // raw events
+        /**
+         * @event click
+         * The raw click event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "click" : true,
+        /**
+         * @event dblclick
+         * The raw dblclick event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "dblclick" : true,
+        /**
+         * @event contextmenu
+         * The raw contextmenu event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "contextmenu" : true,
+        /**
+         * @event mousedown
+         * The raw mousedown event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "mousedown" : true,
+        /**
+         * @event mouseup
+         * The raw mouseup event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "mouseup" : true,
+        /**
+         * @event mouseover
+         * The raw mouseover event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "mouseover" : true,
+        /**
+         * @event mouseout
+         * The raw mouseout event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "mouseout" : true,
+        /**
+         * @event keypress
+         * The raw keypress event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "keypress" : true,
+        /**
+         * @event keydown
+         * The raw keydown event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "keydown" : true,
+
+        // custom events
+
+        /**
+         * @event cellclick
+         * Fires when a cell is clicked
+         * @param {Grid} this
+         * @param {Number} rowIndex
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "cellclick" : true,
+        /**
+         * @event celldblclick
+         * Fires when a cell is double clicked
+         * @param {Grid} this
+         * @param {Number} rowIndex
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "celldblclick" : true,
+        /**
+         * @event rowclick
+         * Fires when a row is clicked
+         * @param {Grid} this
+         * @param {Number} rowIndex
+         * @param {Roo.EventObject} e
+         */
+        "rowclick" : true,
+        /**
+         * @event rowdblclick
+         * Fires when a row is double clicked
+         * @param {Grid} this
+         * @param {Number} rowIndex
+         * @param {Roo.EventObject} e
+         */
+        "rowdblclick" : true,
+        /**
+         * @event headerclick
+         * Fires when a header is clicked
+         * @param {Grid} this
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "headerclick" : true,
+        /**
+         * @event headerdblclick
+         * Fires when a header cell is double clicked
+         * @param {Grid} this
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "headerdblclick" : true,
+        /**
+         * @event rowcontextmenu
+         * Fires when a row is right clicked
+         * @param {Grid} this
+         * @param {Number} rowIndex
+         * @param {Roo.EventObject} e
+         */
+        "rowcontextmenu" : true,
+        /**
+         * @event cellcontextmenu
+         * Fires when a cell is right clicked
+         * @param {Grid} this
+         * @param {Number} rowIndex
+         * @param {Number} cellIndex
+         * @param {Roo.EventObject} e
+         */
+         "cellcontextmenu" : true,
+        /**
+         * @event headercontextmenu
+         * Fires when a header is right clicked
+         * @param {Grid} this
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "headercontextmenu" : true,
+        /**
+         * @event bodyscroll
+         * Fires when the body element is scrolled
+         * @param {Number} scrollLeft
+         * @param {Number} scrollTop
+         */
+        "bodyscroll" : true,
+        /**
+         * @event columnresize
+         * Fires when the user resizes a column
+         * @param {Number} columnIndex
+         * @param {Number} newSize
+         */
+        "columnresize" : true,
+        /**
+         * @event columnmove
+         * Fires when the user moves a column
+         * @param {Number} oldIndex
+         * @param {Number} newIndex
+         */
+        "columnmove" : true,
+        /**
+         * @event startdrag
+         * Fires when row(s) start being dragged
+         * @param {Grid} this
+         * @param {Roo.GridDD} dd The drag drop object
+         * @param {event} e The raw browser event
+         */
+        "startdrag" : true,
+        /**
+         * @event enddrag
+         * Fires when a drag operation is complete
+         * @param {Grid} this
+         * @param {Roo.GridDD} dd The drag drop object
+         * @param {event} e The raw browser event
+         */
+        "enddrag" : true,
+        /**
+         * @event dragdrop
+         * Fires when dragged row(s) are dropped on a valid DD target
+         * @param {Grid} this
+         * @param {Roo.GridDD} dd The drag drop object
+         * @param {String} targetId The target drag drop object
+         * @param {event} e The raw browser event
+         */
+        "dragdrop" : true,
+        /**
+         * @event dragover
+         * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
+         * @param {Grid} this
+         * @param {Roo.GridDD} dd The drag drop object
+         * @param {String} targetId The target drag drop object
+         * @param {event} e The raw browser event
+         */
+        "dragover" : true,
+        /**
+         * @event dragenter
+         *  Fires when the dragged row(s) first cross another DD target while being dragged
+         * @param {Grid} this
+         * @param {Roo.GridDD} dd The drag drop object
+         * @param {String} targetId The target drag drop object
+         * @param {event} e The raw browser event
+         */
+        "dragenter" : true,
+        /**
+         * @event dragout
+         * Fires when the dragged row(s) leave another DD target while being dragged
+         * @param {Grid} this
+         * @param {Roo.GridDD} dd The drag drop object
+         * @param {String} targetId The target drag drop object
+         * @param {event} e The raw browser event
+         */
+        "dragout" : true,
+        /**
+         * @event rowclass
+         * Fires when a row is rendered, so you can change add a style to it.
+         * @param {GridView} gridview   The grid view
+         * @param {Object} rowcfg   contains record  rowIndex and rowClass - set rowClass to add a style.
+         */
+        'rowclass' : true,
+
+        /**
+         * @event render
+         * Fires when the grid is rendered
+         * @param {Grid} grid
+         */
+        'render' : true,
+            /**
+            * @event select
+            * Fires when a date is selected
+            * @param {DatePicker} this
+            * @param {Date} date The selected date
+            */
+        'select': true,
+        /**
+            * @event monthchange
+            * Fires when the displayed month changes 
+            * @param {DatePicker} this
+            * @param {Date} date The selected month
+            */
+        'monthchange': true,
+        /**
+            * @event evententer
+            * Fires when mouse over an event
+            * @param {Calendar} this
+            * @param {event} Event
+            */
+        'evententer': true,
+        /**
+            * @event eventleave
+            * Fires when the mouse leaves an
+            * @param {Calendar} this
+            * @param {event}
+            */
+        'eventleave': true,
+        /**
+            * @event eventclick
+            * Fires when the mouse click an
+            * @param {Calendar} this
+            * @param {event}
+            */
+        'eventclick': true,
+        /**
+            * @event eventrender
+            * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
+            * @param {Calendar} this
+            * @param {data} data to be modified
+            */
+        'eventrender': true
+        
+    });
+
+    Roo.grid.Grid.superclass.constructor.call(this);
+    this.on('render', function() {
+        this.view.el.addClass('x-grid-cal'); 
+        
+        (function() { this.setDate(new Date()); }).defer(100,this); //default today..
+
+    },this);
+    
+    if (!Roo.grid.Calendar.style) {
+        Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
+            
+            
+            '.x-grid-cal .x-grid-col' :  {
+                height: 'auto !important',
+                'vertical-align': 'top'
+            },
+            '.x-grid-cal  .fc-event-hori' : {
+                height: '14px'
+            }
+             
+            
+        }, Roo.id());
+    }
+
+    
+    
+};
+Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
+    /**
+     * @cfg {Store} eventStore The store that loads events.
+     */
+    eventStore : 25,
+
+     
+    activeDate : false,
+    startDay : 0,
+    autoWidth : true,
+    monitorWindowResize : false,
+
+    
+    resizeColumns : function() {
+        var col = (this.view.el.getWidth() / 7) - 3;
+        // loop through cols, and setWidth
+        for(var i =0 ; i < 7 ; i++){
+            this.cm.setColumnWidth(i, col);
+        }
+    },
+     setDate :function(date) {
+        
+        Roo.log('setDate?');
+        
+        this.resizeColumns();
+        var vd = this.activeDate;
+        this.activeDate = date;
+//        if(vd && this.el){
+//            var t = date.getTime();
+//            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
+//                Roo.log('using add remove');
+//                
+//                this.fireEvent('monthchange', this, date);
+//                
+//                this.cells.removeClass("fc-state-highlight");
+//                this.cells.each(function(c){
+//                   if(c.dateValue == t){
+//                       c.addClass("fc-state-highlight");
+//                       setTimeout(function(){
+//                            try{c.dom.firstChild.focus();}catch(e){}
+//                       }, 50);
+//                       return false;
+//                   }
+//                   return true;
+//                });
+//                return;
+//            }
+//        }
+        
+        var days = date.getDaysInMonth();
+        
+        var firstOfMonth = date.getFirstDateOfMonth();
+        var startingPos = firstOfMonth.getDay()-this.startDay;
+        
+        if(startingPos < this.startDay){
+            startingPos += 7;
+        }
+        
+        var pm = date.add(Date.MONTH, -1);
+        var prevStart = pm.getDaysInMonth()-startingPos;
+//        
+        
+        
+        this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
+        
+        this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
+        //this.cells.addClassOnOver('fc-state-hover');
+        
+        var cells = this.cells.elements;
+        var textEls = this.textNodes;
+        
+        //Roo.each(cells, function(cell){
+        //    cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
+        //});
+        
+        days += startingPos;
+
+        // convert everything to numbers so it's fast
+        var day = 86400000;
+        var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
+        //Roo.log(d);
+        //Roo.log(pm);
+        //Roo.log(prevStart);
+        
+        var today = new Date().clearTime().getTime();
+        var sel = date.clearTime().getTime();
+        var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
+        var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
+        var ddMatch = this.disabledDatesRE;
+        var ddText = this.disabledDatesText;
+        var ddays = this.disabledDays ? this.disabledDays.join("") : false;
+        var ddaysText = this.disabledDaysText;
+        var format = this.format;
+        
+        var setCellClass = function(cal, cell){
+            
+            //Roo.log('set Cell Class');
+            cell.title = "";
+            var t = d.getTime();
+            
+            //Roo.log(d);
+            
+            
+            cell.dateValue = t;
+            if(t == today){
+                cell.className += " fc-today";
+                cell.className += " fc-state-highlight";
+                cell.title = cal.todayText;
+            }
+            if(t == sel){
+                // disable highlight in other month..
+                cell.className += " fc-state-highlight";
+                
+            }
+            // disabling
+            if(t < min) {
+                //cell.className = " fc-state-disabled";
+                cell.title = cal.minText;
+                return;
+            }
+            if(t > max) {
+                //cell.className = " fc-state-disabled";
+                cell.title = cal.maxText;
+                return;
+            }
+            if(ddays){
+                if(ddays.indexOf(d.getDay()) != -1){
+                    // cell.title = ddaysText;
+                   // cell.className = " fc-state-disabled";
+                }
+            }
+            if(ddMatch && format){
+                var fvalue = d.dateFormat(format);
+                if(ddMatch.test(fvalue)){
+                    cell.title = ddText.replace("%0", fvalue);
+                   cell.className = " fc-state-disabled";
+                }
+            }
+            
+            if (!cell.initialClassName) {
+                cell.initialClassName = cell.dom.className;
+            }
+            
+            cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
+        };
+
+        var i = 0;
+        
+        for(; i < startingPos; i++) {
+            cells[i].dayName =  (++prevStart);
+            Roo.log(textEls[i]);
+            d.setDate(d.getDate()+1);
+            
+            //cells[i].className = "fc-past fc-other-month";
+            setCellClass(this, cells[i]);
+        }
+        
+        var intDay = 0;
+        
+        for(; i < days; i++){
+            intDay = i - startingPos + 1;
+            cells[i].dayName =  (intDay);
+            d.setDate(d.getDate()+1);
+            
+            cells[i].className = ''; // "x-date-active";
+            setCellClass(this, cells[i]);
+        }
+        var extraDays = 0;
+        
+        for(; i < 42; i++) {
+            //textEls[i].innerHTML = (++extraDays);
+            
+            d.setDate(d.getDate()+1);
+            cells[i].dayName = (++extraDays);
+            cells[i].className = "fc-future fc-other-month";
+            setCellClass(this, cells[i]);
+        }
+        
+        //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
+        
+        var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
+        
+        // this will cause all the cells to mis
+        var rows= [];
+        var i =0;
+        for (var r = 0;r < 6;r++) {
+            for (var c =0;c < 7;c++) {
+                this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
+            }    
+        }
+        
+        this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
+        for(i=0;i<cells.length;i++) {
+            
+            this.cells.elements[i].dayName = cells[i].dayName ;
+            this.cells.elements[i].className = cells[i].className;
+            this.cells.elements[i].initialClassName = cells[i].initialClassName ;
+            this.cells.elements[i].title = cells[i].title ;
+            this.cells.elements[i].dateValue = cells[i].dateValue ;
+        }
+        
+        
+        
+        
+        //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
+        //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
+        
+        ////if(totalRows != 6){
+            //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
+           // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
+       // }
+        
+        this.fireEvent('monthchange', this, date);
+        
+        
+    },
+ /**
+     * Returns the grid's SelectionModel.
+     * @return {SelectionModel}
+     */
+    getSelectionModel : function(){
+        if(!this.selModel){
+            this.selModel = new Roo.grid.CellSelectionModel();
+        }
+        return this.selModel;
+    },
+
+    load: function() {
+        this.eventStore.load()
+        
+        
+        
+    },
+    
+    findCell : function(dt) {
+        dt = dt.clearTime().getTime();
+        var ret = false;
+        this.cells.each(function(c){
+            //Roo.log("check " +c.dateValue + '?=' + dt);
+            if(c.dateValue == dt){
+                ret = c;
+                return false;
+            }
+            return true;
+        });
+        
+        return ret;
+    },
+    
+    findCells : function(rec) {
+        var s = rec.data.start_dt.clone().clearTime().getTime();
+       // Roo.log(s);
+        var e= rec.data.end_dt.clone().clearTime().getTime();
+       // Roo.log(e);
+        var ret = [];
+        this.cells.each(function(c){
+             ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
+            
+            if(c.dateValue > e){
+                return ;
+            }
+            if(c.dateValue < s){
+                return ;
+            }
+            ret.push(c);
+        });
+        
+        return ret;    
+    },
+    
+    findBestRow: function(cells)
+    {
+        var ret = 0;
+        
+        for (var i =0 ; i < cells.length;i++) {
+            ret  = Math.max(cells[i].rows || 0,ret);
+        }
+        return ret;
+        
+    },
+    
+    
+    addItem : function(rec)
+    {
+        // look for vertical location slot in
+        var cells = this.findCells(rec);
+        
+        rec.row = this.findBestRow(cells);
+        
+        // work out the location.
+        
+        var crow = false;
+        var rows = [];
+        for(var i =0; i < cells.length; i++) {
+            if (!crow) {
+                crow = {
+                    start : cells[i],
+                    end :  cells[i]
+                };
+                continue;
+            }
+            if (crow.start.getY() == cells[i].getY()) {
+                // on same row.
+                crow.end = cells[i];
+                continue;
+            }
+            // different row.
+            rows.push(crow);
+            crow = {
+                start: cells[i],
+                end : cells[i]
+            };
+            
+        }
+        
+        rows.push(crow);
+        rec.els = [];
+        rec.rows = rows;
+        rec.cells = cells;
+        for (var i = 0; i < cells.length;i++) {
+            cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
+            
+        }
+        
+        
+    },
+    
+    clearEvents: function() {
+        
+        if (!this.eventStore.getCount()) {
+            return;
+        }
+        // reset number of rows in cells.
+        Roo.each(this.cells.elements, function(c){
+            c.rows = 0;
+        });
+        
+        this.eventStore.each(function(e) {
+            this.clearEvent(e);
+        },this);
+        
+    },
+    
+    clearEvent : function(ev)
+    {
+        if (ev.els) {
+            Roo.each(ev.els, function(el) {
+                el.un('mouseenter' ,this.onEventEnter, this);
+                el.un('mouseleave' ,this.onEventLeave, this);
+                el.remove();
+            },this);
+            ev.els = [];
+        }
+    },
+    
+    
+    renderEvent : function(ev,ctr) {
+        if (!ctr) {
+             ctr = this.view.el.select('.fc-event-container',true).first();
+        }
+        
+         
+        this.clearEvent(ev);
+            //code
+       
+        
+        
+        ev.els = [];
+        var cells = ev.cells;
+        var rows = ev.rows;
+        this.fireEvent('eventrender', this, ev);
+        
+        for(var i =0; i < rows.length; i++) {
+            
+            cls = '';
+            if (i == 0) {
+                cls += ' fc-event-start';
+            }
+            if ((i+1) == rows.length) {
+                cls += ' fc-event-end';
+            }
+            
+            //Roo.log(ev.data);
+            // how many rows should it span..
+            var cg = this.eventTmpl.append(ctr,Roo.apply({
+                fccls : cls
+                
+            }, ev.data) , true);
+            
+            
+            cg.on('mouseenter' ,this.onEventEnter, this, ev);
+            cg.on('mouseleave' ,this.onEventLeave, this, ev);
+            cg.on('click', this.onEventClick, this, ev);
+            
+            ev.els.push(cg);
+            
+            var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
+            var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
+            //Roo.log(cg);
+             
+            cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);    
+            cg.setWidth(ebox.right - sbox.x -2);
+        }
+    },
+    
+    renderEvents: function()
+    {   
+        // first make sure there is enough space..
+        
+        if (!this.eventTmpl) {
+            this.eventTmpl = new Roo.Template(
+                '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}"  style="position: absolute" unselectable="on">' +
+                    '<div class="fc-event-inner">' +
+                        '<span class="fc-event-time">{time}</span>' +
+                        '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
+                    '</div>' +
+                    '<div class="ui-resizable-heandle ui-resizable-e">&nbsp;&nbsp;&nbsp;</div>' +
+                '</div>'
+            );
+                
+        }
+               
+        
+        
+        this.cells.each(function(c) {
+            //Roo.log(c.select('.fc-day-content div',true).first());
+            c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
+        });
+        
+        var ctr = this.view.el.select('.fc-event-container',true).first();
+        
+        var cls;
+        this.eventStore.each(function(ev){
+            
+            this.renderEvent(ev);
+             
+             
+        }, this);
+        this.view.layout();
+        
+    },
+    
+    onEventEnter: function (e, el,event,d) {
+        this.fireEvent('evententer', this, el, event);
+    },
+    
+    onEventLeave: function (e, el,event,d) {
+        this.fireEvent('eventleave', this, el, event);
+    },
+    
+    onEventClick: function (e, el,event,d) {
+        this.fireEvent('eventclick', this, el, event);
+    },
+    
+    onMonthChange: function () {
+        this.store.load();
+    },
+    
+    onLoad: function () {
+        
+        //Roo.log('calendar onload');
+//         
+        if(this.eventStore.getCount() > 0){
+            
+           
+            
+            this.eventStore.each(function(d){
+                
+                
+                // FIXME..
+                var add =   d.data;
+                if (typeof(add.end_dt) == 'undefined')  {
+                    Roo.log("Missing End time in calendar data: ");
+                    Roo.log(d);
+                    return;
+                }
+                if (typeof(add.start_dt) == 'undefined')  {
+                    Roo.log("Missing Start time in calendar data: ");
+                    Roo.log(d);
+                    return;
+                }
+                add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
+                add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
+                add.id = add.id || d.id;
+                add.title = add.title || '??';
+                
+                this.addItem(d);
+                
+             
+            },this);
+        }
+        
+        this.renderEvents();
+    }
+    
+
+});
+/*
+ grid : {
+                xtype: 'Grid',
+                xns: Roo.grid,
+                listeners : {
+                    render : function ()
+                    {
+                        _this.grid = this;
+                        
+                        if (!this.view.el.hasClass('course-timesheet')) {
+                            this.view.el.addClass('course-timesheet');
+                        }
+                        if (this.tsStyle) {
+                            this.ds.load({});
+                            return; 
+                        }
+                        Roo.log('width');
+                        Roo.log(_this.grid.view.el.getWidth());
+                        
+                        
+                        this.tsStyle =  Roo.util.CSS.createStyleSheet({
+                            '.course-timesheet .x-grid-row' : {
+                                height: '80px'
+                            },
+                            '.x-grid-row td' : {
+                                'vertical-align' : 0
+                            },
+                            '.course-edit-link' : {
+                                'color' : 'blue',
+                                'text-overflow' : 'ellipsis',
+                                'overflow' : 'hidden',
+                                'white-space' : 'nowrap',
+                                'cursor' : 'pointer'
+                            },
+                            '.sub-link' : {
+                                'color' : 'green'
+                            },
+                            '.de-act-sup-link' : {
+                                'color' : 'purple',
+                                'text-decoration' : 'line-through'
+                            },
+                            '.de-act-link' : {
+                                'color' : 'red',
+                                'text-decoration' : 'line-through'
+                            },
+                            '.course-timesheet .course-highlight' : {
+                                'border-top-style': 'dashed !important',
+                                'border-bottom-bottom': 'dashed !important'
+                            },
+                            '.course-timesheet .course-item' : {
+                                'font-family'   : 'tahoma, arial, helvetica',
+                                'font-size'     : '11px',
+                                'overflow'      : 'hidden',
+                                'padding-left'  : '10px',
+                                'padding-right' : '10px',
+                                'padding-top' : '10px' 
+                            }
+                            
+                        }, Roo.id());
+                                this.ds.load({});
+                    }
+                },
+                autoWidth : true,
+                monitorWindowResize : false,
+                cellrenderer : function(v,x,r)
+                {
+                    return v;
+                },
+                sm : {
+                    xtype: 'CellSelectionModel',
+                    xns: Roo.grid
+                },
+                dataSource : {
+                    xtype: 'Store',
+                    xns: Roo.data,
+                    listeners : {
+                        beforeload : function (_self, options)
+                        {
+                            options.params = options.params || {};
+                            options.params._month = _this.monthField.getValue();
+                            options.params.limit = 9999;
+                            options.params['sort'] = 'when_dt';    
+                            options.params['dir'] = 'ASC';    
+                            this.proxy.loadResponse = this.loadResponse;
+                            Roo.log("load?");
+                            //this.addColumns();
+                        },
+                        load : function (_self, records, options)
+                        {
+                            _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
+                                // if you click on the translation.. you can edit it...
+                                var el = Roo.get(this);
+                                var id = el.dom.getAttribute('data-id');
+                                var d = el.dom.getAttribute('data-date');
+                                var t = el.dom.getAttribute('data-time');
+                                //var id = this.child('span').dom.textContent;
+                                
+                                //Roo.log(this);
+                                Pman.Dialog.CourseCalendar.show({
+                                    id : id,
+                                    when_d : d,
+                                    when_t : t,
+                                    productitem_active : id ? 1 : 0
+                                }, function() {
+                                    _this.grid.ds.load({});
+                                });
+                           
+                           });
+                           
+                           _this.panel.fireEvent('resize', [ '', '' ]);
+                        }
+                    },
+                    loadResponse : function(o, success, response){
+                            // this is overridden on before load..
+                            
+                            Roo.log("our code?");      
+                            //Roo.log(success);
+                            //Roo.log(response)
+                            delete this.activeRequest;
+                            if(!success){
+                                this.fireEvent("loadexception", this, o, response);
+                                o.request.callback.call(o.request.scope, null, o.request.arg, false);
+                                return;
+                            }
+                            var result;
+                            try {
+                                result = o.reader.read(response);
+                            }catch(e){
+                                Roo.log("load exception?");
+                                this.fireEvent("loadexception", this, o, response, e);
+                                o.request.callback.call(o.request.scope, null, o.request.arg, false);
+                                return;
+                            }
+                            Roo.log("ready...");        
+                            // loop through result.records;
+                            // and set this.tdate[date] = [] << array of records..
+                            _this.tdata  = {};
+                            Roo.each(result.records, function(r){
+                                //Roo.log(r.data);
+                                if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
+                                    _this.tdata[r.data.when_dt.format('j')] = [];
+                                }
+                                _this.tdata[r.data.when_dt.format('j')].push(r.data);
+                            });
+                            
+                            //Roo.log(_this.tdata);
+                            
+                            result.records = [];
+                            result.totalRecords = 6;
+                    
+                            // let's generate some duumy records for the rows.
+                            //var st = _this.dateField.getValue();
+                            
+                            // work out monday..
+                            //st = st.add(Date.DAY, -1 * st.format('w'));
+                            
+                            var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
+                            
+                            var firstOfMonth = date.getFirstDayOfMonth();
+                            var days = date.getDaysInMonth();
+                            var d = 1;
+                            var firstAdded = false;
+                            for (var i = 0; i < result.totalRecords ; i++) {
+                                //var d= st.add(Date.DAY, i);
+                                var row = {};
+                                var added = 0;
+                                for(var w = 0 ; w < 7 ; w++){
+                                    if(!firstAdded && firstOfMonth != w){
+                                        continue;
+                                    }
+                                    if(d > days){
+                                        continue;
+                                    }
+                                    firstAdded = true;
+                                    var dd = (d > 0 && d < 10) ? "0"+d : d;
+                                    row['weekday'+w] = String.format(
+                                                    '<span style="font-size: 16px;"><b>{0}</b></span>'+
+                                                    '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
+                                                    d,
+                                                    date.format('Y-m-')+dd
+                                                );
+                                    added++;
+                                    if(typeof(_this.tdata[d]) != 'undefined'){
+                                        Roo.each(_this.tdata[d], function(r){
+                                            var is_sub = '';
+                                            var deactive = '';
+                                            var id = r.id;
+                                            var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
+                                            if(r.parent_id*1>0){
+                                                is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
+                                                id = r.parent_id;
+                                            }
+                                            if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
+                                                deactive = 'de-act-link';
+                                            }
+                                            
+                                            row['weekday'+w] += String.format(
+                                                    '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
+                                                    id, //0
+                                                    r.product_id_name, //1
+                                                    r.when_dt.format('h:ia'), //2
+                                                    is_sub, //3
+                                                    deactive, //4
+                                                    desc // 5
+                                            );
+                                        });
+                                    }
+                                    d++;
+                                }
+                                
+                                // only do this if something added..
+                                if(added > 0){ 
+                                    result.records.push(_this.grid.dataSource.reader.newRow(row));
+                                }
+                                
+                                
+                                // push it twice. (second one with an hour..
+                                
+                            }
+                            //Roo.log(result);
+                            this.fireEvent("load", this, o, o.request.arg);
+                            o.request.callback.call(o.request.scope, result, o.request.arg, true);
+                        },
+                    sortInfo : {field: 'when_dt', direction : 'ASC' },
+                    proxy : {
+                        xtype: 'HttpProxy',
+                        xns: Roo.data,
+                        method : 'GET',
+                        url : baseURL + '/Roo/Shop_course.php'
+                    },
+                    reader : {
+                        xtype: 'JsonReader',
+                        xns: Roo.data,
+                        id : 'id',
+                        fields : [
+                            {
+                                'name': 'id',
+                                'type': 'int'
+                            },
+                            {
+                                'name': 'when_dt',
+                                'type': 'string'
+                            },
+                            {
+                                'name': 'end_dt',
+                                'type': 'string'
+                            },
+                            {
+                                'name': 'parent_id',
+                                'type': 'int'
+                            },
+                            {
+                                'name': 'product_id',
+                                'type': 'int'
+                            },
+                            {
+                                'name': 'productitem_id',
+                                'type': 'int'
+                            },
+                            {
+                                'name': 'guid',
+                                'type': 'int'
+                            }
+                        ]
+                    }
+                },
+                toolbar : {
+                    xtype: 'Toolbar',
+                    xns: Roo,
+                    items : [
+                        {
+                            xtype: 'Button',
+                            xns: Roo.Toolbar,
+                            listeners : {
+                                click : function (_self, e)
+                                {
+                                    var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
+                                    sd.setMonth(sd.getMonth()-1);
+                                    _this.monthField.setValue(sd.format('Y-m-d'));
+                                    _this.grid.ds.load({});
+                                }
+                            },
+                            text : "Back"
+                        },
+                        {
+                            xtype: 'Separator',
+                            xns: Roo.Toolbar
+                        },
+                        {
+                            xtype: 'MonthField',
+                            xns: Roo.form,
+                            listeners : {
+                                render : function (_self)
+                                {
+                                    _this.monthField = _self;
+                                   // _this.monthField.set  today
+                                },
+                                select : function (combo, date)
+                                {
+                                    _this.grid.ds.load({});
+                                }
+                            },
+                            value : (function() { return new Date(); })()
+                        },
+                        {
+                            xtype: 'Separator',
+                            xns: Roo.Toolbar
+                        },
+                        {
+                            xtype: 'TextItem',
+                            xns: Roo.Toolbar,
+                            text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
+                        },
+                        {
+                            xtype: 'Fill',
+                            xns: Roo.Toolbar
+                        },
+                        {
+                            xtype: 'Button',
+                            xns: Roo.Toolbar,
+                            listeners : {
+                                click : function (_self, e)
+                                {
+                                    var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
+                                    sd.setMonth(sd.getMonth()+1);
+                                    _this.monthField.setValue(sd.format('Y-m-d'));
+                                    _this.grid.ds.load({});
+                                }
+                            },
+                            text : "Next"
+                        }
+                    ]
+                },
+                 
+            }
+        };
+        
+        *//*
+ * 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.LoadMask
+ * A simple utility class for generically masking elements while loading data.  If the element being masked has
+ * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
+ * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
+ * element's UpdateManager load indicator and will be destroyed after the initial load.
+ * @constructor
+ * Create a new LoadMask
+ * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
+ * @param {Object} config The config object
+ */
+Roo.LoadMask = function(el, config){
+    this.el = Roo.get(el);
+    Roo.apply(this, config);
+    if(this.store){
+        this.store.on('beforeload', this.onBeforeLoad, this);
+        this.store.on('load', this.onLoad, this);
+        this.store.on('loadexception', this.onLoadException, this);
+        this.removeMask = false;
+    }else{
+        var um = this.el.getUpdateManager();
+        um.showLoadIndicator = false; // disable the default indicator
+        um.on('beforeupdate', this.onBeforeLoad, this);
+        um.on('update', this.onLoad, this);
+        um.on('failure', this.onLoad, this);
+        this.removeMask = true;
+    }
+};
+
+Roo.LoadMask.prototype = {
+    /**
+     * @cfg {Boolean} removeMask
+     * 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...')
+     */
+    msg : 'Loading...',
+    /**
+     * @cfg {String} msgCls
+     * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
+     */
+    msgCls : 'x-mask-loading',
+
+    /**
+     * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
+     * @type Boolean
+     */
+    disabled: false,
+
+    /**
+     * Disables the mask to prevent it from being displayed
+     */
+    disable : function(){
+       this.disabled = true;
+    },
+
+    /**
+     * Enables the mask so that it can be displayed
+     */
+    enable : function(){
+        this.disabled = false;
+    },
     
-      /**
-     * @cfg {Object} propertyNames map of property Names to their displayed value
-        */
+    onLoadException : function()
+    {
+        Roo.log(arguments);
+        
+        if (typeof(arguments[3]) != 'undefined') {
+            Roo.MessageBox.alert("Error loading",arguments[3]);
+        } 
+        /*
+        try {
+            if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
+                Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
+            }   
+        } catch(e) {
+            
+        }
+        */
     
-    render : function(){
-        Roo.grid.PropertyGrid.superclass.render.call(this);
-        this.autoSize.defer(100, this);
+        (function() { this.el.unmask(this.removeMask); }).defer(50, this);
+    },
+    // private
+    onLoad : function()
+    {
+        (function() { this.el.unmask(this.removeMask); }).defer(50, this);
     },
 
-    autoSize : function(){
-        Roo.grid.PropertyGrid.superclass.autoSize.call(this);
-        if(this.view){
-            this.view.fitColumns();
+    // private
+    onBeforeLoad : function(){
+        if(!this.disabled){
+            (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
         }
     },
 
-    onColumnResize : function(){
-        this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
-        this.autoSize();
-    },
+    // private
+    destroy : function(){
+        if(this.store){
+            this.store.un('beforeload', this.onBeforeLoad, this);
+            this.store.un('load', this.onLoad, this);
+            this.store.un('loadexception', this.onLoadException, this);
+        }else{
+            var um = this.el.getUpdateManager();
+            um.un('beforeupdate', this.onBeforeLoad, this);
+            um.un('update', this.onLoad, this);
+            um.un('failure', this.onLoad, this);
+        }
+    }
+};/*
+ * 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.XTemplate
+ * @extends Roo.Template
+ * Provides a template that can have nested templates for loops or conditionals. The syntax is:
+<pre><code>
+var t = new Roo.XTemplate(
+       '&lt;select name="{name}"&gt;',
+               '&lt;tpl for="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
+       '&lt;/select&gt;'
+);
+// then append, applying the master template values
+ </code></pre>
+ *
+ * Supported features:
+ *
+ *  Tags:
+
+<pre><code>
+      {a_variable} - output encoded.
+      {a_variable.format:("Y-m-d")} - call a method on the variable
+      {a_variable:raw} - unencoded output
+      {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
+      {a_variable:this.method_on_template(...)} - call a method on the template object.
+</code></pre>
+ *  The tpl tag:
+<pre><code>
+        &lt;tpl for="a_variable or condition.."&gt;&lt;/tpl&gt;
+        &lt;tpl if="a_variable or condition"&gt;&lt;/tpl&gt;
+        &lt;tpl exec="some javascript"&gt;&lt;/tpl&gt;
+        &lt;tpl name="named_template"&gt;&lt;/tpl&gt; (experimental)
+  
+        &lt;tpl for="."&gt;&lt;/tpl&gt; - just iterate the property..
+        &lt;tpl for=".."&gt;&lt;/tpl&gt; - iterates with the parent (probably the template) 
+</code></pre>
+ *      
+ */
+Roo.XTemplate = function()
+{
+    Roo.XTemplate.superclass.constructor.apply(this, arguments);
+    if (this.html) {
+        this.compile();
+    }
+};
+
+
+Roo.extend(Roo.XTemplate, Roo.Template, {
+
     /**
-     * Sets the data for the Grid
-     * accepts a Key => Value object of all the elements avaiable.
-     * @param {Object} data  to appear in grid.
+     * The various sub templates
      */
-    setSource : function(source){
-        this.store.setSource(source);
-        //this.autoSize();
-    },
+    tpls : false,
     /**
-     * Gets all the data from the grid.
-     * @return {Object} data  data stored in grid
+     *
+     * basic tag replacing syntax
+     * WORD:WORD()
+     *
+     * // you can fake an object call by doing this
+     *  x.t:(test,tesT) 
+     * 
      */
-    getSource : function(){
-        return this.store.getSource();
-    }
-});/*
-  
- * Licence LGPL
- */
-/**
- * @class Roo.grid.Calendar
- * @extends Roo.util.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", {
-     ds: myDataStore,
-     cm: myColModel,
-     selModel: mySelectionModel,
-     autoSizeColumns: true,
-     monitorWindowResize: false,
-     trackMouseOver: true
-     eventstore : real data store..
- });
- // set any options
- grid.render();
-  
-  * @constructor
- * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
- * The container MUST have some type of size defined for the grid to fill. The container will be
- * automatically set to position relative if it isn't already.
- * @param {Object} config A config object that sets properties on this grid.
- */
-Roo.grid.Calendar = function(container, config){
-       // initialize the container
-       this.container = Roo.get(container);
-       this.container.update("");
-       this.container.setStyle("overflow", "hidden");
-    this.container.addClass('x-grid-container');
-
-    this.id = this.container.id;
+    re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
 
-    Roo.apply(this, config);
-    // check and correct shorthanded configs
+    /**
+     * compile the template
+     *
+     * This is not recursive, so I'm not sure how nested templates are really going to be handled..
+     *
+     */
+    compile: function()
+    {
+        var s = this.html;
+     
+        s = ['<tpl>', s, '</tpl>'].join('');
     
-    var rows = [];
-    var d =1;
-    for (var r = 0;r < 6;r++) {
+        var re     = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
+            nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
+            ifRe   = /^<tpl\b[^>]*?if="(.*?)"/,
+            execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
+            namedRe = /^<tpl\b[^>]*?name="(\w+)"/,  // named templates..
+            m,
+            id     = 0,
+            tpls   = [];
+    
+        while(true == !!(m = s.match(re))){
+            var forMatch   = m[0].match(nameRe),
+                ifMatch   = m[0].match(ifRe),
+                execMatch   = m[0].match(execRe),
+                namedMatch   = m[0].match(namedRe),
+                
+                exp  = null, 
+                fn   = null,
+                exec = null,
+                name = forMatch && forMatch[1] ? forMatch[1] : '';
+                
+            if (ifMatch) {
+                // if - puts fn into test..
+                exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
+                if(exp){
+                   fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
+                }
+            }
+            
+            if (execMatch) {
+                // exec - calls a function... returns empty if true is  returned.
+                exp = execMatch && execMatch[1] ? execMatch[1] : null;
+                if(exp){
+                   exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
+                }
+            }
+            
+            
+            if (name) {
+                // for = 
+                switch(name){
+                    case '.':  name = new Function('values', 'parent', 'with(values){ return values; }'); break;
+                    case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
+                    default:   name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
+                }
+            }
+            var uid = namedMatch ? namedMatch[1] : id;
+            
+            
+            tpls.push({
+                id:     namedMatch ? namedMatch[1] : id,
+                target: name,
+                exec:   exec,
+                test:   fn,
+                body:   m[1] || ''
+            });
+            if (namedMatch) {
+                s = s.replace(m[0], '');
+            } else { 
+                s = s.replace(m[0], '{xtpl'+ id + '}');
+            }
+            ++id;
+        }
+        this.tpls = [];
+        for(var i = tpls.length-1; i >= 0; --i){
+            this.compileTpl(tpls[i]);
+            this.tpls[tpls[i].id] = tpls[i];
+        }
+        this.master = tpls[tpls.length-1];
+        return this;
+    },
+    /**
+     * same as applyTemplate, except it's done to one of the subTemplates
+     * when using named templates, you can do:
+     *
+     * var str = pl.applySubTemplate('your-name', values);
+     *
+     * 
+     * @param {Number} id of the template
+     * @param {Object} values to apply to template
+     * @param {Object} parent (normaly the instance of this object)
+     */
+    applySubTemplate : function(id, values, parent)
+    {
         
-        rows[r]=[];
-        for (var c =0;c < 7;c++) {
-            rows[r][c]= '';
+        
+        var t = this.tpls[id];
+        
+        
+        try { 
+            if(t.test && !t.test.call(this, values, parent)){
+                return '';
+            }
+        } catch(e) {
+            Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
+            Roo.log(e.toString());
+            Roo.log(t.test);
+            return ''
         }
-    }
-    if (this.eventStore) {
-        this.eventStore= Roo.factory(this.eventStore, Roo.data);
-        this.eventStore.on('load',this.onLoad, this);
-        this.eventStore.on('beforeload',this.clearEvents, this);
-         
-    }
-    
-    this.dataSource = new Roo.data.Store({
-            proxy: new Roo.data.MemoryProxy(rows),
-            reader: new Roo.data.ArrayReader({}, [
-                   'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
-    });
+        try { 
+            
+            if(t.exec && t.exec.call(this, values, parent)){
+                return '';
+            }
+        } catch(e) {
+            Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
+            Roo.log(e.toString());
+            Roo.log(t.exec);
+            return ''
+        }
+        try {
+            var vs = t.target ? t.target.call(this, values, parent) : values;
+            parent = t.target ? values : parent;
+            if(t.target && vs instanceof Array){
+                var buf = [];
+                for(var i = 0, len = vs.length; i < len; i++){
+                    buf[buf.length] = t.compiled.call(this, vs[i], parent);
+                }
+                return buf.join('');
+            }
+            return t.compiled.call(this, vs, parent);
+        } catch (e) {
+            Roo.log("Xtemplate.applySubTemplate : Exception thrown");
+            Roo.log(e.toString());
+            Roo.log(t.compiled);
+            return '';
+        }
+    },
 
-    this.dataSource.load();
-    this.ds = this.dataSource;
-    this.ds.xmodule = this.xmodule || false;
-    
-    
-    var cellRender = function(v,x,r)
+    compileTpl : function(tpl)
     {
-        return String.format(
-            '<div class="fc-day  fc-widget-content"><div>' +
-                '<div class="fc-event-container"></div>' +
-                '<div class="fc-day-number">{0}</div>'+
-                
-                '<div class="fc-day-content"><div style="position:relative"></div></div>' +
-            '</div></div>', v);
-    
-    }
-    
-    
-    this.colModel = new Roo.grid.ColumnModel( [
-        {
-            xtype: 'ColumnModel',
-            xns: Roo.grid,
-            dataIndex : 'weekday0',
-            header : 'Sunday',
-            renderer : cellRender
-        },
-        {
-            xtype: 'ColumnModel',
-            xns: Roo.grid,
-            dataIndex : 'weekday1',
-            header : 'Monday',
-            renderer : cellRender
-        },
-        {
-            xtype: 'ColumnModel',
-            xns: Roo.grid,
-            dataIndex : 'weekday2',
-            header : 'Tuesday',
-            renderer : cellRender
-        },
-        {
-            xtype: 'ColumnModel',
-            xns: Roo.grid,
-            dataIndex : 'weekday3',
-            header : 'Wednesday',
-            renderer : cellRender
-        },
-        {
-            xtype: 'ColumnModel',
-            xns: Roo.grid,
-            dataIndex : 'weekday4',
-            header : 'Thursday',
-            renderer : cellRender
-        },
-        {
-            xtype: 'ColumnModel',
-            xns: Roo.grid,
-            dataIndex : 'weekday5',
-            header : 'Friday',
-            renderer : cellRender
-        },
+        var fm = Roo.util.Format;
+        var useF = this.disableFormats !== true;
+        var sep = Roo.isGecko ? "+" : ",";
+        var undef = function(str) {
+            Roo.log("Property not found :"  + str);
+            return '';
+        };
+        
+        var fn = function(m, name, format, args)
         {
-            xtype: 'ColumnModel',
-            xns: Roo.grid,
-            dataIndex : 'weekday6',
-            header : 'Saturday',
-            renderer : cellRender
+            //Roo.log(arguments);
+            args = args ? args.replace(/\\'/g,"'") : args;
+            //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
+            if (typeof(format) == 'undefined') {
+                format= 'htmlEncode';
+            }
+            if (format == 'raw' ) {
+                format = false;
+            }
+            
+            if(name.substr(0, 4) == 'xtpl'){
+                return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
+            }
+            
+            // build an array of options to determine if value is undefined..
+            
+            // basically get 'xxxx.yyyy' then do
+            // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
+            //    (function () { Roo.log("Property not found"); return ''; })() :
+            //    ......
+            
+            var udef_ar = [];
+            var lookfor = '';
+            Roo.each(name.split('.'), function(st) {
+                lookfor += (lookfor.length ? '.': '') + st;
+                udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
+            });
+            
+            var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
+            
+            
+            if(format && useF){
+                
+                args = args ? ',' + args : "";
+                 
+                if(format.substr(0, 5) != "this."){
+                    format = "fm." + format + '(';
+                }else{
+                    format = 'this.call("'+ format.substr(5) + '", ';
+                    args = ", values";
+                }
+                
+                return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
+            }
+             
+            if (args.length) {
+                // called with xxyx.yuu:(test,test)
+                // change to ()
+                return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
+            }
+            // raw.. - :raw modifier..
+            return "'"+ sep + udef_st  + name + ")"+sep+"'";
+            
+        };
+        var body;
+        // branched to use + in gecko and [].join() in others
+        if(Roo.isGecko){
+            body = "tpl.compiled = function(values, parent){  with(values) { return '" +
+                   tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
+                    "';};};";
+        }else{
+            body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
+            body.push(tpl.body.replace(/(\r\n|\n)/g,
+                            '\\n').replace(/'/g, "\\'").replace(this.re, fn));
+            body.push("'].join('');};};");
+            body = body.join('');
         }
-    ]);
-    this.cm = this.colModel;
-    this.cm.xmodule = this.xmodule || false;
         
-          
-    //this.selModel = new Roo.grid.CellSelectionModel();
-    //this.sm = this.selModel;
-    //this.selModel.init(this);
-    
-    
-    if(this.width){
-        this.container.setWidth(this.width);
-    }
+        Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
+       
+        /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
+        eval(body);
+        
+        return this;
+    },
 
-    if(this.height){
-        this.container.setHeight(this.height);
+    applyTemplate : function(values){
+        return this.master.compiled.call(this, values, {});
+        //var s = this.subs;
+    },
+
+    apply : function(){
+        return this.applyTemplate.apply(this, arguments);
     }
-    /** @private */
-       this.addEvents({
-        // raw events
-        /**
-         * @event click
-         * The raw click event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        "click" : true,
-        /**
-         * @event dblclick
-         * The raw dblclick event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        "dblclick" : true,
-        /**
-         * @event contextmenu
-         * The raw contextmenu event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        "contextmenu" : true,
-        /**
-         * @event mousedown
-         * The raw mousedown event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        "mousedown" : true,
-        /**
-         * @event mouseup
-         * The raw mouseup event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        "mouseup" : true,
-        /**
-         * @event mouseover
-         * The raw mouseover event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        "mouseover" : true,
-        /**
-         * @event mouseout
-         * The raw mouseout event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        "mouseout" : true,
-        /**
-         * @event keypress
-         * The raw keypress event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        "keypress" : true,
-        /**
-         * @event keydown
-         * The raw keydown event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        "keydown" : true,
 
-        // custom events
+ });
 
+Roo.XTemplate.from = function(el){
+    el = Roo.getDom(el);
+    return new Roo.XTemplate(el.value || el.innerHTML);
+};Roo.dialog = {};
+/*
+* Licence: LGPL
+*/
+
+/**
+ * @class Roo.dialog.UploadCropbox
+ * @extends Roo.BoxComponent
+ * Dialog UploadCropbox class
+ * @cfg {String} emptyText show when image has been loaded
+ * @cfg {String} rotateNotify show when image too small to rotate
+ * @cfg {Number} errorTimeout default 3000
+ * @cfg {Number} minWidth default 300
+ * @cfg {Number} minHeight default 300
+ * @cfg {Number} outputMaxWidth default 1200
+ * @cfg {Number} windowSize default 300
+ * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
+ * @cfg {Boolean} isDocument (true|false) default false
+ * @cfg {String} url action url
+ * @cfg {String} paramName default 'imageUpload'
+ * @cfg {String} method default POST
+ * @cfg {Boolean} loadMask (true|false) default true
+ * @cfg {Boolean} loadingText default 'Loading...'
+ * 
+ * @constructor
+ * Create a new UploadCropbox
+ * @param {Object} config The config object
+ */
+
+ Roo.dialog.UploadCropbox = function(config){
+    Roo.dialog.UploadCropbox.superclass.constructor.call(this, config);
+    
+    this.addEvents({
         /**
-         * @event cellclick
-         * Fires when a cell is clicked
-         * @param {Grid} this
-         * @param {Number} rowIndex
-         * @param {Number} columnIndex
-         * @param {Roo.EventObject} e
-         */
-        "cellclick" : true,
-        /**
-         * @event celldblclick
-         * Fires when a cell is double clicked
-         * @param {Grid} this
-         * @param {Number} rowIndex
-         * @param {Number} columnIndex
-         * @param {Roo.EventObject} e
-         */
-        "celldblclick" : true,
-        /**
-         * @event rowclick
-         * Fires when a row is clicked
-         * @param {Grid} this
-         * @param {Number} rowIndex
-         * @param {Roo.EventObject} e
-         */
-        "rowclick" : true,
-        /**
-         * @event rowdblclick
-         * Fires when a row is double clicked
-         * @param {Grid} this
-         * @param {Number} rowIndex
-         * @param {Roo.EventObject} e
-         */
-        "rowdblclick" : true,
-        /**
-         * @event headerclick
-         * Fires when a header is clicked
-         * @param {Grid} this
-         * @param {Number} columnIndex
-         * @param {Roo.EventObject} e
-         */
-        "headerclick" : true,
-        /**
-         * @event headerdblclick
-         * Fires when a header cell is double clicked
-         * @param {Grid} this
-         * @param {Number} columnIndex
-         * @param {Roo.EventObject} e
-         */
-        "headerdblclick" : true,
-        /**
-         * @event rowcontextmenu
-         * Fires when a row is right clicked
-         * @param {Grid} this
-         * @param {Number} rowIndex
-         * @param {Roo.EventObject} e
+         * @event beforeselectfile
+         * Fire before select file
+         * @param {Roo.dialog.UploadCropbox} this
          */
-        "rowcontextmenu" : true,
+        "beforeselectfile" : true,
         /**
-         * @event cellcontextmenu
-         * Fires when a cell is right clicked
-         * @param {Grid} this
-         * @param {Number} rowIndex
-         * @param {Number} cellIndex
-         * @param {Roo.EventObject} e
+         * @event initial
+         * Fire after initEvent
+         * @param {Roo.dialog.UploadCropbox} this
          */
-         "cellcontextmenu" : true,
+        "initial" : true,
         /**
-         * @event headercontextmenu
-         * Fires when a header is right clicked
-         * @param {Grid} this
-         * @param {Number} columnIndex
-         * @param {Roo.EventObject} e
+         * @event crop
+         * Fire after initEvent
+         * @param {Roo.dialog.UploadCropbox} this
+         * @param {String} data
          */
-        "headercontextmenu" : true,
+        "crop" : true,
         /**
-         * @event bodyscroll
-         * Fires when the body element is scrolled
-         * @param {Number} scrollLeft
-         * @param {Number} scrollTop
+         * @event prepare
+         * Fire when preparing the file data
+         * @param {Roo.dialog.UploadCropbox} this
+         * @param {Object} file
          */
-        "bodyscroll" : true,
+        "prepare" : true,
         /**
-         * @event columnresize
-         * Fires when the user resizes a column
-         * @param {Number} columnIndex
-         * @param {Number} newSize
+         * @event exception
+         * Fire when get exception
+         * @param {Roo.dialog.UploadCropbox} this
+         * @param {XMLHttpRequest} xhr
          */
-        "columnresize" : true,
+        "exception" : true,
         /**
-         * @event columnmove
-         * Fires when the user moves a column
-         * @param {Number} oldIndex
-         * @param {Number} newIndex
+         * @event beforeloadcanvas
+         * Fire before load the canvas
+         * @param {Roo.dialog.UploadCropbox} this
+         * @param {String} src
          */
-        "columnmove" : true,
+        "beforeloadcanvas" : true,
         /**
-         * @event startdrag
-         * Fires when row(s) start being dragged
-         * @param {Grid} this
-         * @param {Roo.GridDD} dd The drag drop object
-         * @param {event} e The raw browser event
+         * @event trash
+         * Fire when trash image
+         * @param {Roo.dialog.UploadCropbox} this
          */
-        "startdrag" : true,
+        "trash" : true,
         /**
-         * @event enddrag
-         * Fires when a drag operation is complete
-         * @param {Grid} this
-         * @param {Roo.GridDD} dd The drag drop object
-         * @param {event} e The raw browser event
+         * @event download
+         * Fire when download the image
+         * @param {Roo.dialog.UploadCropbox} this
          */
-        "enddrag" : true,
+        "download" : true,
         /**
-         * @event dragdrop
-         * Fires when dragged row(s) are dropped on a valid DD target
-         * @param {Grid} this
-         * @param {Roo.GridDD} dd The drag drop object
-         * @param {String} targetId The target drag drop object
-         * @param {event} e The raw browser event
+         * @event footerbuttonclick
+         * Fire when footerbuttonclick
+         * @param {Roo.dialog.UploadCropbox} this
+         * @param {String} type
          */
-        "dragdrop" : true,
+        "footerbuttonclick" : true,
         /**
-         * @event dragover
-         * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
-         * @param {Grid} this
-         * @param {Roo.GridDD} dd The drag drop object
-         * @param {String} targetId The target drag drop object
-         * @param {event} e The raw browser event
+         * @event resize
+         * Fire when resize
+         * @param {Roo.dialog.UploadCropbox} this
          */
-        "dragover" : true,
+        "resize" : true,
         /**
-         * @event dragenter
-         *  Fires when the dragged row(s) first cross another DD target while being dragged
-         * @param {Grid} this
-         * @param {Roo.GridDD} dd The drag drop object
-         * @param {String} targetId The target drag drop object
-         * @param {event} e The raw browser event
+         * @event rotate
+         * Fire when rotate the image
+         * @param {Roo.dialog.UploadCropbox} this
+         * @param {String} pos
          */
-        "dragenter" : true,
+        "rotate" : true,
         /**
-         * @event dragout
-         * Fires when the dragged row(s) leave another DD target while being dragged
-         * @param {Grid} this
-         * @param {Roo.GridDD} dd The drag drop object
-         * @param {String} targetId The target drag drop object
-         * @param {event} e The raw browser event
+         * @event inspect
+         * Fire when inspect the file
+         * @param {Roo.dialog.UploadCropbox} this
+         * @param {Object} file
          */
-        "dragout" : true,
+        "inspect" : true,
         /**
-         * @event rowclass
-         * Fires when a row is rendered, so you can change add a style to it.
-         * @param {GridView} gridview   The grid view
-         * @param {Object} rowcfg   contains record  rowIndex and rowClass - set rowClass to add a style.
+         * @event upload
+         * Fire when xhr upload the file
+         * @param {Roo.dialog.UploadCropbox} this
+         * @param {Object} data
          */
-        'rowclass' : true,
-
+        "upload" : true,
         /**
-         * @event render
-         * Fires when the grid is rendered
-         * @param {Grid} grid
+         * @event arrange
+         * Fire when arrange the file data
+         * @param {Roo.dialog.UploadCropbox} this
+         * @param {Object} formData
          */
-        'render' : true,
-            /**
-            * @event select
-            * Fires when a date is selected
-            * @param {DatePicker} this
-            * @param {Date} date The selected date
-            */
-        'select': true,
-        /**
-            * @event monthchange
-            * Fires when the displayed month changes 
-            * @param {DatePicker} this
-            * @param {Date} date The selected month
-            */
-        'monthchange': true,
-        /**
-            * @event evententer
-            * Fires when mouse over an event
-            * @param {Calendar} this
-            * @param {event} Event
-            */
-        'evententer': true,
+        "arrange" : true,
         /**
-            * @event eventleave
-            * Fires when the mouse leaves an
-            * @param {Calendar} this
-            * @param {event}
-            */
-        'eventleave': true,
-        /**
-            * @event eventclick
-            * Fires when the mouse click an
-            * @param {Calendar} this
-            * @param {event}
-            */
-        'eventclick': true,
-        /**
-            * @event eventrender
-            * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
-            * @param {Calendar} this
-            * @param {data} data to be modified
-            */
-        'eventrender': true
-        
+         * @event loadcanvas
+         * Fire after load the canvas
+         * @param {Roo.dialog.UploadCropbox}
+         * @param {Object} imgEl
+         */
+        "loadcanvas" : true
     });
-
-    Roo.grid.Grid.superclass.constructor.call(this);
-    this.on('render', function() {
-        this.view.el.addClass('x-grid-cal'); 
-        
-        (function() { this.setDate(new Date()); }).defer(100,this); //default today..
-
-    },this);
-    
-    if (!Roo.grid.Calendar.style) {
-        Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
-            
-            
-            '.x-grid-cal .x-grid-col' :  {
-                height: 'auto !important',
-                'vertical-align': 'top'
-            },
-            '.x-grid-cal  .fc-event-hori' : {
-                height: '14px'
-            }
-             
-            
-        }, Roo.id());
-    }
-
-    
     
+    this.buttons = this.buttons || Roo.dialog.UploadCropbox.footer.STANDARD;
 };
-Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
-    /**
-     * @cfg {Store} eventStore The store that loads events.
-     */
-    eventStore : 25,
-
-     
-    activeDate : false,
-    startDay : 0,
-    autoWidth : true,
-    monitorWindowResize : false,
-
-    
-    resizeColumns : function() {
-        var col = (this.view.el.getWidth() / 7) - 3;
-        // loop through cols, and setWidth
-        for(var i =0 ; i < 7 ; i++){
-            this.cm.setColumnWidth(i, col);
-        }
-    },
-     setDate :function(date) {
-        
-        Roo.log('setDate?');
-        
-        this.resizeColumns();
-        var vd = this.activeDate;
-        this.activeDate = date;
-//        if(vd && this.el){
-//            var t = date.getTime();
-//            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
-//                Roo.log('using add remove');
-//                
-//                this.fireEvent('monthchange', this, date);
-//                
-//                this.cells.removeClass("fc-state-highlight");
-//                this.cells.each(function(c){
-//                   if(c.dateValue == t){
-//                       c.addClass("fc-state-highlight");
-//                       setTimeout(function(){
-//                            try{c.dom.firstChild.focus();}catch(e){}
-//                       }, 50);
-//                       return false;
-//                   }
-//                   return true;
-//                });
-//                return;
-//            }
-//        }
-        
-        var days = date.getDaysInMonth();
-        
-        var firstOfMonth = date.getFirstDateOfMonth();
-        var startingPos = firstOfMonth.getDay()-this.startDay;
-        
-        if(startingPos < this.startDay){
-            startingPos += 7;
-        }
-        
-        var pm = date.add(Date.MONTH, -1);
-        var prevStart = pm.getDaysInMonth()-startingPos;
-//        
-        
-        
-        this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
-        
-        this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
-        //this.cells.addClassOnOver('fc-state-hover');
-        
-        var cells = this.cells.elements;
-        var textEls = this.textNodes;
-        
-        //Roo.each(cells, function(cell){
-        //    cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
-        //});
-        
-        days += startingPos;
-
-        // convert everything to numbers so it's fast
-        var day = 86400000;
-        var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
-        //Roo.log(d);
-        //Roo.log(pm);
-        //Roo.log(prevStart);
-        
-        var today = new Date().clearTime().getTime();
-        var sel = date.clearTime().getTime();
-        var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
-        var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
-        var ddMatch = this.disabledDatesRE;
-        var ddText = this.disabledDatesText;
-        var ddays = this.disabledDays ? this.disabledDays.join("") : false;
-        var ddaysText = this.disabledDaysText;
-        var format = this.format;
-        
-        var setCellClass = function(cal, cell){
-            
-            //Roo.log('set Cell Class');
-            cell.title = "";
-            var t = d.getTime();
-            
-            //Roo.log(d);
-            
-            
-            cell.dateValue = t;
-            if(t == today){
-                cell.className += " fc-today";
-                cell.className += " fc-state-highlight";
-                cell.title = cal.todayText;
-            }
-            if(t == sel){
-                // disable highlight in other month..
-                cell.className += " fc-state-highlight";
-                
-            }
-            // disabling
-            if(t < min) {
-                //cell.className = " fc-state-disabled";
-                cell.title = cal.minText;
-                return;
-            }
-            if(t > max) {
-                //cell.className = " fc-state-disabled";
-                cell.title = cal.maxText;
-                return;
-            }
-            if(ddays){
-                if(ddays.indexOf(d.getDay()) != -1){
-                    // cell.title = ddaysText;
-                   // cell.className = " fc-state-disabled";
-                }
-            }
-            if(ddMatch && format){
-                var fvalue = d.dateFormat(format);
-                if(ddMatch.test(fvalue)){
-                    cell.title = ddText.replace("%0", fvalue);
-                   cell.className = " fc-state-disabled";
-                }
-            }
-            
-            if (!cell.initialClassName) {
-                cell.initialClassName = cell.dom.className;
-            }
-            
-            cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
-        };
-
-        var i = 0;
-        
-        for(; i < startingPos; i++) {
-            cells[i].dayName =  (++prevStart);
-            Roo.log(textEls[i]);
-            d.setDate(d.getDate()+1);
-            
-            //cells[i].className = "fc-past fc-other-month";
-            setCellClass(this, cells[i]);
-        }
-        
-        var intDay = 0;
-        
-        for(; i < days; i++){
-            intDay = i - startingPos + 1;
-            cells[i].dayName =  (intDay);
-            d.setDate(d.getDate()+1);
-            
-            cells[i].className = ''; // "x-date-active";
-            setCellClass(this, cells[i]);
-        }
-        var extraDays = 0;
-        
-        for(; i < 42; i++) {
-            //textEls[i].innerHTML = (++extraDays);
-            
-            d.setDate(d.getDate()+1);
-            cells[i].dayName = (++extraDays);
-            cells[i].className = "fc-future fc-other-month";
-            setCellClass(this, cells[i]);
-        }
-        
-        //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
-        
-        var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
-        
-        // this will cause all the cells to mis
-        var rows= [];
-        var i =0;
-        for (var r = 0;r < 6;r++) {
-            for (var c =0;c < 7;c++) {
-                this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
-            }    
-        }
-        
-        this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
-        for(i=0;i<cells.length;i++) {
-            
-            this.cells.elements[i].dayName = cells[i].dayName ;
-            this.cells.elements[i].className = cells[i].className;
-            this.cells.elements[i].initialClassName = cells[i].initialClassName ;
-            this.cells.elements[i].title = cells[i].title ;
-            this.cells.elements[i].dateValue = cells[i].dateValue ;
-        }
-        
-        
-        
-        
-        //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
-        //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
-        
-        ////if(totalRows != 6){
-            //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
-           // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
-       // }
-        
-        this.fireEvent('monthchange', this, date);
-        
-        
-    },
- /**
-     * Returns the grid's SelectionModel.
-     * @return {SelectionModel}
-     */
-    getSelectionModel : function(){
-        if(!this.selModel){
-            this.selModel = new Roo.grid.CellSelectionModel();
-        }
-        return this.selModel;
-    },
 
-    load: function() {
-        this.eventStore.load()
-        
-        
-        
-    },
-    
-    findCell : function(dt) {
-        dt = dt.clearTime().getTime();
-        var ret = false;
-        this.cells.each(function(c){
-            //Roo.log("check " +c.dateValue + '?=' + dt);
-            if(c.dateValue == dt){
-                ret = c;
-                return false;
-            }
-            return true;
-        });
-        
-        return ret;
-    },
-    
-    findCells : function(rec) {
-        var s = rec.data.start_dt.clone().clearTime().getTime();
-       // Roo.log(s);
-        var e= rec.data.end_dt.clone().clearTime().getTime();
-       // Roo.log(e);
-        var ret = [];
-        this.cells.each(function(c){
-             ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
-            
-            if(c.dateValue > e){
-                return ;
-            }
-            if(c.dateValue < s){
-                return ;
-            }
-            ret.push(c);
-        });
-        
-        return ret;    
-    },
-    
-    findBestRow: function(cells)
-    {
-        var ret = 0;
-        
-        for (var i =0 ; i < cells.length;i++) {
-            ret  = Math.max(cells[i].rows || 0,ret);
-        }
-        return ret;
-        
-    },
-    
+Roo.extend(Roo.dialog.UploadCropbox, Roo.Component,  {
+    
+    emptyText : 'Click to upload image',
+    rotateNotify : 'Image is too small to rotate',
+    errorTimeout : 3000,
+    scale : 0,
+    baseScale : 1,
+    rotate : 0,
+    dragable : false,
+    pinching : false,
+    mouseX : 0,
+    mouseY : 0,
+    cropData : false,
+    minWidth : 300,
+    minHeight : 300,
+    outputMaxWidth : 1200,
+    windowSize : 300,
+    file : false,
+    exif : {},
+    baseRotate : 1,
+    cropType : 'image/jpeg',
+    buttons : false,
+    canvasLoaded : false,
+    isDocument : false,
+    method : 'POST',
+    paramName : 'imageUpload',
+    loadMask : true,
+    loadingText : 'Loading...',
+    maskEl : false,
     
-    addItem : function(rec)
+    getAutoCreate : function()
     {
-        // look for vertical location slot in
-        var cells = this.findCells(rec);
-        
-        rec.row = this.findBestRow(cells);
-        
-        // work out the location.
-        
-        var crow = false;
-        var rows = [];
-        for(var i =0; i < cells.length; i++) {
-            if (!crow) {
-                crow = {
-                    start : cells[i],
-                    end :  cells[i]
-                };
-                continue;
-            }
-            if (crow.start.getY() == cells[i].getY()) {
-                // on same row.
-                crow.end = cells[i];
-                continue;
-            }
-            // different row.
-            rows.push(crow);
-            crow = {
-                start: cells[i],
-                end : cells[i]
-            };
-            
-        }
-        
-        rows.push(crow);
-        rec.els = [];
-        rec.rows = rows;
-        rec.cells = cells;
-        for (var i = 0; i < cells.length;i++) {
-            cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
-            
-        }
-        
-        
-    },
-    
-    clearEvents: function() {
-        
-        if (!this.eventStore.getCount()) {
-            return;
-        }
-        // reset number of rows in cells.
-        Roo.each(this.cells.elements, function(c){
-            c.rows = 0;
-        });
-        
-        this.eventStore.each(function(e) {
-            this.clearEvent(e);
-        },this);
+        var cfg = {
+            tag : 'div',
+            cls : 'roo-upload-cropbox',
+            cn : [
+                {
+                    tag : 'input',
+                    cls : 'roo-upload-cropbox-selector',
+                    type : 'file'
+                },
+                {
+                    tag : 'div',
+                    cls : 'roo-upload-cropbox-body',
+                    style : 'cursor:pointer',
+                    cn : [
+                        {
+                            tag : 'div',
+                            cls : 'roo-upload-cropbox-preview'
+                        },
+                        {
+                            tag : 'div',
+                            cls : 'roo-upload-cropbox-thumb'
+                        },
+                        {
+                            tag : 'div',
+                            cls : 'roo-upload-cropbox-empty-notify',
+                            html : this.emptyText
+                        },
+                        {
+                            tag : 'div',
+                            cls : 'roo-upload-cropbox-error-notify alert alert-danger',
+                            html : this.rotateNotify
+                        }
+                    ]
+                },
+                {
+                    tag : 'div',
+                    cls : 'roo-upload-cropbox-footer',
+                    cn : {
+                        tag : 'div',
+                        cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
+                        cn : []
+                    }
+                }
+            ]
+        };
         
+        return cfg;
     },
     
-    clearEvent : function(ev)
+    onRender : function(ct, position)
     {
-        if (ev.els) {
-            Roo.each(ev.els, function(el) {
-                el.un('mouseenter' ,this.onEventEnter, this);
-                el.un('mouseleave' ,this.onEventLeave, this);
-                el.remove();
-            },this);
-            ev.els = [];
-        }
-    },
-    
-    
-    renderEvent : function(ev,ctr) {
-        if (!ctr) {
-             ctr = this.view.el.select('.fc-event-container',true).first();
+        Roo.dialog.UploadCropbox.superclass.onRender.call(this, ct, position);
+
+        if(this.el){
+            if (this.el.attr('xtype')) {
+                this.el.attr('xtypex', this.el.attr('xtype'));
+                this.el.dom.removeAttribute('xtype');
+                
+                this.initEvents();
+            }
         }
+        else {
+            var cfg = Roo.apply({},  this.getAutoCreate());
         
-         
-        this.clearEvent(ev);
-            //code
-       
-        
-        
-        ev.els = [];
-        var cells = ev.cells;
-        var rows = ev.rows;
-        this.fireEvent('eventrender', this, ev);
-        
-        for(var i =0; i < rows.length; i++) {
+            cfg.id = this.id || Roo.id();
             
-            cls = '';
-            if (i == 0) {
-                cls += ' fc-event-start';
-            }
-            if ((i+1) == rows.length) {
-                cls += ' fc-event-end';
+            if (this.cls) {
+                cfg.cls = (typeof(cfg.cls) == 'undefined' ? this.cls : cfg.cls) + ' ' + this.cls;
             }
             
-            //Roo.log(ev.data);
-            // how many rows should it span..
-            var cg = this.eventTmpl.append(ctr,Roo.apply({
-                fccls : cls
-                
-            }, ev.data) , true);
-            
+            if (this.style) { // fixme needs to support more complex style data.
+                cfg.style = (typeof(cfg.style) == 'undefined' ? this.style : cfg.style) + '; ' + this.style;
+            }
             
-            cg.on('mouseenter' ,this.onEventEnter, this, ev);
-            cg.on('mouseleave' ,this.onEventLeave, this, ev);
-            cg.on('click', this.onEventClick, this, ev);
+            this.el = ct.createChild(cfg, position);
             
-            ev.els.push(cg);
+            this.initEvents();
+        }
+        
+        if (this.buttons.length) {
             
-            var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
-            var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
-            //Roo.log(cg);
-             
-            cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);    
-            cg.setWidth(ebox.right - sbox.x -2);
+            Roo.each(this.buttons, function(bb) {
+                
+                var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
+                
+                btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
+                
+            }, this);
+        }
+        
+        if(this.loadMask){
+            this.maskEl = this.el;
         }
     },
     
-    renderEvents: function()
-    {   
-        // first make sure there is enough space..
+    initEvents : function()
+    {
+        this.urlAPI = (window.createObjectURL && window) || 
+                                (window.URL && URL.revokeObjectURL && URL) || 
+                                (window.webkitURL && webkitURL);
+                        
+        this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
+        this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
         
-        if (!this.eventTmpl) {
-            this.eventTmpl = new Roo.Template(
-                '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}"  style="position: absolute" unselectable="on">' +
-                    '<div class="fc-event-inner">' +
-                        '<span class="fc-event-time">{time}</span>' +
-                        '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
-                    '</div>' +
-                    '<div class="ui-resizable-heandle ui-resizable-e">&nbsp;&nbsp;&nbsp;</div>' +
-                '</div>'
-            );
-                
-        }
-               
+        this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
+        this.selectorEl.hide();
         
+        this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
+        this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
         
-        this.cells.each(function(c) {
-            //Roo.log(c.select('.fc-day-content div',true).first());
-            c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
-        });
+        this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
+        this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+        this.thumbEl.hide();
         
-        var ctr = this.view.el.select('.fc-event-container',true).first();
+        this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
+        this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
         
-        var cls;
-        this.eventStore.each(function(ev){
-            
-            this.renderEvent(ev);
-             
-             
-        }, this);
-        this.view.layout();
+        this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
+        this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+        this.errorEl.hide();
         
+        this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
+        this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+        this.footerEl.hide();
+        
+        this.setThumbBoxSize();
+        
+        this.bind();
+        
+        this.resize();
+        
+        this.fireEvent('initial', this);
     },
-    
-    onEventEnter: function (e, el,event,d) {
-        this.fireEvent('evententer', this, el, event);
-    },
-    
-    onEventLeave: function (e, el,event,d) {
-        this.fireEvent('eventleave', this, el, event);
-    },
-    
-    onEventClick: function (e, el,event,d) {
-        this.fireEvent('eventclick', this, el, event);
+
+    bind : function()
+    {
+        var _this = this;
+        
+        window.addEventListener("resize", function() { _this.resize(); } );
+        
+        this.bodyEl.on('click', this.beforeSelectFile, this);
+        
+        if(Roo.isTouch){
+            this.bodyEl.on('touchstart', this.onTouchStart, this);
+            this.bodyEl.on('touchmove', this.onTouchMove, this);
+            this.bodyEl.on('touchend', this.onTouchEnd, this);
+        }
+        
+        if(!Roo.isTouch){
+            this.bodyEl.on('mousedown', this.onMouseDown, this);
+            this.bodyEl.on('mousemove', this.onMouseMove, this);
+            var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
+            this.bodyEl.on(mousewheel, this.onMouseWheel, this);
+            Roo.get(document).on('mouseup', this.onMouseUp, this);
+        }
+        
+        this.selectorEl.on('change', this.onFileSelected, this);
     },
     
-    onMonthChange: function () {
-        this.store.load();
+    reset : function()
+    {    
+        this.scale = 0;
+        this.baseScale = 1;
+        this.rotate = 0;
+        this.baseRotate = 1;
+        this.dragable = false;
+        this.pinching = false;
+        this.mouseX = 0;
+        this.mouseY = 0;
+        this.cropData = false;
+        this.notifyEl.dom.innerHTML = this.emptyText;
+        
+        // this.selectorEl.dom.value = '';
+        
     },
     
-    onLoad: function () {
-        
-        //Roo.log('calendar onload');
-//         
-        if(this.eventStore.getCount() > 0){
-            
-           
-            
-            this.eventStore.each(function(d){
-                
-                
-                // FIXME..
-                var add =   d.data;
-                if (typeof(add.end_dt) == 'undefined')  {
-                    Roo.log("Missing End time in calendar data: ");
-                    Roo.log(d);
-                    return;
-                }
-                if (typeof(add.start_dt) == 'undefined')  {
-                    Roo.log("Missing Start time in calendar data: ");
-                    Roo.log(d);
-                    return;
-                }
-                add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
-                add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
-                add.id = add.id || d.id;
-                add.title = add.title || '??';
-                
-                this.addItem(d);
-                
-             
-            },this);
+    resize : function()
+    {
+        if(this.fireEvent('resize', this) != false){
+            this.setThumbBoxPosition();
+            this.setCanvasPosition();
         }
-        
-        this.renderEvents();
-    }
+    },
     
-
-});
-/*
- grid : {
-                xtype: 'Grid',
-                xns: Roo.grid,
-                listeners : {
-                    render : function ()
-                    {
-                        _this.grid = this;
-                        
-                        if (!this.view.el.hasClass('course-timesheet')) {
-                            this.view.el.addClass('course-timesheet');
-                        }
-                        if (this.tsStyle) {
-                            this.ds.load({});
-                            return; 
-                        }
-                        Roo.log('width');
-                        Roo.log(_this.grid.view.el.getWidth());
-                        
-                        
-                        this.tsStyle =  Roo.util.CSS.createStyleSheet({
-                            '.course-timesheet .x-grid-row' : {
-                                height: '80px'
-                            },
-                            '.x-grid-row td' : {
-                                'vertical-align' : 0
-                            },
-                            '.course-edit-link' : {
-                                'color' : 'blue',
-                                'text-overflow' : 'ellipsis',
-                                'overflow' : 'hidden',
-                                'white-space' : 'nowrap',
-                                'cursor' : 'pointer'
-                            },
-                            '.sub-link' : {
-                                'color' : 'green'
-                            },
-                            '.de-act-sup-link' : {
-                                'color' : 'purple',
-                                'text-decoration' : 'line-through'
-                            },
-                            '.de-act-link' : {
-                                'color' : 'red',
-                                'text-decoration' : 'line-through'
-                            },
-                            '.course-timesheet .course-highlight' : {
-                                'border-top-style': 'dashed !important',
-                                'border-bottom-bottom': 'dashed !important'
-                            },
-                            '.course-timesheet .course-item' : {
-                                'font-family'   : 'tahoma, arial, helvetica',
-                                'font-size'     : '11px',
-                                'overflow'      : 'hidden',
-                                'padding-left'  : '10px',
-                                'padding-right' : '10px',
-                                'padding-top' : '10px' 
-                            }
-                            
-                        }, Roo.id());
-                                this.ds.load({});
-                    }
-                },
-                autoWidth : true,
-                monitorWindowResize : false,
-                cellrenderer : function(v,x,r)
-                {
-                    return v;
-                },
-                sm : {
-                    xtype: 'CellSelectionModel',
-                    xns: Roo.grid
-                },
-                dataSource : {
-                    xtype: 'Store',
-                    xns: Roo.data,
-                    listeners : {
-                        beforeload : function (_self, options)
-                        {
-                            options.params = options.params || {};
-                            options.params._month = _this.monthField.getValue();
-                            options.params.limit = 9999;
-                            options.params['sort'] = 'when_dt';    
-                            options.params['dir'] = 'ASC';    
-                            this.proxy.loadResponse = this.loadResponse;
-                            Roo.log("load?");
-                            //this.addColumns();
-                        },
-                        load : function (_self, records, options)
-                        {
-                            _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
-                                // if you click on the translation.. you can edit it...
-                                var el = Roo.get(this);
-                                var id = el.dom.getAttribute('data-id');
-                                var d = el.dom.getAttribute('data-date');
-                                var t = el.dom.getAttribute('data-time');
-                                //var id = this.child('span').dom.textContent;
-                                
-                                //Roo.log(this);
-                                Pman.Dialog.CourseCalendar.show({
-                                    id : id,
-                                    when_d : d,
-                                    when_t : t,
-                                    productitem_active : id ? 1 : 0
-                                }, function() {
-                                    _this.grid.ds.load({});
-                                });
-                           
-                           });
-                           
-                           _this.panel.fireEvent('resize', [ '', '' ]);
-                        }
-                    },
-                    loadResponse : function(o, success, response){
-                            // this is overridden on before load..
-                            
-                            Roo.log("our code?");      
-                            //Roo.log(success);
-                            //Roo.log(response)
-                            delete this.activeRequest;
-                            if(!success){
-                                this.fireEvent("loadexception", this, o, response);
-                                o.request.callback.call(o.request.scope, null, o.request.arg, false);
-                                return;
-                            }
-                            var result;
-                            try {
-                                result = o.reader.read(response);
-                            }catch(e){
-                                Roo.log("load exception?");
-                                this.fireEvent("loadexception", this, o, response, e);
-                                o.request.callback.call(o.request.scope, null, o.request.arg, false);
-                                return;
-                            }
-                            Roo.log("ready...");        
-                            // loop through result.records;
-                            // and set this.tdate[date] = [] << array of records..
-                            _this.tdata  = {};
-                            Roo.each(result.records, function(r){
-                                //Roo.log(r.data);
-                                if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
-                                    _this.tdata[r.data.when_dt.format('j')] = [];
-                                }
-                                _this.tdata[r.data.when_dt.format('j')].push(r.data);
-                            });
-                            
-                            //Roo.log(_this.tdata);
-                            
-                            result.records = [];
-                            result.totalRecords = 6;
-                    
-                            // let's generate some duumy records for the rows.
-                            //var st = _this.dateField.getValue();
-                            
-                            // work out monday..
-                            //st = st.add(Date.DAY, -1 * st.format('w'));
-                            
-                            var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
-                            
-                            var firstOfMonth = date.getFirstDayOfMonth();
-                            var days = date.getDaysInMonth();
-                            var d = 1;
-                            var firstAdded = false;
-                            for (var i = 0; i < result.totalRecords ; i++) {
-                                //var d= st.add(Date.DAY, i);
-                                var row = {};
-                                var added = 0;
-                                for(var w = 0 ; w < 7 ; w++){
-                                    if(!firstAdded && firstOfMonth != w){
-                                        continue;
-                                    }
-                                    if(d > days){
-                                        continue;
-                                    }
-                                    firstAdded = true;
-                                    var dd = (d > 0 && d < 10) ? "0"+d : d;
-                                    row['weekday'+w] = String.format(
-                                                    '<span style="font-size: 16px;"><b>{0}</b></span>'+
-                                                    '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
-                                                    d,
-                                                    date.format('Y-m-')+dd
-                                                );
-                                    added++;
-                                    if(typeof(_this.tdata[d]) != 'undefined'){
-                                        Roo.each(_this.tdata[d], function(r){
-                                            var is_sub = '';
-                                            var deactive = '';
-                                            var id = r.id;
-                                            var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
-                                            if(r.parent_id*1>0){
-                                                is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
-                                                id = r.parent_id;
-                                            }
-                                            if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
-                                                deactive = 'de-act-link';
-                                            }
-                                            
-                                            row['weekday'+w] += String.format(
-                                                    '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
-                                                    id, //0
-                                                    r.product_id_name, //1
-                                                    r.when_dt.format('h:ia'), //2
-                                                    is_sub, //3
-                                                    deactive, //4
-                                                    desc // 5
-                                            );
-                                        });
-                                    }
-                                    d++;
-                                }
-                                
-                                // only do this if something added..
-                                if(added > 0){ 
-                                    result.records.push(_this.grid.dataSource.reader.newRow(row));
-                                }
-                                
-                                
-                                // push it twice. (second one with an hour..
-                                
-                            }
-                            //Roo.log(result);
-                            this.fireEvent("load", this, o, o.request.arg);
-                            o.request.callback.call(o.request.scope, result, o.request.arg, true);
-                        },
-                    sortInfo : {field: 'when_dt', direction : 'ASC' },
-                    proxy : {
-                        xtype: 'HttpProxy',
-                        xns: Roo.data,
-                        method : 'GET',
-                        url : baseURL + '/Roo/Shop_course.php'
-                    },
-                    reader : {
-                        xtype: 'JsonReader',
-                        xns: Roo.data,
-                        id : 'id',
-                        fields : [
-                            {
-                                'name': 'id',
-                                'type': 'int'
-                            },
-                            {
-                                'name': 'when_dt',
-                                'type': 'string'
-                            },
-                            {
-                                'name': 'end_dt',
-                                'type': 'string'
-                            },
-                            {
-                                'name': 'parent_id',
-                                'type': 'int'
-                            },
-                            {
-                                'name': 'product_id',
-                                'type': 'int'
-                            },
-                            {
-                                'name': 'productitem_id',
-                                'type': 'int'
-                            },
-                            {
-                                'name': 'guid',
-                                'type': 'int'
-                            }
-                        ]
-                    }
-                },
-                toolbar : {
-                    xtype: 'Toolbar',
-                    xns: Roo,
-                    items : [
-                        {
-                            xtype: 'Button',
-                            xns: Roo.Toolbar,
-                            listeners : {
-                                click : function (_self, e)
-                                {
-                                    var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
-                                    sd.setMonth(sd.getMonth()-1);
-                                    _this.monthField.setValue(sd.format('Y-m-d'));
-                                    _this.grid.ds.load({});
-                                }
-                            },
-                            text : "Back"
-                        },
-                        {
-                            xtype: 'Separator',
-                            xns: Roo.Toolbar
-                        },
-                        {
-                            xtype: 'MonthField',
-                            xns: Roo.form,
-                            listeners : {
-                                render : function (_self)
-                                {
-                                    _this.monthField = _self;
-                                   // _this.monthField.set  today
-                                },
-                                select : function (combo, date)
-                                {
-                                    _this.grid.ds.load({});
-                                }
-                            },
-                            value : (function() { return new Date(); })()
-                        },
-                        {
-                            xtype: 'Separator',
-                            xns: Roo.Toolbar
-                        },
-                        {
-                            xtype: 'TextItem',
-                            xns: Roo.Toolbar,
-                            text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
-                        },
-                        {
-                            xtype: 'Fill',
-                            xns: Roo.Toolbar
-                        },
-                        {
-                            xtype: 'Button',
-                            xns: Roo.Toolbar,
-                            listeners : {
-                                click : function (_self, e)
-                                {
-                                    var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
-                                    sd.setMonth(sd.getMonth()+1);
-                                    _this.monthField.setValue(sd.format('Y-m-d'));
-                                    _this.grid.ds.load({});
-                                }
-                            },
-                            text : "Next"
-                        }
-                    ]
-                },
-                 
+    onFooterButtonClick : function(e, el, o, type)
+    {
+        switch (type) {
+            case 'rotate-left' :
+                this.onRotateLeft(e);
+                break;
+            case 'rotate-right' :
+                this.onRotateRight(e);
+                break;
+            case 'picture' :
+                this.beforeSelectFile(e);
+                break;
+            case 'trash' :
+                this.trash(e);
+                break;
+            case 'crop' :
+                this.crop(e);
+                break;
+            case 'download' :
+                this.download(e);
+                break;
+            case 'center' :
+                this.center(e);
+                break;
+            default :
+                break;
+        }
+        
+        this.fireEvent('footerbuttonclick', this, type);
+    },
+    
+    beforeSelectFile : function(e)
+    {
+        e.preventDefault();
+        
+        if(this.fireEvent('beforeselectfile', this) != false){
+            this.selectorEl.dom.click();
+        }
+    },
+    
+    onFileSelected : function(e)
+    {
+        e.preventDefault();
+        
+        if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
+            return;
+        }
+        
+        var file = this.selectorEl.dom.files[0];
+        
+        if(this.fireEvent('inspect', this, file) != false){
+            this.prepare(file);
+        }
+        
+    },
+    
+    trash : function(e)
+    {
+        this.fireEvent('trash', this);
+    },
+    
+    download : function(e)
+    {
+        this.fireEvent('download', this);
+    },
+
+    center : function(e)
+    {
+        this.setCanvasPosition();
+    },
+    
+    loadCanvas : function(src)
+    {   
+        if(this.fireEvent('beforeloadcanvas', this, src) != false){
+            
+            this.reset();
+            
+            this.imageEl = document.createElement('img');
+            
+            var _this = this;
+            
+            this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
+            
+            this.imageEl.src = src;
+        }
+    },
+    
+    onLoadCanvas : function()
+    {   
+        this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
+        this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
+
+        if(this.fireEvent('loadcanvas', this, this.imageEl) != false){
+        
+            this.bodyEl.un('click', this.beforeSelectFile, this);
+            
+            this.notifyEl.hide();
+            this.thumbEl.show();
+            this.footerEl.show();
+            
+            this.baseRotateLevel();
+            
+            if(this.isDocument){
+                this.setThumbBoxSize();
             }
-        };
+            
+            this.setThumbBoxPosition();
+            
+            this.baseScaleLevel();
+            
+            this.draw();
+            
+            this.resize();
+            
+            this.canvasLoaded = true;
         
-        *//*
- * 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.LoadMask
- * A simple utility class for generically masking elements while loading data.  If the element being masked has
- * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
- * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
- * element's UpdateManager load indicator and will be destroyed after the initial load.
- * @constructor
- * Create a new LoadMask
- * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
- * @param {Object} config The config object
- */
-Roo.LoadMask = function(el, config){
-    this.el = Roo.get(el);
-    Roo.apply(this, config);
-    if(this.store){
-        this.store.on('beforeload', this.onBeforeLoad, this);
-        this.store.on('load', this.onLoad, this);
-        this.store.on('loadexception', this.onLoadException, this);
-        this.removeMask = false;
-    }else{
-        var um = this.el.getUpdateManager();
-        um.showLoadIndicator = false; // disable the default indicator
-        um.on('beforeupdate', this.onBeforeLoad, this);
-        um.on('update', this.onLoad, this);
-        um.on('failure', this.onLoad, this);
-        this.removeMask = true;
-    }
-};
+        }
+        
+        if(this.loadMask){
+            this.maskEl.unmask();
+        }
+        
+    },
+    
+    setCanvasPosition : function(center = true)
+    {   
+        if(!this.canvasEl){
+            return;
+        }
 
-Roo.LoadMask.prototype = {
-    /**
-     * @cfg {Boolean} removeMask
-     * 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.
-     */
-    /**
-     * @cfg {String} msg
-     * The text to display in a centered loading message box (defaults to 'Loading...')
-     */
-    msg : 'Loading...',
-    /**
-     * @cfg {String} msgCls
-     * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
-     */
-    msgCls : 'x-mask-loading',
+        var newCenterLeft = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
+        var newCenterTop = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
 
-    /**
-     * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
-     * @type Boolean
-     */
-    disabled: false,
+        if(center) {
+            this.previewEl.setLeft(newCenterLeft);
+            this.previewEl.setTop(newCenterTop);
 
-    /**
-     * Disables the mask to prevent it from being displayed
-     */
-    disable : function(){
-       this.disabled = true;
+            return;
+        }
+        
+        var oldScaleLevel = this.baseScale * Math.pow(1.02, this.startScale);
+        var oldCanvasWidth = Math.floor(this.imageEl.OriginWidth * oldScaleLevel);
+        var oldCanvasHeight = Math.floor(this.imageEl.OriginHeight * oldScaleLevel);
+
+        var oldCenterLeft = Math.ceil((this.bodyEl.getWidth() - oldCanvasWidth) / 2);
+        var oldCenterTop = Math.ceil((this.bodyEl.getHeight() - oldCanvasHeight) / 2);
+
+        var leftDiff = newCenterLeft - oldCenterLeft;
+        var topDiff = newCenterTop - oldCenterTop;
+
+        var newPreviewLeft = this.previewEl.getLeft(true) + leftDiff;
+        var newPreviewTop = this.previewEl.getTop(true) + topDiff;
+
+        this.previewEl.setLeft(newPreviewLeft);
+        this.previewEl.setTop(newPreviewTop);
+        
+    },
+    
+    onMouseDown : function(e)
+    {   
+        e.stopEvent();
+        
+        this.dragable = true;
+        this.pinching = false;
+        
+        if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
+            this.dragable = false;
+            return;
+        }
+        
+        this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
+        this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
+        
     },
+    
+    onMouseMove : function(e)
+    {   
+        e.stopEvent();
+        
+        if(!this.canvasLoaded){
+            return;
+        }
+        
+        if (!this.dragable){
+            return;
+        }
 
-    /**
-     * Enables the mask so that it can be displayed
-     */
-    enable : function(){
-        this.disabled = false;
+        var maxPaddingLeft = this.canvasEl.width / 0.9 * 0.05;
+        var maxPaddingTop = maxPaddingLeft * this.minHeight / this.minWidth;
+
+        if ((this.imageEl.OriginWidth / this.imageEl.OriginHeight <= this.minWidth / this.minHeight)) {
+            maxPaddingLeft = (this.canvasEl.height * this.minWidth / this.minHeight - this.canvasEl.width) / 2 + maxPaddingLeft;
+        }
+
+        if ((this.imageEl.OriginWidth / this.imageEl.OriginHeight >= this.minWidth / this.minHeight)) {
+            maxPaddingTop = (this.canvasEl.width * this.minHeight / this.minWidth - this.canvasEl.height) / 2 + maxPaddingTop;
+        }
+        
+        var minX = Math.ceil(this.thumbEl.getLeft(true) + this.thumbEl.getWidth() - this.canvasEl.width - maxPaddingLeft);
+        var minY = Math.ceil(this.thumbEl.getTop(true) + this.thumbEl.getHeight() - this.canvasEl.height - maxPaddingTop);
+        
+        var maxX = Math.ceil(this.thumbEl.getLeft(true) + maxPaddingLeft);
+        var maxY = Math.ceil(this.thumbEl.getTop(true) +  maxPaddingTop);
+
+        if(minX > maxX) {
+            var tempX = minX;
+            minX = maxX;
+            maxX = tempX;
+        }
+
+        if(minY > maxY) {
+            var tempY = minY;
+            minY = maxY;
+            maxY = tempY;
+        }
+
+        var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
+        var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
+        
+        x = x - this.mouseX;
+        y = y - this.mouseY;
+
+        var bgX = Math.ceil(x + this.previewEl.getLeft(true));
+        var bgY = Math.ceil(y + this.previewEl.getTop(true));
+        
+        bgX = (bgX < minX) ? minX : ((bgX > maxX) ? maxX : bgX);
+        bgY = (bgY < minY) ? minY : ((bgY > maxY) ? maxY : bgY);
+        
+        this.previewEl.setLeft(bgX);
+        this.previewEl.setTop(bgY);
+        
+        this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
+        this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
     },
     
-    onLoadException : function()
+    onMouseUp : function(e)
+    {   
+        e.stopEvent();
+        
+        this.dragable = false;
+    },
+    
+    onMouseWheel : function(e)
+    {   
+        e.stopEvent();
+        
+        this.startScale = this.scale;
+        this.scale = (e.getWheelDelta() > 0) ? (this.scale + 1) : (this.scale - 1);
+        
+        if(!this.zoomable()){
+            this.scale = this.startScale;
+            return;
+        }
+
+        
+        this.draw();
+        
+        return;
+    },
+    
+    zoomable : function()
     {
-        Roo.log(arguments);
+        var minScale = this.thumbEl.getWidth() / this.minWidth;
         
-        if (typeof(arguments[3]) != 'undefined') {
-            Roo.MessageBox.alert("Error loading",arguments[3]);
-        } 
-        /*
-        try {
-            if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
-                Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
-            }   
-        } catch(e) {
+        if(this.minWidth < this.minHeight){
+            minScale = this.thumbEl.getHeight() / this.minHeight;
+        }
+        
+        var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
+        var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
+        var maxWidth = this.imageEl.OriginWidth;
+        var maxHeight = this.imageEl.OriginHeight;
+
+
+        var newCanvasWidth = Math.floor(this.imageEl.OriginWidth * this.getScaleLevel());
+        var newCanvasHeight = Math.floor(this.imageEl.OriginHeight * this.getScaleLevel());
+
+        var oldCenterLeft = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
+        var oldCenterTop = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
+
+        var newCenterLeft = Math.ceil((this.bodyEl.getWidth() - newCanvasWidth) / 2);
+        var newCenterTop = Math.ceil((this.bodyEl.getHeight() - newCanvasHeight) / 2);
+
+        var leftDiff = newCenterLeft - oldCenterLeft;
+        var topDiff = newCenterTop - oldCenterTop;
+
+        var newPreviewLeft = this.previewEl.getLeft(true) + leftDiff;
+        var newPreviewTop = this.previewEl.getTop(true) + topDiff;
+
+        var paddingLeft = newPreviewLeft - this.thumbEl.getLeft(true);
+        var paddingTop = newPreviewTop - this.thumbEl.getTop(true);
+
+        var paddingRight = this.thumbEl.getLeft(true) + this.thumbEl.getWidth() - newCanvasWidth - newPreviewLeft;
+        var paddingBottom = this.thumbEl.getTop(true) + this.thumbEl.getHeight() - newCanvasHeight - newPreviewTop;
+
+        var maxPaddingLeft = newCanvasWidth / 0.9 * 0.05;
+        var maxPaddingTop = maxPaddingLeft * this.minHeight / this.minWidth;
+
+        if ((this.imageEl.OriginWidth / this.imageEl.OriginHeight <= this.minWidth / this.minHeight)) {
+            maxPaddingLeft = (newCanvasHeight * this.minWidth / this.minHeight - newCanvasWidth) / 2 + maxPaddingLeft;
+        }
+
+        if ((this.imageEl.OriginWidth / this.imageEl.OriginHeight >= this.minWidth / this.minHeight)) {
+            maxPaddingTop = (newCanvasWidth * this.minHeight / this.minWidth - newCanvasHeight) / 2 + maxPaddingTop;
+        }
+        
+        if(
+                this.isDocument &&
+                (this.rotate == 0 || this.rotate == 180) && 
+                (
+                    width > this.imageEl.OriginWidth || 
+                    height > this.imageEl.OriginHeight ||
+                    (width < this.minWidth && height < this.minHeight)
+                )
+        ){
+            return false;
+        }
+        
+        if(
+                this.isDocument &&
+                (this.rotate == 90 || this.rotate == 270) && 
+                (
+                    width > this.imageEl.OriginWidth || 
+                    height > this.imageEl.OriginHeight ||
+                    (width < this.minHeight && height < this.minWidth)
+                )
+        ){
+            return false;
+        }
+        
+        if(
+                !this.isDocument &&
+                (this.rotate == 0 || this.rotate == 180) && 
+                (
+                    // for zoom out
+                    paddingLeft > maxPaddingLeft ||
+                    paddingRight > maxPaddingLeft ||
+                    paddingTop > maxPaddingTop ||
+                    paddingBottom > maxPaddingTop ||
+                    // for zoom in
+                    width > maxWidth ||
+                    height > maxHeight
+                )
+        ){
+            return false;
+        }
+        
+        if(
+                !this.isDocument &&
+                (this.rotate == 90 || this.rotate == 270) && 
+                (
+                    width < this.minHeight || 
+                    width > this.imageEl.OriginWidth || 
+                    height < this.minWidth || 
+                    height > this.imageEl.OriginHeight
+                )
+        ){
+            return false;
+        }
+        
+        return true;
+        
+    },
+    
+    onRotateLeft : function(e)
+    {   
+        if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
+            
+            var minScale = this.thumbEl.getWidth() / this.minWidth;
+            
+            var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
+            var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
+            
+            this.startScale = this.scale;
             
+            while (this.getScaleLevel() < minScale){
+            
+                this.scale = this.scale + 1;
+                
+                if(!this.zoomable()){
+                    break;
+                }
+                
+                if(
+                        Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
+                        Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
+                ){
+                    continue;
+                }
+                
+                this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
+
+                this.draw();
+                
+                return;
+            }
+            
+            this.scale = this.startScale;
+            
+            this.onRotateFail();
+            
+            return false;
         }
-        */
+        
+        this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
+
+        if(this.isDocument){
+            this.setThumbBoxSize();
+            this.setThumbBoxPosition();
+            this.setCanvasPosition();
+        }
+        
+        this.draw();
+        
+        this.fireEvent('rotate', this, 'left');
+        
+    },
     
-        (function() { this.el.unmask(this.removeMask); }).defer(50, this);
+    onRotateRight : function(e)
+    {
+        if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
+            
+            var minScale = this.thumbEl.getWidth() / this.minWidth;
+        
+            var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
+            var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
+            
+            this.startScale = this.scale;
+            
+            while (this.getScaleLevel() < minScale){
+            
+                this.scale = this.scale + 1;
+                
+                if(!this.zoomable()){
+                    break;
+                }
+                
+                if(
+                        Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
+                        Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
+                ){
+                    continue;
+                }
+                
+                this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
+
+                this.draw();
+                
+                return;
+            }
+            
+            this.scale = this.startScale;
+            
+            this.onRotateFail();
+            
+            return false;
+        }
+        
+        this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
+
+        if(this.isDocument){
+            this.setThumbBoxSize();
+            this.setThumbBoxPosition();
+            this.setCanvasPosition();
+        }
+        
+        this.draw();
+        
+        this.fireEvent('rotate', this, 'right');
     },
-    // private
-    onLoad : function()
+    
+    onRotateFail : function()
     {
-        (function() { this.el.unmask(this.removeMask); }).defer(50, this);
+        this.errorEl.show(true);
+        
+        var _this = this;
+        
+        (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
     },
+    
+    draw : function()
+    {
+        this.previewEl.dom.innerHTML = '';
+        
+        var canvasEl = document.createElement("canvas");
+        
+        var contextEl = canvasEl.getContext("2d");
+        
+        canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
+        canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
+        var center = this.imageEl.OriginWidth / 2;
+        
+        if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
+            canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
+            canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
+            center = this.imageEl.OriginHeight / 2;
+        }
+        
+        contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
+        
+        contextEl.translate(center, center);
+        contextEl.rotate(this.rotate * Math.PI / 180);
 
-    // private
-    onBeforeLoad : function(){
-        if(!this.disabled){
-            (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
+        contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
+        
+        this.canvasEl = document.createElement("canvas");
+        
+        this.contextEl = this.canvasEl.getContext("2d");
+        
+        switch (this.rotate) {
+            case 0 :
+                
+                this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
+                this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
+                
+                this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
+                
+                break;
+            case 90 : 
+                
+                this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
+                this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
+                
+                if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
+                    this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
+                    break;
+                }
+                
+                this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
+                
+                break;
+            case 180 :
+                
+                this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
+                this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
+                
+                if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
+                    this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
+                    break;
+                }
+                
+                this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
+                
+                break;
+            case 270 :
+                
+                this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
+                this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
+        
+                if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
+                    this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
+                    break;
+                }
+                
+                this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
+                
+                break;
+            default : 
+                break;
         }
+        
+        this.previewEl.appendChild(this.canvasEl);
+        
+        this.setCanvasPosition(false);
     },
-
-    // private
-    destroy : function(){
-        if(this.store){
-            this.store.un('beforeload', this.onBeforeLoad, this);
-            this.store.un('load', this.onLoad, this);
-            this.store.un('loadexception', this.onLoadException, this);
-        }else{
-            var um = this.el.getUpdateManager();
-            um.un('beforeupdate', this.onBeforeLoad, this);
-            um.un('update', this.onLoad, this);
-            um.un('failure', this.onLoad, this);
+    
+    crop : function()
+    {
+        if(!this.canvasLoaded){
+            return;
         }
-    }
-};/*
- * 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">
- */
+        
+        var imageCanvas = document.createElement("canvas");
+        
+        var imageContext = imageCanvas.getContext("2d");
+        
+        imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
+        imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
+        
+        var center = imageCanvas.width / 2;
+        
+        imageContext.translate(center, center);
+        
+        imageContext.rotate(this.rotate * Math.PI / 180);
+        
+        imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
+        
+        var canvas = document.createElement("canvas");
+        
+        var context = canvas.getContext("2d");
 
+        canvas.width = this.thumbEl.getWidth() / this.getScaleLevel();
+        
+        canvas.height = this.thumbEl.getHeight() / this.getScaleLevel();
 
-/**
- * @class Roo.XTemplate
- * @extends Roo.Template
- * Provides a template that can have nested templates for loops or conditionals. The syntax is:
-<pre><code>
-var t = new Roo.XTemplate(
-       '&lt;select name="{name}"&gt;',
-               '&lt;tpl for="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
-       '&lt;/select&gt;'
-);
-// then append, applying the master template values
- </code></pre>
- *
- * Supported features:
- *
- *  Tags:
+        switch (this.rotate) {
+            case 0 :
+                
+                var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
+                var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
+                
+                var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
+                var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
+                
+                var sx = this.thumbEl.getLeft(true) - this.previewEl.getLeft(true);
+                var sy = this.thumbEl.getTop(true) - this.previewEl.getTop(true);
 
-<pre><code>
-      {a_variable} - output encoded.
-      {a_variable.format:("Y-m-d")} - call a method on the variable
-      {a_variable:raw} - unencoded output
-      {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
-      {a_variable:this.method_on_template(...)} - call a method on the template object.
-</code></pre>
- *  The tpl tag:
-<pre><code>
-        &lt;tpl for="a_variable or condition.."&gt;&lt;/tpl&gt;
-        &lt;tpl if="a_variable or condition"&gt;&lt;/tpl&gt;
-        &lt;tpl exec="some javascript"&gt;&lt;/tpl&gt;
-        &lt;tpl name="named_template"&gt;&lt;/tpl&gt; (experimental)
-  
-        &lt;tpl for="."&gt;&lt;/tpl&gt; - just iterate the property..
-        &lt;tpl for=".."&gt;&lt;/tpl&gt; - iterates with the parent (probably the template) 
-</code></pre>
- *      
- */
-Roo.XTemplate = function()
-{
-    Roo.XTemplate.superclass.constructor.apply(this, arguments);
-    if (this.html) {
-        this.compile();
-    }
-};
+                sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
+                sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
 
+                if(canvas.width > this.outputMaxWidth) {
+                    var scale = this.outputMaxWidth / canvas.width;
+                    canvas.width = canvas.width * scale;
+                    canvas.height = canvas.height * scale;
+                    context.scale(scale, scale);
+                }
 
-Roo.extend(Roo.XTemplate, Roo.Template, {
+                context.fillStyle = 'white';
+                context.fillRect(0, 0, this.thumbEl.getWidth() / this.getScaleLevel(), this.thumbEl.getHeight() / this.getScaleLevel());
 
-    /**
-     * The various sub templates
-     */
-    tpls : false,
-    /**
-     *
-     * basic tag replacing syntax
-     * WORD:WORD()
-     *
-     * // you can fake an object call by doing this
-     *  x.t:(test,tesT) 
-     * 
-     */
-    re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
 
-    /**
-     * compile the template
-     *
-     * This is not recursive, so I'm not sure how nested templates are really going to be handled..
-     *
-     */
-    compile: function()
-    {
-        var s = this.html;
-     
-        s = ['<tpl>', s, '</tpl>'].join('');
-    
-        var re     = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
-            nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
-            ifRe   = /^<tpl\b[^>]*?if="(.*?)"/,
-            execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
-            namedRe = /^<tpl\b[^>]*?name="(\w+)"/,  // named templates..
-            m,
-            id     = 0,
-            tpls   = [];
-    
-        while(true == !!(m = s.match(re))){
-            var forMatch   = m[0].match(nameRe),
-                ifMatch   = m[0].match(ifRe),
-                execMatch   = m[0].match(execRe),
-                namedMatch   = m[0].match(namedRe),
+                context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
+                
+                break;
+            case 90 : 
+                
+                var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
+                var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
+                
+                var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
+                var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
+                
+                var targetWidth = this.minWidth - 2 * x;
+                var targetHeight = this.minHeight - 2 * y;
+                
+                var scale = 1;
+                
+                if((x == 0 && y == 0) || (x == 0 && y > 0)){
+                    scale = targetWidth / width;
+                }
+                
+                if(x > 0 && y == 0){
+                    scale = targetHeight / height;
+                }
+                
+                if(x > 0 && y > 0){
+                    scale = targetWidth / width;
+                    
+                    if(width < height){
+                        scale = targetHeight / height;
+                    }
+                }
+                
+                context.scale(scale, scale);
+                
+                var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
+                var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
+
+                sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
+                sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
+                
+                sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
+                
+                context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
+                
+                break;
+            case 180 :
+                
+                var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
+                var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
+                
+                var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
+                var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
+                
+                var targetWidth = this.minWidth - 2 * x;
+                var targetHeight = this.minHeight - 2 * y;
+                
+                var scale = 1;
+                
+                if((x == 0 && y == 0) || (x == 0 && y > 0)){
+                    scale = targetWidth / width;
+                }
+                
+                if(x > 0 && y == 0){
+                    scale = targetHeight / height;
+                }
                 
-                exp  = null, 
-                fn   = null,
-                exec = null,
-                name = forMatch && forMatch[1] ? forMatch[1] : '';
+                if(x > 0 && y > 0){
+                    scale = targetWidth / width;
+                    
+                    if(width < height){
+                        scale = targetHeight / height;
+                    }
+                }
                 
-            if (ifMatch) {
-                // if - puts fn into test..
-                exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
-                if(exp){
-                   fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
+                context.scale(scale, scale);
+                
+                var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
+                var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
+
+                sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
+                sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
+
+                sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
+                sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
+                
+                context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
+                
+                break;
+            case 270 :
+                
+                var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
+                var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
+                
+                var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
+                var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
+                
+                var targetWidth = this.minWidth - 2 * x;
+                var targetHeight = this.minHeight - 2 * y;
+                
+                var scale = 1;
+                
+                if((x == 0 && y == 0) || (x == 0 && y > 0)){
+                    scale = targetWidth / width;
                 }
+                
+                if(x > 0 && y == 0){
+                    scale = targetHeight / height;
+                }
+                
+                if(x > 0 && y > 0){
+                    scale = targetWidth / width;
+                    
+                    if(width < height){
+                        scale = targetHeight / height;
+                    }
+                }
+                
+                context.scale(scale, scale);
+                var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
+                var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
+
+                sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
+                sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
+                
+                sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
+                
+                context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
+                
+                break;
+            default : 
+                break;
+        }
+        
+        this.cropData = canvas.toDataURL(this.cropType);
+        
+        if(this.fireEvent('crop', this, this.cropData) !== false){
+            this.process(this.file, this.cropData);
+        }
+        
+        return;
+        
+    },
+    
+    setThumbBoxSize : function()
+    {
+        var width, height;
+        
+        if(this.isDocument && typeof(this.imageEl) != 'undefined'){
+            width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
+            height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
+            
+            this.minWidth = width;
+            this.minHeight = height;
+            
+            if(this.rotate == 90 || this.rotate == 270){
+                this.minWidth = height;
+                this.minHeight = width;
             }
+        }
+        
+        height = this.windowSize;
+        width = Math.ceil(this.minWidth * height / this.minHeight);
+        
+        if(this.minWidth > this.minHeight){
+            width = this.windowSize;
+            height = Math.ceil(this.minHeight * width / this.minWidth);
+        }
+        
+        this.thumbEl.setStyle({
+            width : width + 'px',
+            height : height + 'px'
+        });
+
+        return;
             
-            if (execMatch) {
-                // exec - calls a function... returns empty if true is  returned.
-                exp = execMatch && execMatch[1] ? execMatch[1] : null;
-                if(exp){
-                   exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
+    },
+    
+    setThumbBoxPosition : function()
+    {
+        var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
+        var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
+        
+        this.thumbEl.setLeft(x);
+        this.thumbEl.setTop(y);
+        
+    },
+    
+    baseRotateLevel : function()
+    {
+        this.baseRotate = 1;
+        
+        if(
+                typeof(this.exif) != 'undefined' &&
+                typeof(this.exif[Roo.dialog.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
+                [1, 3, 6, 8].indexOf(this.exif[Roo.dialog.UploadCropbox['tags']['Orientation']]) != -1
+        ){
+            this.baseRotate = this.exif[Roo.dialog.UploadCropbox['tags']['Orientation']];
+        }
+        
+        this.rotate = Roo.dialog.UploadCropbox['Orientation'][this.baseRotate];
+        
+    },
+    
+    baseScaleLevel : function()
+    {
+        var width, height;
+        
+        if(this.isDocument){
+            
+            if(this.baseRotate == 6 || this.baseRotate == 8){
+            
+                height = this.thumbEl.getHeight();
+                this.baseScale = height / this.imageEl.OriginWidth;
+
+                if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
+                    width = this.thumbEl.getWidth();
+                    this.baseScale = width / this.imageEl.OriginHeight;
                 }
+
+                return;
+            }
+
+            height = this.thumbEl.getHeight();
+            this.baseScale = height / this.imageEl.OriginHeight;
+
+            if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
+                width = this.thumbEl.getWidth();
+                this.baseScale = width / this.imageEl.OriginWidth;
             }
+
+            return;
+        }
+        
+        if(this.baseRotate == 6 || this.baseRotate == 8){
             
+            width = this.thumbEl.getHeight();
+            this.baseScale = width / this.imageEl.OriginHeight;
             
-            if (name) {
-                // for = 
-                switch(name){
-                    case '.':  name = new Function('values', 'parent', 'with(values){ return values; }'); break;
-                    case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
-                    default:   name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
+            if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
+                height = this.thumbEl.getWidth();
+                this.baseScale = height / this.imageEl.OriginHeight;
+            }
+            
+            if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
+                height = this.thumbEl.getWidth();
+                this.baseScale = height / this.imageEl.OriginHeight;
+                
+                if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
+                    width = this.thumbEl.getHeight();
+                    this.baseScale = width / this.imageEl.OriginWidth;
                 }
             }
-            var uid = namedMatch ? namedMatch[1] : id;
             
+            return;
+        }
+        
+        width = this.thumbEl.getWidth();
+        this.baseScale = width / this.imageEl.OriginWidth;
+        
+        if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
+            height = this.thumbEl.getHeight();
+            this.baseScale = height / this.imageEl.OriginHeight;
+        }
+        
+        if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
             
-            tpls.push({
-                id:     namedMatch ? namedMatch[1] : id,
-                target: name,
-                exec:   exec,
-                test:   fn,
-                body:   m[1] || ''
-            });
-            if (namedMatch) {
-                s = s.replace(m[0], '');
-            } else { 
-                s = s.replace(m[0], '{xtpl'+ id + '}');
+            height = this.thumbEl.getHeight();
+            this.baseScale = height / this.imageEl.OriginHeight;
+            
+            if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
+                width = this.thumbEl.getWidth();
+                this.baseScale = width / this.imageEl.OriginWidth;
             }
-            ++id;
+            
         }
-        this.tpls = [];
-        for(var i = tpls.length-1; i >= 0; --i){
-            this.compileTpl(tpls[i]);
-            this.tpls[tpls[i].id] = tpls[i];
+
+        if(this.imageEl.OriginWidth < this.minWidth || this.imageEl.OriginHeight < this.minHeight) {
+            this.baseScale = width / this.minWidth;
         }
-        this.master = tpls[tpls.length-1];
-        return this;
+
+        return;
     },
-    /**
-     * same as applyTemplate, except it's done to one of the subTemplates
-     * when using named templates, you can do:
-     *
-     * var str = pl.applySubTemplate('your-name', values);
-     *
-     * 
-     * @param {Number} id of the template
-     * @param {Object} values to apply to template
-     * @param {Object} parent (normaly the instance of this object)
-     */
-    applySubTemplate : function(id, values, parent)
+    
+    getScaleLevel : function()
     {
+        return this.baseScale * Math.pow(1.02, this.scale);
+    },
+    
+    onTouchStart : function(e)
+    {
+        if(!this.canvasLoaded){
+            this.beforeSelectFile(e);
+            return;
+        }
         
+        var touches = e.browserEvent.touches;
         
-        var t = this.tpls[id];
+        if(!touches){
+            return;
+        }
         
+        if(touches.length == 1){
+            this.onMouseDown(e);
+            return;
+        }
         
-        try { 
-            if(t.test && !t.test.call(this, values, parent)){
-                return '';
-            }
-        } catch(e) {
-            Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
-            Roo.log(e.toString());
-            Roo.log(t.test);
-            return ''
+        if(touches.length != 2){
+            return;
         }
-        try { 
-            
-            if(t.exec && t.exec.call(this, values, parent)){
-                return '';
-            }
-        } catch(e) {
-            Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
-            Roo.log(e.toString());
-            Roo.log(t.exec);
-            return ''
+        
+        var coords = [];
+        
+        for(var i = 0, finger; finger = touches[i]; i++){
+            coords.push(finger.pageX, finger.pageY);
         }
-        try {
-            var vs = t.target ? t.target.call(this, values, parent) : values;
-            parent = t.target ? values : parent;
-            if(t.target && vs instanceof Array){
-                var buf = [];
-                for(var i = 0, len = vs.length; i < len; i++){
-                    buf[buf.length] = t.compiled.call(this, vs[i], parent);
-                }
-                return buf.join('');
-            }
-            return t.compiled.call(this, vs, parent);
-        } catch (e) {
-            Roo.log("Xtemplate.applySubTemplate : Exception thrown");
-            Roo.log(e.toString());
-            Roo.log(t.compiled);
-            return '';
+        
+        var x = Math.pow(coords[0] - coords[2], 2);
+        var y = Math.pow(coords[1] - coords[3], 2);
+        
+        this.startDistance = Math.sqrt(x + y);
+        
+        this.startScale = this.scale;
+        
+        this.pinching = true;
+        this.dragable = false;
+        
+    },
+    
+    onTouchMove : function(e)
+    {
+        if(!this.pinching && !this.dragable){
+            return;
+        }
+        
+        var touches = e.browserEvent.touches;
+        
+        if(!touches){
+            return;
+        }
+        
+        if(this.dragable){
+            this.onMouseMove(e);
+            return;
         }
+        
+        var coords = [];
+        
+        for(var i = 0, finger; finger = touches[i]; i++){
+            coords.push(finger.pageX, finger.pageY);
+        }
+        
+        var x = Math.pow(coords[0] - coords[2], 2);
+        var y = Math.pow(coords[1] - coords[3], 2);
+        
+        this.endDistance = Math.sqrt(x + y);
+        
+        this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
+        
+        if(!this.zoomable()){
+            this.scale = this.startScale;
+            return;
+        }
+        
+        this.draw();
+        
     },
-
-    compileTpl : function(tpl)
+    
+    onTouchEnd : function(e)
     {
-        var fm = Roo.util.Format;
-        var useF = this.disableFormats !== true;
-        var sep = Roo.isGecko ? "+" : ",";
-        var undef = function(str) {
-            Roo.log("Property not found :"  + str);
-            return '';
+        this.pinching = false;
+        this.dragable = false;
+        
+    },
+    
+    process : function(file, crop)
+    {
+        if(this.loadMask){
+            this.maskEl.mask(this.loadingText);
+        }
+        
+        this.xhr = new XMLHttpRequest();
+        
+        file.xhr = this.xhr;
+
+        this.xhr.open(this.method, this.url, true);
+        
+        var headers = {
+            "Accept": "application/json",
+            "Cache-Control": "no-cache",
+            "X-Requested-With": "XMLHttpRequest"
         };
         
-        var fn = function(m, name, format, args)
-        {
-            //Roo.log(arguments);
-            args = args ? args.replace(/\\'/g,"'") : args;
-            //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
-            if (typeof(format) == 'undefined') {
-                format= 'htmlEncode';
-            }
-            if (format == 'raw' ) {
-                format = false;
+        for (var headerName in headers) {
+            var headerValue = headers[headerName];
+            if (headerValue) {
+                this.xhr.setRequestHeader(headerName, headerValue);
             }
-            
-            if(name.substr(0, 4) == 'xtpl'){
-                return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
+        }
+        
+        var _this = this;
+        
+        this.xhr.onload = function()
+        {
+            _this.xhrOnLoad(_this.xhr);
+        }
+        
+        this.xhr.onerror = function()
+        {
+            _this.xhrOnError(_this.xhr);
+        }
+        
+        var formData = new FormData();
+
+        formData.append('returnHTML', 'NO');
+
+        if(crop){
+            formData.append('crop', crop);
+            var blobBin = atob(crop.split(',')[1]);
+            var array = [];
+            for(var i = 0; i < blobBin.length; i++) {
+                array.push(blobBin.charCodeAt(i));
             }
+            var croppedFile =new Blob([new Uint8Array(array)], {type: this.cropType});
+            formData.append(this.paramName, croppedFile, file.name);
+        }
+        
+        if(typeof(file.filename) != 'undefined'){
+            formData.append('filename', file.filename);
+        }
+        
+        if(typeof(file.mimetype) != 'undefined'){
+            formData.append('mimetype', file.mimetype);
+        }
+
+        if(this.fireEvent('arrange', this, formData) != false){
+            this.xhr.send(formData);
+        };
+    },
+    
+    xhrOnLoad : function(xhr)
+    {
+        if(this.loadMask){
+            this.maskEl.unmask();
+        }
+        
+        if (xhr.readyState !== 4) {
+            this.fireEvent('exception', this, xhr);
+            return;
+        }
+
+        var response = Roo.decode(xhr.responseText);
+        
+        if(!response.success){
+            this.fireEvent('exception', this, xhr);
+            return;
+        }
+        
+        var response = Roo.decode(xhr.responseText);
+        
+        this.fireEvent('upload', this, response);
+        
+    },
+    
+    xhrOnError : function()
+    {
+        if(this.loadMask){
+            this.maskEl.unmask();
+        }
+        
+        Roo.log('xhr on error');
+        
+        var response = Roo.decode(xhr.responseText);
+          
+        Roo.log(response);
+        
+    },
+    
+    prepare : function(file)
+    {   
+        if(this.loadMask){
+            this.maskEl.mask(this.loadingText);
+        }
+        
+        this.file = false;
+        this.exif = {};
+        
+        if(typeof(file) === 'string'){
+            this.loadCanvas(file);
+            return;
+        }
+        
+        if(!file || !this.urlAPI){
+            return;
+        }
+        
+        this.file = file;
+        if(typeof(file.type) != 'undefined' && file.type.length != 0) {
+            this.cropType = file.type;
+        }
+        
+        var _this = this;
+        
+        if(this.fireEvent('prepare', this, this.file) != false){
             
-            // build an array of options to determine if value is undefined..
-            
-            // basically get 'xxxx.yyyy' then do
-            // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
-            //    (function () { Roo.log("Property not found"); return ''; })() :
-            //    ......
-            
-            var udef_ar = [];
-            var lookfor = '';
-            Roo.each(name.split('.'), function(st) {
-                lookfor += (lookfor.length ? '.': '') + st;
-                udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
-            });
-            
-            var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
-            
+            var reader = new FileReader();
             
-            if(format && useF){
+            reader.onload = function (e) {
+                if (e.target.error) {
+                    Roo.log(e.target.error);
+                    return;
+                }
                 
-                args = args ? ',' + args : "";
-                 
-                if(format.substr(0, 5) != "this."){
-                    format = "fm." + format + '(';
-                }else{
-                    format = 'this.call("'+ format.substr(5) + '", ';
-                    args = ", values";
+                var buffer = e.target.result,
+                    dataView = new DataView(buffer),
+                    offset = 2,
+                    maxOffset = dataView.byteLength - 4,
+                    markerBytes,
+                    markerLength;
+                
+                if (dataView.getUint16(0) === 0xffd8) {
+                    while (offset < maxOffset) {
+                        markerBytes = dataView.getUint16(offset);
+                        
+                        if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
+                            markerLength = dataView.getUint16(offset + 2) + 2;
+                            if (offset + markerLength > dataView.byteLength) {
+                                Roo.log('Invalid meta data: Invalid segment size.');
+                                break;
+                            }
+                            
+                            if(markerBytes == 0xffe1){
+                                _this.parseExifData(
+                                    dataView,
+                                    offset,
+                                    markerLength
+                                );
+                            }
+                            
+                            offset += markerLength;
+                            
+                            continue;
+                        }
+                        
+                        break;
+                    }
+                    
                 }
                 
-                return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
-            }
-             
-            if (args.length) {
-                // called with xxyx.yuu:(test,test)
-                // change to ()
-                return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
+                var url = _this.urlAPI.createObjectURL(_this.file);
+                
+                _this.loadCanvas(url);
+                
+                return;
             }
-            // raw.. - :raw modifier..
-            return "'"+ sep + udef_st  + name + ")"+sep+"'";
             
-        };
-        var body;
-        // branched to use + in gecko and [].join() in others
-        if(Roo.isGecko){
-            body = "tpl.compiled = function(values, parent){  with(values) { return '" +
-                   tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
-                    "';};};";
-        }else{
-            body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
-            body.push(tpl.body.replace(/(\r\n|\n)/g,
-                            '\\n').replace(/'/g, "\\'").replace(this.re, fn));
-            body.push("'].join('');};};");
-            body = body.join('');
+            reader.readAsArrayBuffer(this.file);
+            
         }
         
-        Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
-       
-        /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
-        eval(body);
+    },
+    
+    parseExifData : function(dataView, offset, length)
+    {
+        var tiffOffset = offset + 10,
+            littleEndian,
+            dirOffset;
+    
+        if (dataView.getUint32(offset + 4) !== 0x45786966) {
+            // No Exif data, might be XMP data instead
+            return;
+        }
         
-        return this;
+        // Check for the ASCII code for "Exif" (0x45786966):
+        if (dataView.getUint32(offset + 4) !== 0x45786966) {
+            // No Exif data, might be XMP data instead
+            return;
+        }
+        if (tiffOffset + 8 > dataView.byteLength) {
+            Roo.log('Invalid Exif data: Invalid segment size.');
+            return;
+        }
+        // Check for the two null bytes:
+        if (dataView.getUint16(offset + 8) !== 0x0000) {
+            Roo.log('Invalid Exif data: Missing byte alignment offset.');
+            return;
+        }
+        // Check the byte alignment:
+        switch (dataView.getUint16(tiffOffset)) {
+        case 0x4949:
+            littleEndian = true;
+            break;
+        case 0x4D4D:
+            littleEndian = false;
+            break;
+        default:
+            Roo.log('Invalid Exif data: Invalid byte alignment marker.');
+            return;
+        }
+        // Check for the TIFF tag marker (0x002A):
+        if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
+            Roo.log('Invalid Exif data: Missing TIFF marker.');
+            return;
+        }
+        // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
+        dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
+        
+        this.parseExifTags(
+            dataView,
+            tiffOffset,
+            tiffOffset + dirOffset,
+            littleEndian
+        );
     },
-
-    applyTemplate : function(values){
-        return this.master.compiled.call(this, values, {});
-        //var s = this.subs;
+    
+    parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
+    {
+        var tagsNumber,
+            dirEndOffset,
+            i;
+        if (dirOffset + 6 > dataView.byteLength) {
+            Roo.log('Invalid Exif data: Invalid directory offset.');
+            return;
+        }
+        tagsNumber = dataView.getUint16(dirOffset, littleEndian);
+        dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
+        if (dirEndOffset + 4 > dataView.byteLength) {
+            Roo.log('Invalid Exif data: Invalid directory size.');
+            return;
+        }
+        for (i = 0; i < tagsNumber; i += 1) {
+            this.parseExifTag(
+                dataView,
+                tiffOffset,
+                dirOffset + 2 + 12 * i, // tag offset
+                littleEndian
+            );
+        }
+        // Return the offset to the next directory:
+        return dataView.getUint32(dirEndOffset, littleEndian);
     },
-
-    apply : function(){
-        return this.applyTemplate.apply(this, arguments);
+    
+    parseExifTag : function (dataView, tiffOffset, offset, littleEndian) 
+    {
+        var tag = dataView.getUint16(offset, littleEndian);
+        
+        this.exif[tag] = this.getExifValue(
+            dataView,
+            tiffOffset,
+            offset,
+            dataView.getUint16(offset + 2, littleEndian), // tag type
+            dataView.getUint32(offset + 4, littleEndian), // tag length
+            littleEndian
+        );
+    },
+    
+    getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
+    {
+        var tagType = Roo.dialog.UploadCropbox.exifTagTypes[type],
+            tagSize,
+            dataOffset,
+            values,
+            i,
+            str,
+            c;
+    
+        if (!tagType) {
+            Roo.log('Invalid Exif data: Invalid tag type.');
+            return;
+        }
+        
+        tagSize = tagType.size * length;
+        // Determine if the value is contained in the dataOffset bytes,
+        // or if the value at the dataOffset is a pointer to the actual data:
+        dataOffset = tagSize > 4 ?
+                tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
+        if (dataOffset + tagSize > dataView.byteLength) {
+            Roo.log('Invalid Exif data: Invalid data offset.');
+            return;
+        }
+        if (length === 1) {
+            return tagType.getValue(dataView, dataOffset, littleEndian);
+        }
+        values = [];
+        for (i = 0; i < length; i += 1) {
+            values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
+        }
+        
+        if (tagType.ascii) {
+            str = '';
+            // Concatenate the chars:
+            for (i = 0; i < values.length; i += 1) {
+                c = values[i];
+                // Ignore the terminating NULL byte(s):
+                if (c === '\u0000') {
+                    break;
+                }
+                str += c;
+            }
+            return str;
+        }
+        return values;
     }
+    
+});
 
- });
-
-Roo.XTemplate.from = function(el){
-    el = Roo.getDom(el);
-    return new Roo.XTemplate(el.value || el.innerHTML);
-};
\ No newline at end of file
+Roo.apply(Roo.dialog.UploadCropbox, {
+    tags : {
+        'Orientation': 0x0112
+    },
+    
+    Orientation: {
+            1: 0, //'top-left',
+//            2: 'top-right',
+            3: 180, //'bottom-right',
+//            4: 'bottom-left',
+//            5: 'left-top',
+            6: 90, //'right-top',
+//            7: 'right-bottom',
+            8: 270 //'left-bottom'
+    },
+    
+    exifTagTypes : {
+        // byte, 8-bit unsigned int:
+        1: {
+            getValue: function (dataView, dataOffset) {
+                return dataView.getUint8(dataOffset);
+            },
+            size: 1
+        },
+        // ascii, 8-bit byte:
+        2: {
+            getValue: function (dataView, dataOffset) {
+                return String.fromCharCode(dataView.getUint8(dataOffset));
+            },
+            size: 1,
+            ascii: true
+        },
+        // short, 16 bit int:
+        3: {
+            getValue: function (dataView, dataOffset, littleEndian) {
+                return dataView.getUint16(dataOffset, littleEndian);
+            },
+            size: 2
+        },
+        // long, 32 bit int:
+        4: {
+            getValue: function (dataView, dataOffset, littleEndian) {
+                return dataView.getUint32(dataOffset, littleEndian);
+            },
+            size: 4
+        },
+        // rational = two long values, first is numerator, second is denominator:
+        5: {
+            getValue: function (dataView, dataOffset, littleEndian) {
+                return dataView.getUint32(dataOffset, littleEndian) /
+                    dataView.getUint32(dataOffset + 4, littleEndian);
+            },
+            size: 8
+        },
+        // slong, 32 bit signed int:
+        9: {
+            getValue: function (dataView, dataOffset, littleEndian) {
+                return dataView.getInt32(dataOffset, littleEndian);
+            },
+            size: 4
+        },
+        // srational, two slongs, first is numerator, second is denominator:
+        10: {
+            getValue: function (dataView, dataOffset, littleEndian) {
+                return dataView.getInt32(dataOffset, littleEndian) /
+                    dataView.getInt32(dataOffset + 4, littleEndian);
+            },
+            size: 8
+        }
+    },
+    
+    footer : {
+        STANDARD : [
+            {
+                tag : 'div',
+                cls : 'btn-group roo-upload-cropbox-rotate-left',
+                action : 'rotate-left',
+                cn : [
+                    {
+                        tag : 'button',
+                        cls : 'btn btn-default',
+                        html : '<i class="fa fa-undo"></i>'
+                    }
+                ]
+            },
+            {
+                tag : 'div',
+                cls : 'btn-group roo-upload-cropbox-picture',
+                action : 'picture',
+                cn : [
+                    {
+                        tag : 'button',
+                        cls : 'btn btn-default',
+                        html : '<i class="fa fa-picture-o"></i>'
+                    }
+                ]
+            },
+            {
+                tag : 'div',
+                cls : 'btn-group roo-upload-cropbox-rotate-right',
+                action : 'rotate-right',
+                cn : [
+                    {
+                        tag : 'button',
+                        cls : 'btn btn-default',
+                        html : '<i class="fa fa-repeat"></i>'
+                    }
+                ]
+            }
+        ],
+        DOCUMENT : [
+            {
+                tag : 'div',
+                cls : 'btn-group roo-upload-cropbox-rotate-left',
+                action : 'rotate-left',
+                cn : [
+                    {
+                        tag : 'button',
+                        cls : 'btn btn-default',
+                        html : '<i class="fa fa-undo"></i>'
+                    }
+                ]
+            },
+            {
+                tag : 'div',
+                cls : 'btn-group roo-upload-cropbox-download',
+                action : 'download',
+                cn : [
+                    {
+                        tag : 'button',
+                        cls : 'btn btn-default',
+                        html : '<i class="fa fa-download"></i>'
+                    }
+                ]
+            },
+            {
+                tag : 'div',
+                cls : 'btn-group roo-upload-cropbox-crop',
+                action : 'crop',
+                cn : [
+                    {
+                        tag : 'button',
+                        cls : 'btn btn-default',
+                        html : '<i class="fa fa-crop"></i>'
+                    }
+                ]
+            },
+            {
+                tag : 'div',
+                cls : 'btn-group roo-upload-cropbox-trash',
+                action : 'trash',
+                cn : [
+                    {
+                        tag : 'button',
+                        cls : 'btn btn-default',
+                        html : '<i class="fa fa-trash"></i>'
+                    }
+                ]
+            },
+            {
+                tag : 'div',
+                cls : 'btn-group roo-upload-cropbox-rotate-right',
+                action : 'rotate-right',
+                cn : [
+                    {
+                        tag : 'button',
+                        cls : 'btn btn-default',
+                        html : '<i class="fa fa-repeat"></i>'
+                    }
+                ]
+            }
+        ],
+        ROTATOR : [
+            {
+                tag : 'div',
+                cls : 'btn-group roo-upload-cropbox-rotate-left',
+                action : 'rotate-left',
+                cn : [
+                    {
+                        tag : 'button',
+                        cls : 'btn btn-default',
+                        html : '<i class="fa fa-undo"></i>'
+                    }
+                ]
+            },
+            {
+                tag : 'div',
+                cls : 'btn-group roo-upload-cropbox-rotate-right',
+                action : 'rotate-right',
+                cn : [
+                    {
+                        tag : 'button',
+                        cls : 'btn btn-default',
+                        html : '<i class="fa fa-repeat"></i>'
+                    }
+                ]
+            }
+        ],
+        CENTER : [
+            {
+                tag : 'div',
+                cls : 'btn-group roo-upload-cropbox-center',
+                action : 'center',
+                cn : [
+                    {
+                        tag : 'button',
+                        cls : 'btn btn-default',
+                        html : 'CENTER'
+                    }
+                ]
+            }
+        ]
+    }
+});