fix button upload - due to adding preventDefault on buttons
[roojs1] / roojs-debug.js
index 7599f12..8d917e9 100644 (file)
@@ -19,7 +19,7 @@ window["undefined"] = window["undefined"];
 /**
  * @class Roo
  * Roo core utilities and functions.
- * @singleton
+ * @static
  */
 var Roo = {}; 
 /**
@@ -57,14 +57,24 @@ Roo.apply = function(o, c, defaults){
         isIE = ua.indexOf("msie") > -1,
         isIE7 = ua.indexOf("msie 7") > -1,
         isIE11 = /trident.*rv\:11\./.test(ua),
+        isEdge = ua.indexOf("edge") > -1,
         isGecko = !isSafari && ua.indexOf("gecko") > -1,
         isBorderBox = isIE && !isStrict,
         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
         isLinux = (ua.indexOf("linux") != -1),
         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
+        isIOS = /iphone|ipad/.test(ua),
+        isAndroid = /android/.test(ua),
         isTouch =  (function() {
-            try {  
+            try {
+                if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
+                    window.addEventListener('touchstart', function __set_has_touch__ () {
+                        Roo.isTouch = true;
+                        window.removeEventListener('touchstart', __set_has_touch__);
+                    });
+                    return false; // no touch on chrome!?
+                }
                 document.createEvent("TouchEvent");  
                 return true;  
             } catch (e) {  
@@ -313,7 +323,7 @@ Roo.factory(conf, Roo.data);
                 return c;
             }
             if (ns[c.xtype]) {
-                if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
+                if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
                 var ret = new ns[c.xtype](c);
                 ret.xns = false;
                 return ret;
@@ -332,8 +342,8 @@ Roo.factory(conf, Roo.data);
             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
                 return; // alerT?
             }
-            console.log(s);
             
+            console.log(s);
         },
         /**
          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
@@ -620,6 +630,8 @@ Roo.factory(conf, Roo.data);
         /** @type Boolean */
         isIE11 : isIE11,
         /** @type Boolean */
+        isEdge : isEdge,
+        /** @type Boolean */
         isGecko : isGecko,
         /** @type Boolean */
         isBorderBox : isBorderBox,
@@ -630,6 +642,10 @@ Roo.factory(conf, Roo.data);
         /** @type Boolean */
         isMac : isMac,
         /** @type Boolean */
+        isIOS : isIOS,
+        /** @type Boolean */
+        isAndroid : isAndroid,
+        /** @type Boolean */
         isTouch : isTouch,
 
         /**
@@ -652,7 +668,30 @@ Roo.factory(conf, Roo.data);
         {
             var node = Roo.DomQuery.selectNode(selector,root);
             return node ? Roo.get(node) : new Roo.Element(false);
-        }
+        },
+               /**
+                * Find the current bootstrap width Grid size
+                * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
+                * @returns {String} (xs|sm|md|lg|xl)
+                */
+               
+               getGridSize : function()
+               {
+                       var w = Roo.lib.Dom.getViewWidth();
+                       switch(true) {
+                               case w > 1200:
+                                       return 'xl';
+                               case w > 992:
+                                       return 'lg';
+                               case w > 768:
+                                       return 'md';
+                               case w > 576:
+                                       return 'sm';
+                               default:
+                                       return 'xs'
+                       }
+                       
+               }
         
     });
 
@@ -869,6 +908,8 @@ var s = String.format('<div class="{0}">{1}</div>', cls, text);
             return Roo.util.Format.htmlEncode(args[i]);
         });
     }
+  
+    
 });
 
 /**
@@ -890,7 +931,31 @@ sort = (sort == 'ASC' ? 'DESC' : 'ASC');
  
 String.prototype.toggle = function(value, other){
     return this == value ? other : value;
-};/*
+};
+
+
+/**
+  * Remove invalid unicode characters from a string 
+  *
+  * @return {String} The clean string
+  */
+String.prototype.unicodeClean = function () {
+    return this.replace(/[\s\S]/g,
+        function(character) {
+            if (character.charCodeAt()< 256) {
+              return character;
+           }
+           try {
+                encodeURIComponent(character);
+           } catch(e) { 
+              return '';
+           }
+           return character;
+        }
+    );
+};
+  
+/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -938,7 +1003,7 @@ Roo.applyIf(Array.prototype, {
      */
     indexOf : function(o){
        for (var i = 0, len = this.length; i < len; i++){
-             if(this[i] == o) return i;
+             if(this[i] == o) { return i; }
        }
           return -1;
     },
@@ -960,24 +1025,52 @@ Roo.applyIf(Array.prototype, {
     map : function(fun )
     {
         var len = this.length >>> 0;
-        if (typeof fun != "function")
+        if (typeof fun != "function") {
             throw new TypeError();
-
+        }
         var res = new Array(len);
         var thisp = arguments[1];
         for (var i = 0; i < len; i++)
         {
-            if (i in this)
+            if (i in this) {
                 res[i] = fun.call(thisp, this[i], i, this);
+            }
         }
 
         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;
     }
-    
 });
 
 
- /*
+/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -1683,8 +1776,8 @@ Date.prototype.clearTime = function(clone){
 };
 
 // private
-// safari setMonth is broken
-if(Roo.isSafari){
+// safari setMonth is broken -- check that this is only donw once...
+if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
     Date.brokenSetMonth = Date.prototype.setMonth;
        Date.prototype.setMonth = function(num){
                if(num <= -1){
@@ -1754,7 +1847,7 @@ document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
  */
 Date.prototype.add = function(interval, value){
   var d = this.clone();
-  if (!interval || value === 0) return d;
+  if (!interval || value === 0) { return d; }
   switch(interval.toLowerCase()){
     case Date.MILLI:
       d.setMilliseconds(this.getMilliseconds() + value);
@@ -1785,22 +1878,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 = {
@@ -1821,17 +1905,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;
@@ -1844,7 +1937,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;
@@ -2508,18 +2604,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 = {
@@ -2545,7 +2643,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]);
@@ -3567,7 +3671,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:
@@ -4129,7 +4909,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;
@@ -4148,7 +4928,7 @@ Roo.DomHelper = function(){
         }
         b += "<" + o.tag;
         for(var attr in o){
-            if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
+            if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
             if(attr == "style"){
                 var s = o["style"];
                 if(typeof s == "function"){
@@ -4231,13 +5011,15 @@ Roo.DomHelper = function(){
         for(var attr in o){
             
             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
-                    attr == "style" || typeof o[attr] == "function") continue;
+                    attr == "style" || typeof o[attr] == "function") { continue; }
                     
             if(attr=="cls" && Roo.isIE){
                 el.className = o["cls"];
             }else{
-                if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
-                else el[attr] = o[attr];
+                if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
+                else { 
+                    el[attr] = o[attr];
+                }
             }
         }
         Roo.DomHelper.applyStyles(el, o.style);
@@ -4264,7 +5046,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;
@@ -4606,6 +5388,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...
@@ -4615,12 +5403,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){
@@ -4679,9 +5475,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);
@@ -4698,7 +5498,7 @@ Roo.Template.prototype = {
      */
     set : function(html, compile){
         this.html = html;
-        this.compiled = null;
+        this.compiled = false;
         if(compile){
             this.compile();
         }
@@ -4921,7 +5721,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 = {};
@@ -4976,7 +5776,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;
             }
         }
@@ -4994,7 +5798,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];
 
@@ -5098,7 +5902,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"){
@@ -5859,12 +6663,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);
         }
     },
@@ -6027,10 +6834,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;
                     }
@@ -6041,6 +6848,51 @@ Roo.util.Observable.releaseCapture = function(o){
         }
     };
 })();/*
+ * RooJS Library 
+ * Copyright(c) 2007-2017, Roo J Solutions Ltd
+ *
+ * Licence LGPL 
+ *
+ */
+/**
+ * @class Roo.Document
+ * @extends Roo.util.Observable
+ * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
+ * 
+ * @param {Object} config the methods and properties of the 'base' class for the application.
+ * 
+ *  Generic Page handler - implement this to start your app..
+ * 
+ * eg.
+ *  MyProject = new Roo.Document({
+        events : {
+            'load' : true // your events..
+        },
+        listeners : {
+            'ready' : function() {
+                // fired on Roo.onReady()
+            }
+        }
+ * 
+ */
+Roo.Document = function(cfg) {
+     
+    this.addEvents({ 
+        'ready' : true
+    });
+    Roo.util.Observable.call(this,cfg);
+    
+    var _this = this;
+    
+    Roo.onReady(function() {
+        _this.fireEvent('ready');
+    },null,false);
+    
+    
+}
+
+Roo.extend(Roo.Document, Roo.util.Observable, {});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -6056,7 +6908,7 @@ Roo.util.Observable.releaseCapture = function(o){
  * 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;
@@ -6164,8 +7016,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);
@@ -6214,6 +7068,7 @@ Roo.EventManager = function(){
         if(o.buffer){
             h = createBuffered(h, o);
         }
+        
         fn._handlers = fn._handlers || [];
         
         
@@ -6221,7 +7076,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(){
@@ -6407,16 +7264,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());
                     }
                 });
@@ -6566,6 +7425,8 @@ Roo.onReady(function(){
 
     var cls = [
             Roo.isIE ? "roo-ie"
+            : Roo.isIE11 ? "roo-ie11"
+            : Roo.isEdge ? "roo-edge"
             : Roo.isGecko ? "roo-gecko"
             : Roo.isOpera ? "roo-opera"
             : Roo.isSafari ? "roo-safari" : ""];
@@ -6576,6 +7437,12 @@ Roo.onReady(function(){
     if(Roo.isLinux){
         cls.push("roo-linux");
     }
+    if(Roo.isIOS){
+        cls.push("roo-ios");
+    }
+    if(Roo.isTouch){
+        cls.push("roo-touch");
+    }
     if(Roo.isBorderBox){
         cls.push('roo-border-box');
     }
@@ -6605,7 +7472,7 @@ Roo.onReady(function(){
  Roo.EventManager.on("myDiv", 'click', handleClick);
  Roo.EventManager.addListener("myDiv", 'click', handleClick);
  </code></pre>
- * @singleton
+ * @static
  */
 Roo.EventObject = function(){
     
@@ -6998,9 +7865,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;
         }
@@ -7020,23 +7891,28 @@ 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
          */
         defaultUnit : "px",
+        
         /**
          * Sets the element's visibility mode. When setVisible() is called it
          * will use this to determine whether to set the visibility or the display property.
@@ -7054,7 +7930,7 @@ if(opt.anim.isAnimated()){
          */
         enableDisplayMode : function(display){
             this.setVisibilityMode(El.DISPLAY);
-            if(typeof display != "undefined") this.originalDisplay = display;
+            if(typeof display != "undefined") { this.originalDisplay = display; }
             return this;
         },
 
@@ -7096,6 +7972,37 @@ if(opt.anim.isAnimated()){
             var p = Roo.fly(this.dom.parentNode, '_internal');
             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
         },
+        
+        /**
+         * Looks at  the scrollable parent element
+         */
+        findScrollableParent : function()
+        {
+            var overflowRegex = /(auto|scroll)/;
+            
+            if(this.getStyle('position') === 'fixed'){
+                return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
+            }
+            
+            var excludeStaticParent = this.getStyle('position') === "absolute";
+            
+            for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
+                
+                if (excludeStaticParent && parent.getStyle('position') === "static") {
+                    continue;
+                }
+                
+                if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
+                    return parent;
+                }
+                
+                if(parent.dom.nodeName.toLowerCase() == 'body'){
+                    return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
+                }
+            }
+            
+            return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
+        },
 
         /**
          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
@@ -7275,7 +8182,7 @@ if(opt.anim.isAnimated()){
                     this.setHeight(oldHeight); // restore original height
                     this.setHeight(height, animate, duration, function(){
                         this.unclip();
-                        if(typeof onComplete == "function") onComplete();
+                        if(typeof onComplete == "function") { onComplete(); }
                     }.createDelegate(this), easing);
                 }
             }.createDelegate(this), 0);
@@ -7493,7 +8400,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;
@@ -7522,7 +8433,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){
@@ -7536,8 +8449,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;
@@ -7566,6 +8482,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;
         },
 
@@ -8047,20 +8966,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;
         },
 
@@ -8070,6 +9036,7 @@ if(opt.anim.isAnimated()){
          */
         removeAllListeners : function(){
             E.purgeElement(this.dom);
+            this.listeners = {};
             return this;
         },
 
@@ -8079,6 +9046,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
@@ -8427,7 +9395,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){
@@ -8468,7 +9437,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;
@@ -8982,7 +9951,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)
@@ -8993,12 +9962,13 @@ if(opt.anim.isAnimated()){
             if(!this._mask){
                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
             }
+            
             this.addClass("x-masked");
             this._mask.setDisplayed(true);
             
             // we wander
             var z = 0;
-            var dom = this.dom
+            var dom = this.dom;
             while (dom && dom.style) {
                 if (!isNaN(parseInt(dom.style.zIndex))) {
                     z = Math.max(z, parseInt(dom.style.zIndex));
@@ -9014,12 +9984,23 @@ if(opt.anim.isAnimated()){
            
             if(typeof msg == 'string'){
                 if(!this._maskMsg){
-                    this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
+                    this._maskMsg = Roo.DomHelper.append(this.dom, {
+                        cls: "roo-el-mask-msg", 
+                        cn: [
+                            {
+                                tag: 'i',
+                                cls: 'fa fa-spinner fa-spin'
+                            },
+                            {
+                                tag: 'div'
+                            }   
+                        ]
+                    }, true);
                 }
                 var mm = this._maskMsg;
                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
-                if (mm.dom.firstChild) { // weird IE issue?
-                    mm.dom.firstChild.innerHTML = msg;
+                if (mm.dom.lastChild) { // weird IE issue?
+                    mm.dom.lastChild.innerHTML = msg;
                 }
                 mm.setDisplayed(true);
                 mm.center(this);
@@ -9170,7 +10151,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
@@ -9183,7 +10164,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'));
@@ -9373,12 +10354,15 @@ if(opt.anim.isAnimated()){
             var el = this.dom;
             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
             for(var attr in o){
-                if(attr == "style" || typeof o[attr] == "function") continue;
+                if(attr == "style" || typeof o[attr] == "function")  { continue; }
                 if(attr=="cls"){
                     el.className = o["cls"];
                 }else{
-                    if(useSet) el.setAttribute(attr, o[attr]);
-                    else el[attr] = o[attr];
+                    if(useSet) {
+                        el.setAttribute(attr, o[attr]);
+                    } else {
+                        el[attr] = o[attr];
+                    }
                 }
             }
             if(o.style){
@@ -10986,7 +11970,9 @@ Roo.CompositeElement = function(els){
 Roo.CompositeElement.prototype = {
     isComposite: true,
     addElements : function(els){
-        if(!els) return this;
+        if(!els) {
+            return this;
+        }
         if(typeof els == "string"){
             els = Roo.Element.selectorFunction(els);
         }
@@ -11322,16 +12308,17 @@ Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addLi
  * @class Roo.data.Connection
  * @extends Roo.util.Observable
  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
- * either to a configured URL, or to a URL specified at request time.<br><br>
- * <p>
+ * either to a configured URL, or to a URL specified at request time. 
+ * 
  * Requests made by this class are asynchronous, and will return immediately. No data from
  * the server will be available to the statement immediately following the {@link #request} call.
- * To process returned data, use a callback in the request options object, or an event listener.</p><br>
- * <p>
+ * To process returned data, use a callback in the request options object, or an event listener.
+ * 
  * Note: If you are doing a file upload, you will not get a normal response object sent back to
  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
  * The response object is created using the innerHTML of the IFRAME's document as the responseText
- * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
+ * property and, if present, the IFRAME's XML document as the responseXML property.
+ * 
  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
@@ -11463,12 +12450,27 @@ Roo.extend(Roo.data.Connection, Roo.util.Observable, {
                 url = url || form.action;
 
                 var enctype = form.getAttribute("enctype");
+                
+                if (o.formData) {
+                    return this.doFormDataUpload(o, url);
+                }
+                
                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
                     return this.doFormUpload(o, p, url);
                 }
                 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){
@@ -11504,7 +12506,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]);
@@ -11640,7 +12644,46 @@ Roo.extend(Roo.data.Connection, Roo.util.Observable, {
                 form.removeChild(hiddens[i]);
             }
         }
+    },
+    // this is a 'formdata version???'
+    
+    
+    doFormDataUpload : function(o,  url)
+    {
+        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,
+            failure: this.handleFailure,
+            scope: this,
+            argument: {options: o},
+            timeout : o.timeout || this.timeout
+        };
+        if(typeof o.autoAbort == 'boolean'){ // options gets top priority
+            if(o.autoAbort){
+                this.abort();
+            }
+        }else if(this.autoAbort !== false){
+            this.abort();
+        }
+
+        //Roo.lib.Ajax.defaultPostHeader = null;
+        Roo.lib.Ajax.useDefaultHeader = false;
+        this.transId = Roo.lib.Ajax.request( "POST", url, cb,  formData, o);
+        Roo.lib.Ajax.useDefaultHeader = true;
+         
     }
+    
 });
 /*
  * Based on:
@@ -12699,7 +13742,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;
@@ -12759,6 +13807,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);
@@ -12768,12 +13822,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++){
@@ -13077,7 +14136,9 @@ mc.add(otherEl);
     indexOf : function(o){
         if(!this.items.indexOf){
             for(var i = 0, len = this.items.length; i < len; i++){
-                if(this.items[i] == o) return i;
+                if(this.items[i] == o) {
+                    return i;
+                }
             }
             return -1;
         }else{
@@ -13093,7 +14154,9 @@ mc.add(otherEl);
     indexOfKey : function(key){
         if(!this.keys.indexOf){
             for(var i = 0, len = this.keys.length; i < len; i++){
-                if(this.keys[i] == key) return i;
+                if(this.keys[i] == key) {
+                    return i;
+                }
             }
             return -1;
         }else{
@@ -13107,6 +14170,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!
     },
@@ -13320,7 +14386,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;
@@ -13468,7 +14534,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;
@@ -13627,12 +14693,15 @@ Roo.util.Format = function(){
          * eventually this should probably emulate php's number_format
          * @param {Number/String} value The numeric value to format
          * @param {Number} decimals number of decimal places
+         * @param {String} delimiter for thousands (default comma)
          * @return {String} The formatted currency string
          */
-        number : function(v,decimals)
+        number : function(v, decimals, thousandsDelimiter)
         {
             // multiply and round.
             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
+            thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
+            
             var mul = Math.pow(10, decimals);
             var zero = String(mul).substring(1);
             v = (Math.round((v-0)*mul))/mul;
@@ -13644,13 +14713,12 @@ Roo.util.Format = function(){
             var ps = v.split('.');
             var whole = ps[0];
             
-            
             var r = /(\d+)(\d{3})/;
             // add comma's
-            while (r.test(whole)) {
-                whole = whole.replace(r, '$1' + ',' + '$2');
-            }
             
+            if(thousandsDelimiter.length != 0) {
+                whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
+            } 
             
             var sub = ps[1] ?
                     // has decimals..
@@ -13699,7 +14767,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 = {
@@ -13871,7 +14958,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;
@@ -14214,7 +15302,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.
@@ -14607,7 +15732,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;
@@ -14644,9 +15769,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');
@@ -14660,7 +15793,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)}
          */
@@ -14674,7 +15806,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){
@@ -14686,7 +15817,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){
@@ -14695,7 +15825,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
          */
@@ -14707,7 +15836,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
          */
@@ -14792,7 +15920,9 @@ Roo.extend(Roo.state.Provider, Roo.util.Observable, {
     decodeValue : function(cookie){
         var re = /^(a|n|d|b|s|o)\:(.*)$/;
         var matches = re.exec(unescape(cookie));
-        if(!matches || !matches[1]) return; // non state cookie
+        if(!matches || !matches[1]) {
+            return; // non state cookie
+        }
         var type = matches[1];
         var v = matches[2];
         switch(type){
@@ -14839,7 +15969,9 @@ Roo.extend(Roo.state.Provider, Roo.util.Observable, {
             var flat = "";
             for(var i = 0, len = v.length; i < len; i++){
                 flat += this.encodeValue(v[i]);
-                if(i != len-1) flat += "^";
+                if(i != len-1) {
+                    flat += "^";
+                }
             }
             enc = "a:" + flat;
         }else if(typeof v == "object"){
@@ -14884,7 +16016,7 @@ init : function(){
    var dialog = new Roo.BasicDialog(...);
    dialog.restoreState();
  </code></pre>
- * @singleton
+ * @static
  */
 Roo.state.Manager = function(){
     var provider = new Roo.state.Provider();
@@ -15042,7 +16174,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();
@@ -15235,7 +16367,7 @@ Roo.extend(Roo.Component, Roo.util.Observable, {
     /**
      * @cfg {String} actionMode 
      * which property holds the element that used for  hide() / show() / disable() / enable()
-     * default is 'el' 
+     * default is 'el' for forms you probably want to set this to fieldEl 
      */
     actionMode : "el",
 
@@ -15250,40 +16382,49 @@ Roo.extend(Roo.Component, Roo.util.Observable, {
      * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
      */
     render : function(container, position){
-        if(!this.rendered && this.fireEvent("beforerender", this) !== false){
-            if(!container && this.el){
-                this.el = Roo.get(this.el);
-                container = this.el.dom.parentNode;
-                this.allowDomMove = false;
-            }
-            this.container = Roo.get(container);
-            this.rendered = true;
-            if(position !== undefined){
-                if(typeof position == 'number'){
-                    position = this.container.dom.childNodes[position];
-                }else{
-                    position = Roo.getDom(position);
-                }
-            }
-            this.onRender(this.container, position || null);
-            if(this.cls){
-                this.el.addClass(this.cls);
-                delete this.cls;
-            }
-            if(this.style){
-                this.el.applyStyles(this.style);
-                delete this.style;
-            }
-            this.fireEvent("render", this);
-            this.afterRender(this.container);
-            if(this.hidden){
-                this.hide();
-            }
-            if(this.disabled){
-                this.disable();
+        
+        if(this.rendered){
+            return this;
+        }
+        
+        if(this.fireEvent("beforerender", this) === false){
+            return false;
+        }
+        
+        if(!container && this.el){
+            this.el = Roo.get(this.el);
+            container = this.el.dom.parentNode;
+            this.allowDomMove = false;
+        }
+        this.container = Roo.get(container);
+        this.rendered = true;
+        if(position !== undefined){
+            if(typeof position == 'number'){
+                position = this.container.dom.childNodes[position];
+            }else{
+                position = Roo.getDom(position);
             }
         }
+        this.onRender(this.container, position || null);
+        if(this.cls){
+            this.el.addClass(this.cls);
+            delete this.cls;
+        }
+        if(this.style){
+            this.el.applyStyles(this.style);
+            delete this.style;
+        }
+        this.fireEvent("render", this);
+        this.afterRender(this.container);
+        if(this.hidden){
+            this.hide();
+        }
+        if(this.disabled){
+            this.disable();
+        }
+
         return this;
+        
     },
 
     /** @private */
@@ -15524,7 +16665,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.
@@ -15791,267 +16932,793 @@ Roo.extend(Roo.BoxComponent, Roo.Component, {
         return {x : x, y: y};
     }
 });/*
- * Original code for Roojs - LGPL
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
  * <script type="text/javascript">
  */
+ (function(){ 
 /**
- * @class Roo.XComponent
- * A delayed Element creator...
- * Or a way to group chunks of interface together.
- * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
- *  used in conjunction with XComponent.build() it will create an instance of each element,
- *  then call addxtype() to build the User interface.
- * 
- * Mypart.xyx = new Roo.XComponent({
-
-    parent : 'Mypart.xyz', // empty == document.element.!!
-    order : '001',
-    name : 'xxxx'
-    region : 'xxxx'
-    disabled : function() {} 
-     
-    tree : function() { // return an tree of xtype declared components
-        var MODULE = this;
-        return 
-        {
-            xtype : 'NestedLayoutPanel',
-            // technicall
-        }
-     ]
- *})
- *
- *
- * It can be used to build a big heiracy, with parent etc.
- * or you can just use this to render a single compoent to a dom element
- * MYPART.render(Roo.Element | String(id) | dom_element )
- *
- *
- * Usage patterns.
- *
- * Classic Roo
- *
- * Roo is designed primarily as a single page application, so the UI build for a standard interface will
- * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
- *
- * Each sub module is expected to have a parent pointing to the class name of it's parent module.
- *
- * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
- * - if mulitple topModules exist, the last one is defined as the top module.
- *
- * Embeded Roo
- * 
- * When the top level or multiple modules are to embedded into a existing HTML page,
- * the parent element can container '#id' of the element where the module will be drawn.
- *
- * Bootstrap Roo
- *
- * Unlike classic Roo, the bootstrap tends not to be used as a single page.
- * it relies more on a include mechanism, where sub modules are included into an outer page.
- * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
- * 
- * Bootstrap Roo Included elements
- *
- * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
- * hence confusing the component builder as it thinks there are multiple top level elements. 
- *
- * 
- * 
- * @extends Roo.util.Observable
+ * @class Roo.Layer
+ * @extends Roo.Element
+ * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
+ * automatic maintaining of shadow/shim positions.
+ * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
+ * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
+ * you can pass a string with a CSS class name. False turns off the shadow.
+ * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
+ * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
+ * @cfg {String} cls CSS class to add to the element
+ * @cfg {Number} zindex Starting z-index (defaults to 11000)
+ * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
  * @constructor
- * @param cfg {Object} configuration of component
- * 
+ * @param {Object} config An object with config options.
+ * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
  */
-Roo.XComponent = function(cfg) {
-    Roo.apply(this, cfg);
-    this.addEvents({ 
-        /**
-            * @event built
-            * Fires when this the componnt is built
-            * @param {Roo.XComponent} c the component
-            */
-        'built' : true
-        
-    });
-    this.region = this.region || 'center'; // default..
-    Roo.XComponent.register(this);
-    this.modules = false;
-    this.el = false; // where the layout goes..
-    
-    
-}
-Roo.extend(Roo.XComponent, Roo.util.Observable, {
-    /**
-     * @property el
-     * The created element (with Roo.factory())
-     * @type {Roo.Layout}
-     */
-    el  : false,
-    
-    /**
-     * @property el
-     * for BC  - use el in new code
-     * @type {Roo.Layout}
-     */
-    panel : false,
-    
-    /**
-     * @property layout
-     * for BC  - use el in new code
-     * @type {Roo.Layout}
-     */
-    layout : false,
-    
-     /**
-     * @cfg {Function|boolean} disabled
-     * If this module is disabled by some rule, return true from the funtion
-     */
-    disabled : false,
-    
-    /**
-     * @cfg {String} parent 
-     * Name of parent element which it get xtype added to..
-     */
-    parent: false,
-    
-    /**
-     * @cfg {String} order
-     * Used to set the order in which elements are created (usefull for multiple tabs)
-     */
-    
-    order : false,
-    /**
-     * @cfg {String} name
-     * String to display while loading.
-     */
-    name : false,
-    /**
-     * @cfg {String} region
-     * Region to render component to (defaults to center)
-     */
-    region : 'center',
-    
-    /**
-     * @cfg {Array} items
-     * A single item array - the first element is the root of the tree..
-     * It's done this way to stay compatible with the Xtype system...
-     */
-    items : false,
-    
-    /**
-     * @property _tree
-     * The method that retuns the tree of parts that make up this compoennt 
-     * @type {function}
-     */
-    _tree  : false,
-    
-     /**
-     * render
-     * render element to dom or tree
-     * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
-     */
-    
-    render : function(el)
-    {
-        
-        el = el || false;
-        var hp = this.parent ? 1 : 0;
-        Roo.debug &&  Roo.log(this);
-        
-        if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
-            // if parent is a '#.....' string, then let's use that..
-            var ename = this.parent.substr(1);
-            this.parent = false;
-            Roo.debug && Roo.log(ename);
-            switch (ename) {
-                case 'bootstrap-body' :
-                    if (typeof(Roo.bootstrap.Body) != 'undefined') {
-                        this.parent = { el :  new  Roo.bootstrap.Body() };
-                        Roo.debug && Roo.log("setting el to doc body");
-                         
-                    } else {
-                        throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
-                    }
-                    break;
-                case 'bootstrap':
-                    this.parent = { el : true};
-                    // fall through
-                default:
-                    el = Roo.get(ename);
-                    break;
-            }
-                
-            
-            if (!el && !this.parent) {
-                Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
-                return;
-            }
-        }
-        Roo.debug && Roo.log("EL:");
-        Roo.debug && Roo.log(el);
-        Roo.debug && Roo.log("this.parent.el:");
-        Roo.debug && Roo.log(this.parent.el);
-        
-        var tree = this._tree ? this._tree() : this.tree();
-
-        // altertive root elements ??? - we need a better way to indicate these.
-        var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
-                        (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
-        
-        if (!this.parent && is_alt) {
-            //el = Roo.get(document.body);
-            this.parent = { el : true };
-        }
-            
-            
-        
-        if (!this.parent) {
-            
-            Roo.debug && Roo.log("no parent - creating one");
-            
-            el = el ? Roo.get(el) : false;     
-            
-            // it's a top level one..
-            this.parent =  {
-                el : new Roo.BorderLayout(el || document.body, {
-                
-                     center: {
-                         titlebar: false,
-                         autoScroll:false,
-                         closeOnTab: true,
-                         tabPosition: 'top',
-                          //resizeTabs: true,
-                         alwaysShowTabs: el && hp? false :  true,
-                         hideTabs: el || !hp ? true :  false,
-                         minTabWidth: 140
-                     }
-                 })
-            }
-        }
-        
-        if (!this.parent.el) {
-                // probably an old style ctor, which has been disabled.
-                return;
 
-        }
-               // The 'tree' method is  '_tree now' 
-            
-        tree.region = tree.region || this.region;
-        
-        if (this.parent.el === true) {
-            // bootstrap... - body..
-            this.parent.el = Roo.factory(tree);
-        }
-        
-        this.el = this.parent.el.addxtype(tree);
-        this.fireEvent('built', this);
-        
-        this.panel = this.el;
-        this.layout = this.panel.layout;
-        this.parentLayout = this.parent.layout  || false;  
-         
+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);
+        }
+    }
+});
+})();/*
+ * Original code for Roojs - LGPL
+ * <script type="text/javascript">
+ */
+/**
+ * @class Roo.XComponent
+ * A delayed Element creator...
+ * Or a way to group chunks of interface together.
+ * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
+ *  used in conjunction with XComponent.build() it will create an instance of each element,
+ *  then call addxtype() to build the User interface.
+ * 
+ * Mypart.xyx = new Roo.XComponent({
+
+    parent : 'Mypart.xyz', // empty == document.element.!!
+    order : '001',
+    name : 'xxxx'
+    region : 'xxxx'
+    disabled : function() {} 
+     
+    tree : function() { // return an tree of xtype declared components
+        var MODULE = this;
+        return 
+        {
+            xtype : 'NestedLayoutPanel',
+            // technicall
+        }
+     ]
+ *})
+ *
+ *
+ * It can be used to build a big heiracy, with parent etc.
+ * or you can just use this to render a single compoent to a dom element
+ * MYPART.render(Roo.Element | String(id) | dom_element )
+ *
+ *
+ * Usage patterns.
+ *
+ * Classic Roo
+ *
+ * Roo is designed primarily as a single page application, so the UI build for a standard interface will
+ * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
+ *
+ * Each sub module is expected to have a parent pointing to the class name of it's parent module.
+ *
+ * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
+ * - if mulitple topModules exist, the last one is defined as the top module.
+ *
+ * Embeded Roo
+ * 
+ * When the top level or multiple modules are to embedded into a existing HTML page,
+ * the parent element can container '#id' of the element where the module will be drawn.
+ *
+ * Bootstrap Roo
+ *
+ * Unlike classic Roo, the bootstrap tends not to be used as a single page.
+ * it relies more on a include mechanism, where sub modules are included into an outer page.
+ * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
+ * 
+ * Bootstrap Roo Included elements
+ *
+ * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
+ * hence confusing the component builder as it thinks there are multiple top level elements. 
+ *
+ * String Over-ride & Translations
+ *
+ * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
+ * and also the 'overlaying of string values - needed when different versions of the same application with different text content
+ * are needed. @see Roo.XComponent.overlayString  
+ * 
+ * 
+ * 
+ * @extends Roo.util.Observable
+ * @constructor
+ * @param cfg {Object} configuration of component
+ * 
+ */
+Roo.XComponent = function(cfg) {
+    Roo.apply(this, cfg);
+    this.addEvents({ 
+        /**
+            * @event built
+            * Fires when this the componnt is built
+            * @param {Roo.XComponent} c the component
+            */
+        'built' : true
+        
+    });
+    this.region = this.region || 'center'; // default..
+    Roo.XComponent.register(this);
+    this.modules = false;
+    this.el = false; // where the layout goes..
+    
+    
+}
+Roo.extend(Roo.XComponent, Roo.util.Observable, {
+    /**
+     * @property el
+     * The created element (with Roo.factory())
+     * @type {Roo.Layout}
+     */
+    el  : false,
+    
+    /**
+     * @property el
+     * for BC  - use el in new code
+     * @type {Roo.Layout}
+     */
+    panel : false,
+    
+    /**
+     * @property layout
+     * for BC  - use el in new code
+     * @type {Roo.Layout}
+     */
+    layout : false,
+    
+     /**
+     * @cfg {Function|boolean} disabled
+     * If this module is disabled by some rule, return true from the funtion
+     */
+    disabled : false,
+    
+    /**
+     * @cfg {String} parent 
+     * Name of parent element which it get xtype added to..
+     */
+    parent: false,
+    
+    /**
+     * @cfg {String} order
+     * Used to set the order in which elements are created (usefull for multiple tabs)
+     */
+    
+    order : false,
+    /**
+     * @cfg {String} name
+     * String to display while loading.
+     */
+    name : false,
+    /**
+     * @cfg {String} region
+     * Region to render component to (defaults to center)
+     */
+    region : 'center',
+    
+    /**
+     * @cfg {Array} items
+     * A single item array - the first element is the root of the tree..
+     * It's done this way to stay compatible with the Xtype system...
+     */
+    items : false,
+    
+    /**
+     * @property _tree
+     * The method that retuns the tree of parts that make up this compoennt 
+     * @type {function}
+     */
+    _tree  : false,
+    
+     /**
+     * render
+     * render element to dom or tree
+     * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
+     */
+    
+    render : function(el)
+    {
+        
+        el = el || false;
+        var hp = this.parent ? 1 : 0;
+        Roo.debug &&  Roo.log(this);
+        
+        var tree = this._tree ? this._tree() : this.tree();
+
+        
+        if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
+            // if parent is a '#.....' string, then let's use that..
+            var ename = this.parent.substr(1);
+            this.parent = false;
+            Roo.debug && Roo.log(ename);
+            switch (ename) {
+                case 'bootstrap-body':
+                    if (typeof(tree.el) != 'undefined' && tree.el == document.body)  {
+                        // this is the BorderLayout standard?
+                       this.parent = { el : true };
+                       break;
+                    }
+                    if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype)  > -1)  {
+                        // need to insert stuff...
+                        this.parent =  {
+                             el : new Roo.bootstrap.layout.Border({
+                                 el : document.body, 
+                     
+                                 center: {
+                                    titlebar: false,
+                                    autoScroll:false,
+                                    closeOnTab: true,
+                                    tabPosition: 'top',
+                                      //resizeTabs: true,
+                                    alwaysShowTabs: true,
+                                    hideTabs: false
+                                     //minTabWidth: 140
+                                 }
+                             })
+                        
+                         };
+                         break;
+                    }
+                         
+                    if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
+                        this.parent = { el :  new  Roo.bootstrap.Body() };
+                        Roo.debug && Roo.log("setting el to doc body");
+                         
+                    } else {
+                        throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
+                    }
+                    break;
+                case 'bootstrap':
+                    this.parent = { el : true};
+                    // fall through
+                default:
+                    el = Roo.get(ename);
+                    if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
+                        this.parent = { el : true};
+                    }
+                    
+                    break;
+            }
+                
+            
+            if (!el && !this.parent) {
+                Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
+                return;
+            }
+        }
+        
+        Roo.debug && Roo.log("EL:");
+        Roo.debug && Roo.log(el);
+        Roo.debug && Roo.log("this.parent.el:");
+        Roo.debug && Roo.log(this.parent.el);
+        
+
+        // altertive root elements ??? - we need a better way to indicate these.
+        var is_alt = Roo.XComponent.is_alt ||
+                    (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
+                    (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
+                    (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
+        
+        
+        
+        if (!this.parent && is_alt) {
+            //el = Roo.get(document.body);
+            this.parent = { el : true };
+        }
+            
+            
+        
+        if (!this.parent) {
+            
+            Roo.debug && Roo.log("no parent - creating one");
+            
+            el = el ? Roo.get(el) : false;     
+            
+            if (typeof(Roo.BorderLayout) == 'undefined' ) {
+                
+                this.parent =  {
+                    el : new Roo.bootstrap.layout.Border({
+                        el: el || document.body,
+                    
+                        center: {
+                            titlebar: false,
+                            autoScroll:false,
+                            closeOnTab: true,
+                            tabPosition: 'top',
+                             //resizeTabs: true,
+                            alwaysShowTabs: false,
+                            hideTabs: true,
+                            minTabWidth: 140,
+                            overflow: 'visible'
+                         }
+                     })
+                };
+            } else {
+            
+                // it's a top level one..
+                this.parent =  {
+                    el : new Roo.BorderLayout(el || document.body, {
+                        center: {
+                            titlebar: false,
+                            autoScroll:false,
+                            closeOnTab: true,
+                            tabPosition: 'top',
+                             //resizeTabs: true,
+                            alwaysShowTabs: el && hp? false :  true,
+                            hideTabs: el || !hp ? true :  false,
+                            minTabWidth: 140
+                         }
+                    })
+                };
+            }
+        }
+        
+        if (!this.parent.el) {
+                // probably an old style ctor, which has been disabled.
+                return;
+
+        }
+               // The 'tree' method is  '_tree now' 
+            
+        tree.region = tree.region || this.region;
+        var is_body = false;
+        if (this.parent.el === true) {
+            // bootstrap... - body..
+            if (el) {
+                tree.el = el;
+            }
+            this.parent.el = Roo.factory(tree);
+            is_body = true;
+        }
+        
+        this.el = this.parent.el.addxtype(tree, undefined, is_body);
+        this.fireEvent('built', this);
+        
+        this.panel = this.el;
+        this.layout = this.panel.layout;
+        this.parentLayout = this.parent.layout  || false;  
+         
+    }
+    
 });
 
 Roo.apply(Roo.XComponent, {
@@ -16092,14 +17759,21 @@ Roo.apply(Roo.XComponent, {
     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,
+    /**
      * @property  build_from_html
      * Build elements from html - used by bootstrap HTML stuff 
      *    - this is cleared after build is completed
-     * @type {boolean} true  (default false)
+     * @type {boolean}    (default false)
      */
      
     build_from_html : false,
-
     /**
      * Register components to be built later.
      *
@@ -16136,7 +17810,7 @@ Roo.apply(Roo.XComponent, {
                 break;
             
             default:
-                if (obj.disabled) {
+                if (obj.disabled || obj.region == '#disabled') {
                         return;
                 }
                 break;
@@ -16318,3488 +17992,3992 @@ Roo.apply(Roo.XComponent, {
         if (!mods.length) { // should not happen
             throw "NO modules!!!";
         }
-        
-        
-        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,
-               closable:false,
-               modal: false
-              
-            });
-        }
-        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);
-             
-        }
-        progressRun.defer(1, _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
-                       
-               }
-});
-
-Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
- /*
- * 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 , {
-
-    /**
-     * 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
-     */
-    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,
-
-    /**
-     * 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
-     */
-    handleElId: null,
-
-    /**
-     * An associative array of HTML tags that will be ignored if clicked.
-     * @property invalidHandleTypes
-     * @type {string: string}
-     */
-    invalidHandleTypes: null,
-
-    /**
-     * An associative array of ids for elements that will be ignored if clicked
-     * @property invalidHandleIds
-     * @type {string: string}
-     */
-    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) { },
-
+        
+        
+        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
+              
+            });
+        }
+        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);
+             
+        }
+        progressRun.defer(1, _this);
+     
+        
+        
+    },
     /**
-     * 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
+     * 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.
+     * 
      */
-    startDrag: function(x, y) { /* override this */ },
-
+       overlayStrings : function( component, strings )
+    {
+        if (typeof(component['_named_strings']) == 'undefined') {
+            throw "ERROR: component does not have _named_strings";
+        }
+        for ( var k in strings ) {
+            var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
+            if (md !== false) {
+                component['_strings'][md] = strings[k];
+            } else {
+                Roo.log('could not find named string: ' + k + ' in');
+                Roo.log(component);
+            }
+            
+        }
+        
+    },
+    
+       
+       /**
+        * Event Object.
+        *
+        *
+        */
+       event: false, 
     /**
-     * Code that executes immediately before the onDrag event
-     * @method b4Drag
-     * @private
-     */
-    b4Drag: function(e) { },
+        * 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
+   
+    
+    
+});
 
-    /**
-     * Abstract method called during the onMouseMove event while dragging an
-     * object.
-     * @method onDrag
-     * @param {Event} e the mousemove event
-     */
-    onDrag: function(e) { /* override this */ },
+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
+                       
+               }
+});
 
-    /**
-     * Abstract method called when this element fist begins hovering over
-     * another DragDrop obj
-     * @method onDragEnter
-     * @param {Event} e the mousemove event
-     * @param {String|DragDrop[]} id In POINT mode, the element
-     * id this is hovering over.  In INTERSECT mode, an array of one or more
-     * dragdrop items being hovered over.
-     */
-    onDragEnter: function(e, id) { /* override this */ },
+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
+ */
 
-    /**
-     * Code that executes immediately before the onDragOver event
-     * @method b4DragOver
-     * @private
-     */
-    b4DragOver: function(e) { },
 
-    /**
-     * Abstract method called when this element is hovering over another
-     * DragDrop obj
-     * @method onDragOver
-     * @param {Event} e the mousemove event
-     * @param {String|DragDrop[]} id In POINT mode, the element
-     * id this is hovering over.  In INTERSECT mode, an array of dd items
-     * being hovered over.
-     */
-    onDragOver: function(e, id) { /* override this */ },
+/**
+ *
+ * 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) {
+    
+    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!!?
+    
+    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
+         */
+      
     /**
-     * Code that executes immediately before the onDragOut event
-     * @method b4DragOut
-     * @private
+     * Helpers
      */
-    b4DragOut: function(e) { },
+    
+    var escape = function (html, encode) {
+      return html
+        .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
+        .replace(/</g, '&lt;')
+        .replace(/>/g, '&gt;')
+        .replace(/"/g, '&quot;')
+        .replace(/'/g, '&#39;');
+    }
+    
+    var unescape = function (html) {
+        // explicitly match decimal, hex, and named HTML entities 
+      return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
+        n = n.toLowerCase();
+        if (n === 'colon') { return ':'; }
+        if (n.charAt(0) === '#') {
+          return n.charAt(1) === 'x'
+            ? String.fromCharCode(parseInt(n.substring(2), 16))
+            : String.fromCharCode(+n.substring(1));
+        }
+        return '';
+      });
+    }
+    
+    var replace = function (regex, opt) {
+      regex = regex.source;
+      opt = opt || '';
+      return function self(name, val) {
+        if (!name) { return new RegExp(regex, opt); }
+        val = val.source || val;
+        val = val.replace(/(^|[^\[])\^/g, '$1');
+        regex = regex.replace(name, val);
+        return self;
+      };
+    }
 
-    /**
-     * Abstract method called when we are no longer hovering over an element
-     * @method onDragOut
-     * @param {Event} e the mousemove event
-     * @param {String|DragDrop[]} id In POINT mode, the element
-     * id this was hovering over.  In INTERSECT mode, an array of dd items
-     * that the mouse is no longer over.
-     */
-    onDragOut: function(e, id) { /* override this */ },
 
+         /**
+         * eval:var:noop
+    */
+    var noop = function () {}
+    noop.exec = noop;
+    
+         /**
+         * eval:var:merge
+    */
+    var merge = function (obj) {
+      var i = 1
+        , target
+        , key;
+    
+      for (; i < arguments.length; i++) {
+        target = arguments[i];
+        for (key in target) {
+          if (Object.prototype.hasOwnProperty.call(target, key)) {
+            obj[key] = target[key];
+          }
+        }
+      }
+    
+      return obj;
+    }
+    
+    
     /**
-     * Code that executes immediately before the onDragDrop event
-     * @method b4DragDrop
-     * @private
+     * Block-Level Grammar
      */
-    b4DragDrop: function(e) { },
-
+    
+    
+    
+    
+    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)
+      ();
+    
     /**
-     * Abstract method called when this item is dropped on another DragDrop
-     * obj
-     * @method onDragDrop
-     * @param {Event} e the mouseup event
-     * @param {String|DragDrop[]} id In POINT mode, the element
-     * id this was dropped on.  In INTERSECT mode, an array of dd items this
-     * was dropped on.
+     * Normal Block Grammar
      */
-    onDragDrop: function(e, id) { /* override this */ },
-
+    
+    block.normal = merge({}, block);
+    
     /**
-     * Abstract method called when this item is dropped on an area with no
-     * drop target
-     * @method onInvalidDrop
-     * @param {Event} e the mouseup event
+     * GFM Block Grammar
      */
-    onInvalidDrop: function(e) { /* override this */ },
-
+    
+    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') + '|')
+      ();
+    
     /**
-     * Code that executes immediately before the endDrag event
-     * @method b4EndDrag
-     * @private
+     * GFM + Tables Block Grammar
      */
-    b4EndDrag: function(e) { },
-
+    
+    block.tables = merge({}, block.gfm, {
+      nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
+      table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
+    });
+    
     /**
-     * Fired when we are done dragging the object
-     * @method endDrag
-     * @param {Event} e the mouseup event
+     * Block Lexer
      */
-    endDrag: function(e) { /* override this */ },
-
+    
+    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;
+        }
+      }
+    }
+    
     /**
-     * Code executed immediately before the onMouseDown event
-     * @method b4MouseDown
-     * @param {Event} e the mousedown event
-     * @private
+     * Expose Block Rules
      */
-    b4MouseDown: function(e) {  },
-
+    
+    Lexer.rules = block;
+    
     /**
-     * Event handler that fires when a drag/drop obj gets a mousedown
-     * @method onMouseDown
-     * @param {Event} e the mousedown event
+     * Static Lex Method
      */
-    onMouseDown: function(e) { /* override this */ },
-
+    
+    Lexer.lex = function(src, options) {
+      var lexer = new Lexer(options);
+      return lexer.lex(src);
+    };
+    
     /**
-     * Event handler that fires when a drag/drop obj gets a mouseup
-     * @method onMouseUp
-     * @param {Event} e the mouseup event
+     * Preprocessing
      */
-    onMouseUp: function(e) { /* override this */ },
-
+    
+    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);
+    };
+    
     /**
-     * Override the onAvailable method to do what is needed after the initial
-     * position was determined.
-     * @method onAvailable
-     */
-    onAvailable: function () {
-    },
-
-    /*
-     * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
-     * @type Object
-     */
-    defaultPadding : {left:0, right:0, top:0, bottom:0},
-
-    /*
-     * Initializes the drag drop object's constraints to restrict movement to a certain element.
- *
- * Usage:
- <pre><code>
- var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
-                { dragElId: "existingProxyDiv" });
- dd.startDrag = function(){
-     this.constrainTo("parent-id");
- };
- </code></pre>
- * Or you can initalize it using the {@link Roo.Element} object:
- <pre><code>
- Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
-     startDrag : function(){
-         this.constrainTo("parent-id");
-     }
- });
- </code></pre>
-     * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
-     * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
-     * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
-     * an object containing the sides to pad. For example: {right:10, bottom:10}
-     * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
-     */
-    constrainTo : function(constrainTo, pad, inContent){
-        if(typeof pad == "number"){
-            pad = {left: pad, right:pad, top:pad, bottom:pad};
+     * Lexing
+     */
+    
+    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'
+            });
+          }
         }
-        pad = pad || this.defaultPadding;
-        var b = Roo.get(this.getEl()).getBox();
-        var ce = Roo.get(constrainTo);
-        var s = ce.getScroll();
-        var c, cd = ce.dom;
-        if(cd == document.body){
-            c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
-        }else{
-            xy = ce.getXY();
-            c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
+    
+        // 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;
         }
-
-
-        var topSpace = b.y - c.y;
-        var leftSpace = b.x - c.x;
-
-        this.resetConstraints();
-        this.setXConstraint(leftSpace - (pad.left||0), // left
-                c.width - leftSpace - b.width - (pad.right||0) //right
-        );
-        this.setYConstraint(topSpace - (pad.top||0), //top
-                c.height - topSpace - b.height - (pad.bottom||0) //bottom
-        );
-    },
-
-    /**
-     * Returns a reference to the linked element
-     * @method getEl
-     * @return {HTMLElement} the html element
-     */
-    getEl: function() {
-        if (!this._domRef) {
-            this._domRef = Roo.getDom(this.id);
+    
+        // 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;
         }
-
-        return this._domRef;
-    },
-
-    /**
-     * Returns a reference to the actual element to drag.  By default this is
-     * the same as the html element, but it can be assigned to another
-     * element. An example of this can be found in Roo.dd.DDProxy
-     * @method getDragEl
-     * @return {HTMLElement} the html element
-     */
-    getDragEl: function() {
-        return Roo.getDom(this.dragElId);
-    },
-
-    /**
-     * Sets up the DragDrop object.  Must be called in the constructor of any
-     * Roo.dd.DragDrop subclass
-     * @method init
-     * @param id the id of the linked element
-     * @param {String} sGroup the group of related items
-     * @param {object} config configuration attributes
-     */
-    init: function(id, sGroup, config) {
-        this.initTarget(id, sGroup, config);
-        if (!Roo.isTouch) {
-            Event.on(this.id, "mousedown", this.handleMouseDown, this);
+    
+        // hr
+        if (cap = this.rules.hr.exec(src)) {
+          src = src.substring(cap[0].length);
+          this.tokens.push({
+            type: 'hr'
+          });
+          continue;
         }
-        Event.on(this.id, "touchstart", this.handleMouseDown, this);
-        // Event.on(this.id, "selectstart", Event.preventDefault);
-    },
-
-    /**
-     * Initializes Targeting functionality only... the object does not
-     * get a mousedown handler.
-     * @method initTarget
-     * @param id the id of the linked element
-     * @param {String} sGroup the group of related items
-     * @param {object} config configuration attributes
-     */
-    initTarget: function(id, sGroup, config) {
-
-        // configuration attributes
-        this.config = config || {};
-
-        // create a local reference to the drag and drop manager
-        this.DDM = Roo.dd.DDM;
-        // initialize the groups array
-        this.groups = {};
-
-        // assume that we have an element reference instead of an id if the
-        // parameter is not a string
-        if (typeof id !== "string") {
-            id = Roo.id(id);
+    
+        // 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;
         }
-
-        // set the id
-        this.id = id;
-
-        // add to an interaction group
-        this.addToGroup((sGroup) ? sGroup : "default");
-
-        // We don't want to register this as the handle with the manager
-        // so we just set the id rather than calling the setter.
-        this.handleElId = id;
-
-        // the linked element is the element that gets dragged by default
-        this.setDragElId(id);
-
-        // by default, clicked anchors will not start drag operations.
-        this.invalidHandleTypes = { A: "A" };
-        this.invalidHandleIds = {};
-        this.invalidHandleClasses = [];
-
-        this.applyConfig();
-
-        this.handleOnAvailable();
-    },
-
+    
+        // 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;
+    };
+    
     /**
-     * Applies the configuration parameters that were passed into the constructor.
-     * This is supposed to happen at each level through the inheritance chain.  So
-     * a DDProxy implentation will execute apply config on DDProxy, DD, and
-     * DragDrop in order to get all of the parameters that are available in
-     * each object.
-     * @method applyConfig
+     * Inline-Level Grammar
      */
-    applyConfig: function() {
-
-        // configurable properties:
-        //    padding, isTarget, maintainOffset, primaryButtonOnly
-        this.padding           = this.config.padding || [0, 0, 0, 0];
-        this.isTarget          = (this.config.isTarget !== false);
-        this.maintainOffset    = (this.config.maintainOffset);
-        this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
-
-    },
-
+    
+    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)
+      ();
+    
     /**
-     * Executed when the linked element is available
-     * @method handleOnAvailable
-     * @private
+     * Normal Inline Grammar
      */
-    handleOnAvailable: function() {
-        this.available = true;
-        this.resetConstraints();
-        this.onAvailable();
-    },
-
-     /**
-     * Configures the padding for the target zone in px.  Effectively expands
-     * (or reduces) the virtual object size for targeting calculations.
-     * Supports css-style shorthand; if only one parameter is passed, all sides
-     * will have that padding, and if only two are passed, the top and bottom
-     * will have the first param, the left and right the second.
-     * @method setPadding
-     * @param {int} iTop    Top pad
-     * @param {int} iRight  Right pad
-     * @param {int} iBot    Bot pad
-     * @param {int} iLeft   Left pad
+    
+    inline.normal = merge({}, inline);
+    
+    /**
+     * Pedantic Inline Grammar
      */
-    setPadding: function(iTop, iRight, iBot, iLeft) {
-        // this.padding = [iLeft, iRight, iTop, iBot];
-        if (!iRight && 0 !== iRight) {
-            this.padding = [iTop, iTop, iTop, iTop];
-        } else if (!iBot && 0 !== iBot) {
-            this.padding = [iTop, iRight, iTop, iRight];
-        } else {
-            this.padding = [iTop, iRight, iBot, iLeft];
-        }
-    },
-
+    
+    inline.pedantic = merge({}, inline.normal, {
+      strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
+      em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
+    });
+    
     /**
-     * Stores the initial placement of the linked element.
-     * @method setInitialPosition
-     * @param {int} diffX   the X offset, default 0
-     * @param {int} diffY   the Y offset, default 0
+     * GFM Inline Grammar
      */
-    setInitPosition: function(diffX, diffY) {
-        var el = this.getEl();
-
-        if (!this.DDM.verifyEl(el)) {
-            return;
+    
+    inline.gfm = merge({}, inline.normal, {
+      escape: replace(inline.escape)('])', '~|])')(),
+      url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
+      del: /^~~(?=\S)([\s\S]*?\S)~~/,
+      text: replace(inline.text)
+        (']|', '~]|')
+        ('|', '|https?://|')
+        ()
+    });
+    
+    /**
+     * GFM + Line Breaks Inline Grammar
+     */
+    
+    inline.breaks = merge({}, inline.gfm, {
+      br: replace(inline.br)('{2,}', '*')(),
+      text: replace(inline.gfm.text)('{2,}', '*')()
+    });
+    
+    /**
+     * Inline Lexer & Compiler
+     */
+    
+    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;
         }
-
-        var dx = diffX || 0;
-        var dy = diffY || 0;
-
-        var p = Dom.getXY( el );
-
-        this.initPageX = p[0] - dx;
-        this.initPageY = p[1] - dy;
-
-        this.lastPageX = p[0];
-        this.lastPageY = p[1];
-
-
-        this.setStartPosition(p);
-    },
-
+      } else if (this.options.pedantic) {
+        this.rules = inline.pedantic;
+      }
+    }
+    
     /**
-     * Sets the start position of the element.  This is set when the obj
-     * is initialized, the reset when a drag is started.
-     * @method setStartPosition
-     * @param pos current position (from previous lookup)
-     * @private
+     * Expose Inline Rules
      */
-    setStartPosition: function(pos) {
-        var p = pos || Dom.getXY( this.getEl() );
-        this.deltaSetXY = null;
-
-        this.startPageX = p[0];
-        this.startPageY = p[1];
-    },
-
+    
+    InlineLexer.rules = inline;
+    
     /**
-     * Add this instance to a group of related drag/drop objects.  All
-     * instances belong to at least one group, and can belong to as many
-     * groups as needed.
-     * @method addToGroup
-     * @param sGroup {string} the name of the group
+     * Static Lexing/Compiling Method
      */
-    addToGroup: function(sGroup) {
-        this.groups[sGroup] = true;
-        this.DDM.regDragDrop(this, sGroup);
-    },
-
+    
+    InlineLexer.output = function(src, links, options) {
+      var inline = new InlineLexer(links, options);
+      return inline.output(src);
+    };
+    
     /**
-     * Remove's this instance from the supplied interaction group
-     * @method removeFromGroup
-     * @param {string}  sGroup  The group to drop
+     * Lexing/Compiling
      */
-    removeFromGroup: function(sGroup) {
-        if (this.groups[sGroup]) {
-            delete this.groups[sGroup];
+    
+    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;
         }
-
-        this.DDM.removeDDFromGroup(this, sGroup);
-    },
-
+    
+        // 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;
+    };
+    
     /**
-     * Allows you to specify that an element other than the linked element
-     * will be moved with the cursor during a drag
-     * @method setDragElId
-     * @param id {string} the id of the element that will be used to initiate the drag
+     * Compile Link
      */
-    setDragElId: function(id) {
-        this.dragElId = id;
-    },
-
+    
+    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]));
+    };
+    
     /**
-     * Allows you to specify a child of the linked element that should be
-     * used to initiate the drag operation.  An example of this would be if
-     * you have a content div with text and links.  Clicking anywhere in the
-     * content area would normally start the drag operation.  Use this method
-     * to specify that an element inside of the content div is the element
-     * that starts the drag operation.
-     * @method setHandleElId
-     * @param id {string} the id of the element that will be used to
-     * initiate the drag.
+     * Smartypants Transformations
+     */
+    
+    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');
+    };
+    
+    /**
+     * Mangle Links
      */
-    setHandleElId: function(id) {
-        if (typeof id !== "string") {
-            id = Roo.id(id);
+    
+    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);
         }
-        this.handleElId = id;
-        this.DDM.regHandle(this.id, id);
-    },
-
+        out += '&#' + ch + ';';
+      }
+    
+      return out;
+    };
+    
     /**
-     * Allows you to set an element outside of the linked element as a drag
-     * handle
-     * @method setOuterHandleElId
-     * @param id the id of the element that will be used to initiate the drag
+     * Renderer
      */
-    setOuterHandleElId: function(id) {
-        if (typeof id !== "string") {
-            id = Roo.id(id);
+    
+     /**
+         * 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;
         }
-        Event.on(id, "mousedown",
-                this.handleMouseDown, this);
-        this.setHandleElId(id);
-
-        this.hasOuterHandles = true;
-    },
-
+      } 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;
+    };
+    
     /**
-     * Remove all drag and drop hooks for this element
-     * @method unreg
+     * Parsing & Compiling
      */
-    unreg: function() {
-        Event.un(this.id, "mousedown",
-                this.handleMouseDown);
-        Event.un(this.id, "touchstart",
-                this.handleMouseDown);
-        this._domRef = null;
-        this.DDM._remove(this);
-    },
-
-    destroy : function(){
-        this.unreg();
-    },
-
+         /**
+         * 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;
+    }
+    
     /**
-     * Returns true if this instance is locked, or the drag drop mgr is locked
-     * (meaning that all drag/drop is disabled on the page.)
-     * @method isLocked
-     * @return {boolean} true if this obj or all drag/drop is locked, else
-     * false
+     * Static Parse Method
      */
-    isLocked: function() {
-        return (this.DDM.isLocked() || this.locked);
-    },
-
+    
+    Parser.parse = function(src, options, renderer) {
+      var parser = new Parser(options, renderer);
+      return parser.parse(src);
+    };
+    
     /**
-     * Fired when this object is clicked
-     * @method handleMouseDown
-     * @param {Event} e
-     * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
-     * @private
+     * Parse Loop
      */
-    handleMouseDown: function(e, oDD){
-     
-        if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
-            //Roo.log('not touch/ button !=0');
-            return;
+    
+    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);
         }
-        if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
-            return; // double touch..
+        case 'blockquote_start': {
+          var body = '';
+    
+          while (this.next().type !== 'blockquote_end') {
+            body += this.tok();
+          }
+    
+          return this.renderer.blockquote(body);
         }
-        
-
-        if (this.isLocked()) {
-            //Roo.log('locked');
-            return;
+        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());
+        }
+      }
+    };
+  
+    
+    /**
+     * Marked
+     */
+         /**
+         * 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;
+      }
+    }
+    
+    /**
+     * Options
+     */
+    
+    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
+    };
+    
+    /**
+     * Expose
+     */
+    
+    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;
 
-        this.DDM.refreshCache(this.groups);
-//        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
-        var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
-        if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
-            //Roo.log('no outer handes or not over target');
-                // do nothing.
-        } else {
-//            Roo.log('check validator');
-            if (this.clickValidator(e)) {
-//                Roo.log('validate success');
-                // set the initial element position
-                this.setStartPosition();
+})();/*
+ * 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">
+ */
 
 
-                this.b4MouseDown(e);
-                this.onMouseDown(e);
 
-                this.DDM.handleMouseDown(e, this);
+/*
+ * 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
+ */
 
-                this.DDM.stopEvent(e);
-            } else {
+(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);
+    }
+    
+};
 
-    clickValidator: function(e) {
-        var target = e.getTarget();
-        return ( this.isValidHandleChild(target) &&
-                    (this.id == this.handleElId ||
-                        this.DDM.handleWasClicked(target, this.id)) );
-    },
+Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
 
     /**
-     * Allows you to specify a tag name that should not start a drag operation
-     * when clicked.  This is designed to facilitate embedding links within a
-     * drag handle that do something other than start the drag.
-     * @method addInvalidHandleType
-     * @param {string} tagName the type of element to exclude
+     * 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
      */
-    addInvalidHandleType: function(tagName) {
-        var type = tagName.toUpperCase();
-        this.invalidHandleTypes[type] = type;
-    },
+    id: null,
 
     /**
-     * Lets you to specify an element id for a child of a drag handle
-     * that should not initiate a drag
-     * @method addInvalidHandleId
-     * @param {string} id the element id of the element you wish to ignore
+     * Configuration attributes passed into the constructor
+     * @property config
+     * @type object
      */
-    addInvalidHandleId: function(id) {
-        if (typeof id !== "string") {
-            id = Roo.id(id);
-        }
-        this.invalidHandleIds[id] = id;
-    },
+    config: null,
 
     /**
-     * Lets you specify a css class of elements that will not initiate a drag
-     * @method addInvalidHandleClass
-     * @param {string} cssClass the class of the elements you wish to ignore
+     * 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
      */
-    addInvalidHandleClass: function(cssClass) {
-        this.invalidHandleClasses.push(cssClass);
-    },
+    dragElId: null,
 
     /**
-     * Unsets an excluded tag name set by addInvalidHandleType
-     * @method removeInvalidHandleType
-     * @param {string} tagName the type of element to unexclude
+     * 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
      */
-    removeInvalidHandleType: function(tagName) {
-        var type = tagName.toUpperCase();
-        // this.invalidHandleTypes[type] = null;
-        delete this.invalidHandleTypes[type];
-    },
+    handleElId: null,
 
     /**
-     * Unsets an invalid handle id
-     * @method removeInvalidHandleId
-     * @param {string} id the id of the element to re-enable
+     * An associative array of HTML tags that will be ignored if clicked.
+     * @property invalidHandleTypes
+     * @type {string: string}
      */
-    removeInvalidHandleId: function(id) {
-        if (typeof id !== "string") {
-            id = Roo.id(id);
-        }
-        delete this.invalidHandleIds[id];
-    },
+    invalidHandleTypes: null,
 
     /**
-     * Unsets an invalid css class
-     * @method removeInvalidHandleClass
-     * @param {string} cssClass the class of the element(s) you wish to
-     * re-enable
+     * An associative array of ids for elements that will be ignored if clicked
+     * @property invalidHandleIds
+     * @type {string: string}
      */
-    removeInvalidHandleClass: function(cssClass) {
-        for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
-            if (this.invalidHandleClasses[i] == cssClass) {
-                delete this.invalidHandleClasses[i];
-            }
-        }
-    },
+    invalidHandleIds: null,
 
     /**
-     * Checks the tag exclusion list to see if this click should be ignored
-     * @method isValidHandleChild
-     * @param {HTMLElement} node the HTMLElement to evaluate
-     * @return {boolean} true if this is a valid tag type, false if not
+     * An indexted array of css class names for elements that will be ignored
+     * if clicked.
+     * @property invalidHandleClasses
+     * @type string[]
      */
-    isValidHandleChild: function(node) {
-
-        var valid = true;
-        // var n = (node.nodeName == "#text") ? node.parentNode : node;
-        var nodeName;
-        try {
-            nodeName = node.nodeName.toUpperCase();
-        } catch(e) {
-            nodeName = node.nodeName;
-        }
-        valid = valid && !this.invalidHandleTypes[nodeName];
-        valid = valid && !this.invalidHandleIds[node.id];
-
-        for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
-            valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
-        }
-
-
-        return valid;
-
-    },
+    invalidHandleClasses: null,
 
     /**
-     * Create the array of horizontal tick marks if an interval was specified
-     * in setXConstraint().
-     * @method setXTicks
+     * The linked element's absolute X position at the time the drag was
+     * started
+     * @property startPageX
+     * @type int
      * @private
      */
-    setXTicks: function(iStartX, iTickSize) {
-        this.xTicks = [];
-        this.xTickSize = iTickSize;
-
-        var tickMap = {};
-
-        for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
-            if (!tickMap[i]) {
-                this.xTicks[this.xTicks.length] = i;
-                tickMap[i] = true;
-            }
-        }
-
-        for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
-            if (!tickMap[i]) {
-                this.xTicks[this.xTicks.length] = i;
-                tickMap[i] = true;
-            }
-        }
-
-        this.xTicks.sort(this.DDM.numericSort) ;
-    },
+    startPageX: 0,
 
     /**
-     * Create the array of vertical tick marks if an interval was specified in
-     * setYConstraint().
-     * @method setYTicks
+     * The linked element's absolute X position at the time the drag was
+     * started
+     * @property startPageY
+     * @type int
      * @private
      */
-    setYTicks: function(iStartY, iTickSize) {
-        this.yTicks = [];
-        this.yTickSize = iTickSize;
-
-        var tickMap = {};
-
-        for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
-            if (!tickMap[i]) {
-                this.yTicks[this.yTicks.length] = i;
-                tickMap[i] = true;
-            }
-        }
-
-        for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
-            if (!tickMap[i]) {
-                this.yTicks[this.yTicks.length] = i;
-                tickMap[i] = true;
-            }
-        }
-
-        this.yTicks.sort(this.DDM.numericSort) ;
-    },
+    startPageY: 0,
 
     /**
-     * By default, the element can be dragged any place on the screen.  Use
-     * this method to limit the horizontal travel of the element.  Pass in
-     * 0,0 for the parameters if you want to lock the drag to the y axis.
-     * @method setXConstraint
-     * @param {int} iLeft the number of pixels the element can move to the left
-     * @param {int} iRight the number of pixels the element can move to the
-     * right
-     * @param {int} iTickSize optional parameter for specifying that the
-     * element
-     * should move iTickSize pixels at a time.
+     * 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}
      */
-    setXConstraint: function(iLeft, iRight, iTickSize) {
-        this.leftConstraint = iLeft;
-        this.rightConstraint = iRight;
-
-        this.minX = this.initPageX - iLeft;
-        this.maxX = this.initPageX + iRight;
-        if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
-
-        this.constrainX = true;
-    },
+    groups: null,
 
     /**
-     * Clears any constraints applied to this instance.  Also clears ticks
-     * since they can't exist independent of a constraint at this time.
-     * @method clearConstraints
+     * Individual drag/drop instances can be locked.  This will prevent
+     * onmousedown start drag.
+     * @property locked
+     * @type boolean
+     * @private
      */
-    clearConstraints: function() {
-        this.constrainX = false;
-        this.constrainY = false;
-        this.clearTicks();
-    },
+    locked: false,
 
     /**
-     * Clears any tick interval defined for this instance
-     * @method clearTicks
+     * Lock this instance
+     * @method lock
      */
-    clearTicks: function() {
-        this.xTicks = null;
-        this.yTicks = null;
-        this.xTickSize = 0;
-        this.yTickSize = 0;
-    },
+    lock: function() { this.locked = true; },
 
     /**
-     * By default, the element can be dragged any place on the screen.  Set
-     * this to limit the vertical travel of the element.  Pass in 0,0 for the
-     * parameters if you want to lock the drag to the x axis.
-     * @method setYConstraint
-     * @param {int} iUp the number of pixels the element can move up
-     * @param {int} iDown the number of pixels the element can move down
-     * @param {int} iTickSize optional parameter for specifying that the
-     * element should move iTickSize pixels at a time.
+     * Unlock this instace
+     * @method unlock
      */
-    setYConstraint: function(iUp, iDown, iTickSize) {
-        this.topConstraint = iUp;
-        this.bottomConstraint = iDown;
-
-        this.minY = this.initPageY - iUp;
-        this.maxY = this.initPageY + iDown;
-        if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
-
-        this.constrainY = true;
-
-    },
+    unlock: function() { this.locked = false; },
 
     /**
-     * resetConstraints must be called if you manually reposition a dd element.
-     * @method resetConstraints
-     * @param {boolean} maintainOffset
+     * By default, all insances can be a drop target.  This can be disabled by
+     * setting isTarget to false.
+     * @method isTarget
+     * @type boolean
      */
-    resetConstraints: function() {
-
-
-        // Maintain offsets if necessary
-        if (this.initPageX || this.initPageX === 0) {
-            // figure out how much this thing has moved
-            var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
-            var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
-
-            this.setInitPosition(dx, dy);
-
-        // This is the first time we have detected the element's position
-        } else {
-            this.setInitPosition();
-        }
-
-        if (this.constrainX) {
-            this.setXConstraint( this.leftConstraint,
-                                 this.rightConstraint,
-                                 this.xTickSize        );
-        }
+    isTarget: true,
 
-        if (this.constrainY) {
-            this.setYConstraint( this.topConstraint,
-                                 this.bottomConstraint,
-                                 this.yTickSize         );
-        }
-    },
+    /**
+     * The padding configured for this drag and drop object for calculating
+     * the drop zone intersection with this object.
+     * @method padding
+     * @type int[]
+     */
+    padding: null,
 
     /**
-     * Normally the drag element is moved pixel by pixel, but we can specify
-     * that it move a number of pixels at a time.  This method resolves the
-     * location when we have it set up like this.
-     * @method getTick
-     * @param {int} val where we want to place the object
-     * @param {int[]} tickArray sorted array of valid points
-     * @return {int} the closest tick
+     * Cached reference to the linked element
+     * @property _domRef
      * @private
      */
-    getTick: function(val, tickArray) {
+    _domRef: null,
 
-        if (!tickArray) {
-            // If tick interval is not defined, it is effectively 1 pixel,
-            // so we return the value passed to us.
-            return val;
-        } else if (tickArray[0] >= val) {
-            // The value is lower than the first tick, so we return the first
-            // tick.
-            return tickArray[0];
-        } else {
-            for (var i=0, len=tickArray.length; i<len; ++i) {
-                var next = i + 1;
-                if (tickArray[next] && tickArray[next] >= val) {
-                    var diff1 = val - tickArray[i];
-                    var diff2 = tickArray[next] - val;
-                    return (diff2 > diff1) ? tickArray[i] : tickArray[next];
-                }
-            }
+    /**
+     * Internal typeof flag
+     * @property __ygDragDrop
+     * @private
+     */
+    __ygDragDrop: true,
 
-            // The value is larger than the last tick, so we return the last
-            // tick.
-            return tickArray[tickArray.length - 1];
-        }
-    },
+    /**
+     * Set to true when horizontal contraints are applied
+     * @property constrainX
+     * @type boolean
+     * @private
+     */
+    constrainX: false,
 
     /**
-     * toString method
-     * @method toString
-     * @return {string} string representation of the dd obj
+     * Set to true when vertical contraints are applied
+     * @property constrainY
+     * @type boolean
+     * @private
      */
-    toString: function() {
-        return ("DragDrop " + this.id);
-    }
+    constrainY: false,
 
-});
+    /**
+     * The left constraint
+     * @property minX
+     * @type int
+     * @private
+     */
+    minX: 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">
- */
+    /**
+     * The right constraint
+     * @property maxX
+     * @type int
+     * @private
+     */
+    maxX: 0,
 
+    /**
+     * The up constraint
+     * @property minY
+     * @type int
+     * @type int
+     * @private
+     */
+    minY: 0,
 
-/**
- * The drag and drop utility provides a framework for building drag and drop
- * applications.  In addition to enabling drag and drop for specific elements,
- * the drag and drop elements are tracked by the manager class, and the
- * interactions between the various elements are tracked during the drag and
- * the implementing code is notified about these important moments.
- */
+    /**
+     * The down constraint
+     * @property maxY
+     * @type int
+     * @private
+     */
+    maxY: 0,
 
-// Only load the library once.  Rewriting the manager class would orphan
-// existing drag and drop instances.
-if (!Roo.dd.DragDropMgr) {
+    /**
+     * 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,
 
-/**
- * @class Roo.dd.DragDropMgr
- * DragDropMgr is a singleton that tracks the element interaction for
- * 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
- */
-Roo.dd.DragDropMgr = function() {
+    /**
+     * 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,
 
-    var Event = Roo.EventManager;
+    /**
+     * 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,
 
-    return {
+    /**
+     * 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,
 
-        /**
-         * Two dimensional Array of registered DragDrop objects.  The first
-         * dimension is the DragDrop item group, the second the DragDrop
-         * object.
-         * @property ids
-         * @type {string: string}
-         * @private
-         * @static
-         */
-        ids: {},
+    /**
+     * The availabe property is false until the linked dom element is accessible.
+     * @property available
+     * @type boolean
+     */
+    available: false,
 
-        /**
-         * Array of element ids defined as drag handles.  Used to determine
-         * if the element that generated the mousedown event is actually the
-         * handle and not the html element itself.
-         * @property handleIds
-         * @type {string: string}
-         * @private
-         * @static
-         */
-        handleIds: {},
+    /**
+     * 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,
 
-        /**
-         * the DragDrop object that is currently being dragged
-         * @property dragCurrent
-         * @type DragDrop
-         * @private
-         * @static
-         **/
-        dragCurrent: null,
+    /**
+     * Code that executes immediately before the startDrag event
+     * @method b4StartDrag
+     * @private
+     */
+    b4StartDrag: function(x, y) { },
 
-        /**
-         * the DragDrop object(s) that are being hovered over
-         * @property dragOvers
-         * @type Array
-         * @private
-         * @static
-         */
-        dragOvers: {},
+    /**
+     * 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 */ },
 
-        /**
-         * the X distance between the cursor and the object being dragged
-         * @property deltaX
-         * @type int
-         * @private
-         * @static
-         */
-        deltaX: 0,
+    /**
+     * Code that executes immediately before the onDrag event
+     * @method b4Drag
+     * @private
+     */
+    b4Drag: function(e) { },
 
-        /**
-         * the Y distance between the cursor and the object being dragged
-         * @property deltaY
-         * @type int
-         * @private
-         * @static
-         */
-        deltaY: 0,
+    /**
+     * Abstract method called during the onMouseMove event while dragging an
+     * object.
+     * @method onDrag
+     * @param {Event} e the mousemove event
+     */
+    onDrag: function(e) { /* override this */ },
 
-        /**
-         * Flag to determine if we should prevent the default behavior of the
-         * events we define. By default this is true, but this can be set to
-         * false if you need the default behavior (not recommended)
-         * @property preventDefault
-         * @type boolean
-         * @static
-         */
-        preventDefault: true,
+    /**
+     * Abstract method called when this element fist begins hovering over
+     * another DragDrop obj
+     * @method onDragEnter
+     * @param {Event} e the mousemove event
+     * @param {String|DragDrop[]} id In POINT mode, the element
+     * id this is hovering over.  In INTERSECT mode, an array of one or more
+     * dragdrop items being hovered over.
+     */
+    onDragEnter: function(e, id) { /* override this */ },
 
-        /**
-         * Flag to determine if we should stop the propagation of the events
-         * we generate. This is true by default but you may want to set it to
-         * false if the html element contains other features that require the
-         * mouse click.
-         * @property stopPropagation
-         * @type boolean
-         * @static
-         */
-        stopPropagation: true,
+    /**
+     * Code that executes immediately before the onDragOver event
+     * @method b4DragOver
+     * @private
+     */
+    b4DragOver: function(e) { },
 
-        /**
-         * Internal flag that is set to true when drag and drop has been
-         * intialized
-         * @property initialized
-         * @private
-         * @static
-         */
-        initalized: false,
+    /**
+     * Abstract method called when this element is hovering over another
+     * DragDrop obj
+     * @method onDragOver
+     * @param {Event} e the mousemove event
+     * @param {String|DragDrop[]} id In POINT mode, the element
+     * id this is hovering over.  In INTERSECT mode, an array of dd items
+     * being hovered over.
+     */
+    onDragOver: function(e, id) { /* override this */ },
 
-        /**
-         * All drag and drop can be disabled.
-         * @property locked
-         * @private
-         * @static
-         */
-        locked: false,
+    /**
+     * Code that executes immediately before the onDragOut event
+     * @method b4DragOut
+     * @private
+     */
+    b4DragOut: function(e) { },
 
-        /**
-         * Called the first time an element is registered.
-         * @method init
-         * @private
-         * @static
-         */
-        init: function() {
-            this.initialized = true;
-        },
+    /**
+     * Abstract method called when we are no longer hovering over an element
+     * @method onDragOut
+     * @param {Event} e the mousemove event
+     * @param {String|DragDrop[]} id In POINT mode, the element
+     * id this was hovering over.  In INTERSECT mode, an array of dd items
+     * that the mouse is no longer over.
+     */
+    onDragOut: function(e, id) { /* override this */ },
 
-        /**
-         * In point mode, drag and drop interaction is defined by the
-         * location of the cursor during the drag/drop
-         * @property POINT
-         * @type int
-         * @static
-         */
-        POINT: 0,
+    /**
+     * Code that executes immediately before the onDragDrop event
+     * @method b4DragDrop
+     * @private
+     */
+    b4DragDrop: function(e) { },
 
-        /**
-         * In intersect mode, drag and drop interactio nis defined by the
-         * overlap of two or more drag and drop objects.
-         * @property INTERSECT
-         * @type int
-         * @static
-         */
-        INTERSECT: 1,
+    /**
+     * Abstract method called when this item is dropped on another DragDrop
+     * obj
+     * @method onDragDrop
+     * @param {Event} e the mouseup event
+     * @param {String|DragDrop[]} id In POINT mode, the element
+     * id this was dropped on.  In INTERSECT mode, an array of dd items this
+     * was dropped on.
+     */
+    onDragDrop: function(e, id) { /* override this */ },
 
-        /**
-         * The current drag and drop mode.  Default: POINT
-         * @property mode
-         * @type int
-         * @static
-         */
-        mode: 0,
+    /**
+     * Abstract method called when this item is dropped on an area with no
+     * drop target
+     * @method onInvalidDrop
+     * @param {Event} e the mouseup event
+     */
+    onInvalidDrop: function(e) { /* override this */ },
 
-        /**
-         * Runs method on all drag and drop objects
-         * @method _execOnAll
-         * @private
-         * @static
-         */
-        _execOnAll: function(sMethod, args) {
-            for (var i in this.ids) {
-                for (var j in this.ids[i]) {
-                    var oDD = this.ids[i][j];
-                    if (! this.isTypeOfDD(oDD)) {
-                        continue;
-                    }
-                    oDD[sMethod].apply(oDD, args);
-                }
-            }
-        },
+    /**
+     * Code that executes immediately before the endDrag event
+     * @method b4EndDrag
+     * @private
+     */
+    b4EndDrag: function(e) { },
 
-        /**
-         * Drag and drop initialization.  Sets up the global event handlers
-         * @method _onLoad
-         * @private
-         * @static
-         */
-        _onLoad: function() {
+    /**
+     * Fired when we are done dragging the object
+     * @method endDrag
+     * @param {Event} e the mouseup event
+     */
+    endDrag: function(e) { /* override this */ },
 
-            this.init();
+    /**
+     * Code executed immediately before the onMouseDown event
+     * @method b4MouseDown
+     * @param {Event} e the mousedown event
+     * @private
+     */
+    b4MouseDown: function(e) {  },
 
-            if (!Roo.isTouch) {
-                Event.on(document, "mouseup",   this.handleMouseUp, this, true);
-                Event.on(document, "mousemove", this.handleMouseMove, this, true);
-            }
-            Event.on(document, "touchend",   this.handleMouseUp, this, true);
-            Event.on(document, "touchmove", this.handleMouseMove, this, true);
-            
-            Event.on(window,   "unload",    this._onUnload, this, true);
-            Event.on(window,   "resize",    this._onResize, this, true);
-            // Event.on(window,   "mouseout",    this._test);
+    /**
+     * Event handler that fires when a drag/drop obj gets a mousedown
+     * @method onMouseDown
+     * @param {Event} e the mousedown event
+     */
+    onMouseDown: function(e) { /* override this */ },
 
-        },
+    /**
+     * Event handler that fires when a drag/drop obj gets a mouseup
+     * @method onMouseUp
+     * @param {Event} e the mouseup event
+     */
+    onMouseUp: function(e) { /* override this */ },
 
-        /**
-         * Reset constraints on all drag and drop objs
-         * @method _onResize
-         * @private
-         * @static
-         */
-        _onResize: function(e) {
-            this._execOnAll("resetConstraints", []);
-        },
+    /**
+     * Override the onAvailable method to do what is needed after the initial
+     * position was determined.
+     * @method onAvailable
+     */
+    onAvailable: function () {
+    },
 
-        /**
-         * Lock all drag and drop functionality
-         * @method lock
-         * @static
-         */
-        lock: function() { this.locked = true; },
+    /*
+     * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
+     * @type Object
+     */
+    defaultPadding : {left:0, right:0, top:0, bottom:0},
 
-        /**
-         * Unlock all drag and drop functionality
-         * @method unlock
-         * @static
-         */
-        unlock: function() { this.locked = false; },
+    /*
+     * Initializes the drag drop object's constraints to restrict movement to a certain element.
+ *
+ * Usage:
+ <pre><code>
+ var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
+                { dragElId: "existingProxyDiv" });
+ dd.startDrag = function(){
+     this.constrainTo("parent-id");
+ };
+ </code></pre>
+ * Or you can initalize it using the {@link Roo.Element} object:
+ <pre><code>
+ Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
+     startDrag : function(){
+         this.constrainTo("parent-id");
+     }
+ });
+ </code></pre>
+     * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
+     * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
+     * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
+     * an object containing the sides to pad. For example: {right:10, bottom:10}
+     * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
+     */
+    constrainTo : function(constrainTo, pad, inContent){
+        if(typeof pad == "number"){
+            pad = {left: pad, right:pad, top:pad, bottom:pad};
+        }
+        pad = pad || this.defaultPadding;
+        var b = Roo.get(this.getEl()).getBox();
+        var ce = Roo.get(constrainTo);
+        var s = ce.getScroll();
+        var c, cd = ce.dom;
+        if(cd == document.body){
+            c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
+        }else{
+            xy = ce.getXY();
+            c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
+        }
 
-        /**
-         * Is drag and drop locked?
-         * @method isLocked
-         * @return {boolean} True if drag and drop is locked, false otherwise.
-         * @static
-         */
-        isLocked: function() { return this.locked; },
 
-        /**
-         * Location cache that is set for all drag drop objects when a drag is
-         * initiated, cleared when the drag is finished.
-         * @property locationCache
-         * @private
-         * @static
-         */
-        locationCache: {},
+        var topSpace = b.y - c.y;
+        var leftSpace = b.x - c.x;
 
-        /**
-         * Set useCache to false if you want to force object the lookup of each
-         * drag and drop linked element constantly during a drag.
-         * @property useCache
-         * @type boolean
-         * @static
-         */
-        useCache: true,
+        this.resetConstraints();
+        this.setXConstraint(leftSpace - (pad.left||0), // left
+                c.width - leftSpace - b.width - (pad.right||0) //right
+        );
+        this.setYConstraint(topSpace - (pad.top||0), //top
+                c.height - topSpace - b.height - (pad.bottom||0) //bottom
+        );
+    },
 
-        /**
-         * The number of pixels that the mouse needs to move after the
-         * mousedown before the drag is initiated.  Default=3;
-         * @property clickPixelThresh
-         * @type int
-         * @static
-         */
-        clickPixelThresh: 3,
+    /**
+     * Returns a reference to the linked element
+     * @method getEl
+     * @return {HTMLElement} the html element
+     */
+    getEl: function() {
+        if (!this._domRef) {
+            this._domRef = Roo.getDom(this.id);
+        }
 
-        /**
-         * The number of milliseconds after the mousedown event to initiate the
-         * drag if we don't get a mouseup event. Default=1000
-         * @property clickTimeThresh
-         * @type int
-         * @static
-         */
-        clickTimeThresh: 350,
+        return this._domRef;
+    },
 
-        /**
-         * Flag that indicates that either the drag pixel threshold or the
-         * mousdown time threshold has been met
-         * @property dragThreshMet
-         * @type boolean
-         * @private
-         * @static
-         */
-        dragThreshMet: false,
+    /**
+     * Returns a reference to the actual element to drag.  By default this is
+     * the same as the html element, but it can be assigned to another
+     * element. An example of this can be found in Roo.dd.DDProxy
+     * @method getDragEl
+     * @return {HTMLElement} the html element
+     */
+    getDragEl: function() {
+        return Roo.getDom(this.dragElId);
+    },
 
-        /**
-         * Timeout used for the click time threshold
-         * @property clickTimeout
-         * @type Object
-         * @private
-         * @static
-         */
-        clickTimeout: null,
+    /**
+     * Sets up the DragDrop object.  Must be called in the constructor of any
+     * Roo.dd.DragDrop subclass
+     * @method init
+     * @param id the id of the linked element
+     * @param {String} sGroup the group of related items
+     * @param {object} config configuration attributes
+     */
+    init: function(id, sGroup, config) {
+        this.initTarget(id, sGroup, config);
+        if (!Roo.isTouch) {
+            Event.on(this.id, "mousedown", this.handleMouseDown, this);
+        }
+        Event.on(this.id, "touchstart", this.handleMouseDown, this);
+        // Event.on(this.id, "selectstart", Event.preventDefault);
+    },
 
-        /**
-         * The X position of the mousedown event stored for later use when a
-         * drag threshold is met.
-         * @property startX
-         * @type int
-         * @private
-         * @static
-         */
-        startX: 0,
+    /**
+     * Initializes Targeting functionality only... the object does not
+     * get a mousedown handler.
+     * @method initTarget
+     * @param id the id of the linked element
+     * @param {String} sGroup the group of related items
+     * @param {object} config configuration attributes
+     */
+    initTarget: function(id, sGroup, config) {
 
-        /**
-         * The Y position of the mousedown event stored for later use when a
-         * drag threshold is met.
-         * @property startY
-         * @type int
-         * @private
-         * @static
-         */
-        startY: 0,
+        // configuration attributes
+        this.config = config || {};
 
-        /**
-         * Each DragDrop instance must be registered with the DragDropMgr.
-         * This is executed in DragDrop.init()
-         * @method regDragDrop
-         * @param {DragDrop} oDD the DragDrop object to register
-         * @param {String} sGroup the name of the group this element belongs to
-         * @static
-         */
-        regDragDrop: function(oDD, sGroup) {
-            if (!this.initialized) { this.init(); }
+        // create a local reference to the drag and drop manager
+        this.DDM = Roo.dd.DDM;
+        // initialize the groups array
+        this.groups = {};
 
-            if (!this.ids[sGroup]) {
-                this.ids[sGroup] = {};
-            }
-            this.ids[sGroup][oDD.id] = oDD;
-        },
+        // assume that we have an element reference instead of an id if the
+        // parameter is not a string
+        if (typeof id !== "string") {
+            id = Roo.id(id);
+        }
 
-        /**
-         * Removes the supplied dd instance from the supplied group. Executed
-         * by DragDrop.removeFromGroup, so don't call this function directly.
-         * @method removeDDFromGroup
-         * @private
-         * @static
-         */
-        removeDDFromGroup: function(oDD, sGroup) {
-            if (!this.ids[sGroup]) {
-                this.ids[sGroup] = {};
-            }
+        // set the id
+        this.id = id;
 
-            var obj = this.ids[sGroup];
-            if (obj && obj[oDD.id]) {
-                delete obj[oDD.id];
-            }
-        },
+        // add to an interaction group
+        this.addToGroup((sGroup) ? sGroup : "default");
 
-        /**
-         * Unregisters a drag and drop item.  This is executed in
-         * DragDrop.unreg, use that method instead of calling this directly.
-         * @method _remove
-         * @private
-         * @static
-         */
-        _remove: function(oDD) {
-            for (var g in oDD.groups) {
-                if (g && this.ids[g][oDD.id]) {
-                    delete this.ids[g][oDD.id];
-                }
-            }
-            delete this.handleIds[oDD.id];
-        },
+        // We don't want to register this as the handle with the manager
+        // so we just set the id rather than calling the setter.
+        this.handleElId = id;
 
-        /**
-         * Each DragDrop handle element must be registered.  This is done
-         * automatically when executing DragDrop.setHandleElId()
-         * @method regHandle
-         * @param {String} sDDId the DragDrop id this element is a handle for
-         * @param {String} sHandleId the id of the element that is the drag
-         * handle
-         * @static
-         */
-        regHandle: function(sDDId, sHandleId) {
-            if (!this.handleIds[sDDId]) {
-                this.handleIds[sDDId] = {};
-            }
-            this.handleIds[sDDId][sHandleId] = sHandleId;
-        },
+        // the linked element is the element that gets dragged by default
+        this.setDragElId(id);
 
-        /**
-         * Utility function to determine if a given element has been
-         * registered as a drag drop item.
-         * @method isDragDrop
-         * @param {String} id the element id to check
-         * @return {boolean} true if this element is a DragDrop item,
-         * false otherwise
-         * @static
-         */
-        isDragDrop: function(id) {
-            return ( this.getDDById(id) ) ? true : false;
-        },
+        // by default, clicked anchors will not start drag operations.
+        this.invalidHandleTypes = { A: "A" };
+        this.invalidHandleIds = {};
+        this.invalidHandleClasses = [];
 
-        /**
-         * Returns the drag and drop instances that are in all groups the
-         * passed in instance belongs to.
-         * @method getRelated
-         * @param {DragDrop} p_oDD the obj to get related data for
-         * @param {boolean} bTargetsOnly if true, only return targetable objs
-         * @return {DragDrop[]} the related instances
-         * @static
-         */
-        getRelated: function(p_oDD, bTargetsOnly) {
-            var oDDs = [];
-            for (var i in p_oDD.groups) {
-                for (j in this.ids[i]) {
-                    var dd = this.ids[i][j];
-                    if (! this.isTypeOfDD(dd)) {
-                        continue;
-                    }
-                    if (!bTargetsOnly || dd.isTarget) {
-                        oDDs[oDDs.length] = dd;
-                    }
-                }
-            }
+        this.applyConfig();
 
-            return oDDs;
-        },
+        this.handleOnAvailable();
+    },
 
-        /**
-         * Returns true if the specified dd target is a legal target for
-         * the specifice drag obj
-         * @method isLegalTarget
-         * @param {DragDrop} the drag obj
-         * @param {DragDrop} the target
-         * @return {boolean} true if the target is a legal target for the
-         * dd obj
-         * @static
-         */
-        isLegalTarget: function (oDD, oTargetDD) {
-            var targets = this.getRelated(oDD, true);
-            for (var i=0, len=targets.length;i<len;++i) {
-                if (targets[i].id == oTargetDD.id) {
-                    return true;
-                }
-            }
+    /**
+     * Applies the configuration parameters that were passed into the constructor.
+     * This is supposed to happen at each level through the inheritance chain.  So
+     * a DDProxy implentation will execute apply config on DDProxy, DD, and
+     * DragDrop in order to get all of the parameters that are available in
+     * each object.
+     * @method applyConfig
+     */
+    applyConfig: function() {
 
-            return false;
-        },
+        // configurable properties:
+        //    padding, isTarget, maintainOffset, primaryButtonOnly
+        this.padding           = this.config.padding || [0, 0, 0, 0];
+        this.isTarget          = (this.config.isTarget !== false);
+        this.maintainOffset    = (this.config.maintainOffset);
+        this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
 
-        /**
-         * My goal is to be able to transparently determine if an object is
-         * typeof DragDrop, and the exact subclass of DragDrop.  typeof
-         * returns "object", oDD.constructor.toString() always returns
-         * "DragDrop" and not the name of the subclass.  So for now it just
-         * evaluates a well-known variable in DragDrop.
-         * @method isTypeOfDD
-         * @param {Object} the object to evaluate
-         * @return {boolean} true if typeof oDD = DragDrop
-         * @static
-         */
-        isTypeOfDD: function (oDD) {
-            return (oDD && oDD.__ygDragDrop);
-        },
+    },
 
-        /**
-         * Utility function to determine if a given element has been
-         * registered as a drag drop handle for the given Drag Drop object.
-         * @method isHandle
-         * @param {String} id the element id to check
-         * @return {boolean} true if this element is a DragDrop handle, false
-         * otherwise
-         * @static
-         */
-        isHandle: function(sDDId, sHandleId) {
-            return ( this.handleIds[sDDId] &&
-                            this.handleIds[sDDId][sHandleId] );
-        },
+    /**
+     * Executed when the linked element is available
+     * @method handleOnAvailable
+     * @private
+     */
+    handleOnAvailable: function() {
+        this.available = true;
+        this.resetConstraints();
+        this.onAvailable();
+    },
 
-        /**
-         * Returns the DragDrop instance for a given id
-         * @method getDDById
-         * @param {String} id the id of the DragDrop object
-         * @return {DragDrop} the drag drop object, null if it is not found
-         * @static
-         */
-        getDDById: function(id) {
-            for (var i in this.ids) {
-                if (this.ids[i][id]) {
-                    return this.ids[i][id];
-                }
-            }
-            return null;
-        },
+     /**
+     * Configures the padding for the target zone in px.  Effectively expands
+     * (or reduces) the virtual object size for targeting calculations.
+     * Supports css-style shorthand; if only one parameter is passed, all sides
+     * will have that padding, and if only two are passed, the top and bottom
+     * will have the first param, the left and right the second.
+     * @method setPadding
+     * @param {int} iTop    Top pad
+     * @param {int} iRight  Right pad
+     * @param {int} iBot    Bot pad
+     * @param {int} iLeft   Left pad
+     */
+    setPadding: function(iTop, iRight, iBot, iLeft) {
+        // this.padding = [iLeft, iRight, iTop, iBot];
+        if (!iRight && 0 !== iRight) {
+            this.padding = [iTop, iTop, iTop, iTop];
+        } else if (!iBot && 0 !== iBot) {
+            this.padding = [iTop, iRight, iTop, iRight];
+        } else {
+            this.padding = [iTop, iRight, iBot, iLeft];
+        }
+    },
 
-        /**
-         * Fired after a registered DragDrop object gets the mousedown event.
-         * Sets up the events required to track the object being dragged
-         * @method handleMouseDown
-         * @param {Event} e the event
-         * @param oDD the DragDrop object being dragged
-         * @private
-         * @static
-         */
-        handleMouseDown: function(e, oDD) {
-            if(Roo.QuickTips){
-                Roo.QuickTips.disable();
-            }
-            this.currentTarget = e.getTarget();
+    /**
+     * Stores the initial placement of the linked element.
+     * @method setInitialPosition
+     * @param {int} diffX   the X offset, default 0
+     * @param {int} diffY   the Y offset, default 0
+     */
+    setInitPosition: function(diffX, diffY) {
+        var el = this.getEl();
 
-            this.dragCurrent = oDD;
+        if (!this.DDM.verifyEl(el)) {
+            return;
+        }
 
-            var el = oDD.getEl();
+        var dx = diffX || 0;
+        var dy = diffY || 0;
 
-            // track start position
-            this.startX = e.getPageX();
-            this.startY = e.getPageY();
+        var p = Dom.getXY( el );
 
-            this.deltaX = this.startX - el.offsetLeft;
-            this.deltaY = this.startY - el.offsetTop;
+        this.initPageX = p[0] - dx;
+        this.initPageY = p[1] - dy;
 
-            this.dragThreshMet = false;
+        this.lastPageX = p[0];
+        this.lastPageY = p[1];
 
-            this.clickTimeout = setTimeout(
-                    function() {
-                        var DDM = Roo.dd.DDM;
-                        DDM.startDrag(DDM.startX, DDM.startY);
-                    },
-                    this.clickTimeThresh );
-        },
 
-        /**
-         * Fired when either the drag pixel threshol or the mousedown hold
-         * time threshold has been met.
-         * @method startDrag
-         * @param x {int} the X position of the original mousedown
-         * @param y {int} the Y position of the original mousedown
-         * @static
-         */
-        startDrag: function(x, y) {
-            clearTimeout(this.clickTimeout);
-            if (this.dragCurrent) {
-                this.dragCurrent.b4StartDrag(x, y);
-                this.dragCurrent.startDrag(x, y);
-            }
-            this.dragThreshMet = true;
-        },
+        this.setStartPosition(p);
+    },
 
-        /**
-         * Internal function to handle the mouseup event.  Will be invoked
-         * from the context of the document.
-         * @method handleMouseUp
-         * @param {Event} e the event
-         * @private
-         * @static
-         */
-        handleMouseUp: function(e) {
+    /**
+     * Sets the start position of the element.  This is set when the obj
+     * is initialized, the reset when a drag is started.
+     * @method setStartPosition
+     * @param pos current position (from previous lookup)
+     * @private
+     */
+    setStartPosition: function(pos) {
+        var p = pos || Dom.getXY( this.getEl() );
+        this.deltaSetXY = null;
 
-            if(Roo.QuickTips){
-                Roo.QuickTips.enable();
-            }
-            if (! this.dragCurrent) {
-                return;
-            }
+        this.startPageX = p[0];
+        this.startPageY = p[1];
+    },
 
-            clearTimeout(this.clickTimeout);
+    /**
+     * Add this instance to a group of related drag/drop objects.  All
+     * instances belong to at least one group, and can belong to as many
+     * groups as needed.
+     * @method addToGroup
+     * @param sGroup {string} the name of the group
+     */
+    addToGroup: function(sGroup) {
+        this.groups[sGroup] = true;
+        this.DDM.regDragDrop(this, sGroup);
+    },
 
-            if (this.dragThreshMet) {
-                this.fireEvents(e, true);
-            } else {
-            }
+    /**
+     * Remove's this instance from the supplied interaction group
+     * @method removeFromGroup
+     * @param {string}  sGroup  The group to drop
+     */
+    removeFromGroup: function(sGroup) {
+        if (this.groups[sGroup]) {
+            delete this.groups[sGroup];
+        }
 
-            this.stopDrag(e);
+        this.DDM.removeDDFromGroup(this, sGroup);
+    },
 
-            this.stopEvent(e);
-        },
+    /**
+     * Allows you to specify that an element other than the linked element
+     * will be moved with the cursor during a drag
+     * @method setDragElId
+     * @param id {string} the id of the element that will be used to initiate the drag
+     */
+    setDragElId: function(id) {
+        this.dragElId = id;
+    },
 
-        /**
-         * Utility to stop event propagation and event default, if these
-         * features are turned on.
-         * @method stopEvent
-         * @param {Event} e the event as returned by this.getEvent()
-         * @static
-         */
-        stopEvent: function(e){
-            if(this.stopPropagation) {
-                e.stopPropagation();
-            }
+    /**
+     * Allows you to specify a child of the linked element that should be
+     * used to initiate the drag operation.  An example of this would be if
+     * you have a content div with text and links.  Clicking anywhere in the
+     * content area would normally start the drag operation.  Use this method
+     * to specify that an element inside of the content div is the element
+     * that starts the drag operation.
+     * @method setHandleElId
+     * @param id {string} the id of the element that will be used to
+     * initiate the drag.
+     */
+    setHandleElId: function(id) {
+        if (typeof id !== "string") {
+            id = Roo.id(id);
+        }
+        this.handleElId = id;
+        this.DDM.regHandle(this.id, id);
+    },
 
-            if (this.preventDefault) {
-                e.preventDefault();
-            }
-        },
+    /**
+     * Allows you to set an element outside of the linked element as a drag
+     * handle
+     * @method setOuterHandleElId
+     * @param id the id of the element that will be used to initiate the drag
+     */
+    setOuterHandleElId: function(id) {
+        if (typeof id !== "string") {
+            id = Roo.id(id);
+        }
+        Event.on(id, "mousedown",
+                this.handleMouseDown, this);
+        this.setHandleElId(id);
 
-        /**
-         * Internal function to clean up event handlers after the drag
-         * operation is complete
-         * @method stopDrag
-         * @param {Event} e the event
-         * @private
-         * @static
-         */
-        stopDrag: function(e) {
-            // Fire the drag end event for the item that was dragged
-            if (this.dragCurrent) {
-                if (this.dragThreshMet) {
-                    this.dragCurrent.b4EndDrag(e);
-                    this.dragCurrent.endDrag(e);
-                }
+        this.hasOuterHandles = true;
+    },
 
-                this.dragCurrent.onMouseUp(e);
-            }
+    /**
+     * Remove all drag and drop hooks for this element
+     * @method unreg
+     */
+    unreg: function() {
+        Event.un(this.id, "mousedown",
+                this.handleMouseDown);
+        Event.un(this.id, "touchstart",
+                this.handleMouseDown);
+        this._domRef = null;
+        this.DDM._remove(this);
+    },
 
-            this.dragCurrent = null;
-            this.dragOvers = {};
-        },
+    destroy : function(){
+        this.unreg();
+    },
 
-        /**
-         * Internal function to handle the mousemove event.  Will be invoked
-         * from the context of the html element.
-         *
-         * @TODO figure out what we can do about mouse events lost when the
-         * user drags objects beyond the window boundary.  Currently we can
-         * detect this in internet explorer by verifying that the mouse is
-         * down during the mousemove event.  Firefox doesn't give us the
-         * button state on the mousemove event.
-         * @method handleMouseMove
-         * @param {Event} e the event
-         * @private
-         * @static
-         */
-        handleMouseMove: function(e) {
-            if (! this.dragCurrent) {
-                return true;
-            }
+    /**
+     * Returns true if this instance is locked, or the drag drop mgr is locked
+     * (meaning that all drag/drop is disabled on the page.)
+     * @method isLocked
+     * @return {boolean} true if this obj or all drag/drop is locked, else
+     * false
+     */
+    isLocked: function() {
+        return (this.DDM.isLocked() || this.locked);
+    },
 
-            // var button = e.which || e.button;
+    /**
+     * Fired when this object is clicked
+     * @method handleMouseDown
+     * @param {Event} e
+     * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
+     * @private
+     */
+    handleMouseDown: function(e, oDD){
+     
+        if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
+            //Roo.log('not touch/ button !=0');
+            return;
+        }
+        if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
+            return; // double touch..
+        }
+        
 
-            // check for IE mouseup outside of page boundary
-            if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
-                this.stopEvent(e);
-                return this.handleMouseUp(e);
-            }
+        if (this.isLocked()) {
+            //Roo.log('locked');
+            return;
+        }
 
-            if (!this.dragThreshMet) {
-                var diffX = Math.abs(this.startX - e.getPageX());
-                var diffY = Math.abs(this.startY - e.getPageY());
-                if (diffX > this.clickPixelThresh ||
-                            diffY > this.clickPixelThresh) {
-                    this.startDrag(this.startX, this.startY);
-                }
-            }
+        this.DDM.refreshCache(this.groups);
+//        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
+        var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
+        if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
+            //Roo.log('no outer handes or not over target');
+                // do nothing.
+        } else {
+//            Roo.log('check validator');
+            if (this.clickValidator(e)) {
+//                Roo.log('validate success');
+                // set the initial element position
+                this.setStartPosition();
 
-            if (this.dragThreshMet) {
-                this.dragCurrent.b4Drag(e);
-                this.dragCurrent.onDrag(e);
-                if(!this.dragCurrent.moveOnly){
-                    this.fireEvents(e, false);
-                }
-            }
 
-            this.stopEvent(e);
+                this.b4MouseDown(e);
+                this.onMouseDown(e);
 
-            return true;
-        },
+                this.DDM.handleMouseDown(e, this);
 
-        /**
-         * Iterates over all of the DragDrop elements to find ones we are
-         * hovering over or dropping on
-         * @method fireEvents
-         * @param {Event} e the event
-         * @param {boolean} isDrop is this a drop op or a mouseover op?
-         * @private
-         * @static
-         */
-        fireEvents: function(e, isDrop) {
-            var dc = this.dragCurrent;
+                this.DDM.stopEvent(e);
+            } else {
 
-            // If the user did the mouse up outside of the window, we could
-            // get here even though we have ended the drag.
-            if (!dc || dc.isLocked()) {
-                return;
-            }
 
-            var pt = e.getPoint();
+            }
+        }
+    },
 
-            // cache the previous dragOver array
-            var oldOvers = [];
+    clickValidator: function(e) {
+        var target = e.getTarget();
+        return ( this.isValidHandleChild(target) &&
+                    (this.id == this.handleElId ||
+                        this.DDM.handleWasClicked(target, this.id)) );
+    },
 
-            var outEvts   = [];
-            var overEvts  = [];
-            var dropEvts  = [];
-            var enterEvts = [];
+    /**
+     * Allows you to specify a tag name that should not start a drag operation
+     * when clicked.  This is designed to facilitate embedding links within a
+     * drag handle that do something other than start the drag.
+     * @method addInvalidHandleType
+     * @param {string} tagName the type of element to exclude
+     */
+    addInvalidHandleType: function(tagName) {
+        var type = tagName.toUpperCase();
+        this.invalidHandleTypes[type] = type;
+    },
 
-            // Check to see if the object(s) we were hovering over is no longer
-            // being hovered over so we can fire the onDragOut event
-            for (var i in this.dragOvers) {
+    /**
+     * Lets you to specify an element id for a child of a drag handle
+     * that should not initiate a drag
+     * @method addInvalidHandleId
+     * @param {string} id the element id of the element you wish to ignore
+     */
+    addInvalidHandleId: function(id) {
+        if (typeof id !== "string") {
+            id = Roo.id(id);
+        }
+        this.invalidHandleIds[id] = id;
+    },
 
-                var ddo = this.dragOvers[i];
+    /**
+     * Lets you specify a css class of elements that will not initiate a drag
+     * @method addInvalidHandleClass
+     * @param {string} cssClass the class of the elements you wish to ignore
+     */
+    addInvalidHandleClass: function(cssClass) {
+        this.invalidHandleClasses.push(cssClass);
+    },
 
-                if (! this.isTypeOfDD(ddo)) {
-                    continue;
-                }
+    /**
+     * Unsets an excluded tag name set by addInvalidHandleType
+     * @method removeInvalidHandleType
+     * @param {string} tagName the type of element to unexclude
+     */
+    removeInvalidHandleType: function(tagName) {
+        var type = tagName.toUpperCase();
+        // this.invalidHandleTypes[type] = null;
+        delete this.invalidHandleTypes[type];
+    },
 
-                if (! this.isOverTarget(pt, ddo, this.mode)) {
-                    outEvts.push( ddo );
-                }
+    /**
+     * Unsets an invalid handle id
+     * @method removeInvalidHandleId
+     * @param {string} id the id of the element to re-enable
+     */
+    removeInvalidHandleId: function(id) {
+        if (typeof id !== "string") {
+            id = Roo.id(id);
+        }
+        delete this.invalidHandleIds[id];
+    },
 
-                oldOvers[i] = true;
-                delete this.dragOvers[i];
+    /**
+     * Unsets an invalid css class
+     * @method removeInvalidHandleClass
+     * @param {string} cssClass the class of the element(s) you wish to
+     * re-enable
+     */
+    removeInvalidHandleClass: function(cssClass) {
+        for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
+            if (this.invalidHandleClasses[i] == cssClass) {
+                delete this.invalidHandleClasses[i];
             }
+        }
+    },
 
-            for (var sGroup in dc.groups) {
-
-                if ("string" != typeof sGroup) {
-                    continue;
-                }
+    /**
+     * Checks the tag exclusion list to see if this click should be ignored
+     * @method isValidHandleChild
+     * @param {HTMLElement} node the HTMLElement to evaluate
+     * @return {boolean} true if this is a valid tag type, false if not
+     */
+    isValidHandleChild: function(node) {
 
-                for (i in this.ids[sGroup]) {
-                    var oDD = this.ids[sGroup][i];
-                    if (! this.isTypeOfDD(oDD)) {
-                        continue;
-                    }
+        var valid = true;
+        // var n = (node.nodeName == "#text") ? node.parentNode : node;
+        var nodeName;
+        try {
+            nodeName = node.nodeName.toUpperCase();
+        } catch(e) {
+            nodeName = node.nodeName;
+        }
+        valid = valid && !this.invalidHandleTypes[nodeName];
+        valid = valid && !this.invalidHandleIds[node.id];
 
-                    if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
-                        if (this.isOverTarget(pt, oDD, this.mode)) {
-                            // look for drop interactions
-                            if (isDrop) {
-                                dropEvts.push( oDD );
-                            // look for drag enter and drag over interactions
-                            } else {
+        for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
+            valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
+        }
 
-                                // initial drag over: dragEnter fires
-                                if (!oldOvers[oDD.id]) {
-                                    enterEvts.push( oDD );
-                                // subsequent drag overs: dragOver fires
-                                } else {
-                                    overEvts.push( oDD );
-                                }
 
-                                this.dragOvers[oDD.id] = oDD;
-                            }
-                        }
-                    }
-                }
-            }
+        return valid;
 
-            if (this.mode) {
-                if (outEvts.length) {
-                    dc.b4DragOut(e, outEvts);
-                    dc.onDragOut(e, outEvts);
-                }
+    },
 
-                if (enterEvts.length) {
-                    dc.onDragEnter(e, enterEvts);
-                }
+    /**
+     * Create the array of horizontal tick marks if an interval was specified
+     * in setXConstraint().
+     * @method setXTicks
+     * @private
+     */
+    setXTicks: function(iStartX, iTickSize) {
+        this.xTicks = [];
+        this.xTickSize = iTickSize;
 
-                if (overEvts.length) {
-                    dc.b4DragOver(e, overEvts);
-                    dc.onDragOver(e, overEvts);
-                }
+        var tickMap = {};
 
-                if (dropEvts.length) {
-                    dc.b4DragDrop(e, dropEvts);
-                    dc.onDragDrop(e, dropEvts);
-                }
+        for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
+            if (!tickMap[i]) {
+                this.xTicks[this.xTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
 
-            } else {
-                // fire dragout events
-                var len = 0;
-                for (i=0, len=outEvts.length; i<len; ++i) {
-                    dc.b4DragOut(e, outEvts[i].id);
-                    dc.onDragOut(e, outEvts[i].id);
-                }
+        for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
+            if (!tickMap[i]) {
+                this.xTicks[this.xTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
 
-                // fire enter events
-                for (i=0,len=enterEvts.length; i<len; ++i) {
-                    // dc.b4DragEnter(e, oDD.id);
-                    dc.onDragEnter(e, enterEvts[i].id);
-                }
+        this.xTicks.sort(this.DDM.numericSort) ;
+    },
 
-                // fire over events
-                for (i=0,len=overEvts.length; i<len; ++i) {
-                    dc.b4DragOver(e, overEvts[i].id);
-                    dc.onDragOver(e, overEvts[i].id);
-                }
+    /**
+     * Create the array of vertical tick marks if an interval was specified in
+     * setYConstraint().
+     * @method setYTicks
+     * @private
+     */
+    setYTicks: function(iStartY, iTickSize) {
+        this.yTicks = [];
+        this.yTickSize = iTickSize;
 
-                // fire drop events
-                for (i=0, len=dropEvts.length; i<len; ++i) {
-                    dc.b4DragDrop(e, dropEvts[i].id);
-                    dc.onDragDrop(e, dropEvts[i].id);
-                }
+        var tickMap = {};
 
+        for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
+            if (!tickMap[i]) {
+                this.yTicks[this.yTicks.length] = i;
+                tickMap[i] = true;
             }
+        }
 
-            // notify about a drop that did not find a target
-            if (isDrop && !dropEvts.length) {
-                dc.onInvalidDrop(e);
+        for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
+            if (!tickMap[i]) {
+                this.yTicks[this.yTicks.length] = i;
+                tickMap[i] = true;
             }
+        }
 
-        },
+        this.yTicks.sort(this.DDM.numericSort) ;
+    },
 
-        /**
-         * Helper function for getting the best match from the list of drag
-         * and drop objects returned by the drag and drop events when we are
-         * in INTERSECT mode.  It returns either the first object that the
-         * cursor is over, or the object that has the greatest overlap with
-         * the dragged element.
-         * @method getBestMatch
-         * @param  {DragDrop[]} dds The array of drag and drop objects
-         * targeted
-         * @return {DragDrop}       The best single match
-         * @static
-         */
-        getBestMatch: function(dds) {
-            var winner = null;
-            // Return null if the input is not what we expect
-            //if (!dds || !dds.length || dds.length == 0) {
-               // winner = null;
-            // If there is only one item, it wins
-            //} else if (dds.length == 1) {
+    /**
+     * By default, the element can be dragged any place on the screen.  Use
+     * this method to limit the horizontal travel of the element.  Pass in
+     * 0,0 for the parameters if you want to lock the drag to the y axis.
+     * @method setXConstraint
+     * @param {int} iLeft the number of pixels the element can move to the left
+     * @param {int} iRight the number of pixels the element can move to the
+     * right
+     * @param {int} iTickSize optional parameter for specifying that the
+     * element
+     * should move iTickSize pixels at a time.
+     */
+    setXConstraint: function(iLeft, iRight, iTickSize) {
+        this.leftConstraint = iLeft;
+        this.rightConstraint = iRight;
 
-            var len = dds.length;
+        this.minX = this.initPageX - iLeft;
+        this.maxX = this.initPageX + iRight;
+        if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
 
-            if (len == 1) {
-                winner = dds[0];
-            } else {
-                // Loop through the targeted items
-                for (var i=0; i<len; ++i) {
-                    var dd = dds[i];
-                    // If the cursor is over the object, it wins.  If the
-                    // cursor is over multiple matches, the first one we come
-                    // to wins.
-                    if (dd.cursorIsOver) {
-                        winner = dd;
-                        break;
-                    // Otherwise the object with the most overlap wins
-                    } else {
-                        if (!winner ||
-                            winner.overlap.getArea() < dd.overlap.getArea()) {
-                            winner = dd;
-                        }
-                    }
-                }
-            }
+        this.constrainX = true;
+    },
 
-            return winner;
-        },
+    /**
+     * Clears any constraints applied to this instance.  Also clears ticks
+     * since they can't exist independent of a constraint at this time.
+     * @method clearConstraints
+     */
+    clearConstraints: function() {
+        this.constrainX = false;
+        this.constrainY = false;
+        this.clearTicks();
+    },
 
-        /**
-         * Refreshes the cache of the top-left and bottom-right points of the
-         * drag and drop objects in the specified group(s).  This is in the
-         * format that is stored in the drag and drop instance, so typical
-         * usage is:
-         * <code>
-         * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
-         * </code>
-         * Alternatively:
-         * <code>
-         * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
-         * </code>
-         * @TODO this really should be an indexed array.  Alternatively this
-         * method could accept both.
-         * @method refreshCache
-         * @param {Object} groups an associative array of groups to refresh
-         * @static
-         */
-        refreshCache: function(groups) {
-            for (var sGroup in groups) {
-                if ("string" != typeof sGroup) {
-                    continue;
-                }
-                for (var i in this.ids[sGroup]) {
-                    var oDD = this.ids[sGroup][i];
+    /**
+     * Clears any tick interval defined for this instance
+     * @method clearTicks
+     */
+    clearTicks: function() {
+        this.xTicks = null;
+        this.yTicks = null;
+        this.xTickSize = 0;
+        this.yTickSize = 0;
+    },
 
-                    if (this.isTypeOfDD(oDD)) {
-                    // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
-                        var loc = this.getLocation(oDD);
-                        if (loc) {
-                            this.locationCache[oDD.id] = loc;
-                        } else {
-                            delete this.locationCache[oDD.id];
-                            // this will unregister the drag and drop object if
-                            // the element is not in a usable state
-                            // oDD.unreg();
-                        }
-                    }
-                }
-            }
-        },
+    /**
+     * By default, the element can be dragged any place on the screen.  Set
+     * this to limit the vertical travel of the element.  Pass in 0,0 for the
+     * parameters if you want to lock the drag to the x axis.
+     * @method setYConstraint
+     * @param {int} iUp the number of pixels the element can move up
+     * @param {int} iDown the number of pixels the element can move down
+     * @param {int} iTickSize optional parameter for specifying that the
+     * element should move iTickSize pixels at a time.
+     */
+    setYConstraint: function(iUp, iDown, iTickSize) {
+        this.topConstraint = iUp;
+        this.bottomConstraint = iDown;
 
-        /**
-         * This checks to make sure an element exists and is in the DOM.  The
-         * main purpose is to handle cases where innerHTML is used to remove
-         * drag and drop objects from the DOM.  IE provides an 'unspecified
-         * error' when trying to access the offsetParent of such an element
-         * @method verifyEl
-         * @param {HTMLElement} el the element to check
-         * @return {boolean} true if the element looks usable
-         * @static
-         */
-        verifyEl: function(el) {
-            if (el) {
-                var parent;
-                if(Roo.isIE){
-                    try{
-                        parent = el.offsetParent;
-                    }catch(e){}
-                }else{
-                    parent = el.offsetParent;
-                }
-                if (parent) {
-                    return true;
-                }
-            }
+        this.minY = this.initPageY - iUp;
+        this.maxY = this.initPageY + iDown;
+        if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
 
-            return false;
-        },
+        this.constrainY = true;
 
-        /**
-         * Returns a Region object containing the drag and drop element's position
-         * and size, including the padding configured for it
-         * @method getLocation
-         * @param {DragDrop} oDD the drag and drop object to get the
-         *                       location for
-         * @return {Roo.lib.Region} a Region object representing the total area
-         *                             the element occupies, including any padding
-         *                             the instance is configured for.
-         * @static
-         */
-        getLocation: function(oDD) {
-            if (! this.isTypeOfDD(oDD)) {
-                return null;
-            }
+    },
 
-            var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
+    /**
+     * resetConstraints must be called if you manually reposition a dd element.
+     * @method resetConstraints
+     * @param {boolean} maintainOffset
+     */
+    resetConstraints: function() {
 
-            try {
-                pos= Roo.lib.Dom.getXY(el);
-            } catch (e) { }
 
-            if (!pos) {
-                return null;
-            }
+        // Maintain offsets if necessary
+        if (this.initPageX || this.initPageX === 0) {
+            // figure out how much this thing has moved
+            var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
+            var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
 
-            x1 = pos[0];
-            x2 = x1 + el.offsetWidth;
-            y1 = pos[1];
-            y2 = y1 + el.offsetHeight;
+            this.setInitPosition(dx, dy);
 
-            t = y1 - oDD.padding[0];
-            r = x2 + oDD.padding[1];
-            b = y2 + oDD.padding[2];
-            l = x1 - oDD.padding[3];
+        // This is the first time we have detected the element's position
+        } else {
+            this.setInitPosition();
+        }
 
-            return new Roo.lib.Region( t, r, b, l );
-        },
+        if (this.constrainX) {
+            this.setXConstraint( this.leftConstraint,
+                                 this.rightConstraint,
+                                 this.xTickSize        );
+        }
 
-        /**
-         * Checks the cursor location to see if it over the target
-         * @method isOverTarget
-         * @param {Roo.lib.Point} pt The point to evaluate
-         * @param {DragDrop} oTarget the DragDrop object we are inspecting
-         * @return {boolean} true if the mouse is over the target
-         * @private
-         * @static
-         */
-        isOverTarget: function(pt, oTarget, intersect) {
-            // use cache if available
-            var loc = this.locationCache[oTarget.id];
-            if (!loc || !this.useCache) {
-                loc = this.getLocation(oTarget);
-                this.locationCache[oTarget.id] = loc;
+        if (this.constrainY) {
+            this.setYConstraint( this.topConstraint,
+                                 this.bottomConstraint,
+                                 this.yTickSize         );
+        }
+    },
 
-            }
+    /**
+     * Normally the drag element is moved pixel by pixel, but we can specify
+     * that it move a number of pixels at a time.  This method resolves the
+     * location when we have it set up like this.
+     * @method getTick
+     * @param {int} val where we want to place the object
+     * @param {int[]} tickArray sorted array of valid points
+     * @return {int} the closest tick
+     * @private
+     */
+    getTick: function(val, tickArray) {
 
-            if (!loc) {
-                return false;
+        if (!tickArray) {
+            // If tick interval is not defined, it is effectively 1 pixel,
+            // so we return the value passed to us.
+            return val;
+        } else if (tickArray[0] >= val) {
+            // The value is lower than the first tick, so we return the first
+            // tick.
+            return tickArray[0];
+        } else {
+            for (var i=0, len=tickArray.length; i<len; ++i) {
+                var next = i + 1;
+                if (tickArray[next] && tickArray[next] >= val) {
+                    var diff1 = val - tickArray[i];
+                    var diff2 = tickArray[next] - val;
+                    return (diff2 > diff1) ? tickArray[i] : tickArray[next];
+                }
             }
 
-            oTarget.cursorIsOver = loc.contains( pt );
+            // The value is larger than the last tick, so we return the last
+            // tick.
+            return tickArray[tickArray.length - 1];
+        }
+    },
 
-            // DragDrop is using this as a sanity check for the initial mousedown
-            // in this case we are done.  In POINT mode, if the drag obj has no
-            // contraints, we are also done. Otherwise we need to evaluate the
-            // location of the target as related to the actual location of the
-            // dragged element.
-            var dc = this.dragCurrent;
-            if (!dc || !dc.getTargetCoord ||
-                    (!intersect && !dc.constrainX && !dc.constrainY)) {
-                return oTarget.cursorIsOver;
-            }
+    /**
+     * toString method
+     * @method toString
+     * @return {string} string representation of the dd obj
+     */
+    toString: function() {
+        return ("DragDrop " + this.id);
+    }
+
+});
+
+})();
+/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
 
-            oTarget.overlap = null;
 
-            // Get the current location of the drag element, this is the
-            // location of the mouse event less the delta that represents
-            // where the original mousedown happened on the element.  We
-            // need to consider constraints and ticks as well.
-            var pos = dc.getTargetCoord(pt.x, pt.y);
+/**
+ * The drag and drop utility provides a framework for building drag and drop
+ * applications.  In addition to enabling drag and drop for specific elements,
+ * the drag and drop elements are tracked by the manager class, and the
+ * interactions between the various elements are tracked during the drag and
+ * the implementing code is notified about these important moments.
+ */
 
-            var el = dc.getDragEl();
-            var curRegion = new Roo.lib.Region( pos.y,
-                                                   pos.x + el.offsetWidth,
-                                                   pos.y + el.offsetHeight,
-                                                   pos.x );
+// Only load the library once.  Rewriting the manager class would orphan
+// existing drag and drop instances.
+if (!Roo.dd.DragDropMgr) {
 
-            var overlap = curRegion.intersect(loc);
+/**
+ * @class Roo.dd.DragDropMgr
+ * DragDropMgr is a singleton that tracks the element interaction for
+ * 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.
+ * @static
+ */
+Roo.dd.DragDropMgr = function() {
 
-            if (overlap) {
-                oTarget.overlap = overlap;
-                return (intersect) ? true : oTarget.cursorIsOver;
-            } else {
-                return false;
-            }
-        },
+    var Event = Roo.EventManager;
+
+    return {
 
         /**
-         * unload event handler
-         * @method _onUnload
+         * Two dimensional Array of registered DragDrop objects.  The first
+         * dimension is the DragDrop item group, the second the DragDrop
+         * object.
+         * @property ids
+         * @type {string: string}
          * @private
          * @static
          */
-        _onUnload: function(e, me) {
-            Roo.dd.DragDropMgr.unregAll();
-        },
+        ids: {},
 
         /**
-         * Cleans up the drag and drop events and objects.
-         * @method unregAll
+         * Array of element ids defined as drag handles.  Used to determine
+         * if the element that generated the mousedown event is actually the
+         * handle and not the html element itself.
+         * @property handleIds
+         * @type {string: string}
          * @private
          * @static
          */
-        unregAll: function() {
-
-            if (this.dragCurrent) {
-                this.stopDrag();
-                this.dragCurrent = null;
-            }
-
-            this._execOnAll("unreg", []);
-
-            for (i in this.elementCache) {
-                delete this.elementCache[i];
-            }
-
-            this.elementCache = {};
-            this.ids = {};
-        },
+        handleIds: {},
 
         /**
-         * A cache of DOM elements
-         * @property elementCache
+         * the DragDrop object that is currently being dragged
+         * @property dragCurrent
+         * @type DragDrop
          * @private
          * @static
-         */
-        elementCache: {},
+         **/
+        dragCurrent: null,
 
         /**
-         * Get the wrapper for the DOM element specified
-         * @method getElWrapper
-         * @param {String} id the id of the element to get
-         * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
+         * the DragDrop object(s) that are being hovered over
+         * @property dragOvers
+         * @type Array
          * @private
-         * @deprecated This wrapper isn't that useful
          * @static
          */
-        getElWrapper: function(id) {
-            var oWrapper = this.elementCache[id];
-            if (!oWrapper || !oWrapper.el) {
-                oWrapper = this.elementCache[id] =
-                    new this.ElementWrapper(Roo.getDom(id));
-            }
-            return oWrapper;
-        },
+        dragOvers: {},
 
         /**
-         * Returns the actual DOM element
-         * @method getElement
-         * @param {String} id the id of the elment to get
-         * @return {Object} The element
-         * @deprecated use Roo.getDom instead
+         * the X distance between the cursor and the object being dragged
+         * @property deltaX
+         * @type int
+         * @private
          * @static
          */
-        getElement: function(id) {
-            return Roo.getDom(id);
-        },
+        deltaX: 0,
 
         /**
-         * Returns the style property for the DOM element (i.e.,
-         * document.getElById(id).style)
-         * @method getCss
-         * @param {String} id the id of the elment to get
-         * @return {Object} The style property of the element
-         * @deprecated use Roo.getDom instead
+         * the Y distance between the cursor and the object being dragged
+         * @property deltaY
+         * @type int
+         * @private
          * @static
          */
-        getCss: function(id) {
-            var el = Roo.getDom(id);
-            return (el) ? el.style : null;
-        },
+        deltaY: 0,
 
         /**
-         * Inner class for cached elements
-         * @class DragDropMgr.ElementWrapper
-         * @for DragDropMgr
-         * @private
-         * @deprecated
+         * Flag to determine if we should prevent the default behavior of the
+         * events we define. By default this is true, but this can be set to
+         * false if you need the default behavior (not recommended)
+         * @property preventDefault
+         * @type boolean
+         * @static
          */
-        ElementWrapper: function(el) {
-                /**
-                 * The element
-                 * @property el
-                 */
-                this.el = el || null;
-                /**
-                 * The element id
-                 * @property id
-                 */
-                this.id = this.el && el.id;
-                /**
-                 * A reference to the style property
-                 * @property css
-                 */
-                this.css = this.el && el.style;
-            },
+        preventDefault: true,
 
         /**
-         * Returns the X position of an html element
-         * @method getPosX
-         * @param el the element for which to get the position
-         * @return {int} the X coordinate
-         * @for DragDropMgr
-         * @deprecated use Roo.lib.Dom.getX instead
+         * Flag to determine if we should stop the propagation of the events
+         * we generate. This is true by default but you may want to set it to
+         * false if the html element contains other features that require the
+         * mouse click.
+         * @property stopPropagation
+         * @type boolean
          * @static
          */
-        getPosX: function(el) {
-            return Roo.lib.Dom.getX(el);
-        },
+        stopPropagation: true,
 
         /**
-         * Returns the Y position of an html element
-         * @method getPosY
-         * @param el the element for which to get the position
-         * @return {int} the Y coordinate
-         * @deprecated use Roo.lib.Dom.getY instead
+         * Internal flag that is set to true when drag and drop has been
+         * intialized
+         * @property initialized
+         * @private
          * @static
          */
-        getPosY: function(el) {
-            return Roo.lib.Dom.getY(el);
-        },
+        initalized: false,
 
         /**
-         * Swap two nodes.  In IE, we use the native method, for others we
-         * emulate the IE behavior
-         * @method swapNode
-         * @param n1 the first node to swap
-         * @param n2 the other node to swap
+         * All drag and drop can be disabled.
+         * @property locked
+         * @private
          * @static
          */
-        swapNode: function(n1, n2) {
-            if (n1.swapNode) {
-                n1.swapNode(n2);
-            } else {
-                var p = n2.parentNode;
-                var s = n2.nextSibling;
-
-                if (s == n1) {
-                    p.insertBefore(n1, n2);
-                } else if (n2 == n1.nextSibling) {
-                    p.insertBefore(n2, n1);
-                } else {
-                    n1.parentNode.replaceChild(n2, n1);
-                    p.insertBefore(n1, s);
-                }
-            }
-        },
+        locked: false,
 
         /**
-         * Returns the current scroll position
-         * @method getScroll
+         * Called the first time an element is registered.
+         * @method init
          * @private
          * @static
          */
-        getScroll: function () {
-            var t, l, dde=document.documentElement, db=document.body;
-            if (dde && (dde.scrollTop || dde.scrollLeft)) {
-                t = dde.scrollTop;
-                l = dde.scrollLeft;
-            } else if (db) {
-                t = db.scrollTop;
-                l = db.scrollLeft;
-            } else {
-
-            }
-            return { top: t, left: l };
+        init: function() {
+            this.initialized = true;
         },
 
         /**
-         * Returns the specified element style property
-         * @method getStyle
-         * @param {HTMLElement} el          the element
-         * @param {string}      styleProp   the style property
-         * @return {string} The value of the style property
-         * @deprecated use Roo.lib.Dom.getStyle
+         * In point mode, drag and drop interaction is defined by the
+         * location of the cursor during the drag/drop
+         * @property POINT
+         * @type int
          * @static
          */
-        getStyle: function(el, styleProp) {
-            return Roo.fly(el).getStyle(styleProp);
-        },
+        POINT: 0,
 
         /**
-         * Gets the scrollTop
-         * @method getScrollTop
-         * @return {int} the document's scrollTop
+         * In intersect mode, drag and drop interactio nis defined by the
+         * overlap of two or more drag and drop objects.
+         * @property INTERSECT
+         * @type int
          * @static
          */
-        getScrollTop: function () { return this.getScroll().top; },
+        INTERSECT: 1,
 
         /**
-         * Gets the scrollLeft
-         * @method getScrollLeft
-         * @return {int} the document's scrollTop
+         * The current drag and drop mode.  Default: POINT
+         * @property mode
+         * @type int
          * @static
          */
-        getScrollLeft: function () { return this.getScroll().left; },
+        mode: 0,
 
         /**
-         * Sets the x/y position of an element to the location of the
-         * target element.
-         * @method moveToEl
-         * @param {HTMLElement} moveEl      The element to move
-         * @param {HTMLElement} targetEl    The position reference element
+         * Runs method on all drag and drop objects
+         * @method _execOnAll
+         * @private
          * @static
          */
-        moveToEl: function (moveEl, targetEl) {
-            var aCoord = Roo.lib.Dom.getXY(targetEl);
-            Roo.lib.Dom.setXY(moveEl, aCoord);
+        _execOnAll: function(sMethod, args) {
+            for (var i in this.ids) {
+                for (var j in this.ids[i]) {
+                    var oDD = this.ids[i][j];
+                    if (! this.isTypeOfDD(oDD)) {
+                        continue;
+                    }
+                    oDD[sMethod].apply(oDD, args);
+                }
+            }
         },
 
         /**
-         * Numeric array sort function
-         * @method numericSort
+         * Drag and drop initialization.  Sets up the global event handlers
+         * @method _onLoad
+         * @private
          * @static
          */
-        numericSort: function(a, b) { return (a - b); },
+        _onLoad: function() {
+
+            this.init();
+
+            if (!Roo.isTouch) {
+                Event.on(document, "mouseup",   this.handleMouseUp, this, true);
+                Event.on(document, "mousemove", this.handleMouseMove, this, true);
+            }
+            Event.on(document, "touchend",   this.handleMouseUp, this, true);
+            Event.on(document, "touchmove", this.handleMouseMove, this, true);
+            
+            Event.on(window,   "unload",    this._onUnload, this, true);
+            Event.on(window,   "resize",    this._onResize, this, true);
+            // Event.on(window,   "mouseout",    this._test);
+
+        },
 
         /**
-         * Internal counter
-         * @property _timeoutCount
+         * Reset constraints on all drag and drop objs
+         * @method _onResize
          * @private
          * @static
          */
-        _timeoutCount: 0,
+        _onResize: function(e) {
+            this._execOnAll("resetConstraints", []);
+        },
 
         /**
-         * Trying to make the load order less important.  Without this we get
-         * an error if this file is loaded before the Event Utility.
-         * @method _addListeners
-         * @private
+         * Lock all drag and drop functionality
+         * @method lock
          * @static
          */
-        _addListeners: function() {
-            var DDM = Roo.dd.DDM;
-            if ( Roo.lib.Event && document ) {
-                DDM._onLoad();
-            } else {
-                if (DDM._timeoutCount > 2000) {
-                } else {
-                    setTimeout(DDM._addListeners, 10);
-                    if (document && document.body) {
-                        DDM._timeoutCount += 1;
-                    }
-                }
-            }
-        },
+        lock: function() { this.locked = true; },
 
         /**
-         * Recursively searches the immediate parent and all child nodes for
-         * the handle element in order to determine wheter or not it was
-         * clicked.
-         * @method handleWasClicked
-         * @param node the html element to inspect
+         * Unlock all drag and drop functionality
+         * @method unlock
          * @static
          */
-        handleWasClicked: function(node, id) {
-            if (this.isHandle(id, node.id)) {
-                return true;
-            } else {
-                // check to see if this is a text node child of the one we want
-                var p = node.parentNode;
-
-                while (p) {
-                    if (this.isHandle(id, p.id)) {
-                        return true;
-                    } else {
-                        p = p.parentNode;
-                    }
-                }
-            }
-
-            return false;
-        }
-
-    };
-
-}();
-
-// shorter alias, save a few bytes
-Roo.dd.DDM = Roo.dd.DragDropMgr;
-Roo.dd.DDM._addListeners();
-
-}/*
- * 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.dd.DD
- * A DragDrop implementation where the linked element follows the
- * mouse cursor during a drag.
- * @extends Roo.dd.DragDrop
- * @constructor
- * @param {String} id the id of the linked element
- * @param {String} sGroup the group of related DragDrop items
- * @param {object} config an object containing configurable attributes
- *                Valid properties for DD:
- *                    scroll
- */
-Roo.dd.DD = function(id, sGroup, config) {
-    if (id) {
-        this.init(id, sGroup, config);
-    }
-};
-
-Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
-
-    /**
-     * When set to true, the utility automatically tries to scroll the browser
-     * window wehn a drag and drop element is dragged near the viewport boundary.
-     * Defaults to true.
-     * @property scroll
-     * @type boolean
-     */
-    scroll: true,
-
-    /**
-     * Sets the pointer offset to the distance between the linked element's top
-     * left corner and the location the element was clicked
-     * @method autoOffset
-     * @param {int} iPageX the X coordinate of the click
-     * @param {int} iPageY the Y coordinate of the click
-     */
-    autoOffset: function(iPageX, iPageY) {
-        var x = iPageX - this.startPageX;
-        var y = iPageY - this.startPageY;
-        this.setDelta(x, y);
-    },
-
-    /**
-     * Sets the pointer offset.  You can call this directly to force the
-     * offset to be in a particular location (e.g., pass in 0,0 to set it
-     * to the center of the object)
-     * @method setDelta
-     * @param {int} iDeltaX the distance from the left
-     * @param {int} iDeltaY the distance from the top
-     */
-    setDelta: function(iDeltaX, iDeltaY) {
-        this.deltaX = iDeltaX;
-        this.deltaY = iDeltaY;
-    },
-
-    /**
-     * Sets the drag element to the location of the mousedown or click event,
-     * maintaining the cursor location relative to the location on the element
-     * that was clicked.  Override this if you want to place the element in a
-     * location other than where the cursor is.
-     * @method setDragElPos
-     * @param {int} iPageX the X coordinate of the mousedown or drag event
-     * @param {int} iPageY the Y coordinate of the mousedown or drag event
-     */
-    setDragElPos: function(iPageX, iPageY) {
-        // the first time we do this, we are going to check to make sure
-        // the element has css positioning
-
-        var el = this.getDragEl();
-        this.alignElWithMouse(el, iPageX, iPageY);
-    },
-
-    /**
-     * Sets the element to the location of the mousedown or click event,
-     * maintaining the cursor location relative to the location on the element
-     * that was clicked.  Override this if you want to place the element in a
-     * location other than where the cursor is.
-     * @method alignElWithMouse
-     * @param {HTMLElement} el the element to move
-     * @param {int} iPageX the X coordinate of the mousedown or drag event
-     * @param {int} iPageY the Y coordinate of the mousedown or drag event
-     */
-    alignElWithMouse: function(el, iPageX, iPageY) {
-        var oCoord = this.getTargetCoord(iPageX, iPageY);
-        var fly = el.dom ? el : Roo.fly(el);
-        if (!this.deltaSetXY) {
-            var aCoord = [oCoord.x, oCoord.y];
-            fly.setXY(aCoord);
-            var newLeft = fly.getLeft(true);
-            var newTop  = fly.getTop(true);
-            this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
-        } else {
-            fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
-        }
-
-        this.cachePosition(oCoord.x, oCoord.y);
-        this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
-        return oCoord;
-    },
+        unlock: function() { this.locked = false; },
 
-    /**
-     * Saves the most recent position so that we can reset the constraints and
-     * tick marks on-demand.  We need to know this so that we can calculate the
-     * number of pixels the element is offset from its original position.
-     * @method cachePosition
-     * @param iPageX the current x position (optional, this just makes it so we
-     * don't have to look it up again)
-     * @param iPageY the current y position (optional, this just makes it so we
-     * don't have to look it up again)
-     */
-    cachePosition: function(iPageX, iPageY) {
-        if (iPageX) {
-            this.lastPageX = iPageX;
-            this.lastPageY = iPageY;
-        } else {
-            var aCoord = Roo.lib.Dom.getXY(this.getEl());
-            this.lastPageX = aCoord[0];
-            this.lastPageY = aCoord[1];
-        }
-    },
+        /**
+         * Is drag and drop locked?
+         * @method isLocked
+         * @return {boolean} True if drag and drop is locked, false otherwise.
+         * @static
+         */
+        isLocked: function() { return this.locked; },
 
-    /**
-     * Auto-scroll the window if the dragged object has been moved beyond the
-     * visible window boundary.
-     * @method autoScroll
-     * @param {int} x the drag element's x position
-     * @param {int} y the drag element's y position
-     * @param {int} h the height of the drag element
-     * @param {int} w the width of the drag element
-     * @private
-     */
-    autoScroll: function(x, y, h, w) {
+        /**
+         * Location cache that is set for all drag drop objects when a drag is
+         * initiated, cleared when the drag is finished.
+         * @property locationCache
+         * @private
+         * @static
+         */
+        locationCache: {},
 
-        if (this.scroll) {
-            // The client height
-            var clientH = Roo.lib.Dom.getViewWidth();
+        /**
+         * Set useCache to false if you want to force object the lookup of each
+         * drag and drop linked element constantly during a drag.
+         * @property useCache
+         * @type boolean
+         * @static
+         */
+        useCache: true,
 
-            // The client width
-            var clientW = Roo.lib.Dom.getViewHeight();
+        /**
+         * The number of pixels that the mouse needs to move after the
+         * mousedown before the drag is initiated.  Default=3;
+         * @property clickPixelThresh
+         * @type int
+         * @static
+         */
+        clickPixelThresh: 3,
 
-            // The amt scrolled down
-            var st = this.DDM.getScrollTop();
+        /**
+         * The number of milliseconds after the mousedown event to initiate the
+         * drag if we don't get a mouseup event. Default=1000
+         * @property clickTimeThresh
+         * @type int
+         * @static
+         */
+        clickTimeThresh: 350,
 
-            // The amt scrolled right
-            var sl = this.DDM.getScrollLeft();
+        /**
+         * Flag that indicates that either the drag pixel threshold or the
+         * mousdown time threshold has been met
+         * @property dragThreshMet
+         * @type boolean
+         * @private
+         * @static
+         */
+        dragThreshMet: false,
 
-            // Location of the bottom of the element
-            var bot = h + y;
+        /**
+         * Timeout used for the click time threshold
+         * @property clickTimeout
+         * @type Object
+         * @private
+         * @static
+         */
+        clickTimeout: null,
 
-            // Location of the right of the element
-            var right = w + x;
+        /**
+         * The X position of the mousedown event stored for later use when a
+         * drag threshold is met.
+         * @property startX
+         * @type int
+         * @private
+         * @static
+         */
+        startX: 0,
 
-            // The distance from the cursor to the bottom of the visible area,
-            // adjusted so that we don't scroll if the cursor is beyond the
-            // element drag constraints
-            var toBot = (clientH + st - y - this.deltaY);
+        /**
+         * The Y position of the mousedown event stored for later use when a
+         * drag threshold is met.
+         * @property startY
+         * @type int
+         * @private
+         * @static
+         */
+        startY: 0,
 
-            // The distance from the cursor to the right of the visible area
-            var toRight = (clientW + sl - x - this.deltaX);
+        /**
+         * Each DragDrop instance must be registered with the DragDropMgr.
+         * This is executed in DragDrop.init()
+         * @method regDragDrop
+         * @param {DragDrop} oDD the DragDrop object to register
+         * @param {String} sGroup the name of the group this element belongs to
+         * @static
+         */
+        regDragDrop: function(oDD, sGroup) {
+            if (!this.initialized) { this.init(); }
 
+            if (!this.ids[sGroup]) {
+                this.ids[sGroup] = {};
+            }
+            this.ids[sGroup][oDD.id] = oDD;
+        },
 
-            // How close to the edge the cursor must be before we scroll
-            // var thresh = (document.all) ? 100 : 40;
-            var thresh = 40;
+        /**
+         * Removes the supplied dd instance from the supplied group. Executed
+         * by DragDrop.removeFromGroup, so don't call this function directly.
+         * @method removeDDFromGroup
+         * @private
+         * @static
+         */
+        removeDDFromGroup: function(oDD, sGroup) {
+            if (!this.ids[sGroup]) {
+                this.ids[sGroup] = {};
+            }
 
-            // How many pixels to scroll per autoscroll op.  This helps to reduce
-            // clunky scrolling. IE is more sensitive about this ... it needs this
-            // value to be higher.
-            var scrAmt = (document.all) ? 80 : 30;
+            var obj = this.ids[sGroup];
+            if (obj && obj[oDD.id]) {
+                delete obj[oDD.id];
+            }
+        },
 
-            // Scroll down if we are near the bottom of the visible page and the
-            // obj extends below the crease
-            if ( bot > clientH && toBot < thresh ) {
-                window.scrollTo(sl, st + scrAmt);
+        /**
+         * Unregisters a drag and drop item.  This is executed in
+         * DragDrop.unreg, use that method instead of calling this directly.
+         * @method _remove
+         * @private
+         * @static
+         */
+        _remove: function(oDD) {
+            for (var g in oDD.groups) {
+                if (g && this.ids[g][oDD.id]) {
+                    delete this.ids[g][oDD.id];
+                }
             }
+            delete this.handleIds[oDD.id];
+        },
 
-            // Scroll up if the window is scrolled down and the top of the object
-            // goes above the top border
-            if ( y < st && st > 0 && y - st < thresh ) {
-                window.scrollTo(sl, st - scrAmt);
+        /**
+         * Each DragDrop handle element must be registered.  This is done
+         * automatically when executing DragDrop.setHandleElId()
+         * @method regHandle
+         * @param {String} sDDId the DragDrop id this element is a handle for
+         * @param {String} sHandleId the id of the element that is the drag
+         * handle
+         * @static
+         */
+        regHandle: function(sDDId, sHandleId) {
+            if (!this.handleIds[sDDId]) {
+                this.handleIds[sDDId] = {};
             }
+            this.handleIds[sDDId][sHandleId] = sHandleId;
+        },
 
-            // Scroll right if the obj is beyond the right border and the cursor is
-            // near the border.
-            if ( right > clientW && toRight < thresh ) {
-                window.scrollTo(sl + scrAmt, st);
+        /**
+         * Utility function to determine if a given element has been
+         * registered as a drag drop item.
+         * @method isDragDrop
+         * @param {String} id the element id to check
+         * @return {boolean} true if this element is a DragDrop item,
+         * false otherwise
+         * @static
+         */
+        isDragDrop: function(id) {
+            return ( this.getDDById(id) ) ? true : false;
+        },
+
+        /**
+         * Returns the drag and drop instances that are in all groups the
+         * passed in instance belongs to.
+         * @method getRelated
+         * @param {DragDrop} p_oDD the obj to get related data for
+         * @param {boolean} bTargetsOnly if true, only return targetable objs
+         * @return {DragDrop[]} the related instances
+         * @static
+         */
+        getRelated: function(p_oDD, bTargetsOnly) {
+            var oDDs = [];
+            for (var i in p_oDD.groups) {
+                for (j in this.ids[i]) {
+                    var dd = this.ids[i][j];
+                    if (! this.isTypeOfDD(dd)) {
+                        continue;
+                    }
+                    if (!bTargetsOnly || dd.isTarget) {
+                        oDDs[oDDs.length] = dd;
+                    }
+                }
             }
 
-            // Scroll left if the window has been scrolled to the right and the obj
-            // extends past the left border
-            if ( x < sl && sl > 0 && x - sl < thresh ) {
-                window.scrollTo(sl - scrAmt, st);
+            return oDDs;
+        },
+
+        /**
+         * Returns true if the specified dd target is a legal target for
+         * the specifice drag obj
+         * @method isLegalTarget
+         * @param {DragDrop} the drag obj
+         * @param {DragDrop} the target
+         * @return {boolean} true if the target is a legal target for the
+         * dd obj
+         * @static
+         */
+        isLegalTarget: function (oDD, oTargetDD) {
+            var targets = this.getRelated(oDD, true);
+            for (var i=0, len=targets.length;i<len;++i) {
+                if (targets[i].id == oTargetDD.id) {
+                    return true;
+                }
             }
-        }
-    },
 
-    /**
-     * Finds the location the element should be placed if we want to move
-     * it to where the mouse location less the click offset would place us.
-     * @method getTargetCoord
-     * @param {int} iPageX the X coordinate of the click
-     * @param {int} iPageY the Y coordinate of the click
-     * @return an object that contains the coordinates (Object.x and Object.y)
-     * @private
-     */
-    getTargetCoord: function(iPageX, iPageY) {
+            return false;
+        },
+
+        /**
+         * My goal is to be able to transparently determine if an object is
+         * typeof DragDrop, and the exact subclass of DragDrop.  typeof
+         * returns "object", oDD.constructor.toString() always returns
+         * "DragDrop" and not the name of the subclass.  So for now it just
+         * evaluates a well-known variable in DragDrop.
+         * @method isTypeOfDD
+         * @param {Object} the object to evaluate
+         * @return {boolean} true if typeof oDD = DragDrop
+         * @static
+         */
+        isTypeOfDD: function (oDD) {
+            return (oDD && oDD.__ygDragDrop);
+        },
 
+        /**
+         * Utility function to determine if a given element has been
+         * registered as a drag drop handle for the given Drag Drop object.
+         * @method isHandle
+         * @param {String} id the element id to check
+         * @return {boolean} true if this element is a DragDrop handle, false
+         * otherwise
+         * @static
+         */
+        isHandle: function(sDDId, sHandleId) {
+            return ( this.handleIds[sDDId] &&
+                            this.handleIds[sDDId][sHandleId] );
+        },
 
-        var x = iPageX - this.deltaX;
-        var y = iPageY - this.deltaY;
+        /**
+         * Returns the DragDrop instance for a given id
+         * @method getDDById
+         * @param {String} id the id of the DragDrop object
+         * @return {DragDrop} the drag drop object, null if it is not found
+         * @static
+         */
+        getDDById: function(id) {
+            for (var i in this.ids) {
+                if (this.ids[i][id]) {
+                    return this.ids[i][id];
+                }
+            }
+            return null;
+        },
 
-        if (this.constrainX) {
-            if (x < this.minX) { x = this.minX; }
-            if (x > this.maxX) { x = this.maxX; }
-        }
+        /**
+         * Fired after a registered DragDrop object gets the mousedown event.
+         * Sets up the events required to track the object being dragged
+         * @method handleMouseDown
+         * @param {Event} e the event
+         * @param oDD the DragDrop object being dragged
+         * @private
+         * @static
+         */
+        handleMouseDown: function(e, oDD) {
+            if(Roo.QuickTips){
+                Roo.QuickTips.disable();
+            }
+            this.currentTarget = e.getTarget();
 
-        if (this.constrainY) {
-            if (y < this.minY) { y = this.minY; }
-            if (y > this.maxY) { y = this.maxY; }
-        }
+            this.dragCurrent = oDD;
 
-        x = this.getTick(x, this.xTicks);
-        y = this.getTick(y, this.yTicks);
+            var el = oDD.getEl();
 
+            // track start position
+            this.startX = e.getPageX();
+            this.startY = e.getPageY();
 
-        return {x:x, y:y};
-    },
+            this.deltaX = this.startX - el.offsetLeft;
+            this.deltaY = this.startY - el.offsetTop;
 
-    /*
-     * Sets up config options specific to this class. Overrides
-     * Roo.dd.DragDrop, but all versions of this method through the
-     * inheritance chain are called
-     */
-    applyConfig: function() {
-        Roo.dd.DD.superclass.applyConfig.call(this);
-        this.scroll = (this.config.scroll !== false);
-    },
+            this.dragThreshMet = false;
 
-    /*
-     * Event that fires prior to the onMouseDown event.  Overrides
-     * Roo.dd.DragDrop.
-     */
-    b4MouseDown: function(e) {
-        // this.resetConstraints();
-        this.autoOffset(e.getPageX(),
-                            e.getPageY());
-    },
+            this.clickTimeout = setTimeout(
+                    function() {
+                        var DDM = Roo.dd.DDM;
+                        DDM.startDrag(DDM.startX, DDM.startY);
+                    },
+                    this.clickTimeThresh );
+        },
 
-    /*
-     * Event that fires prior to the onDrag event.  Overrides
-     * Roo.dd.DragDrop.
-     */
-    b4Drag: function(e) {
-        this.setDragElPos(e.getPageX(),
-                            e.getPageY());
-    },
+        /**
+         * Fired when either the drag pixel threshol or the mousedown hold
+         * time threshold has been met.
+         * @method startDrag
+         * @param x {int} the X position of the original mousedown
+         * @param y {int} the Y position of the original mousedown
+         * @static
+         */
+        startDrag: function(x, y) {
+            clearTimeout(this.clickTimeout);
+            if (this.dragCurrent) {
+                this.dragCurrent.b4StartDrag(x, y);
+                this.dragCurrent.startDrag(x, y);
+            }
+            this.dragThreshMet = true;
+        },
 
-    toString: function() {
-        return ("DD " + this.id);
-    }
+        /**
+         * Internal function to handle the mouseup event.  Will be invoked
+         * from the context of the document.
+         * @method handleMouseUp
+         * @param {Event} e the event
+         * @private
+         * @static
+         */
+        handleMouseUp: function(e) {
 
-    //////////////////////////////////////////////////////////////////////////
-    // Debugging ygDragDrop events that can be overridden
-    //////////////////////////////////////////////////////////////////////////
-    /*
-    startDrag: function(x, y) {
-    },
+            if(Roo.QuickTips){
+                Roo.QuickTips.enable();
+            }
+            if (! this.dragCurrent) {
+                return;
+            }
 
-    onDrag: function(e) {
-    },
+            clearTimeout(this.clickTimeout);
 
-    onDragEnter: function(e, id) {
-    },
+            if (this.dragThreshMet) {
+                this.fireEvents(e, true);
+            } else {
+            }
 
-    onDragOver: function(e, id) {
-    },
+            this.stopDrag(e);
 
-    onDragOut: function(e, id) {
-    },
+            this.stopEvent(e);
+        },
 
-    onDragDrop: function(e, id) {
-    },
+        /**
+         * Utility to stop event propagation and event default, if these
+         * features are turned on.
+         * @method stopEvent
+         * @param {Event} e the event as returned by this.getEvent()
+         * @static
+         */
+        stopEvent: function(e){
+            if(this.stopPropagation) {
+                e.stopPropagation();
+            }
 
-    endDrag: function(e) {
-    }
+            if (this.preventDefault) {
+                e.preventDefault();
+            }
+        },
 
-    */
+        /**
+         * Internal function to clean up event handlers after the drag
+         * operation is complete
+         * @method stopDrag
+         * @param {Event} e the event
+         * @private
+         * @static
+         */
+        stopDrag: function(e) {
+            // Fire the drag end event for the item that was dragged
+            if (this.dragCurrent) {
+                if (this.dragThreshMet) {
+                    this.dragCurrent.b4EndDrag(e);
+                    this.dragCurrent.endDrag(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">
- */
+                this.dragCurrent.onMouseUp(e);
+            }
 
-/**
- * @class Roo.dd.DDProxy
- * A DragDrop implementation that inserts an empty, bordered div into
- * the document that follows the cursor during drag operations.  At the time of
- * the click, the frame div is resized to the dimensions of the linked html
- * element, and moved to the exact location of the linked element.
- *
- * References to the "frame" element refer to the single proxy element that
- * was created to be dragged in place of all DDProxy elements on the
- * page.
- *
- * @extends Roo.dd.DD
- * @constructor
- * @param {String} id the id of the linked html element
- * @param {String} sGroup the group of related DragDrop objects
- * @param {object} config an object containing configurable attributes
- *                Valid properties for DDProxy in addition to those in DragDrop:
- *                   resizeFrame, centerFrame, dragElId
- */
-Roo.dd.DDProxy = function(id, sGroup, config) {
-    if (id) {
-        this.init(id, sGroup, config);
-        this.initFrame();
-    }
-};
+            this.dragCurrent = null;
+            this.dragOvers = {};
+        },
 
-/**
- * The default drag frame div id
- * @property Roo.dd.DDProxy.dragElId
- * @type String
- * @static
- */
-Roo.dd.DDProxy.dragElId = "ygddfdiv";
+        /**
+         * Internal function to handle the mousemove event.  Will be invoked
+         * from the context of the html element.
+         *
+         * @TODO figure out what we can do about mouse events lost when the
+         * user drags objects beyond the window boundary.  Currently we can
+         * detect this in internet explorer by verifying that the mouse is
+         * down during the mousemove event.  Firefox doesn't give us the
+         * button state on the mousemove event.
+         * @method handleMouseMove
+         * @param {Event} e the event
+         * @private
+         * @static
+         */
+        handleMouseMove: function(e) {
+            if (! this.dragCurrent) {
+                return true;
+            }
 
-Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
+            // var button = e.which || e.button;
 
-    /**
-     * By default we resize the drag frame to be the same size as the element
-     * we want to drag (this is to get the frame effect).  We can turn it off
-     * if we want a different behavior.
-     * @property resizeFrame
-     * @type boolean
-     */
-    resizeFrame: true,
+            // check for IE mouseup outside of page boundary
+            if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
+                this.stopEvent(e);
+                return this.handleMouseUp(e);
+            }
 
-    /**
-     * By default the frame is positioned exactly where the drag element is, so
-     * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
-     * you do not have constraints on the obj is to have the drag frame centered
-     * around the cursor.  Set centerFrame to true for this effect.
-     * @property centerFrame
-     * @type boolean
-     */
-    centerFrame: false,
+            if (!this.dragThreshMet) {
+                var diffX = Math.abs(this.startX - e.getPageX());
+                var diffY = Math.abs(this.startY - e.getPageY());
+                if (diffX > this.clickPixelThresh ||
+                            diffY > this.clickPixelThresh) {
+                    this.startDrag(this.startX, this.startY);
+                }
+            }
 
-    /**
-     * Creates the proxy element if it does not yet exist
-     * @method createFrame
-     */
-    createFrame: function() {
-        var self = this;
-        var body = document.body;
+            if (this.dragThreshMet) {
+                this.dragCurrent.b4Drag(e);
+                this.dragCurrent.onDrag(e);
+                if(!this.dragCurrent.moveOnly){
+                    this.fireEvents(e, false);
+                }
+            }
 
-        if (!body || !body.firstChild) {
-            setTimeout( function() { self.createFrame(); }, 50 );
-            return;
-        }
+            this.stopEvent(e);
 
-        var div = this.getDragEl();
+            return true;
+        },
 
-        if (!div) {
-            div    = document.createElement("div");
-            div.id = this.dragElId;
-            var s  = div.style;
+        /**
+         * Iterates over all of the DragDrop elements to find ones we are
+         * hovering over or dropping on
+         * @method fireEvents
+         * @param {Event} e the event
+         * @param {boolean} isDrop is this a drop op or a mouseover op?
+         * @private
+         * @static
+         */
+        fireEvents: function(e, isDrop) {
+            var dc = this.dragCurrent;
 
-            s.position   = "absolute";
-            s.visibility = "hidden";
-            s.cursor     = "move";
-            s.border     = "2px solid #aaa";
-            s.zIndex     = 999;
+            // If the user did the mouse up outside of the window, we could
+            // get here even though we have ended the drag.
+            if (!dc || dc.isLocked()) {
+                return;
+            }
 
-            // appendChild can blow up IE if invoked prior to the window load event
-            // while rendering a table.  It is possible there are other scenarios
-            // that would cause this to happen as well.
-            body.insertBefore(div, body.firstChild);
-        }
-    },
+            var pt = e.getPoint();
 
-    /**
-     * Initialization for the drag frame element.  Must be called in the
-     * constructor of all subclasses
-     * @method initFrame
-     */
-    initFrame: function() {
-        this.createFrame();
-    },
+            // cache the previous dragOver array
+            var oldOvers = [];
 
-    applyConfig: function() {
-        Roo.dd.DDProxy.superclass.applyConfig.call(this);
+            var outEvts   = [];
+            var overEvts  = [];
+            var dropEvts  = [];
+            var enterEvts = [];
 
-        this.resizeFrame = (this.config.resizeFrame !== false);
-        this.centerFrame = (this.config.centerFrame);
-        this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
-    },
+            // Check to see if the object(s) we were hovering over is no longer
+            // being hovered over so we can fire the onDragOut event
+            for (var i in this.dragOvers) {
 
-    /**
-     * Resizes the drag frame to the dimensions of the clicked object, positions
-     * it over the object, and finally displays it
-     * @method showFrame
-     * @param {int} iPageX X click position
-     * @param {int} iPageY Y click position
-     * @private
-     */
-    showFrame: function(iPageX, iPageY) {
-        var el = this.getEl();
-        var dragEl = this.getDragEl();
-        var s = dragEl.style;
+                var ddo = this.dragOvers[i];
 
-        this._resizeProxy();
+                if (! this.isTypeOfDD(ddo)) {
+                    continue;
+                }
 
-        if (this.centerFrame) {
-            this.setDelta( Math.round(parseInt(s.width,  10)/2),
-                           Math.round(parseInt(s.height, 10)/2) );
-        }
+                if (! this.isOverTarget(pt, ddo, this.mode)) {
+                    outEvts.push( ddo );
+                }
 
-        this.setDragElPos(iPageX, iPageY);
+                oldOvers[i] = true;
+                delete this.dragOvers[i];
+            }
 
-        Roo.fly(dragEl).show();
-    },
+            for (var sGroup in dc.groups) {
 
-    /**
-     * The proxy is automatically resized to the dimensions of the linked
-     * element when a drag is initiated, unless resizeFrame is set to false
-     * @method _resizeProxy
-     * @private
-     */
-    _resizeProxy: function() {
-        if (this.resizeFrame) {
-            var el = this.getEl();
-            Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
-        }
-    },
+                if ("string" != typeof sGroup) {
+                    continue;
+                }
 
-    // overrides Roo.dd.DragDrop
-    b4MouseDown: function(e) {
-        var x = e.getPageX();
-        var y = e.getPageY();
-        this.autoOffset(x, y);
-        this.setDragElPos(x, y);
-    },
+                for (i in this.ids[sGroup]) {
+                    var oDD = this.ids[sGroup][i];
+                    if (! this.isTypeOfDD(oDD)) {
+                        continue;
+                    }
 
-    // overrides Roo.dd.DragDrop
-    b4StartDrag: function(x, y) {
-        // show the drag frame
-        this.showFrame(x, y);
-    },
+                    if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
+                        if (this.isOverTarget(pt, oDD, this.mode)) {
+                            // look for drop interactions
+                            if (isDrop) {
+                                dropEvts.push( oDD );
+                            // look for drag enter and drag over interactions
+                            } else {
 
-    // overrides Roo.dd.DragDrop
-    b4EndDrag: function(e) {
-        Roo.fly(this.getDragEl()).hide();
-    },
+                                // initial drag over: dragEnter fires
+                                if (!oldOvers[oDD.id]) {
+                                    enterEvts.push( oDD );
+                                // subsequent drag overs: dragOver fires
+                                } else {
+                                    overEvts.push( oDD );
+                                }
 
-    // overrides Roo.dd.DragDrop
-    // By default we try to move the element to the last location of the frame.
-    // This is so that the default behavior mirrors that of Roo.dd.DD.
-    endDrag: function(e) {
+                                this.dragOvers[oDD.id] = oDD;
+                            }
+                        }
+                    }
+                }
+            }
 
-        var lel = this.getEl();
-        var del = this.getDragEl();
+            if (this.mode) {
+                if (outEvts.length) {
+                    dc.b4DragOut(e, outEvts);
+                    dc.onDragOut(e, outEvts);
+                }
 
-        // Show the drag frame briefly so we can get its position
-        del.style.visibility = "";
+                if (enterEvts.length) {
+                    dc.onDragEnter(e, enterEvts);
+                }
 
-        this.beforeMove();
-        // Hide the linked element before the move to get around a Safari
-        // rendering bug.
-        lel.style.visibility = "hidden";
-        Roo.dd.DDM.moveToEl(lel, del);
-        del.style.visibility = "hidden";
-        lel.style.visibility = "";
+                if (overEvts.length) {
+                    dc.b4DragOver(e, overEvts);
+                    dc.onDragOver(e, overEvts);
+                }
 
-        this.afterDrag();
-    },
+                if (dropEvts.length) {
+                    dc.b4DragDrop(e, dropEvts);
+                    dc.onDragDrop(e, dropEvts);
+                }
 
-    beforeMove : function(){
+            } else {
+                // fire dragout events
+                var len = 0;
+                for (i=0, len=outEvts.length; i<len; ++i) {
+                    dc.b4DragOut(e, outEvts[i].id);
+                    dc.onDragOut(e, outEvts[i].id);
+                }
 
-    },
+                // fire enter events
+                for (i=0,len=enterEvts.length; i<len; ++i) {
+                    // dc.b4DragEnter(e, oDD.id);
+                    dc.onDragEnter(e, enterEvts[i].id);
+                }
 
-    afterDrag : function(){
+                // fire over events
+                for (i=0,len=overEvts.length; i<len; ++i) {
+                    dc.b4DragOver(e, overEvts[i].id);
+                    dc.onDragOver(e, overEvts[i].id);
+                }
 
-    },
+                // fire drop events
+                for (i=0, len=dropEvts.length; i<len; ++i) {
+                    dc.b4DragDrop(e, dropEvts[i].id);
+                    dc.onDragDrop(e, dropEvts[i].id);
+                }
 
-    toString: function() {
-        return ("DDProxy " + this.id);
-    }
+            }
 
-});
-/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
+            // notify about a drop that did not find a target
+            if (isDrop && !dropEvts.length) {
+                dc.onInvalidDrop(e);
+            }
 
- /**
- * @class Roo.dd.DDTarget
- * A DragDrop implementation that does not move, but can be a drop
- * target.  You would get the same result by simply omitting implementation
- * for the event callbacks, but this way we reduce the processing cost of the
- * event listener and the callbacks.
- * @extends Roo.dd.DragDrop
- * @constructor
- * @param {String} id the id of the element that is a drop target
- * @param {String} sGroup the group of related DragDrop objects
- * @param {object} config an object containing configurable attributes
- *                 Valid properties for DDTarget in addition to those in
- *                 DragDrop:
- *                    none
- */
-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,  { 
-            listeners : config.listeners || {}, 
-            events : config.events || {} 
-        });    
-    }
-};
+        },
 
-// Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
-Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
-    toString: function() {
-        return ("DDTarget " + this.id);
-    }
-});
-/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
+        /**
+         * Helper function for getting the best match from the list of drag
+         * and drop objects returned by the drag and drop events when we are
+         * in INTERSECT mode.  It returns either the first object that the
+         * cursor is over, or the object that has the greatest overlap with
+         * the dragged element.
+         * @method getBestMatch
+         * @param  {DragDrop[]} dds The array of drag and drop objects
+         * targeted
+         * @return {DragDrop}       The best single match
+         * @static
+         */
+        getBestMatch: function(dds) {
+            var winner = null;
+            // Return null if the input is not what we expect
+            //if (!dds || !dds.length || dds.length == 0) {
+               // winner = null;
+            // If there is only one item, it wins
+            //} else if (dds.length == 1) {
 
-/**
- * @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
- */
-Roo.dd.ScrollManager = function(){
-    var ddm = Roo.dd.DragDropMgr;
-    var els = {};
-    var dragEl = null;
-    var proc = {};
-    
-    
-    
-    var onStop = function(e){
-        dragEl = null;
-        clearProc();
-    };
-    
-    var triggerRefresh = function(){
-        if(ddm.dragCurrent){
-             ddm.refreshCache(ddm.dragCurrent.groups);
-        }
-    };
-    
-    var doScroll = function(){
-        if(ddm.dragCurrent){
-            var dds = Roo.dd.ScrollManager;
-            if(!dds.animate){
-                if(proc.el.scroll(proc.dir, dds.increment)){
-                    triggerRefresh();
+            var len = dds.length;
+
+            if (len == 1) {
+                winner = dds[0];
+            } else {
+                // Loop through the targeted items
+                for (var i=0; i<len; ++i) {
+                    var dd = dds[i];
+                    // If the cursor is over the object, it wins.  If the
+                    // cursor is over multiple matches, the first one we come
+                    // to wins.
+                    if (dd.cursorIsOver) {
+                        winner = dd;
+                        break;
+                    // Otherwise the object with the most overlap wins
+                    } else {
+                        if (!winner ||
+                            winner.overlap.getArea() < dd.overlap.getArea()) {
+                            winner = dd;
+                        }
+                    }
                 }
-            }else{
-                proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
             }
-        }
-    };
-    
-    var clearProc = function(){
-        if(proc.id){
-            clearInterval(proc.id);
-        }
-        proc.id = 0;
-        proc.el = null;
-        proc.dir = "";
-    };
-    
-    var startProc = function(el, dir){
-         Roo.log('scroll startproc');
-        clearProc();
-        proc.el = el;
-        proc.dir = dir;
-        proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
-    };
-    
-    var onFire = function(e, isDrop){
-       
-        if(isDrop || !ddm.dragCurrent){ return; }
-        var dds = Roo.dd.ScrollManager;
-        if(!dragEl || dragEl != ddm.dragCurrent){
-            dragEl = ddm.dragCurrent;
-            // refresh regions on drag start
-            dds.refreshCache();
-        }
-        
-        var xy = Roo.lib.Event.getXY(e);
-        var pt = new Roo.lib.Point(xy[0], xy[1]);
-        for(var id in els){
-            var el = els[id], r = el._region;
-            if(r && r.contains(pt) && el.isScrollable()){
-                if(r.bottom - pt.y <= dds.thresh){
-                    if(proc.el != el){
-                        startProc(el, "down");
-                    }
-                    return;
-                }else if(r.right - pt.x <= dds.thresh){
-                    if(proc.el != el){
-                        startProc(el, "left");
-                    }
-                    return;
-                }else if(pt.y - r.top <= dds.thresh){
-                    if(proc.el != el){
-                        startProc(el, "up");
-                    }
-                    return;
-                }else if(pt.x - r.left <= dds.thresh){
-                    if(proc.el != el){
-                        startProc(el, "right");
+
+            return winner;
+        },
+
+        /**
+         * Refreshes the cache of the top-left and bottom-right points of the
+         * drag and drop objects in the specified group(s).  This is in the
+         * format that is stored in the drag and drop instance, so typical
+         * usage is:
+         * <code>
+         * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
+         * </code>
+         * Alternatively:
+         * <code>
+         * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
+         * </code>
+         * @TODO this really should be an indexed array.  Alternatively this
+         * method could accept both.
+         * @method refreshCache
+         * @param {Object} groups an associative array of groups to refresh
+         * @static
+         */
+        refreshCache: function(groups) {
+            for (var sGroup in groups) {
+                if ("string" != typeof sGroup) {
+                    continue;
+                }
+                for (var i in this.ids[sGroup]) {
+                    var oDD = this.ids[sGroup][i];
+
+                    if (this.isTypeOfDD(oDD)) {
+                    // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
+                        var loc = this.getLocation(oDD);
+                        if (loc) {
+                            this.locationCache[oDD.id] = loc;
+                        } else {
+                            delete this.locationCache[oDD.id];
+                            // this will unregister the drag and drop object if
+                            // the element is not in a usable state
+                            // oDD.unreg();
+                        }
                     }
-                    return;
                 }
             }
-        }
-        clearProc();
-    };
-    
-    ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
-    ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
-    
-    return {
+        },
+
+        /**
+         * This checks to make sure an element exists and is in the DOM.  The
+         * main purpose is to handle cases where innerHTML is used to remove
+         * drag and drop objects from the DOM.  IE provides an 'unspecified
+         * error' when trying to access the offsetParent of such an element
+         * @method verifyEl
+         * @param {HTMLElement} el the element to check
+         * @return {boolean} true if the element looks usable
+         * @static
+         */
+        verifyEl: function(el) {
+            if (el) {
+                var parent;
+                if(Roo.isIE){
+                    try{
+                        parent = el.offsetParent;
+                    }catch(e){}
+                }else{
+                    parent = el.offsetParent;
+                }
+                if (parent) {
+                    return true;
+                }
+            }
+
+            return false;
+        },
+
         /**
-         * Registers new overflow element(s) to auto scroll
-         * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
+         * Returns a Region object containing the drag and drop element's position
+         * and size, including the padding configured for it
+         * @method getLocation
+         * @param {DragDrop} oDD the drag and drop object to get the
+         *                       location for
+         * @return {Roo.lib.Region} a Region object representing the total area
+         *                             the element occupies, including any padding
+         *                             the instance is configured for.
+         * @static
          */
-        register : function(el){
-            if(el instanceof Array){
-                for(var i = 0, len = el.length; i < len; i++) {
-                       this.register(el[i]);
-                }
-            }else{
-                el = Roo.get(el);
-                els[el.id] = el;
+        getLocation: function(oDD) {
+            if (! this.isTypeOfDD(oDD)) {
+                return null;
             }
-            Roo.dd.ScrollManager.els = els;
+
+            var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
+
+            try {
+                pos= Roo.lib.Dom.getXY(el);
+            } catch (e) { }
+
+            if (!pos) {
+                return null;
+            }
+
+            x1 = pos[0];
+            x2 = x1 + el.offsetWidth;
+            y1 = pos[1];
+            y2 = y1 + el.offsetHeight;
+
+            t = y1 - oDD.padding[0];
+            r = x2 + oDD.padding[1];
+            b = y2 + oDD.padding[2];
+            l = x1 - oDD.padding[3];
+
+            return new Roo.lib.Region( t, r, b, l );
         },
-        
+
         /**
-         * Unregisters overflow element(s) so they are no longer scrolled
-         * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
+         * Checks the cursor location to see if it over the target
+         * @method isOverTarget
+         * @param {Roo.lib.Point} pt The point to evaluate
+         * @param {DragDrop} oTarget the DragDrop object we are inspecting
+         * @return {boolean} true if the mouse is over the target
+         * @private
+         * @static
          */
-        unregister : function(el){
-            if(el instanceof Array){
-                for(var i = 0, len = el.length; i < len; i++) {
-                       this.unregister(el[i]);
-                }
-            }else{
-                el = Roo.get(el);
-                delete els[el.id];
+        isOverTarget: function(pt, oTarget, intersect) {
+            // use cache if available
+            var loc = this.locationCache[oTarget.id];
+            if (!loc || !this.useCache) {
+                loc = this.getLocation(oTarget);
+                this.locationCache[oTarget.id] = loc;
+
+            }
+
+            if (!loc) {
+                return false;
+            }
+
+            oTarget.cursorIsOver = loc.contains( pt );
+
+            // DragDrop is using this as a sanity check for the initial mousedown
+            // in this case we are done.  In POINT mode, if the drag obj has no
+            // contraints, we are also done. Otherwise we need to evaluate the
+            // location of the target as related to the actual location of the
+            // dragged element.
+            var dc = this.dragCurrent;
+            if (!dc || !dc.getTargetCoord ||
+                    (!intersect && !dc.constrainX && !dc.constrainY)) {
+                return oTarget.cursorIsOver;
+            }
+
+            oTarget.overlap = null;
+
+            // Get the current location of the drag element, this is the
+            // location of the mouse event less the delta that represents
+            // where the original mousedown happened on the element.  We
+            // need to consider constraints and ticks as well.
+            var pos = dc.getTargetCoord(pt.x, pt.y);
+
+            var el = dc.getDragEl();
+            var curRegion = new Roo.lib.Region( pos.y,
+                                                   pos.x + el.offsetWidth,
+                                                   pos.y + el.offsetHeight,
+                                                   pos.x );
+
+            var overlap = curRegion.intersect(loc);
+
+            if (overlap) {
+                oTarget.overlap = overlap;
+                return (intersect) ? true : oTarget.cursorIsOver;
+            } else {
+                return false;
             }
         },
-        
+
         /**
-         * The number of pixels from the edge of a container the pointer needs to be to 
-         * trigger scrolling (defaults to 25)
-         * @type Number
+         * unload event handler
+         * @method _onUnload
+         * @private
+         * @static
          */
-        thresh : 25,
-        
+        _onUnload: function(e, me) {
+            Roo.dd.DragDropMgr.unregAll();
+        },
+
         /**
-         * The number of pixels to scroll in each scroll increment (defaults to 50)
-         * @type Number
+         * Cleans up the drag and drop events and objects.
+         * @method unregAll
+         * @private
+         * @static
          */
-        increment : 100,
-        
+        unregAll: function() {
+
+            if (this.dragCurrent) {
+                this.stopDrag();
+                this.dragCurrent = null;
+            }
+
+            this._execOnAll("unreg", []);
+
+            for (i in this.elementCache) {
+                delete this.elementCache[i];
+            }
+
+            this.elementCache = {};
+            this.ids = {};
+        },
+
         /**
-         * The frequency of scrolls in milliseconds (defaults to 500)
-         * @type Number
+         * A cache of DOM elements
+         * @property elementCache
+         * @private
+         * @static
          */
-        frequency : 500,
-        
+        elementCache: {},
+
         /**
-         * True to animate the scroll (defaults to true)
-         * @type Boolean
+         * Get the wrapper for the DOM element specified
+         * @method getElWrapper
+         * @param {String} id the id of the element to get
+         * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
+         * @private
+         * @deprecated This wrapper isn't that useful
+         * @static
          */
-        animate: true,
-        
+        getElWrapper: function(id) {
+            var oWrapper = this.elementCache[id];
+            if (!oWrapper || !oWrapper.el) {
+                oWrapper = this.elementCache[id] =
+                    new this.ElementWrapper(Roo.getDom(id));
+            }
+            return oWrapper;
+        },
+
         /**
-         * The animation duration in seconds - 
-         * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
-         * @type Number
+         * Returns the actual DOM element
+         * @method getElement
+         * @param {String} id the id of the elment to get
+         * @return {Object} The element
+         * @deprecated use Roo.getDom instead
+         * @static
          */
-        animDuration: .4,
-        
+        getElement: function(id) {
+            return Roo.getDom(id);
+        },
+
         /**
-         * Manually trigger a cache refresh.
+         * Returns the style property for the DOM element (i.e.,
+         * document.getElById(id).style)
+         * @method getCss
+         * @param {String} id the id of the elment to get
+         * @return {Object} The style property of the element
+         * @deprecated use Roo.getDom instead
+         * @static
          */
-        refreshCache : function(){
-            for(var id in els){
-                if(typeof els[id] == 'object'){ // for people extending the object prototype
-                    els[id]._region = els[id].getRegion();
-                }
-            }
-        }
-    };
-}();/*
- * 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">
- */
+        getCss: function(id) {
+            var el = Roo.getDom(id);
+            return (el) ? el.style : null;
+        },
 
-/**
- * @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
- */
-Roo.dd.Registry = function(){
-    var elements = {}; 
-    var handles = {}; 
-    var autoIdSeed = 0;
+        /**
+         * Inner class for cached elements
+         * @class DragDropMgr.ElementWrapper
+         * @for DragDropMgr
+         * @private
+         * @deprecated
+         */
+        ElementWrapper: function(el) {
+                /**
+                 * The element
+                 * @property el
+                 */
+                this.el = el || null;
+                /**
+                 * The element id
+                 * @property id
+                 */
+                this.id = this.el && el.id;
+                /**
+                 * A reference to the style property
+                 * @property css
+                 */
+                this.css = this.el && el.style;
+            },
 
-    var getId = function(el, autogen){
-        if(typeof el == "string"){
-            return el;
-        }
-        var id = el.id;
-        if(!id && autogen !== false){
-            id = "roodd-" + (++autoIdSeed);
-            el.id = id;
-        }
-        return id;
-    };
-    
-    return {
-    /**
-     * Register a drag drop element
-     * @param {String|HTMLElement} element The id or DOM node to register
-     * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
-     * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
-     * knows how to interpret, plus there are some specific properties known to the Registry that should be
-     * populated in the data object (if applicable):
-     * <pre>
-Value      Description<br />
----------  ------------------------------------------<br />
-handles    Array of DOM nodes that trigger dragging<br />
-           for the element being registered<br />
-isHandle   True if the element passed in triggers<br />
-           dragging itself, else false
-</pre>
-     */
-        register : function(el, data){
-            data = data || {};
-            if(typeof el == "string"){
-                el = document.getElementById(el);
-            }
-            data.ddel = el;
-            elements[getId(el)] = data;
-            if(data.isHandle !== false){
-                handles[data.ddel.id] = data;
-            }
-            if(data.handles){
-                var hs = data.handles;
-                for(var i = 0, len = hs.length; i < len; i++){
-                       handles[getId(hs[i])] = data;
-                }
-            }
+        /**
+         * Returns the X position of an html element
+         * @method getPosX
+         * @param el the element for which to get the position
+         * @return {int} the X coordinate
+         * @for DragDropMgr
+         * @deprecated use Roo.lib.Dom.getX instead
+         * @static
+         */
+        getPosX: function(el) {
+            return Roo.lib.Dom.getX(el);
         },
 
-    /**
-     * Unregister a drag drop element
-     * @param {String|HTMLElement}  element The id or DOM node to unregister
-     */
-        unregister : function(el){
-            var id = getId(el, false);
-            var data = elements[id];
-            if(data){
-                delete elements[id];
-                if(data.handles){
-                    var hs = data.handles;
-                    for(var i = 0, len = hs.length; i < len; i++){
-                       delete handles[getId(hs[i], false)];
-                    }
+        /**
+         * Returns the Y position of an html element
+         * @method getPosY
+         * @param el the element for which to get the position
+         * @return {int} the Y coordinate
+         * @deprecated use Roo.lib.Dom.getY instead
+         * @static
+         */
+        getPosY: function(el) {
+            return Roo.lib.Dom.getY(el);
+        },
+
+        /**
+         * Swap two nodes.  In IE, we use the native method, for others we
+         * emulate the IE behavior
+         * @method swapNode
+         * @param n1 the first node to swap
+         * @param n2 the other node to swap
+         * @static
+         */
+        swapNode: function(n1, n2) {
+            if (n1.swapNode) {
+                n1.swapNode(n2);
+            } else {
+                var p = n2.parentNode;
+                var s = n2.nextSibling;
+
+                if (s == n1) {
+                    p.insertBefore(n1, n2);
+                } else if (n2 == n1.nextSibling) {
+                    p.insertBefore(n2, n1);
+                } else {
+                    n1.parentNode.replaceChild(n2, n1);
+                    p.insertBefore(n1, s);
                 }
             }
         },
 
-    /**
-     * Returns the handle registered for a DOM Node by id
-     * @param {String|HTMLElement} id The DOM node or id to look up
-     * @return {Object} handle The custom handle data
-     */
-        getHandle : function(id){
-            if(typeof id != "string"){ // must be element?
-                id = id.id;
+        /**
+         * Returns the current scroll position
+         * @method getScroll
+         * @private
+         * @static
+         */
+        getScroll: function () {
+            var t, l, dde=document.documentElement, db=document.body;
+            if (dde && (dde.scrollTop || dde.scrollLeft)) {
+                t = dde.scrollTop;
+                l = dde.scrollLeft;
+            } else if (db) {
+                t = db.scrollTop;
+                l = db.scrollLeft;
+            } else {
+
             }
-            return handles[id];
+            return { top: t, left: l };
         },
 
-    /**
-     * Returns the handle that is registered for the DOM node that is the target of the event
-     * @param {Event} e The event
-     * @return {Object} handle The custom handle data
-     */
-        getHandleFromEvent : function(e){
-            var t = Roo.lib.Event.getTarget(e);
-            return t ? handles[t.id] : null;
+        /**
+         * Returns the specified element style property
+         * @method getStyle
+         * @param {HTMLElement} el          the element
+         * @param {string}      styleProp   the style property
+         * @return {string} The value of the style property
+         * @deprecated use Roo.lib.Dom.getStyle
+         * @static
+         */
+        getStyle: function(el, styleProp) {
+            return Roo.fly(el).getStyle(styleProp);
         },
 
-    /**
-     * Returns a custom data object that is registered for a DOM node by id
-     * @param {String|HTMLElement} id The DOM node or id to look up
-     * @return {Object} data The custom data
-     */
-        getTarget : function(id){
-            if(typeof id != "string"){ // must be element?
-                id = id.id;
+        /**
+         * Gets the scrollTop
+         * @method getScrollTop
+         * @return {int} the document's scrollTop
+         * @static
+         */
+        getScrollTop: function () { return this.getScroll().top; },
+
+        /**
+         * Gets the scrollLeft
+         * @method getScrollLeft
+         * @return {int} the document's scrollTop
+         * @static
+         */
+        getScrollLeft: function () { return this.getScroll().left; },
+
+        /**
+         * Sets the x/y position of an element to the location of the
+         * target element.
+         * @method moveToEl
+         * @param {HTMLElement} moveEl      The element to move
+         * @param {HTMLElement} targetEl    The position reference element
+         * @static
+         */
+        moveToEl: function (moveEl, targetEl) {
+            var aCoord = Roo.lib.Dom.getXY(targetEl);
+            Roo.lib.Dom.setXY(moveEl, aCoord);
+        },
+
+        /**
+         * Numeric array sort function
+         * @method numericSort
+         * @static
+         */
+        numericSort: function(a, b) { return (a - b); },
+
+        /**
+         * Internal counter
+         * @property _timeoutCount
+         * @private
+         * @static
+         */
+        _timeoutCount: 0,
+
+        /**
+         * Trying to make the load order less important.  Without this we get
+         * an error if this file is loaded before the Event Utility.
+         * @method _addListeners
+         * @private
+         * @static
+         */
+        _addListeners: function() {
+            var DDM = Roo.dd.DDM;
+            if ( Roo.lib.Event && document ) {
+                DDM._onLoad();
+            } else {
+                if (DDM._timeoutCount > 2000) {
+                } else {
+                    setTimeout(DDM._addListeners, 10);
+                    if (document && document.body) {
+                        DDM._timeoutCount += 1;
+                    }
+                }
+            }
+        },
+
+        /**
+         * Recursively searches the immediate parent and all child nodes for
+         * the handle element in order to determine wheter or not it was
+         * clicked.
+         * @method handleWasClicked
+         * @param node the html element to inspect
+         * @static
+         */
+        handleWasClicked: function(node, id) {
+            if (this.isHandle(id, node.id)) {
+                return true;
+            } else {
+                // check to see if this is a text node child of the one we want
+                var p = node.parentNode;
+
+                while (p) {
+                    if (this.isHandle(id, p.id)) {
+                        return true;
+                    } else {
+                        p = p.parentNode;
+                    }
+                }
             }
-            return elements[id];
-        },
 
-    /**
-     * Returns a custom data object that is registered for the DOM node that is the target of the event
-     * @param {Event} e The event
-     * @return {Object} data The custom data
-     */
-        getTargetFromEvent : function(e){
-            var t = Roo.lib.Event.getTarget(e);
-            return t ? elements[t.id] || handles[t.id] : null;
+            return false;
         }
+
     };
-}();/*
+
+}();
+
+// shorter alias, save a few bytes
+Roo.dd.DDM = Roo.dd.DragDropMgr;
+Roo.dd.DDM._addListeners();
+
+}/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -19809,173 +21987,296 @@ isHandle   True if the element passed in triggers<br />
  * Fork - LGPL
  * <script type="text/javascript">
  */
 
 /**
- * @class Roo.dd.StatusProxy
- * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
- * default drag proxy used by all Roo.dd components.
+ * @class Roo.dd.DD
+ * A DragDrop implementation where the linked element follows the
+ * mouse cursor during a drag.
+ * @extends Roo.dd.DragDrop
  * @constructor
- * @param {Object} config
+ * @param {String} id the id of the linked element
+ * @param {String} sGroup the group of related DragDrop items
+ * @param {object} config an object containing configurable attributes
+ *                Valid properties for DD:
+ *                    scroll
  */
-Roo.dd.StatusProxy = function(config){
-    Roo.apply(this, config);
-    this.id = this.id || Roo.id();
-    this.el = new Roo.Layer({
-        dh: {
-            id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
-                {tag: "div", cls: "x-dd-drop-icon"},
-                {tag: "div", cls: "x-dd-drag-ghost"}
-            ]
-        }, 
-        shadow: !config || config.shadow !== false
-    });
-    this.ghost = Roo.get(this.el.dom.childNodes[1]);
-    this.dropStatus = this.dropNotAllowed;
+Roo.dd.DD = function(id, sGroup, config) {
+    if (id) {
+        this.init(id, sGroup, config);
+    }
 };
 
-Roo.dd.StatusProxy.prototype = {
+Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
+
     /**
-     * @cfg {String} dropAllowed
-     * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
+     * When set to true, the utility automatically tries to scroll the browser
+     * window wehn a drag and drop element is dragged near the viewport boundary.
+     * Defaults to true.
+     * @property scroll
+     * @type boolean
      */
-    dropAllowed : "x-dd-drop-ok",
+    scroll: true,
+
     /**
-     * @cfg {String} dropNotAllowed
-     * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
+     * Sets the pointer offset to the distance between the linked element's top
+     * left corner and the location the element was clicked
+     * @method autoOffset
+     * @param {int} iPageX the X coordinate of the click
+     * @param {int} iPageY the Y coordinate of the click
      */
-    dropNotAllowed : "x-dd-drop-nodrop",
+    autoOffset: function(iPageX, iPageY) {
+        var x = iPageX - this.startPageX;
+        var y = iPageY - this.startPageY;
+        this.setDelta(x, y);
+    },
 
     /**
-     * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
-     * over the current target element.
-     * @param {String} cssClass The css class for the new drop status indicator image
+     * Sets the pointer offset.  You can call this directly to force the
+     * offset to be in a particular location (e.g., pass in 0,0 to set it
+     * to the center of the object)
+     * @method setDelta
+     * @param {int} iDeltaX the distance from the left
+     * @param {int} iDeltaY the distance from the top
      */
-    setStatus : function(cssClass){
-        cssClass = cssClass || this.dropNotAllowed;
-        if(this.dropStatus != cssClass){
-            this.el.replaceClass(this.dropStatus, cssClass);
-            this.dropStatus = cssClass;
-        }
+    setDelta: function(iDeltaX, iDeltaY) {
+        this.deltaX = iDeltaX;
+        this.deltaY = iDeltaY;
     },
 
     /**
-     * Resets the status indicator to the default dropNotAllowed value
-     * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
+     * Sets the drag element to the location of the mousedown or click event,
+     * maintaining the cursor location relative to the location on the element
+     * that was clicked.  Override this if you want to place the element in a
+     * location other than where the cursor is.
+     * @method setDragElPos
+     * @param {int} iPageX the X coordinate of the mousedown or drag event
+     * @param {int} iPageY the Y coordinate of the mousedown or drag event
      */
-    reset : function(clearGhost){
-        this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
-        this.dropStatus = this.dropNotAllowed;
-        if(clearGhost){
-            this.ghost.update("");
-        }
+    setDragElPos: function(iPageX, iPageY) {
+        // the first time we do this, we are going to check to make sure
+        // the element has css positioning
+
+        var el = this.getDragEl();
+        this.alignElWithMouse(el, iPageX, iPageY);
     },
 
     /**
-     * Updates the contents of the ghost element
-     * @param {String} html The html that will replace the current innerHTML of the ghost element
+     * Sets the element to the location of the mousedown or click event,
+     * maintaining the cursor location relative to the location on the element
+     * that was clicked.  Override this if you want to place the element in a
+     * location other than where the cursor is.
+     * @method alignElWithMouse
+     * @param {HTMLElement} el the element to move
+     * @param {int} iPageX the X coordinate of the mousedown or drag event
+     * @param {int} iPageY the Y coordinate of the mousedown or drag event
      */
-    update : function(html){
-        if(typeof html == "string"){
-            this.ghost.update(html);
-        }else{
-            this.ghost.update("");
-            html.style.margin = "0";
-            this.ghost.dom.appendChild(html);
+    alignElWithMouse: function(el, iPageX, iPageY) {
+        var oCoord = this.getTargetCoord(iPageX, iPageY);
+        var fly = el.dom ? el : Roo.fly(el);
+        if (!this.deltaSetXY) {
+            var aCoord = [oCoord.x, oCoord.y];
+            fly.setXY(aCoord);
+            var newLeft = fly.getLeft(true);
+            var newTop  = fly.getTop(true);
+            this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
+        } else {
+            fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
         }
-        // ensure float = none set?? cant remember why though.
-        var el = this.ghost.dom.firstChild;
-               if(el){
-                       Roo.fly(el).setStyle('float', 'none');
-               }
-    },
-    
-    /**
-     * Returns the underlying proxy {@link Roo.Layer}
-     * @return {Roo.Layer} el
-    */
-    getEl : function(){
-        return this.el;
+
+        this.cachePosition(oCoord.x, oCoord.y);
+        this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
+        return oCoord;
     },
 
     /**
-     * Returns the ghost element
-     * @return {Roo.Element} el
+     * Saves the most recent position so that we can reset the constraints and
+     * tick marks on-demand.  We need to know this so that we can calculate the
+     * number of pixels the element is offset from its original position.
+     * @method cachePosition
+     * @param iPageX the current x position (optional, this just makes it so we
+     * don't have to look it up again)
+     * @param iPageY the current y position (optional, this just makes it so we
+     * don't have to look it up again)
      */
-    getGhost : function(){
-        return this.ghost;
+    cachePosition: function(iPageX, iPageY) {
+        if (iPageX) {
+            this.lastPageX = iPageX;
+            this.lastPageY = iPageY;
+        } else {
+            var aCoord = Roo.lib.Dom.getXY(this.getEl());
+            this.lastPageX = aCoord[0];
+            this.lastPageY = aCoord[1];
+        }
     },
 
     /**
-     * Hides the proxy
-     * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
+     * Auto-scroll the window if the dragged object has been moved beyond the
+     * visible window boundary.
+     * @method autoScroll
+     * @param {int} x the drag element's x position
+     * @param {int} y the drag element's y position
+     * @param {int} h the height of the drag element
+     * @param {int} w the width of the drag element
+     * @private
      */
-    hide : function(clear){
-        this.el.hide();
-        if(clear){
-            this.reset(true);
+    autoScroll: function(x, y, h, w) {
+
+        if (this.scroll) {
+            // The client height
+            var clientH = Roo.lib.Dom.getViewWidth();
+
+            // The client width
+            var clientW = Roo.lib.Dom.getViewHeight();
+
+            // The amt scrolled down
+            var st = this.DDM.getScrollTop();
+
+            // The amt scrolled right
+            var sl = this.DDM.getScrollLeft();
+
+            // Location of the bottom of the element
+            var bot = h + y;
+
+            // Location of the right of the element
+            var right = w + x;
+
+            // The distance from the cursor to the bottom of the visible area,
+            // adjusted so that we don't scroll if the cursor is beyond the
+            // element drag constraints
+            var toBot = (clientH + st - y - this.deltaY);
+
+            // The distance from the cursor to the right of the visible area
+            var toRight = (clientW + sl - x - this.deltaX);
+
+
+            // How close to the edge the cursor must be before we scroll
+            // var thresh = (document.all) ? 100 : 40;
+            var thresh = 40;
+
+            // How many pixels to scroll per autoscroll op.  This helps to reduce
+            // clunky scrolling. IE is more sensitive about this ... it needs this
+            // value to be higher.
+            var scrAmt = (document.all) ? 80 : 30;
+
+            // Scroll down if we are near the bottom of the visible page and the
+            // obj extends below the crease
+            if ( bot > clientH && toBot < thresh ) {
+                window.scrollTo(sl, st + scrAmt);
+            }
+
+            // Scroll up if the window is scrolled down and the top of the object
+            // goes above the top border
+            if ( y < st && st > 0 && y - st < thresh ) {
+                window.scrollTo(sl, st - scrAmt);
+            }
+
+            // Scroll right if the obj is beyond the right border and the cursor is
+            // near the border.
+            if ( right > clientW && toRight < thresh ) {
+                window.scrollTo(sl + scrAmt, st);
+            }
+
+            // Scroll left if the window has been scrolled to the right and the obj
+            // extends past the left border
+            if ( x < sl && sl > 0 && x - sl < thresh ) {
+                window.scrollTo(sl - scrAmt, st);
+            }
         }
     },
 
     /**
-     * Stops the repair animation if it's currently running
+     * Finds the location the element should be placed if we want to move
+     * it to where the mouse location less the click offset would place us.
+     * @method getTargetCoord
+     * @param {int} iPageX the X coordinate of the click
+     * @param {int} iPageY the Y coordinate of the click
+     * @return an object that contains the coordinates (Object.x and Object.y)
+     * @private
      */
-    stop : function(){
-        if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
-            this.anim.stop();
+    getTargetCoord: function(iPageX, iPageY) {
+
+
+        var x = iPageX - this.deltaX;
+        var y = iPageY - this.deltaY;
+
+        if (this.constrainX) {
+            if (x < this.minX) { x = this.minX; }
+            if (x > this.maxX) { x = this.maxX; }
+        }
+
+        if (this.constrainY) {
+            if (y < this.minY) { y = this.minY; }
+            if (y > this.maxY) { y = this.maxY; }
         }
+
+        x = this.getTick(x, this.xTicks);
+        y = this.getTick(y, this.yTicks);
+
+
+        return {x:x, y:y};
     },
 
-    /**
-     * Displays this proxy
+    /*
+     * Sets up config options specific to this class. Overrides
+     * Roo.dd.DragDrop, but all versions of this method through the
+     * inheritance chain are called
      */
-    show : function(){
-        this.el.show();
+    applyConfig: function() {
+        Roo.dd.DD.superclass.applyConfig.call(this);
+        this.scroll = (this.config.scroll !== false);
     },
 
-    /**
-     * Force the Layer to sync its shadow and shim positions to the element
+    /*
+     * Event that fires prior to the onMouseDown event.  Overrides
+     * Roo.dd.DragDrop.
      */
-    sync : function(){
-        this.el.sync();
+    b4MouseDown: function(e) {
+        // this.resetConstraints();
+        this.autoOffset(e.getPageX(),
+                            e.getPageY());
     },
 
-    /**
-     * Causes the proxy to return to its position of origin via an animation.  Should be called after an
-     * invalid drop operation by the item being dragged.
-     * @param {Array} xy The XY position of the element ([x, y])
-     * @param {Function} callback The function to call after the repair is complete
-     * @param {Object} scope The scope in which to execute the callback
+    /*
+     * Event that fires prior to the onDrag event.  Overrides
+     * Roo.dd.DragDrop.
      */
-    repair : function(xy, callback, scope){
-        this.callback = callback;
-        this.scope = scope;
-        if(xy && this.animRepair !== false){
-            this.el.addClass("x-dd-drag-repair");
-            this.el.hideUnders(true);
-            this.anim = this.el.shift({
-                duration: this.repairDuration || .5,
-                easing: 'easeOut',
-                xy: xy,
-                stopFx: true,
-                callback: this.afterRepair,
-                scope: this
-            });
-        }else{
-            this.afterRepair();
-        }
+    b4Drag: function(e) {
+        this.setDragElPos(e.getPageX(),
+                            e.getPageY());
     },
 
-    // private
-    afterRepair : function(){
-        this.hide(true);
-        if(typeof this.callback == "function"){
-            this.callback.call(this.scope || this);
-        }
-        this.callback = null;
-        this.scope = null;
+    toString: function() {
+        return ("DD " + this.id);
     }
-};/*
+
+    //////////////////////////////////////////////////////////////////////////
+    // Debugging ygDragDrop events that can be overridden
+    //////////////////////////////////////////////////////////////////////////
+    /*
+    startDrag: function(x, y) {
+    },
+
+    onDrag: function(e) {
+    },
+
+    onDragEnter: function(e, id) {
+    },
+
+    onDragOver: function(e, id) {
+    },
+
+    onDragOut: function(e, id) {
+    },
+
+    onDragDrop: function(e, id) {
+    },
+
+    endDrag: function(e) {
+    }
+
+    */
+
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -19987,360 +22288,203 @@ Roo.dd.StatusProxy.prototype = {
  */
 
 /**
- * @class Roo.dd.DragSource
- * @extends Roo.dd.DDProxy
- * A simple class that provides the basic implementation needed to make any element draggable.
+ * @class Roo.dd.DDProxy
+ * A DragDrop implementation that inserts an empty, bordered div into
+ * the document that follows the cursor during drag operations.  At the time of
+ * the click, the frame div is resized to the dimensions of the linked html
+ * element, and moved to the exact location of the linked element.
+ *
+ * References to the "frame" element refer to the single proxy element that
+ * was created to be dragged in place of all DDProxy elements on the
+ * page.
+ *
+ * @extends Roo.dd.DD
  * @constructor
- * @param {String/HTMLElement/Element} el The container element
- * @param {Object} config
+ * @param {String} id the id of the linked html element
+ * @param {String} sGroup the group of related DragDrop objects
+ * @param {object} config an object containing configurable attributes
+ *                Valid properties for DDProxy in addition to those in DragDrop:
+ *                   resizeFrame, centerFrame, dragElId
  */
-Roo.dd.DragSource = function(el, config){
-    this.el = Roo.get(el);
-    this.dragData = {};
-    
-    Roo.apply(this, config);
-    
-    if(!this.proxy){
-        this.proxy = new Roo.dd.StatusProxy();
+Roo.dd.DDProxy = function(id, sGroup, config) {
+    if (id) {
+        this.init(id, sGroup, config);
+        this.initFrame();
     }
-
-    Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
-          {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
-    
-    this.dragging = false;
 };
 
-Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
-    /**
-     * @cfg {String} dropAllowed
-     * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
-     */
-    dropAllowed : "x-dd-drop-ok",
-    /**
-     * @cfg {String} dropNotAllowed
-     * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
-     */
-    dropNotAllowed : "x-dd-drop-nodrop",
-
-    /**
-     * Returns the data object associated with this drag source
-     * @return {Object} data An object containing arbitrary data
-     */
-    getDragData : function(e){
-        return this.dragData;
-    },
-
-    // private
-    onDragEnter : function(e, id){
-        var target = Roo.dd.DragDropMgr.getDDById(id);
-        this.cachedTarget = target;
-        if(this.beforeDragEnter(target, e, id) !== false){
-            if(target.isNotifyTarget){
-                var status = target.notifyEnter(this, e, this.dragData);
-                this.proxy.setStatus(status);
-            }else{
-                this.proxy.setStatus(this.dropAllowed);
-            }
-            
-            if(this.afterDragEnter){
-                /**
-                 * An empty function by default, but provided so that you can perform a custom action
-                 * when the dragged item enters the drop target by providing an implementation.
-                 * @param {Roo.dd.DragDrop} target The drop target
-                 * @param {Event} e The event object
-                 * @param {String} id The id of the dragged element
-                 * @method afterDragEnter
-                 */
-                this.afterDragEnter(target, e, id);
-            }
-        }
-    },
-
-    /**
-     * An empty function by default, but provided so that you can perform a custom action
-     * before the dragged item enters the drop target and optionally cancel the onDragEnter.
-     * @param {Roo.dd.DragDrop} target The drop target
-     * @param {Event} e The event object
-     * @param {String} id The id of the dragged element
-     * @return {Boolean} isValid True if the drag event is valid, else false to cancel
-     */
-    beforeDragEnter : function(target, e, id){
-        return true;
-    },
-
-    // private
-    alignElWithMouse: function() {
-        Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
-        this.proxy.sync();
-    },
-
-    // private
-    onDragOver : function(e, id){
-        var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
-        if(this.beforeDragOver(target, e, id) !== false){
-            if(target.isNotifyTarget){
-                var status = target.notifyOver(this, e, this.dragData);
-                Roo.log('run here??????????????');
-                Roo.log(status);
-                this.proxy.setStatus(status);
-            }
-
-            if(this.afterDragOver){
-                /**
-                 * An empty function by default, but provided so that you can perform a custom action
-                 * while the dragged item is over the drop target by providing an implementation.
-                 * @param {Roo.dd.DragDrop} target The drop target
-                 * @param {Event} e The event object
-                 * @param {String} id The id of the dragged element
-                 * @method afterDragOver
-                 */
-                this.afterDragOver(target, e, id);
-            }
-        }
-    },
+/**
+ * The default drag frame div id
+ * @property Roo.dd.DDProxy.dragElId
+ * @type String
+ * @static
+ */
+Roo.dd.DDProxy.dragElId = "ygddfdiv";
+
+Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
 
     /**
-     * An empty function by default, but provided so that you can perform a custom action
-     * while the dragged item is over the drop target and optionally cancel the onDragOver.
-     * @param {Roo.dd.DragDrop} target The drop target
-     * @param {Event} e The event object
-     * @param {String} id The id of the dragged element
-     * @return {Boolean} isValid True if the drag event is valid, else false to cancel
+     * By default we resize the drag frame to be the same size as the element
+     * we want to drag (this is to get the frame effect).  We can turn it off
+     * if we want a different behavior.
+     * @property resizeFrame
+     * @type boolean
      */
-    beforeDragOver : function(target, e, id){
-        return true;
-    },
-
-    // private
-    onDragOut : function(e, id){
-        var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
-        if(this.beforeDragOut(target, e, id) !== false){
-            if(target.isNotifyTarget){
-                target.notifyOut(this, e, this.dragData);
-            }
-            this.proxy.reset();
-            if(this.afterDragOut){
-                /**
-                 * An empty function by default, but provided so that you can perform a custom action
-                 * after the dragged item is dragged out of the target without dropping.
-                 * @param {Roo.dd.DragDrop} target The drop target
-                 * @param {Event} e The event object
-                 * @param {String} id The id of the dragged element
-                 * @method afterDragOut
-                 */
-                this.afterDragOut(target, e, id);
-            }
-        }
-        this.cachedTarget = null;
-    },
+    resizeFrame: true,
 
     /**
-     * An empty function by default, but provided so that you can perform a custom action before the dragged
-     * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
-     * @param {Roo.dd.DragDrop} target The drop target
-     * @param {Event} e The event object
-     * @param {String} id The id of the dragged element
-     * @return {Boolean} isValid True if the drag event is valid, else false to cancel
+     * By default the frame is positioned exactly where the drag element is, so
+     * we use the cursor offset provided by Roo.dd.DD.  Another option that works only if
+     * you do not have constraints on the obj is to have the drag frame centered
+     * around the cursor.  Set centerFrame to true for this effect.
+     * @property centerFrame
+     * @type boolean
      */
-    beforeDragOut : function(target, e, id){
-        return true;
-    },
-    
-    // private
-    onDragDrop : function(e, id){
-        var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
-        if(this.beforeDragDrop(target, e, id) !== false){
-            if(target.isNotifyTarget){
-                if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
-                    this.onValidDrop(target, e, id);
-                }else{
-                    this.onInvalidDrop(target, e, id);
-                }
-            }else{
-                this.onValidDrop(target, e, id);
-            }
-            
-            if(this.afterDragDrop){
-                /**
-                 * An empty function by default, but provided so that you can perform a custom action
-                 * after a valid drag drop has occurred by providing an implementation.
-                 * @param {Roo.dd.DragDrop} target The drop target
-                 * @param {Event} e The event object
-                 * @param {String} id The id of the dropped element
-                 * @method afterDragDrop
-                 */
-                this.afterDragDrop(target, e, id);
-            }
-        }
-        delete this.cachedTarget;
-    },
+    centerFrame: false,
 
     /**
-     * An empty function by default, but provided so that you can perform a custom action before the dragged
-     * item is dropped onto the target and optionally cancel the onDragDrop.
-     * @param {Roo.dd.DragDrop} target The drop target
-     * @param {Event} e The event object
-     * @param {String} id The id of the dragged element
-     * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
+     * Creates the proxy element if it does not yet exist
+     * @method createFrame
      */
-    beforeDragDrop : function(target, e, id){
-        return true;
-    },
+    createFrame: function() {
+        var self = this;
+        var body = document.body;
 
-    // private
-    onValidDrop : function(target, e, id){
-        this.hideProxy();
-        if(this.afterValidDrop){
-            /**
-             * An empty function by default, but provided so that you can perform a custom action
-             * after a valid drop has occurred by providing an implementation.
-             * @param {Object} target The target DD 
-             * @param {Event} e The event object
-             * @param {String} id The id of the dropped element
-             * @method afterInvalidDrop
-             */
-            this.afterValidDrop(target, e, id);
+        if (!body || !body.firstChild) {
+            setTimeout( function() { self.createFrame(); }, 50 );
+            return;
         }
-    },
 
-    // private
-    getRepairXY : function(e, data){
-        return this.el.getXY();  
-    },
+        var div = this.getDragEl();
 
-    // private
-    onInvalidDrop : function(target, e, id){
-        this.beforeInvalidDrop(target, e, id);
-        if(this.cachedTarget){
-            if(this.cachedTarget.isNotifyTarget){
-                this.cachedTarget.notifyOut(this, e, this.dragData);
-            }
-            this.cacheTarget = null;
-        }
-        this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
+        if (!div) {
+            div    = document.createElement("div");
+            div.id = this.dragElId;
+            var s  = div.style;
 
-        if(this.afterInvalidDrop){
-            /**
-             * An empty function by default, but provided so that you can perform a custom action
-             * after an invalid drop has occurred by providing an implementation.
-             * @param {Event} e The event object
-             * @param {String} id The id of the dropped element
-             * @method afterInvalidDrop
-             */
-            this.afterInvalidDrop(e, id);
-        }
-    },
+            s.position   = "absolute";
+            s.visibility = "hidden";
+            s.cursor     = "move";
+            s.border     = "2px solid #aaa";
+            s.zIndex     = 999;
 
-    // private
-    afterRepair : function(){
-        if(Roo.enableFx){
-            this.el.highlight(this.hlColor || "c3daf9");
+            // appendChild can blow up IE if invoked prior to the window load event
+            // while rendering a table.  It is possible there are other scenarios
+            // that would cause this to happen as well.
+            body.insertBefore(div, body.firstChild);
         }
-        this.dragging = false;
     },
 
     /**
-     * An empty function by default, but provided so that you can perform a custom action after an invalid
-     * drop has occurred.
-     * @param {Roo.dd.DragDrop} target The drop target
-     * @param {Event} e The event object
-     * @param {String} id The id of the dragged element
-     * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
+     * Initialization for the drag frame element.  Must be called in the
+     * constructor of all subclasses
+     * @method initFrame
      */
-    beforeInvalidDrop : function(target, e, id){
-        return true;
+    initFrame: function() {
+        this.createFrame();
     },
 
-    // private
-    handleMouseDown : function(e){
-        if(this.dragging) {
-            return;
-        }
-        var data = this.getDragData(e);
-        if(data && this.onBeforeDrag(data, e) !== false){
-            this.dragData = data;
-            this.proxy.stop();
-            Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
-        } 
-    },
+    applyConfig: function() {
+        Roo.dd.DDProxy.superclass.applyConfig.call(this);
 
-    /**
-     * An empty function by default, but provided so that you can perform a custom action before the initial
-     * drag event begins and optionally cancel it.
-     * @param {Object} data An object containing arbitrary data to be shared with drop targets
-     * @param {Event} e The event object
-     * @return {Boolean} isValid True if the drag event is valid, else false to cancel
-     */
-    onBeforeDrag : function(data, e){
-        return true;
+        this.resizeFrame = (this.config.resizeFrame !== false);
+        this.centerFrame = (this.config.centerFrame);
+        this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
     },
 
     /**
-     * An empty function by default, but provided so that you can perform a custom action once the initial
-     * drag event has begun.  The drag cannot be canceled from this function.
-     * @param {Number} x The x position of the click on the dragged object
-     * @param {Number} y The y position of the click on the dragged object
+     * Resizes the drag frame to the dimensions of the clicked object, positions
+     * it over the object, and finally displays it
+     * @method showFrame
+     * @param {int} iPageX X click position
+     * @param {int} iPageY Y click position
+     * @private
      */
-    onStartDrag : Roo.emptyFn,
+    showFrame: function(iPageX, iPageY) {
+        var el = this.getEl();
+        var dragEl = this.getDragEl();
+        var s = dragEl.style;
 
-    // private - YUI override
-    startDrag : function(x, y){
-        this.proxy.reset();
-        this.dragging = true;
-        this.proxy.update("");
-        this.onInitDrag(x, y);
-        this.proxy.show();
-    },
+        this._resizeProxy();
 
-    // private
-    onInitDrag : function(x, y){
-        var clone = this.el.dom.cloneNode(true);
-        clone.id = Roo.id(); // prevent duplicate ids
-        this.proxy.update(clone);
-        this.onStartDrag(x, y);
-        return true;
+        if (this.centerFrame) {
+            this.setDelta( Math.round(parseInt(s.width,  10)/2),
+                           Math.round(parseInt(s.height, 10)/2) );
+        }
+
+        this.setDragElPos(iPageX, iPageY);
+
+        Roo.fly(dragEl).show();
     },
 
     /**
-     * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
-     * @return {Roo.dd.StatusProxy} proxy The StatusProxy
+     * The proxy is automatically resized to the dimensions of the linked
+     * element when a drag is initiated, unless resizeFrame is set to false
+     * @method _resizeProxy
+     * @private
      */
-    getProxy : function(){
-        return this.proxy;  
+    _resizeProxy: function() {
+        if (this.resizeFrame) {
+            var el = this.getEl();
+            Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
+        }
     },
 
-    /**
-     * Hides the drag source's {@link Roo.dd.StatusProxy}
-     */
-    hideProxy : function(){
-        this.proxy.hide();  
-        this.proxy.reset(true);
-        this.dragging = false;
+    // overrides Roo.dd.DragDrop
+    b4MouseDown: function(e) {
+        var x = e.getPageX();
+        var y = e.getPageY();
+        this.autoOffset(x, y);
+        this.setDragElPos(x, y);
     },
 
-    // private
-    triggerCacheRefresh : function(){
-        Roo.dd.DDM.refreshCache(this.groups);
+    // overrides Roo.dd.DragDrop
+    b4StartDrag: function(x, y) {
+        // show the drag frame
+        this.showFrame(x, y);
     },
 
-    // private - override to prevent hiding
+    // overrides Roo.dd.DragDrop
     b4EndDrag: function(e) {
+        Roo.fly(this.getDragEl()).hide();
     },
 
-    // private - override to prevent moving
-    endDrag : function(e){
-        this.onEndDrag(this.dragData, e);
+    // overrides Roo.dd.DragDrop
+    // By default we try to move the element to the last location of the frame.
+    // This is so that the default behavior mirrors that of Roo.dd.DD.
+    endDrag: function(e) {
+
+        var lel = this.getEl();
+        var del = this.getDragEl();
+
+        // Show the drag frame briefly so we can get its position
+        del.style.visibility = "";
+
+        this.beforeMove();
+        // Hide the linked element before the move to get around a Safari
+        // rendering bug.
+        lel.style.visibility = "hidden";
+        Roo.dd.DDM.moveToEl(lel, del);
+        del.style.visibility = "hidden";
+        lel.style.visibility = "";
+
+        this.afterDrag();
     },
 
-    // private
-    onEndDrag : function(data, e){
+    beforeMove : function(){
+
     },
-    
-    // private - pin to cursor
-    autoOffset : function(x, y) {
-        this.setDelta(-12, -20);
-    }    
-});/*
+
+    afterDrag : function(){
+
+    },
+
+    toString: function() {
+        return ("DDProxy " + this.id);
+    }
+
+});
+/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -20351,189 +22495,226 @@ Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
  * <script type="text/javascript">
  */
 
+ /**
+ * @class Roo.dd.DDTarget
+ * A DragDrop implementation that does not move, but can be a drop
+ * target.  You would get the same result by simply omitting implementation
+ * for the event callbacks, but this way we reduce the processing cost of the
+ * event listener and the callbacks.
+ * @extends Roo.dd.DragDrop
+ * @constructor
+ * @param {String} id the id of the element that is a drop target
+ * @param {String} sGroup the group of related DragDrop objects
+ * @param {object} config an object containing configurable attributes
+ *                 Valid properties for DDTarget in addition to those in
+ *                 DragDrop:
+ *                    none
+ */
+Roo.dd.DDTarget = function(id, sGroup, config) {
+    if (id) {
+        this.initTarget(id, sGroup, config);
+    }
+    if (config && (config.listeners || config.events)) { 
+        Roo.dd.DragDrop.superclass.constructor.call(this,  { 
+            listeners : config.listeners || {}, 
+            events : config.events || {} 
+        });    
+    }
+};
+
+// Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
+Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
+    toString: function() {
+        return ("DDTarget " + this.id);
+    }
+});
+/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
 
 /**
- * @class Roo.dd.DropTarget
- * @extends Roo.dd.DDTarget
- * A simple class that provides the basic implementation needed to make any element a drop target that can have
- * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
- * @constructor
- * @param {String/HTMLElement/Element} el The container element
- * @param {Object} config
+ * @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>
+ * @static
  */
-Roo.dd.DropTarget = function(el, config){
-    this.el = Roo.get(el);
+Roo.dd.ScrollManager = function(){
+    var ddm = Roo.dd.DragDropMgr;
+    var els = {};
+    var dragEl = null;
+    var proc = {};
     
-    var listeners = false; ;
-    if (config && config.listeners) {
-        listeners= config.listeners;
-        delete config.listeners;
-    }
-    Roo.apply(this, config);
     
-    if(this.containerScroll){
-        Roo.dd.ScrollManager.register(this.el);
-    }
-    this.addEvents( {
-         /**
-         * @scope Roo.dd.DropTarget
+    
+    var onStop = function(e){
+        dragEl = null;
+        clearProc();
+    };
+    
+    var triggerRefresh = function(){
+        if(ddm.dragCurrent){
+             ddm.refreshCache(ddm.dragCurrent.groups);
+        }
+    };
+    
+    var doScroll = function(){
+        if(ddm.dragCurrent){
+            var dds = Roo.dd.ScrollManager;
+            if(!dds.animate){
+                if(proc.el.scroll(proc.dir, dds.increment)){
+                    triggerRefresh();
+                }
+            }else{
+                proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
+            }
+        }
+    };
+    
+    var clearProc = function(){
+        if(proc.id){
+            clearInterval(proc.id);
+        }
+        proc.id = 0;
+        proc.el = null;
+        proc.dir = "";
+    };
+    
+    var startProc = function(el, dir){
+         Roo.log('scroll startproc');
+        clearProc();
+        proc.el = el;
+        proc.dir = dir;
+        proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
+    };
+    
+    var onFire = function(e, isDrop){
+       
+        if(isDrop || !ddm.dragCurrent){ return; }
+        var dds = Roo.dd.ScrollManager;
+        if(!dragEl || dragEl != ddm.dragCurrent){
+            dragEl = ddm.dragCurrent;
+            // refresh regions on drag start
+            dds.refreshCache();
+        }
+        
+        var xy = Roo.lib.Event.getXY(e);
+        var pt = new Roo.lib.Point(xy[0], xy[1]);
+        for(var id in els){
+            var el = els[id], r = el._region;
+            if(r && r.contains(pt) && el.isScrollable()){
+                if(r.bottom - pt.y <= dds.thresh){
+                    if(proc.el != el){
+                        startProc(el, "down");
+                    }
+                    return;
+                }else if(r.right - pt.x <= dds.thresh){
+                    if(proc.el != el){
+                        startProc(el, "left");
+                    }
+                    return;
+                }else if(pt.y - r.top <= dds.thresh){
+                    if(proc.el != el){
+                        startProc(el, "up");
+                    }
+                    return;
+                }else if(pt.x - r.left <= dds.thresh){
+                    if(proc.el != el){
+                        startProc(el, "right");
+                    }
+                    return;
+                }
+            }
+        }
+        clearProc();
+    };
+    
+    ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
+    ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
+    
+    return {
+        /**
+         * Registers new overflow element(s) to auto scroll
+         * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
+         */
+        register : function(el){
+            if(el instanceof Array){
+                for(var i = 0, len = el.length; i < len; i++) {
+                       this.register(el[i]);
+                }
+            }else{
+                el = Roo.get(el);
+                els[el.id] = el;
+            }
+            Roo.dd.ScrollManager.els = els;
+        },
+        
+        /**
+         * Unregisters overflow element(s) so they are no longer scrolled
+         * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
+         */
+        unregister : function(el){
+            if(el instanceof Array){
+                for(var i = 0, len = el.length; i < len; i++) {
+                       this.unregister(el[i]);
+                }
+            }else{
+                el = Roo.get(el);
+                delete els[el.id];
+            }
+        },
+        
+        /**
+         * The number of pixels from the edge of a container the pointer needs to be to 
+         * trigger scrolling (defaults to 25)
+         * @type Number
          */
-         
-         /**
-         * @event enter
-         * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
-         * 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
-         * 
-         * @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
+        thresh : 25,
+        
+        /**
+         * The number of pixels to scroll in each scroll increment (defaults to 50)
+         * @type Number
          */
-        "enter" : true,
+        increment : 100,
         
-         /**
-         * @event over
-         * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
-         * 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
-         * 
-         * @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
-         
+        /**
+         * The frequency of scrolls in milliseconds (defaults to 500)
+         * @type Number
          */
-        "over" : true,
+        frequency : 500,
+        
         /**
-         * @event out
-         * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
-         * 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
+         * True to animate the scroll (defaults to true)
+         * @type Boolean
          */
-         "out" : true,
-         
+        animate: true,
+        
         /**
-         * @event drop
-         * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
-         * been dropped on it.  This method has no default implementation and returns false, so you must provide an
-         * implementation that does something to process the drop event and returns true so that the drag source's
-         * repair action does not run.
-         * 
-         * IMPORTANT : it should set this.success
-         * 
-         * @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
-        */
-         "drop" : true
-    });
-            
-     
-    Roo.dd.DropTarget.superclass.constructor.call(  this, 
-        this.el.dom, 
-        this.ddGroup || this.group,
-        {
-            isTarget: true,
-            listeners : listeners || {} 
-           
+         * The animation duration in seconds - 
+         * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
+         * @type Number
+         */
+        animDuration: .4,
         
+        /**
+         * Manually trigger a cache refresh.
+         */
+        refreshCache : function(){
+            for(var id in els){
+                if(typeof els[id] == 'object'){ // for people extending the object prototype
+                    els[id]._region = els[id].getRegion();
+                }
+            }
         }
-    );
-
-};
-
-Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
-    /**
-     * @cfg {String} overClass
-     * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
-     */
-     /**
-     * @cfg {String} ddGroup
-     * The drag drop group to handle drop events for
-     */
-     
-    /**
-     * @cfg {String} dropAllowed
-     * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
-     */
-    dropAllowed : "x-dd-drop-ok",
-    /**
-     * @cfg {String} dropNotAllowed
-     * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
-     */
-    dropNotAllowed : "x-dd-drop-nodrop",
-    /**
-     * @cfg {boolean} success
-     * set this after drop listener.. 
-     */
-    success : false,
-    /**
-     * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
-     * if the drop point is valid for over/enter..
-     */
-    valid : false,
-    // private
-    isTarget : true,
-
-    // private
-    isNotifyTarget : true,
-    
-    /**
-     * @hide
-     */
-    notifyEnter : function(dd, e, data)
-    {
-        this.valid = true;
-        this.fireEvent('enter', dd, e, data);
-        if(this.overClass){
-            this.el.addClass(this.overClass);
-        }
-        return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
-            this.valid ? this.dropAllowed : this.dropNotAllowed
-        );
-    },
-
-    /**
-     * @hide
-     */
-    notifyOver : function(dd, e, data)
-    {
-        Roo.log('in?????????????????????????????????');
-        this.valid = true;
-        this.fireEvent('over', dd, e, data);
-        return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
-            this.valid ? this.dropAllowed : this.dropNotAllowed
-        );
-    },
-
-    /**
-     * @hide
-     */
-    notifyOut : function(dd, e, data)
-    {
-        this.fireEvent('out', dd, e, data);
-        if(this.overClass){
-            this.el.removeClass(this.overClass);
-        }
-    },
-
-    /**
-     * @hide
-     */
-    notifyDrop : function(dd, e, data)
-    {
-        this.success = false;
-        this.fireEvent('drop', dd, e, data);
-        return this.success;
-    }
-});/*
+    };
+}();/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -20543,79 +22724,129 @@ Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
  * Fork - LGPL
  * <script type="text/javascript">
  */
-
 
 /**
- * @class Roo.dd.DragZone
- * @extends Roo.dd.DragSource
- * This class provides a container DD instance that proxies for multiple child node sources.<br />
- * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
- * @constructor
- * @param {String/HTMLElement/Element} el The container element
- * @param {Object} config
+ * @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.
+ * @static
  */
-Roo.dd.DragZone = function(el, config){
-    Roo.dd.DragZone.superclass.constructor.call(this, el, config);
-    if(this.containerScroll){
-        Roo.dd.ScrollManager.register(this.el);
-    }
-};
+Roo.dd.Registry = function(){
+    var elements = {}; 
+    var handles = {}; 
+    var autoIdSeed = 0;
 
-Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
+    var getId = function(el, autogen){
+        if(typeof el == "string"){
+            return el;
+        }
+        var id = el.id;
+        if(!id && autogen !== false){
+            id = "roodd-" + (++autoIdSeed);
+            el.id = id;
+        }
+        return id;
+    };
+    
+    return {
     /**
-     * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
-     * for auto scrolling during drag operations.
+     * Register a drag drop element
+     * @param {String|HTMLElement} element The id or DOM node to register
+     * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
+     * in drag drop operations.  You can populate this object with any arbitrary properties that your own code
+     * knows how to interpret, plus there are some specific properties known to the Registry that should be
+     * populated in the data object (if applicable):
+     * <pre>
+Value      Description<br />
+---------  ------------------------------------------<br />
+handles    Array of DOM nodes that trigger dragging<br />
+           for the element being registered<br />
+isHandle   True if the element passed in triggers<br />
+           dragging itself, else false
+</pre>
      */
+        register : function(el, data){
+            data = data || {};
+            if(typeof el == "string"){
+                el = document.getElementById(el);
+            }
+            data.ddel = el;
+            elements[getId(el)] = data;
+            if(data.isHandle !== false){
+                handles[data.ddel.id] = data;
+            }
+            if(data.handles){
+                var hs = data.handles;
+                for(var i = 0, len = hs.length; i < len; i++){
+                       handles[getId(hs[i])] = data;
+                }
+            }
+        },
+
     /**
-     * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
-     * method after a failed drop (defaults to "c3daf9" - light blue)
+     * Unregister a drag drop element
+     * @param {String|HTMLElement}  element The id or DOM node to unregister
      */
+        unregister : function(el){
+            var id = getId(el, false);
+            var data = elements[id];
+            if(data){
+                delete elements[id];
+                if(data.handles){
+                    var hs = data.handles;
+                    for(var i = 0, len = hs.length; i < len; i++){
+                       delete handles[getId(hs[i], false)];
+                    }
+                }
+            }
+        },
 
     /**
-     * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
-     * for a valid target to drag based on the mouse down. Override this method
-     * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
-     * object has a "ddel" attribute (with an HTML Element) for other functions to work.
-     * @param {EventObject} e The mouse down event
-     * @return {Object} The dragData
+     * Returns the handle registered for a DOM Node by id
+     * @param {String|HTMLElement} id The DOM node or id to look up
+     * @return {Object} handle The custom handle data
      */
-    getDragData : function(e){
-        return Roo.dd.Registry.getHandleFromEvent(e);
-    },
-    
+        getHandle : function(id){
+            if(typeof id != "string"){ // must be element?
+                id = id.id;
+            }
+            return handles[id];
+        },
+
     /**
-     * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
-     * this.dragData.ddel
-     * @param {Number} x The x position of the click on the dragged object
-     * @param {Number} y The y position of the click on the dragged object
-     * @return {Boolean} true to continue the drag, false to cancel
+     * Returns the handle that is registered for the DOM node that is the target of the event
+     * @param {Event} e The event
+     * @return {Object} handle The custom handle data
      */
-    onInitDrag : function(x, y){
-        this.proxy.update(this.dragData.ddel.cloneNode(true));
-        this.onStartDrag(x, y);
-        return true;
-    },
-    
+        getHandleFromEvent : function(e){
+            var t = Roo.lib.Event.getTarget(e);
+            return t ? handles[t.id] : null;
+        },
+
     /**
-     * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
+     * Returns a custom data object that is registered for a DOM node by id
+     * @param {String|HTMLElement} id The DOM node or id to look up
+     * @return {Object} data The custom data
      */
-    afterRepair : function(){
-        if(Roo.enableFx){
-            Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
-        }
-        this.dragging = false;
-    },
+        getTarget : function(id){
+            if(typeof id != "string"){ // must be element?
+                id = id.id;
+            }
+            return elements[id];
+        },
 
     /**
-     * Called before a repair of an invalid drop to get the XY to animate to. By default returns
-     * the XY of this.dragData.ddel
-     * @param {EventObject} e The mouse up event
-     * @return {Array} The xy location (e.g. [100, 200])
+     * Returns a custom data object that is registered for the DOM node that is the target of the event
+     * @param {Event} e The event
+     * @return {Object} data The custom data
      */
-    getRepairXY : function(e){
-        return Roo.Element.fly(this.dragData.ddel).getXY();  
-    }
-});/*
+        getTargetFromEvent : function(e){
+            var t = Roo.lib.Event.getTarget(e);
+            return t ? elements[t.id] || handles[t.id] : null;
+        }
+    };
+}();/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -20625,206 +22856,173 @@ Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
  * Fork - LGPL
  * <script type="text/javascript">
  */
+
 /**
- * @class Roo.dd.DropZone
- * @extends Roo.dd.DropTarget
- * This class provides a container DD instance that proxies for multiple child node targets.<br />
- * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
+ * @class Roo.dd.StatusProxy
+ * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair.  This is the
+ * default drag proxy used by all Roo.dd components.
  * @constructor
- * @param {String/HTMLElement/Element} el The container element
  * @param {Object} config
  */
-Roo.dd.DropZone = function(el, config){
-    Roo.dd.DropZone.superclass.constructor.call(this, el, config);
+Roo.dd.StatusProxy = function(config){
+    Roo.apply(this, config);
+    this.id = this.id || Roo.id();
+    this.el = new Roo.Layer({
+        dh: {
+            id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
+                {tag: "div", cls: "x-dd-drop-icon"},
+                {tag: "div", cls: "x-dd-drag-ghost"}
+            ]
+        }, 
+        shadow: !config || config.shadow !== false
+    });
+    this.ghost = Roo.get(this.el.dom.childNodes[1]);
+    this.dropStatus = this.dropNotAllowed;
 };
 
-Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
+Roo.dd.StatusProxy.prototype = {
     /**
-     * Returns a custom data object associated with the DOM node that is the target of the event.  By default
-     * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
-     * provide your own custom lookup.
-     * @param {Event} e The event
-     * @return {Object} data The custom data
+     * @cfg {String} dropAllowed
+     * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
      */
-    getTargetFromEvent : function(e){
-        return Roo.dd.Registry.getTargetFromEvent(e);
-    },
-
+    dropAllowed : "x-dd-drop-ok",
     /**
-     * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
-     * that it has registered.  This method has no default implementation and should be overridden to provide
-     * node-specific processing if necessary.
-     * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
-     * {@link #getTargetFromEvent} for this node)
-     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
-     * @param {Event} e The event
-     * @param {Object} data An object containing arbitrary data supplied by the drag source
+     * @cfg {String} dropNotAllowed
+     * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
      */
-    onNodeEnter : function(n, dd, e, data){
-        
-    },
+    dropNotAllowed : "x-dd-drop-nodrop",
 
     /**
-     * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
-     * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
-     * overridden to provide the proper feedback.
-     * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
-     * {@link #getTargetFromEvent} for this node)
-     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
-     * @param {Event} e The event
-     * @param {Object} data An object containing arbitrary data supplied by the drag source
-     * @return {String} status The CSS class that communicates the drop status back to the source so that the
-     * underlying {@link Roo.dd.StatusProxy} can be updated
+     * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
+     * over the current target element.
+     * @param {String} cssClass The css class for the new drop status indicator image
      */
-    onNodeOver : function(n, dd, e, data){
-        return this.dropAllowed;
+    setStatus : function(cssClass){
+        cssClass = cssClass || this.dropNotAllowed;
+        if(this.dropStatus != cssClass){
+            this.el.replaceClass(this.dropStatus, cssClass);
+            this.dropStatus = cssClass;
+        }
     },
 
     /**
-     * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
-     * the drop node without dropping.  This method has no default implementation and should be overridden to provide
-     * node-specific processing if necessary.
-     * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
-     * {@link #getTargetFromEvent} for this node)
-     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
-     * @param {Event} e The event
-     * @param {Object} data An object containing arbitrary data supplied by the drag source
+     * Resets the status indicator to the default dropNotAllowed value
+     * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
      */
-    onNodeOut : function(n, dd, e, data){
-        
+    reset : function(clearGhost){
+        this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
+        this.dropStatus = this.dropNotAllowed;
+        if(clearGhost){
+            this.ghost.update("");
+        }
     },
 
     /**
-     * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
-     * the drop node.  The default implementation returns false, so it should be overridden to provide the
-     * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
-     * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
-     * {@link #getTargetFromEvent} for this node)
-     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
-     * @param {Event} e The event
-     * @param {Object} data An object containing arbitrary data supplied by the drag source
-     * @return {Boolean} True if the drop was valid, else false
+     * Updates the contents of the ghost element
+     * @param {String} html The html that will replace the current innerHTML of the ghost element
      */
-    onNodeDrop : function(n, dd, e, data){
-        return false;
+    update : function(html){
+        if(typeof html == "string"){
+            this.ghost.update(html);
+        }else{
+            this.ghost.update("");
+            html.style.margin = "0";
+            this.ghost.dom.appendChild(html);
+        }
+        // ensure float = none set?? cant remember why though.
+        var el = this.ghost.dom.firstChild;
+               if(el){
+                       Roo.fly(el).setStyle('float', 'none');
+               }
     },
-
+    
     /**
-     * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
-     * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
-     * it should be overridden to provide the proper feedback if necessary.
-     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
-     * @param {Event} e The event
-     * @param {Object} data An object containing arbitrary data supplied by the drag source
-     * @return {String} status The CSS class that communicates the drop status back to the source so that the
-     * underlying {@link Roo.dd.StatusProxy} can be updated
-     */
-    onContainerOver : function(dd, e, data){
-        return this.dropNotAllowed;
+     * Returns the underlying proxy {@link Roo.Layer}
+     * @return {Roo.Layer} el
+    */
+    getEl : function(){
+        return this.el;
     },
 
     /**
-     * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
-     * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
-     * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
-     * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
-     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
-     * @param {Event} e The event
-     * @param {Object} data An object containing arbitrary data supplied by the drag source
-     * @return {Boolean} True if the drop was valid, else false
+     * Returns the ghost element
+     * @return {Roo.Element} el
      */
-    onContainerDrop : function(dd, e, data){
-        return false;
+    getGhost : function(){
+        return this.ghost;
     },
 
     /**
-     * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
-     * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
-     * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
-     * you should override this method and provide a custom implementation.
-     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
-     * @param {Event} e The event
-     * @param {Object} data An object containing arbitrary data supplied by the drag source
-     * @return {String} status The CSS class that communicates the drop status back to the source so that the
-     * underlying {@link Roo.dd.StatusProxy} can be updated
+     * Hides the proxy
+     * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
      */
-    notifyEnter : function(dd, e, data){
-        return this.dropNotAllowed;
+    hide : function(clear){
+        this.el.hide();
+        if(clear){
+            this.reset(true);
+        }
     },
 
     /**
-     * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
-     * This method will be called on every mouse movement while the drag source is over the drop zone.
-     * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
-     * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
-     * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
-     * registered node, it will call {@link #onContainerOver}.
-     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
-     * @param {Event} e The event
-     * @param {Object} data An object containing arbitrary data supplied by the drag source
-     * @return {String} status The CSS class that communicates the drop status back to the source so that the
-     * underlying {@link Roo.dd.StatusProxy} can be updated
+     * Stops the repair animation if it's currently running
      */
-    notifyOver : function(dd, e, data){
-        var n = this.getTargetFromEvent(e);
-        if(!n){ // not over valid drop target
-            if(this.lastOverNode){
-                this.onNodeOut(this.lastOverNode, dd, e, data);
-                this.lastOverNode = null;
-            }
-            return this.onContainerOver(dd, e, data);
-        }
-        if(this.lastOverNode != n){
-            if(this.lastOverNode){
-                this.onNodeOut(this.lastOverNode, dd, e, data);
-            }
-            this.onNodeEnter(n, dd, e, data);
-            this.lastOverNode = n;
+    stop : function(){
+        if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
+            this.anim.stop();
         }
-        return this.onNodeOver(n, dd, e, data);
     },
 
     /**
-     * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
-     * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
-     * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
-     * @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 zone
+     * Displays this proxy
      */
-    notifyOut : function(dd, e, data){
-        if(this.lastOverNode){
-            this.onNodeOut(this.lastOverNode, dd, e, data);
-            this.lastOverNode = null;
-        }
+    show : function(){
+        this.el.show();
     },
 
     /**
-     * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
-     * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
-     * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
-     * otherwise it will call {@link #onContainerDrop}.
-     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
-     * @param {Event} e The event
-     * @param {Object} data An object containing arbitrary data supplied by the drag source
-     * @return {Boolean} True if the drop was valid, else false
+     * Force the Layer to sync its shadow and shim positions to the element
      */
-    notifyDrop : function(dd, e, data){
-        if(this.lastOverNode){
-            this.onNodeOut(this.lastOverNode, dd, e, data);
-            this.lastOverNode = null;
+    sync : function(){
+        this.el.sync();
+    },
+
+    /**
+     * Causes the proxy to return to its position of origin via an animation.  Should be called after an
+     * invalid drop operation by the item being dragged.
+     * @param {Array} xy The XY position of the element ([x, y])
+     * @param {Function} callback The function to call after the repair is complete
+     * @param {Object} scope The scope in which to execute the callback
+     */
+    repair : function(xy, callback, scope){
+        this.callback = callback;
+        this.scope = scope;
+        if(xy && this.animRepair !== false){
+            this.el.addClass("x-dd-drag-repair");
+            this.el.hideUnders(true);
+            this.anim = this.el.shift({
+                duration: this.repairDuration || .5,
+                easing: 'easeOut',
+                xy: xy,
+                stopFx: true,
+                callback: this.afterRepair,
+                scope: this
+            });
+        }else{
+            this.afterRepair();
         }
-        var n = this.getTargetFromEvent(e);
-        return n ?
-            this.onNodeDrop(n, dd, e, data) :
-            this.onContainerDrop(dd, e, data);
     },
 
     // private
-    triggerCacheRefresh : function(){
-        Roo.dd.DDM.refreshCache(this.groups);
-    }  
-});/*
+    afterRepair : function(){
+        this.hide(true);
+        if(typeof this.callback == "function"){
+            this.callback.call(this.scope || this);
+        }
+        this.callback = null;
+        this.scope = null;
+    }
+};/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -20835,326 +23033,359 @@ Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
  * <script type="text/javascript">
  */
 
-
 /**
- * @class Roo.data.SortTypes
- * @singleton
- * Defines the default sorting (casting?) comparison functions used when sorting data.
+ * @class Roo.dd.DragSource
+ * @extends Roo.dd.DDProxy
+ * A simple class that provides the basic implementation needed to make any element draggable.
+ * @constructor
+ * @param {String/HTMLElement/Element} el The container element
+ * @param {Object} config
  */
-Roo.data.SortTypes = {
-    /**
-     * Default sort that does nothing
-     * @param {Mixed} s The value being converted
-     * @return {Mixed} The comparison value
-     */
-    none : function(s){
-        return s;
-    },
+Roo.dd.DragSource = function(el, config){
+    this.el = Roo.get(el);
+    this.dragData = {};
     
-    /**
-     * The regular expression used to strip tags
-     * @type {RegExp}
-     * @property
-     */
-    stripTagsRE : /<\/?[^>]+>/gi,
+    Roo.apply(this, config);
     
-    /**
-     * Strips all HTML tags to sort on text only
-     * @param {Mixed} s The value being converted
-     * @return {String} The comparison value
-     */
-    asText : function(s){
-        return String(s).replace(this.stripTagsRE, "");
-    },
+    if(!this.proxy){
+        this.proxy = new Roo.dd.StatusProxy();
+    }
+
+    Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
+          {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
     
+    this.dragging = false;
+};
+
+Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
     /**
-     * Strips all HTML tags to sort on text only - Case insensitive
-     * @param {Mixed} s The value being converted
-     * @return {String} The comparison value
+     * @cfg {String} dropAllowed
+     * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
      */
-    asUCText : function(s){
-        return String(s).toUpperCase().replace(this.stripTagsRE, "");
-    },
-    
+    dropAllowed : "x-dd-drop-ok",
     /**
-     * Case insensitive string
-     * @param {Mixed} s The value being converted
-     * @return {String} The comparison value
+     * @cfg {String} dropNotAllowed
+     * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
      */
-    asUCString : function(s) {
-       return String(s).toUpperCase();
-    },
-    
+    dropNotAllowed : "x-dd-drop-nodrop",
+
     /**
-     * Date sorting
-     * @param {Mixed} s The value being converted
-     * @return {Number} The comparison value
+     * Returns the data object associated with this drag source
+     * @return {Object} data An object containing arbitrary data
      */
-    asDate : function(s) {
-        if(!s){
-            return 0;
-        }
-        if(s instanceof Date){
-            return s.getTime();
+    getDragData : function(e){
+        return this.dragData;
+    },
+
+    // private
+    onDragEnter : function(e, id){
+        var target = Roo.dd.DragDropMgr.getDDById(id);
+        this.cachedTarget = target;
+        if(this.beforeDragEnter(target, e, id) !== false){
+            if(target.isNotifyTarget){
+                var status = target.notifyEnter(this, e, this.dragData);
+                this.proxy.setStatus(status);
+            }else{
+                this.proxy.setStatus(this.dropAllowed);
+            }
+            
+            if(this.afterDragEnter){
+                /**
+                 * An empty function by default, but provided so that you can perform a custom action
+                 * when the dragged item enters the drop target by providing an implementation.
+                 * @param {Roo.dd.DragDrop} target The drop target
+                 * @param {Event} e The event object
+                 * @param {String} id The id of the dragged element
+                 * @method afterDragEnter
+                 */
+                this.afterDragEnter(target, e, id);
+            }
         }
-       return Date.parse(String(s));
     },
-    
+
     /**
-     * Float sorting
-     * @param {Mixed} s The value being converted
-     * @return {Float} The comparison value
+     * An empty function by default, but provided so that you can perform a custom action
+     * before the dragged item enters the drop target and optionally cancel the onDragEnter.
+     * @param {Roo.dd.DragDrop} target The drop target
+     * @param {Event} e The event object
+     * @param {String} id The id of the dragged element
+     * @return {Boolean} isValid True if the drag event is valid, else false to cancel
      */
-    asFloat : function(s) {
-       var val = parseFloat(String(s).replace(/,/g, ""));
-        if(isNaN(val)) val = 0;
-       return val;
+    beforeDragEnter : function(target, e, id){
+        return true;
     },
-    
-    /**
-     * Integer sorting
-     * @param {Mixed} s The value being converted
-     * @return {Number} The comparison value
-     */
-    asInt : function(s) {
-        var val = parseInt(String(s).replace(/,/g, ""));
-        if(isNaN(val)) val = 0;
-       return 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.data.Record
- * Instances of this class encapsulate both record <em>definition</em> information, and record
- * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
- * to access Records cached in an {@link Roo.data.Store} object.<br>
- * <p>
- * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
- * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
- * objects.<br>
- * <p>
- * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
- * @constructor
- * This constructor should not be used to create Record objects. Instead, use the constructor generated by
- * {@link #create}. The parameters are the same.
- * @param {Array} data An associative Array of data values keyed by the field name.
- * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
- * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
- * not specified an integer id is generated.
- */
-Roo.data.Record = function(data, id){
-    this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
-    this.data = data;
-};
 
-/**
- * Generate a constructor for a specific record layout.
- * @param {Array} o An Array of field definition objects which specify field names, and optionally,
- * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
- * Each field definition object may contain the following properties: <ul>
- * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
- * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
- * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
- * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
- * is being used, then this is a string containing the javascript expression to reference the data relative to 
- * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
- * to the data item relative to the record element. If the mapping expression is the same as the field name,
- * this may be omitted.</p></li>
- * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
- * <ul><li>auto (Default, implies no conversion)</li>
- * <li>string</li>
- * <li>int</li>
- * <li>float</li>
- * <li>boolean</li>
- * <li>date</li></ul></p></li>
- * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
- * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
- * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
- * by the Reader into an object that will be stored in the Record. It is passed the
- * following parameters:<ul>
- * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
- * </ul></p></li>
- * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
- * </ul>
- * <br>usage:<br><pre><code>
-var TopicRecord = Roo.data.Record.create(
-    {name: 'title', mapping: 'topic_title'},
-    {name: 'author', mapping: 'username'},
-    {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
-    {name: 'lastPost', mapping: 'post_time', type: 'date'},
-    {name: 'lastPoster', mapping: 'user2'},
-    {name: 'excerpt', mapping: 'post_text'}
-);
+    // private
+    alignElWithMouse: function() {
+        Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
+        this.proxy.sync();
+    },
 
-var myNewRecord = new TopicRecord({
-    title: 'Do my job please',
-    author: 'noobie',
-    totalPosts: 1,
-    lastPost: new Date(),
-    lastPoster: 'Animal',
-    excerpt: 'No way dude!'
-});
-myStore.add(myNewRecord);
-</code></pre>
- * @method create
- * @static
- */
-Roo.data.Record.create = function(o){
-    var f = function(){
-        f.superclass.constructor.apply(this, arguments);
-    };
-    Roo.extend(f, Roo.data.Record);
-    var p = f.prototype;
-    p.fields = new Roo.util.MixedCollection(false, function(field){
-        return field.name;
-    });
-    for(var i = 0, len = o.length; i < len; i++){
-        p.fields.add(new Roo.data.Field(o[i]));
-    }
-    f.getField = function(name){
-        return p.fields.get(name);  
-    };
-    return f;
-};
+    // private
+    onDragOver : function(e, id){
+        var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
+        if(this.beforeDragOver(target, e, id) !== false){
+            if(target.isNotifyTarget){
+                var status = target.notifyOver(this, e, this.dragData);
+                this.proxy.setStatus(status);
+            }
 
-Roo.data.Record.AUTO_ID = 1000;
-Roo.data.Record.EDIT = 'edit';
-Roo.data.Record.REJECT = 'reject';
-Roo.data.Record.COMMIT = 'commit';
+            if(this.afterDragOver){
+                /**
+                 * An empty function by default, but provided so that you can perform a custom action
+                 * while the dragged item is over the drop target by providing an implementation.
+                 * @param {Roo.dd.DragDrop} target The drop target
+                 * @param {Event} e The event object
+                 * @param {String} id The id of the dragged element
+                 * @method afterDragOver
+                 */
+                this.afterDragOver(target, e, id);
+            }
+        }
+    },
 
-Roo.data.Record.prototype = {
     /**
-     * Readonly flag - true if this record has been modified.
-     * @type Boolean
+     * An empty function by default, but provided so that you can perform a custom action
+     * while the dragged item is over the drop target and optionally cancel the onDragOver.
+     * @param {Roo.dd.DragDrop} target The drop target
+     * @param {Event} e The event object
+     * @param {String} id The id of the dragged element
+     * @return {Boolean} isValid True if the drag event is valid, else false to cancel
      */
-    dirty : false,
-    editing : false,
-    error: null,
-    modified: null,
+    beforeDragOver : function(target, e, id){
+        return true;
+    },
 
     // private
-    join : function(store){
-        this.store = store;
+    onDragOut : function(e, id){
+        var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
+        if(this.beforeDragOut(target, e, id) !== false){
+            if(target.isNotifyTarget){
+                target.notifyOut(this, e, this.dragData);
+            }
+            this.proxy.reset();
+            if(this.afterDragOut){
+                /**
+                 * An empty function by default, but provided so that you can perform a custom action
+                 * after the dragged item is dragged out of the target without dropping.
+                 * @param {Roo.dd.DragDrop} target The drop target
+                 * @param {Event} e The event object
+                 * @param {String} id The id of the dragged element
+                 * @method afterDragOut
+                 */
+                this.afterDragOut(target, e, id);
+            }
+        }
+        this.cachedTarget = null;
     },
 
     /**
-     * Set the named field to the specified value.
-     * @param {String} name The name of the field to set.
-     * @param {Object} value The value to set the field to.
+     * An empty function by default, but provided so that you can perform a custom action before the dragged
+     * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
+     * @param {Roo.dd.DragDrop} target The drop target
+     * @param {Event} e The event object
+     * @param {String} id The id of the dragged element
+     * @return {Boolean} isValid True if the drag event is valid, else false to cancel
      */
-    set : function(name, value){
-        if(this.data[name] == value){
-            return;
+    beforeDragOut : function(target, e, id){
+        return true;
+    },
+    
+    // private
+    onDragDrop : function(e, id){
+        var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
+        if(this.beforeDragDrop(target, e, id) !== false){
+            if(target.isNotifyTarget){
+                if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
+                    this.onValidDrop(target, e, id);
+                }else{
+                    this.onInvalidDrop(target, e, id);
+                }
+            }else{
+                this.onValidDrop(target, e, id);
+            }
+            
+            if(this.afterDragDrop){
+                /**
+                 * An empty function by default, but provided so that you can perform a custom action
+                 * after a valid drag drop has occurred by providing an implementation.
+                 * @param {Roo.dd.DragDrop} target The drop target
+                 * @param {Event} e The event object
+                 * @param {String} id The id of the dropped element
+                 * @method afterDragDrop
+                 */
+                this.afterDragDrop(target, e, id);
+            }
         }
-        this.dirty = true;
-        if(!this.modified){
-            this.modified = {};
+        delete this.cachedTarget;
+    },
+
+    /**
+     * An empty function by default, but provided so that you can perform a custom action before the dragged
+     * item is dropped onto the target and optionally cancel the onDragDrop.
+     * @param {Roo.dd.DragDrop} target The drop target
+     * @param {Event} e The event object
+     * @param {String} id The id of the dragged element
+     * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
+     */
+    beforeDragDrop : function(target, e, id){
+        return true;
+    },
+
+    // private
+    onValidDrop : function(target, e, id){
+        this.hideProxy();
+        if(this.afterValidDrop){
+            /**
+             * An empty function by default, but provided so that you can perform a custom action
+             * after a valid drop has occurred by providing an implementation.
+             * @param {Object} target The target DD 
+             * @param {Event} e The event object
+             * @param {String} id The id of the dropped element
+             * @method afterInvalidDrop
+             */
+            this.afterValidDrop(target, e, id);
         }
-        if(typeof this.modified[name] == 'undefined'){
-            this.modified[name] = this.data[name];
+    },
+
+    // private
+    getRepairXY : function(e, data){
+        return this.el.getXY();  
+    },
+
+    // private
+    onInvalidDrop : function(target, e, id){
+        this.beforeInvalidDrop(target, e, id);
+        if(this.cachedTarget){
+            if(this.cachedTarget.isNotifyTarget){
+                this.cachedTarget.notifyOut(this, e, this.dragData);
+            }
+            this.cacheTarget = null;
+        }
+        this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
+
+        if(this.afterInvalidDrop){
+            /**
+             * An empty function by default, but provided so that you can perform a custom action
+             * after an invalid drop has occurred by providing an implementation.
+             * @param {Event} e The event object
+             * @param {String} id The id of the dropped element
+             * @method afterInvalidDrop
+             */
+            this.afterInvalidDrop(e, id);
+        }
+    },
+
+    // private
+    afterRepair : function(){
+        if(Roo.enableFx){
+            this.el.highlight(this.hlColor || "c3daf9");
         }
-        this.data[name] = value;
-        if(!this.editing && this.store){
-            this.store.afterEdit(this);
-        }       
+        this.dragging = false;
     },
 
     /**
-     * Get the value of the named field.
-     * @param {String} name The name of the field to get the value of.
-     * @return {Object} The value of the field.
+     * An empty function by default, but provided so that you can perform a custom action after an invalid
+     * drop has occurred.
+     * @param {Roo.dd.DragDrop} target The drop target
+     * @param {Event} e The event object
+     * @param {String} id The id of the dragged element
+     * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
      */
-    get : function(name){
-        return this.data[name]; 
+    beforeInvalidDrop : function(target, e, id){
+        return true;
     },
 
     // private
-    beginEdit : function(){
-        this.editing = true;
-        this.modified = {}; 
+    handleMouseDown : function(e){
+        if(this.dragging) {
+            return;
+        }
+        var data = this.getDragData(e);
+        if(data && this.onBeforeDrag(data, e) !== false){
+            this.dragData = data;
+            this.proxy.stop();
+            Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
+        } 
     },
 
-    // private
-    cancelEdit : function(){
-        this.editing = false;
-        delete this.modified;
+    /**
+     * An empty function by default, but provided so that you can perform a custom action before the initial
+     * drag event begins and optionally cancel it.
+     * @param {Object} data An object containing arbitrary data to be shared with drop targets
+     * @param {Event} e The event object
+     * @return {Boolean} isValid True if the drag event is valid, else false to cancel
+     */
+    onBeforeDrag : function(data, e){
+        return true;
+    },
+
+    /**
+     * An empty function by default, but provided so that you can perform a custom action once the initial
+     * drag event has begun.  The drag cannot be canceled from this function.
+     * @param {Number} x The x position of the click on the dragged object
+     * @param {Number} y The y position of the click on the dragged object
+     */
+    onStartDrag : Roo.emptyFn,
+
+    // private - YUI override
+    startDrag : function(x, y){
+        this.proxy.reset();
+        this.dragging = true;
+        this.proxy.update("");
+        this.onInitDrag(x, y);
+        this.proxy.show();
     },
 
     // private
-    endEdit : function(){
-        this.editing = false;
-        if(this.dirty && this.store){
-            this.store.afterEdit(this);
-        }
+    onInitDrag : function(x, y){
+        var clone = this.el.dom.cloneNode(true);
+        clone.id = Roo.id(); // prevent duplicate ids
+        this.proxy.update(clone);
+        this.onStartDrag(x, y);
+        return true;
     },
 
     /**
-     * Usually called by the {@link Roo.data.Store} which owns the Record.
-     * Rejects all changes made to the Record since either creation, or the last commit operation.
-     * Modified fields are reverted to their original values.
-     * <p>
-     * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
-     * of reject operations.
+     * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
+     * @return {Roo.dd.StatusProxy} proxy The StatusProxy
      */
-    reject : function(){
-        var m = this.modified;
-        for(var n in m){
-            if(typeof m[n] != "function"){
-                this.data[n] = m[n];
-            }
-        }
-        this.dirty = false;
-        delete this.modified;
-        this.editing = false;
-        if(this.store){
-            this.store.afterReject(this);
-        }
+    getProxy : function(){
+        return this.proxy;  
     },
 
     /**
-     * Usually called by the {@link Roo.data.Store} which owns the Record.
-     * Commits all changes made to the Record since either creation, or the last commit operation.
-     * <p>
-     * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
-     * of commit operations.
+     * Hides the drag source's {@link Roo.dd.StatusProxy}
      */
-    commit : function(){
-        this.dirty = false;
-        delete this.modified;
-        this.editing = false;
-        if(this.store){
-            this.store.afterCommit(this);
-        }
+    hideProxy : function(){
+        this.proxy.hide();  
+        this.proxy.reset(true);
+        this.dragging = false;
     },
 
     // private
-    hasError : function(){
-        return this.error != null;
+    triggerCacheRefresh : function(){
+        Roo.dd.DDM.refreshCache(this.groups);
     },
 
-    // private
-    clearError : function(){
-        this.error = null;
+    // private - override to prevent hiding
+    b4EndDrag: function(e) {
     },
 
-    /**
-     * Creates a copy of this record.
-     * @param {String} id (optional) A new record id if you don't want to use this record's id
-     * @return {Record}
-     */
-    copy : function(newId) {
-        return new this.constructor(Roo.apply({}, this.data), newId || this.id);
-    }
-};/*
+    // private - override to prevent moving
+    endDrag : function(e){
+        this.onEndDrag(this.dragData, e);
+    },
+
+    // private
+    onEndDrag : function(data, e){
+    },
+    
+    // private - pin to cursor
+    autoOffset : function(x, y) {
+        this.setDelta(-12, -20);
+    }    
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -21166,722 +23397,580 @@ Roo.data.Record.prototype = {
  */
 
 
-
 /**
- * @class Roo.data.Store
- * @extends Roo.util.Observable
- * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
- * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
- * <p>
- * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
- * has no knowledge of the format of the data returned by the Proxy.<br>
- * <p>
- * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
- * instances from the data object. These records are cached and made available through accessor functions.
+ * @class Roo.dd.DropTarget
+ * @extends Roo.dd.DDTarget
+ * A simple class that provides the basic implementation needed to make any element a drop target that can have
+ * draggable items dropped onto it.  The drop has no effect until an implementation of notifyDrop is provided.
  * @constructor
- * Creates a new Store.
- * @param {Object} config A config object containing the objects needed for the Store to access data,
- * and read the data into Records.
+ * @param {String/HTMLElement/Element} el The container element
+ * @param {Object} config
  */
-Roo.data.Store = function(config){
-    this.data = new Roo.util.MixedCollection(false);
-    this.data.getKey = function(o){
-        return o.id;
-    };
-    this.baseParams = {};
-    // private
-    this.paramNames = {
-        "start" : "start",
-        "limit" : "limit",
-        "sort" : "sort",
-        "dir" : "dir",
-        "multisort" : "_multisort"
-    };
-
-    if(config && config.data){
-        this.inlineData = config.data;
-        delete config.data;
+Roo.dd.DropTarget = function(el, config){
+    this.el = Roo.get(el);
+    
+    var listeners = false; ;
+    if (config && config.listeners) {
+        listeners= config.listeners;
+        delete config.listeners;
     }
-
     Roo.apply(this, config);
     
-    if(this.reader){ // reader passed
-        this.reader = Roo.factory(this.reader, Roo.data);
-        this.reader.xmodule = this.xmodule || false;
-        if(!this.recordType){
-            this.recordType = this.reader.recordType;
-        }
-        if(this.reader.onMetaChange){
-            this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
-        }
-    }
-
-    if(this.recordType){
-        this.fields = this.recordType.prototype.fields;
+    if(this.containerScroll){
+        Roo.dd.ScrollManager.register(this.el);
     }
-    this.modified = [];
-
-    this.addEvents({
-        /**
-         * @event datachanged
-         * Fires when the data cache has changed, and a widget which is using this Store
-         * as a Record cache should refresh its view.
-         * @param {Store} this
-         */
-        datachanged : true,
-        /**
-         * @event metachange
-         * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
-         * @param {Store} this
-         * @param {Object} meta The JSON metadata
-         */
-        metachange : true,
-        /**
-         * @event add
-         * Fires when Records have been added to the Store
-         * @param {Store} this
-         * @param {Roo.data.Record[]} records The array of Records added
-         * @param {Number} index The index at which the record(s) were added
-         */
-        add : true,
-        /**
-         * @event remove
-         * Fires when a Record has been removed from the Store
-         * @param {Store} this
-         * @param {Roo.data.Record} record The Record that was removed
-         * @param {Number} index The index at which the record was removed
-         */
-        remove : true,
-        /**
-         * @event update
-         * Fires when a Record has been updated
-         * @param {Store} this
-         * @param {Roo.data.Record} record The Record that was updated
-         * @param {String} operation The update operation being performed.  Value may be one of:
-         * <pre><code>
- Roo.data.Record.EDIT
- Roo.data.Record.REJECT
- Roo.data.Record.COMMIT
-         * </code></pre>
-         */
-        update : true,
-        /**
-         * @event clear
-         * Fires when the data cache has been cleared.
-         * @param {Store} this
+    this.addEvents( {
+         /**
+         * @scope Roo.dd.DropTarget
          */
-        clear : true,
-        /**
-         * @event beforeload
-         * Fires before a request is made for a new data object.  If the beforeload handler returns false
-         * the load action will be canceled.
-         * @param {Store} this
-         * @param {Object} options The loading options that were specified (see {@link #load} for details)
+         
+         /**
+         * @event enter
+         * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
+         * 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.valid to true|false
+         * 
+         * @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
          */
-        beforeload : true,
-        /**
-         * @event beforeloadadd
-         * Fires after a new set of Records has been loaded.
-         * @param {Store} this
-         * @param {Roo.data.Record[]} records The Records that were loaded
-         * @param {Object} options The loading options that were specified (see {@link #load} for details)
+        "enter" : true,
+        
+         /**
+         * @event over
+         * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
+         * 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.valid to true|false
+         * 
+         * @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
+         
          */
-        beforeloadadd : true,
+        "over" : true,
         /**
-         * @event load
-         * Fires after a new set of Records has been loaded, before they are added to the store.
-         * @param {Store} this
-         * @param {Roo.data.Record[]} records The Records that were loaded
-         * @param {Object} options The loading options that were specified (see {@link #load} for details)
-         * @params {Object} return from reader
+         * @event out
+         * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
+         * 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
          */
-        load : true,
+         "out" : true,
+         
         /**
-         * @event loadexception
-         * Fires if an exception occurs in the Proxy during loading.
-         * Called with the signature of the Proxy's "loadexception" event.
-         * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
+         * @event drop
+         * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
+         * been dropped on it.  This method has no default implementation and returns false, so you must provide an
+         * implementation that does something to process the drop event and returns true so that the drag source's
+         * repair action does not run.
          * 
-         * @param {Proxy} 
-         * @param {Object} return from JsonData.reader() - success, totalRecords, records
-         * @param {Object} load options 
-         * @param {Object} jsonData from your request (normally this contains the Exception)
-         */
-        loadexception : true
+         * IMPORTANT : it should set this.success
+         * 
+         * @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
+        */
+         "drop" : true
     });
-    
-    if(this.proxy){
-        this.proxy = Roo.factory(this.proxy, Roo.data);
-        this.proxy.xmodule = this.xmodule || false;
-        this.relayEvents(this.proxy,  ["loadexception"]);
-    }
-    this.sortToggle = {};
-    this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
-
-    Roo.data.Store.superclass.constructor.call(this);
+            
+     
+    Roo.dd.DropTarget.superclass.constructor.call(  this, 
+        this.el.dom, 
+        this.ddGroup || this.group,
+        {
+            isTarget: true,
+            listeners : listeners || {} 
+           
+        
+        }
+    );
 
-    if(this.inlineData){
-        this.loadData(this.inlineData);
-        delete this.inlineData;
-    }
 };
 
-Roo.extend(Roo.data.Store, Roo.util.Observable, {
-     /**
-    * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
-    * without a remote query - used by combo/forms at present.
-    */
-    
-    /**
-    * @cfg {Roo.data.DataProxy} proxy 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
-    * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
-    */
+Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
     /**
-    * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
-    * on any HTTP request
-    */
+     * @cfg {String} overClass
+     * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
+     */
+     /**
+     * @cfg {String} ddGroup
+     * The drag drop group to handle drop events for
+     */
+     
     /**
-    * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
-    */
+     * @cfg {String} dropAllowed
+     * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
+     */
+    dropAllowed : "x-dd-drop-ok",
     /**
-    * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
-    */
-    multiSort: false,
+     * @cfg {String} dropNotAllowed
+     * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
+     */
+    dropNotAllowed : "x-dd-drop-nodrop",
     /**
-    * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
-    * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
-    */
-    remoteSort : false,
-
+     * @cfg {boolean} success
+     * set this after drop listener.. 
+     */
+    success : false,
     /**
-    * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
-     * loaded or when a record is removed. (defaults to false).
-    */
-    pruneModifiedRecords : false,
-
+     * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
+     * if the drop point is valid for over/enter..
+     */
+    valid : false,
     // private
-    lastOptions : null,
+    isTarget : true,
 
+    // private
+    isNotifyTarget : true,
+    
     /**
-     * Add Records to the Store and fires the add event.
-     * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
+     * @hide
      */
-    add : function(records){
-        records = [].concat(records);
-        for(var i = 0, len = records.length; i < len; i++){
-            records[i].join(this);
+    notifyEnter : function(dd, e, data)
+    {
+        this.valid = true;
+        this.fireEvent('enter', dd, e, data);
+        if(this.overClass){
+            this.el.addClass(this.overClass);
         }
-        var index = this.data.length;
-        this.data.addAll(records);
-        this.fireEvent("add", this, records, index);
+        return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
+            this.valid ? this.dropAllowed : this.dropNotAllowed
+        );
     },
 
     /**
-     * Remove a Record from the Store and fires the remove event.
-     * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
+     * @hide
      */
-    remove : function(record){
-        var index = this.data.indexOf(record);
-        this.data.removeAt(index);
-        if(this.pruneModifiedRecords){
-            this.modified.remove(record);
-        }
-        this.fireEvent("remove", this, record, index);
+    notifyOver : function(dd, e, data)
+    {
+        this.valid = true;
+        this.fireEvent('over', dd, e, data);
+        return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
+            this.valid ? this.dropAllowed : this.dropNotAllowed
+        );
     },
 
     /**
-     * Remove all Records from the Store and fires the clear event.
+     * @hide
      */
-    removeAll : function(){
-        this.data.clear();
-        if(this.pruneModifiedRecords){
-            this.modified = [];
+    notifyOut : function(dd, e, data)
+    {
+        this.fireEvent('out', dd, e, data);
+        if(this.overClass){
+            this.el.removeClass(this.overClass);
         }
-        this.fireEvent("clear", this);
     },
 
     /**
-     * Inserts Records to the Store at the given index and fires the add event.
-     * @param {Number} index The start index at which to insert the passed Records.
-     * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
+     * @hide
      */
-    insert : function(index, records){
-        records = [].concat(records);
-        for(var i = 0, len = records.length; i < len; i++){
-            this.data.insert(index, records[i]);
-            records[i].join(this);
-        }
-        this.fireEvent("add", this, records, index);
-    },
+    notifyDrop : function(dd, e, data)
+    {
+        this.success = false;
+        this.fireEvent('drop', dd, e, data);
+        return this.success;
+    }
+});/*
+ * 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.dd.DragZone
+ * @extends Roo.dd.DragSource
+ * This class provides a container DD instance that proxies for multiple child node sources.<br />
+ * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
+ * @constructor
+ * @param {String/HTMLElement/Element} el The container element
+ * @param {Object} config
+ */
+Roo.dd.DragZone = function(el, config){
+    Roo.dd.DragZone.superclass.constructor.call(this, el, config);
+    if(this.containerScroll){
+        Roo.dd.ScrollManager.register(this.el);
+    }
+};
 
+Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
     /**
-     * Get the index within the cache of the passed Record.
-     * @param {Roo.data.Record} record The Roo.data.Record object to to find.
-     * @return {Number} The index of the passed Record. Returns -1 if not found.
+     * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
+     * for auto scrolling during drag operations.
      */
-    indexOf : function(record){
-        return this.data.indexOf(record);
-    },
-
     /**
-     * Get the index within the cache of the Record with the passed id.
-     * @param {String} id The id of the Record to find.
-     * @return {Number} The index of the Record. Returns -1 if not found.
+     * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
+     * method after a failed drop (defaults to "c3daf9" - light blue)
      */
-    indexOfId : function(id){
-        return this.data.indexOfKey(id);
-    },
 
     /**
-     * Get the Record with the specified id.
-     * @param {String} id The id of the Record to find.
-     * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
+     * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
+     * for a valid target to drag based on the mouse down. Override this method
+     * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
+     * object has a "ddel" attribute (with an HTML Element) for other functions to work.
+     * @param {EventObject} e The mouse down event
+     * @return {Object} The dragData
      */
-    getById : function(id){
-        return this.data.key(id);
+    getDragData : function(e){
+        return Roo.dd.Registry.getHandleFromEvent(e);
     },
-
+    
     /**
-     * Get the Record at the specified index.
-     * @param {Number} index The index of the Record to find.
-     * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
+     * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
+     * this.dragData.ddel
+     * @param {Number} x The x position of the click on the dragged object
+     * @param {Number} y The y position of the click on the dragged object
+     * @return {Boolean} true to continue the drag, false to cancel
      */
-    getAt : function(index){
-        return this.data.itemAt(index);
+    onInitDrag : function(x, y){
+        this.proxy.update(this.dragData.ddel.cloneNode(true));
+        this.onStartDrag(x, y);
+        return true;
     },
-
+    
     /**
-     * Returns a range of Records between specified indices.
-     * @param {Number} startIndex (optional) The starting index (defaults to 0)
-     * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
-     * @return {Roo.data.Record[]} An array of Records
+     * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
      */
-    getRange : function(start, end){
-        return this.data.getRange(start, end);
-    },
-
-    // private
-    storeOptions : function(o){
-        o = Roo.apply({}, o);
-        delete o.callback;
-        delete o.scope;
-        this.lastOptions = o;
+    afterRepair : function(){
+        if(Roo.enableFx){
+            Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
+        }
+        this.dragging = false;
     },
 
     /**
-     * Loads the Record cache from the configured Proxy using the configured Reader.
-     * <p>
-     * If using remote paging, then the first load call must specify the <em>start</em>
-     * and <em>limit</em> properties in the options.params property to establish the initial
-     * position within the dataset, and the number of Records to cache on each read from the Proxy.
-     * <p>
-     * <strong>It is important to note that for remote data sources, loading is asynchronous,
-     * and this call will return before the new data has been loaded. Perform any post-processing
-     * in a callback function, or in a "load" event handler.</strong>
-     * <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>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>
-     * <li>options: Options object from the load call</li>
-     * <li>success: Boolean success indicator</li></ul></li>
-     * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
-     * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
-     * </ul>
+     * Called before a repair of an invalid drop to get the XY to animate to. By default returns
+     * the XY of this.dragData.ddel
+     * @param {EventObject} e The mouse up event
+     * @return {Array} The xy location (e.g. [100, 200])
      */
-    load : function(options){
-        options = options || {};
-        if(this.fireEvent("beforeload", this, options) !== false){
-            this.storeOptions(options);
-            var p = Roo.apply(options.params || {}, this.baseParams);
-            // if meta was not loaded from remote source.. try requesting it.
-            if (!this.reader.metaFromRemote) {
-                p._requestMeta = 1;
-            }
-            if(this.sortInfo && this.remoteSort){
-                var pn = this.paramNames;
-                p[pn["sort"]] = this.sortInfo.field;
-                p[pn["dir"]] = this.sortInfo.direction;
-            }
-            if (this.multiSort) {
-                var pn = this.paramNames;
-                p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
-            }
-            
-            this.proxy.load(p, this.reader, this.loadRecords, this, options);
-        }
-    },
+    getRepairXY : function(e){
+        return Roo.Element.fly(this.dragData.ddel).getXY();  
+    }
+});/*
+ * 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.dd.DropZone
+ * @extends Roo.dd.DropTarget
+ * This class provides a container DD instance that proxies for multiple child node targets.<br />
+ * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
+ * @constructor
+ * @param {String/HTMLElement/Element} el The container element
+ * @param {Object} config
+ */
+Roo.dd.DropZone = function(el, config){
+    Roo.dd.DropZone.superclass.constructor.call(this, el, config);
+};
 
+Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
     /**
-     * Reloads the Record cache from the configured Proxy using the configured Reader and
-     * the options from the last load operation performed.
-     * @param {Object} options (optional) An object containing properties which may override the options
-     * used in the last load operation. See {@link #load} for details (defaults to null, in which case
-     * the most recently used options are reused).
+     * Returns a custom data object associated with the DOM node that is the target of the event.  By default
+     * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
+     * provide your own custom lookup.
+     * @param {Event} e The event
+     * @return {Object} data The custom data
      */
-    reload : function(options){
-        this.load(Roo.applyIf(options||{}, this.lastOptions));
+    getTargetFromEvent : function(e){
+        return Roo.dd.Registry.getTargetFromEvent(e);
     },
 
-    // private
-    // Called as a callback by the Reader during a load operation.
-    loadRecords : function(o, options, success){
-        if(!o || success === false){
-            if(success !== false){
-                this.fireEvent("load", this, [], options, o);
-            }
-            if(options.callback){
-                options.callback.call(options.scope || this, [], options, false);
-            }
-            return;
-        }
-        // if data returned failure - throw an exception.
-        if (o.success === false) {
-            // show a message if no listener is registered.
-            if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
-                    Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
-            }
-            // loadmask wil be hooked into this..
-            this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
-            return;
-        }
-        var r = o.records, t = o.totalRecords || r.length;
-        
-        this.fireEvent("beforeloadadd", this, r, options, o);
+    /**
+     * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
+     * that it has registered.  This method has no default implementation and should be overridden to provide
+     * node-specific processing if necessary.
+     * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
+     * {@link #getTargetFromEvent} for this node)
+     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
+     * @param {Event} e The event
+     * @param {Object} data An object containing arbitrary data supplied by the drag source
+     */
+    onNodeEnter : function(n, dd, e, data){
         
-        if(!options || options.add !== true){
-            if(this.pruneModifiedRecords){
-                this.modified = [];
-            }
-            for(var i = 0, len = r.length; i < len; i++){
-                r[i].join(this);
-            }
-            if(this.snapshot){
-                this.data = this.snapshot;
-                delete this.snapshot;
-            }
-            this.data.clear();
-            this.data.addAll(r);
-            this.totalLength = t;
-            this.applySort();
-            this.fireEvent("datachanged", this);
-        }else{
-            this.totalLength = Math.max(t, this.data.length+r.length);
-            this.add(r);
-        }
-        this.fireEvent("load", this, r, options, o);
-        if(options.callback){
-            options.callback.call(options.scope || this, r, options, true);
-        }
     },
 
-
     /**
-     * Loads data from a passed data block. A Reader which understands the format of the data
-     * must have been configured in the constructor.
-     * @param {Object} data The data block from which to read the Records.  The format of the data expected
-     * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
-     * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
+     * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
+     * that it has registered.  The default implementation returns this.dropNotAllowed, so it should be
+     * overridden to provide the proper feedback.
+     * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
+     * {@link #getTargetFromEvent} for this node)
+     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
+     * @param {Event} e The event
+     * @param {Object} data An object containing arbitrary data supplied by the drag source
+     * @return {String} status The CSS class that communicates the drop status back to the source so that the
+     * underlying {@link Roo.dd.StatusProxy} can be updated
      */
-    loadData : function(o, append){
-        var r = this.reader.readRecords(o);
-        this.loadRecords(r, {add: append}, true);
+    onNodeOver : function(n, dd, e, data){
+        return this.dropAllowed;
     },
 
     /**
-     * Gets the number of cached records.
-     * <p>
-     * <em>If using paging, this may not be the total size of the dataset. If the data object
-     * used by the Reader contains the dataset size, then the getTotalCount() function returns
-     * the data set size</em>
+     * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
+     * the drop node without dropping.  This method has no default implementation and should be overridden to provide
+     * node-specific processing if necessary.
+     * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
+     * {@link #getTargetFromEvent} for this node)
+     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
+     * @param {Event} e The event
+     * @param {Object} data An object containing arbitrary data supplied by the drag source
      */
-    getCount : function(){
-        return this.data.length || 0;
+    onNodeOut : function(n, dd, e, data){
+        
     },
 
     /**
-     * Gets the total number of records in the dataset as returned by the server.
-     * <p>
-     * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
-     * the dataset size</em>
+     * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
+     * the drop node.  The default implementation returns false, so it should be overridden to provide the
+     * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
+     * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
+     * {@link #getTargetFromEvent} for this node)
+     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
+     * @param {Event} e The event
+     * @param {Object} data An object containing arbitrary data supplied by the drag source
+     * @return {Boolean} True if the drop was valid, else false
      */
-    getTotalCount : function(){
-        return this.totalLength || 0;
+    onNodeDrop : function(n, dd, e, data){
+        return false;
     },
 
     /**
-     * Returns the sort state of the Store as an object with two properties:
-     * <pre><code>
- field {String} The name of the field by which the Records are sorted
- direction {String} The sort order, "ASC" or "DESC"
-     * </code></pre>
+     * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
+     * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
+     * it should be overridden to provide the proper feedback if necessary.
+     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
+     * @param {Event} e The event
+     * @param {Object} data An object containing arbitrary data supplied by the drag source
+     * @return {String} status The CSS class that communicates the drop status back to the source so that the
+     * underlying {@link Roo.dd.StatusProxy} can be updated
      */
-    getSortState : function(){
-        return this.sortInfo;
+    onContainerOver : function(dd, e, data){
+        return this.dropNotAllowed;
     },
 
-    // private
-    applySort : function(){
-        if(this.sortInfo && !this.remoteSort){
-            var s = this.sortInfo, f = s.field;
-            var st = this.fields.get(f).sortType;
-            var fn = function(r1, r2){
-                var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
-                return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
-            };
-            this.data.sort(s.direction, fn);
-            if(this.snapshot && this.snapshot != this.data){
-                this.snapshot.sort(s.direction, fn);
-            }
-        }
+    /**
+     * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
+     * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
+     * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
+     * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
+     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
+     * @param {Event} e The event
+     * @param {Object} data An object containing arbitrary data supplied by the drag source
+     * @return {Boolean} True if the drop was valid, else false
+     */
+    onContainerDrop : function(dd, e, data){
+        return false;
     },
 
     /**
-     * Sets the default sort column and order to be used by the next load operation.
-     * @param {String} fieldName The name of the field to sort by.
-     * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
+     * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
+     * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
+     * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
+     * you should override this method and provide a custom implementation.
+     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
+     * @param {Event} e The event
+     * @param {Object} data An object containing arbitrary data supplied by the drag source
+     * @return {String} status The CSS class that communicates the drop status back to the source so that the
+     * underlying {@link Roo.dd.StatusProxy} can be updated
      */
-    setDefaultSort : function(field, dir){
-        this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
+    notifyEnter : function(dd, e, data){
+        return this.dropNotAllowed;
     },
 
     /**
-     * Sort the Records.
-     * If remote sorting is used, the sort is performed on the server, and the cache is
-     * reloaded. If local sorting is used, the cache is sorted internally.
-     * @param {String} fieldName The name of the field to sort by.
-     * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
+     * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
+     * This method will be called on every mouse movement while the drag source is over the drop zone.
+     * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
+     * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
+     * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
+     * registered node, it will call {@link #onContainerOver}.
+     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
+     * @param {Event} e The event
+     * @param {Object} data An object containing arbitrary data supplied by the drag source
+     * @return {String} status The CSS class that communicates the drop status back to the source so that the
+     * underlying {@link Roo.dd.StatusProxy} can be updated
      */
-    sort : function(fieldName, dir){
-        var f = this.fields.get(fieldName);
-        if(!dir){
-            this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
-            
-            if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
-                dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
-            }else{
-                dir = f.sortDir;
+    notifyOver : function(dd, e, data){
+        var n = this.getTargetFromEvent(e);
+        if(!n){ // not over valid drop target
+            if(this.lastOverNode){
+                this.onNodeOut(this.lastOverNode, dd, e, data);
+                this.lastOverNode = null;
             }
+            return this.onContainerOver(dd, e, data);
         }
-        this.sortToggle[f.name] = dir;
-        this.sortInfo = {field: f.name, direction: dir};
-        if(!this.remoteSort){
-            this.applySort();
-            this.fireEvent("datachanged", this);
-        }else{
-            this.load(this.lastOptions);
+        if(this.lastOverNode != n){
+            if(this.lastOverNode){
+                this.onNodeOut(this.lastOverNode, dd, e, data);
+            }
+            this.onNodeEnter(n, dd, e, data);
+            this.lastOverNode = n;
         }
+        return this.onNodeOver(n, dd, e, data);
     },
 
     /**
-     * Calls the specified function for each of the Records in the cache.
-     * @param {Function} fn The function to call. The Record is passed as the first parameter.
-     * Returning <em>false</em> aborts and exits the iteration.
-     * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
+     * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
+     * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
+     * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
+     * @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 zone
      */
-    each : function(fn, scope){
-        this.data.each(fn, scope);
+    notifyOut : function(dd, e, data){
+        if(this.lastOverNode){
+            this.onNodeOut(this.lastOverNode, dd, e, data);
+            this.lastOverNode = null;
+        }
     },
 
     /**
-     * Gets all records modified since the last commit.  Modified records are persisted across load operations
-     * (e.g., during paging).
-     * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
+     * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
+     * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
+     * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
+     * otherwise it will call {@link #onContainerDrop}.
+     * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
+     * @param {Event} e The event
+     * @param {Object} data An object containing arbitrary data supplied by the drag source
+     * @return {Boolean} True if the drop was valid, else false
      */
-    getModifiedRecords : function(){
-        return this.modified;
-    },
-
-    // private
-    createFilterFn : function(property, value, anyMatch){
-        if(!value.exec){ // not a regex
-            value = String(value);
-            if(value.length == 0){
-                return false;
-            }
-            value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
+    notifyDrop : function(dd, e, data){
+        if(this.lastOverNode){
+            this.onNodeOut(this.lastOverNode, dd, e, data);
+            this.lastOverNode = null;
         }
-        return function(r){
-            return value.test(r.data[property]);
-        };
+        var n = this.getTargetFromEvent(e);
+        return n ?
+            this.onNodeDrop(n, dd, e, data) :
+            this.onContainerDrop(dd, e, data);
     },
 
-    /**
-     * Sums the value of <i>property</i> for each record between start and end and returns the result.
-     * @param {String} property A field on your records
-     * @param {Number} start The record index to start at (defaults to 0)
-     * @param {Number} end The last record index to include (defaults to length - 1)
-     * @return {Number} The sum
-     */
-    sum : function(property, start, end){
-        var rs = this.data.items, v = 0;
-        start = start || 0;
-        end = (end || end === 0) ? end : rs.length-1;
+    // private
+    triggerCacheRefresh : function(){
+        Roo.dd.DDM.refreshCache(this.groups);
+    }  
+});/*
+ * 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">
+ */
 
-        for(var i = start; i <= end; i++){
-            v += (rs[i].data[property] || 0);
-        }
-        return v;
-    },
 
+/**
+ * @class Roo.data.SortTypes
+ * @static
+ * Defines the default sorting (casting?) comparison functions used when sorting data.
+ */
+Roo.data.SortTypes = {
     /**
-     * Filter the records by a specified property.
-     * @param {String} field A field on your records
-     * @param {String/RegExp} value Either a string that the field
-     * should start with or a RegExp to test against the field
-     * @param {Boolean} anyMatch True to match any part not just the beginning
+     * Default sort that does nothing
+     * @param {Mixed} s The value being converted
+     * @return {Mixed} The comparison value
      */
-    filter : function(property, value, anyMatch){
-        var fn = this.createFilterFn(property, value, anyMatch);
-        return fn ? this.filterBy(fn) : this.clearFilter();
+    none : function(s){
+        return s;
     },
-
+    
     /**
-     * Filter by a function. The specified function will be called with each
-     * record in this data source. If the function returns true the record is included,
-     * otherwise it is filtered.
-     * @param {Function} fn The function to be called, it will receive 2 args (record, id)
-     * @param {Object} scope (optional) The scope of the function (defaults to this)
+     * The regular expression used to strip tags
+     * @type {RegExp}
+     * @property
      */
-    filterBy : function(fn, scope){
-        this.snapshot = this.snapshot || this.data;
-        this.data = this.queryBy(fn, scope||this);
-        this.fireEvent("datachanged", this);
-    },
-
+    stripTagsRE : /<\/?[^>]+>/gi,
+    
     /**
-     * Query the records by a specified property.
-     * @param {String} field A field on your records
-     * @param {String/RegExp} value Either a string that the field
-     * should start with or a RegExp to test against the field
-     * @param {Boolean} anyMatch True to match any part not just the beginning
-     * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
-     */
-    query : function(property, value, anyMatch){
-        var fn = this.createFilterFn(property, value, anyMatch);
-        return fn ? this.queryBy(fn) : this.data.clone();
+     * Strips all HTML tags to sort on text only
+     * @param {Mixed} s The value being converted
+     * @return {String} The comparison value
+     */
+    asText : function(s){
+        return String(s).replace(this.stripTagsRE, "");
     },
-
+    
     /**
-     * Query by a function. The specified function will be called with each
-     * record in this data source. If the function returns true the record is included
-     * in the results.
-     * @param {Function} fn The function to be called, it will receive 2 args (record, id)
-     * @param {Object} scope (optional) The scope of the function (defaults to this)
-      @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
-     **/
-    queryBy : function(fn, scope){
-        var data = this.snapshot || this.data;
-        return data.filterBy(fn, scope||this);
+     * Strips all HTML tags to sort on text only - Case insensitive
+     * @param {Mixed} s The value being converted
+     * @return {String} The comparison value
+     */
+    asUCText : function(s){
+        return String(s).toUpperCase().replace(this.stripTagsRE, "");
     },
-
+    
     /**
-     * Collects unique values for a particular dataIndex from this store.
-     * @param {String} dataIndex The property to collect
-     * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
-     * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
-     * @return {Array} An array of the unique values
-     **/
-    collect : function(dataIndex, allowNull, bypassFilter){
-        var d = (bypassFilter === true && this.snapshot) ?
-                this.snapshot.items : this.data.items;
-        var v, sv, r = [], l = {};
-        for(var i = 0, len = d.length; i < len; i++){
-            v = d[i].data[dataIndex];
-            sv = String(v);
-            if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
-                l[sv] = true;
-                r[r.length] = v;
-            }
-        }
-        return r;
+     * Case insensitive string
+     * @param {Mixed} s The value being converted
+     * @return {String} The comparison value
+     */
+    asUCString : function(s) {
+       return String(s).toUpperCase();
     },
-
+    
     /**
-     * Revert to a view of the Record cache with no filtering applied.
-     * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
+     * Date sorting
+     * @param {Mixed} s The value being converted
+     * @return {Number} The comparison value
      */
-    clearFilter : function(suppressEvent){
-        if(this.snapshot && this.snapshot != this.data){
-            this.data = this.snapshot;
-            delete this.snapshot;
-            if(suppressEvent !== true){
-                this.fireEvent("datachanged", this);
-            }
+    asDate : function(s) {
+        if(!s){
+            return 0;
         }
-    },
-
-    // private
-    afterEdit : function(record){
-        if(this.modified.indexOf(record) == -1){
-            this.modified.push(record);
+        if(s instanceof Date){
+            return s.getTime();
         }
-        this.fireEvent("update", this, record, Roo.data.Record.EDIT);
+       return Date.parse(String(s));
     },
     
-    // private
-    afterReject : function(record){
-        this.modified.remove(record);
-        this.fireEvent("update", this, record, Roo.data.Record.REJECT);
-    },
-
-    // private
-    afterCommit : function(record){
-        this.modified.remove(record);
-        this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
-    },
-
     /**
-     * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
-     * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
+     * Float sorting
+     * @param {Mixed} s The value being converted
+     * @return {Float} The comparison value
      */
-    commitChanges : function(){
-        var m = this.modified.slice(0);
-        this.modified = [];
-        for(var i = 0, len = m.length; i < len; i++){
-            m[i].commit();
+    asFloat : function(s) {
+       var val = parseFloat(String(s).replace(/,/g, ""));
+        if(isNaN(val)) {
+            val = 0;
         }
+       return val;
     },
-
+    
     /**
-     * Cancel outstanding changes on all changed records.
+     * Integer sorting
+     * @param {Mixed} s The value being converted
+     * @return {Number} The comparison value
      */
-    rejectChanges : function(){
-        var m = this.modified.slice(0);
-        this.modified = [];
-        for(var i = 0, len = m.length; i < len; i++){
-            m[i].reject();
+    asInt : function(s) {
+        var val = parseInt(String(s).replace(/,/g, ""));
+        if(isNaN(val)) {
+            val = 0;
         }
-    },
-
-    onMetaChange : function(meta, rtype, o){
-        this.recordType = rtype;
-        this.fields = rtype.prototype.fields;
-        delete this.snapshot;
-        this.sortInfo = meta.sortInfo || this.sortInfo;
-        this.modified = [];
-        this.fireEvent('metachange', this, this.reader.meta);
-    },
-    
-    moveIndex : function(data, type)
-    {
-        var index = this.indexOf(data);
-        
-        var newIndex = index + type;
-        
-        this.remove(data);
-        
-        this.insert(newIndex, data);
-        
+       return val;
     }
-});/*
+};/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -21893,215 +23982,227 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
  */
 
 /**
- * @class Roo.data.SimpleStore
- * @extends Roo.data.Store
- * 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 {Array} data The multi-dimensional array of data
+* @class Roo.data.Record
+ * Instances of this class encapsulate both record <em>definition</em> information, and record
+ * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
+ * to access Records cached in an {@link Roo.data.Store} object.<br>
+ * <p>
+ * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
+ * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
+ * objects.<br>
+ * <p>
+ * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
  * @constructor
- * @param {Object} config
+ * This constructor should not be used to create Record objects. Instead, use the constructor generated by
+ * {@link #create}. The parameters are the same.
+ * @param {Array} data An associative Array of data values keyed by the field name.
+ * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
+ * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
+ * not specified an integer id is generated.
  */
-Roo.data.SimpleStore = function(config){
-    Roo.data.SimpleStore.superclass.constructor.call(this, {
-        isLocal : true,
-        reader: new Roo.data.ArrayReader({
-                id: config.id
-            },
-            Roo.data.Record.create(config.fields)
-        ),
-        proxy : new Roo.data.MemoryProxy(config.data)
-    });
-    this.load();
+Roo.data.Record = function(data, id){
+    this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
+    this.data = data;
 };
-Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
- * 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.data.Store
- * @class Roo.data.JsonStore
- * Small helper class to make creating Stores for JSON data easier. <br/>
-<pre><code>
-var store = new Roo.data.JsonStore({
-    url: 'get-images.php',
-    root: 'images',
-    fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
+ * Generate a constructor for a specific record layout.
+ * @param {Array} o An Array of field definition objects which specify field names, and optionally,
+ * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
+ * Each field definition object may contain the following properties: <ul>
+ * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
+ * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
+ * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
+ * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
+ * is being used, then this is a string containing the javascript expression to reference the data relative to 
+ * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
+ * to the data item relative to the record element. If the mapping expression is the same as the field name,
+ * this may be omitted.</p></li>
+ * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
+ * <ul><li>auto (Default, implies no conversion)</li>
+ * <li>string</li>
+ * <li>int</li>
+ * <li>float</li>
+ * <li>boolean</li>
+ * <li>date</li></ul></p></li>
+ * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
+ * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
+ * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
+ * by the Reader into an object that will be stored in the Record. It is passed the
+ * following parameters:<ul>
+ * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
+ * </ul></p></li>
+ * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
+ * </ul>
+ * <br>usage:<br><pre><code>
+var TopicRecord = Roo.data.Record.create(
+    {name: 'title', mapping: 'topic_title'},
+    {name: 'author', mapping: 'username'},
+    {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
+    {name: 'lastPost', mapping: 'post_time', type: 'date'},
+    {name: 'lastPoster', mapping: 'user2'},
+    {name: 'excerpt', mapping: 'post_text'}
+);
+
+var myNewRecord = new TopicRecord({
+    title: 'Do my job please',
+    author: 'noobie',
+    totalPosts: 1,
+    lastPost: new Date(),
+    lastPoster: 'Animal',
+    excerpt: 'No way dude!'
 });
+myStore.add(myNewRecord);
 </code></pre>
- * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
- * JsonReader and HttpProxy (unless inline data is provided).</b>
- * @cfg {Array} fields An array of field definition objects, or field name strings.
- * @constructor
- * @param {Object} config
+ * @method create
+ * @static
  */
-Roo.data.JsonStore = function(c){
-    Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
-        proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
-        reader: new Roo.data.JsonReader(c, c.fields)
-    }));
+Roo.data.Record.create = function(o){
+    var f = function(){
+        f.superclass.constructor.apply(this, arguments);
+    };
+    Roo.extend(f, Roo.data.Record);
+    var p = f.prototype;
+    p.fields = new Roo.util.MixedCollection(false, function(field){
+        return field.name;
+    });
+    for(var i = 0, len = o.length; i < len; i++){
+        p.fields.add(new Roo.data.Field(o[i]));
+    }
+    f.getField = function(name){
+        return p.fields.get(name);  
+    };
+    return f;
 };
-Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
- * 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.data.Field = function(config){
-    if(typeof config == "string"){
-        config = {name: config};
-    }
-    Roo.apply(this, config);
-    
-    if(!this.type){
-        this.type = "auto";
-    }
-    
-    var st = Roo.data.SortTypes;
-    // named sortTypes are supported, here we look them up
-    if(typeof this.sortType == "string"){
-        this.sortType = st[this.sortType];
-    }
-    
-    // set default sortType for strings and dates
-    if(!this.sortType){
-        switch(this.type){
-            case "string":
-                this.sortType = st.asUCString;
-                break;
-            case "date":
-                this.sortType = st.asDate;
-                break;
-            default:
-                this.sortType = st.none;
-        }
-    }
+Roo.data.Record.AUTO_ID = 1000;
+Roo.data.Record.EDIT = 'edit';
+Roo.data.Record.REJECT = 'reject';
+Roo.data.Record.COMMIT = 'commit';
 
-    // define once
-    var stripRe = /[\$,%]/g;
+Roo.data.Record.prototype = {
+    /**
+     * Readonly flag - true if this record has been modified.
+     * @type Boolean
+     */
+    dirty : false,
+    editing : false,
+    error: null,
+    modified: null,
 
-    // prebuilt conversion function for this field, instead of
-    // switching every time we're reading a value
-    if(!this.convert){
-        var cv, dateFormat = this.dateFormat;
-        switch(this.type){
-            case "":
-            case "auto":
-            case undefined:
-                cv = function(v){ return v; };
-                break;
-            case "string":
-                cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
-                break;
-            case "int":
-                cv = function(v){
-                    return v !== undefined && v !== null && v !== '' ?
-                           parseInt(String(v).replace(stripRe, ""), 10) : '';
-                    };
-                break;
-            case "float":
-                cv = function(v){
-                    return v !== undefined && v !== null && v !== '' ?
-                           parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
-                    };
-                break;
-            case "bool":
-            case "boolean":
-                cv = function(v){ return v === true || v === "true" || v == 1; };
-                break;
-            case "date":
-                cv = function(v){
-                    if(!v){
-                        return '';
-                    }
-                    if(v instanceof Date){
-                        return v;
-                    }
-                    if(dateFormat){
-                        if(dateFormat == "timestamp"){
-                            return new Date(v*1000);
-                        }
-                        return Date.parseDate(v, dateFormat);
-                    }
-                    var parsed = Date.parse(v);
-                    return parsed ? new Date(parsed) : null;
-                };
-             break;
-            
+    // private
+    join : function(store){
+        this.store = store;
+    },
+
+    /**
+     * Set the named field to the specified value.
+     * @param {String} name The name of the field to set.
+     * @param {Object} value The value to set the field to.
+     */
+    set : function(name, value){
+        if(this.data[name] == value){
+            return;
         }
-        this.convert = cv;
-    }
-};
+        this.dirty = true;
+        if(!this.modified){
+            this.modified = {};
+        }
+        if(typeof this.modified[name] == 'undefined'){
+            this.modified[name] = this.data[name];
+        }
+        this.data[name] = value;
+        if(!this.editing && this.store){
+            this.store.afterEdit(this);
+        }       
+    },
 
-Roo.data.Field.prototype = {
-    dateFormat: null,
-    defaultValue: "",
-    mapping: null,
-    sortType : null,
-    sortDir : "ASC"
-};/*
- * 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">
- */
-// Base class for reading structured data from a data source.  This class is intended to be
-// extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
+    /**
+     * Get the value of the named field.
+     * @param {String} name The name of the field to get the value of.
+     * @return {Object} The value of the field.
+     */
+    get : function(name){
+        return this.data[name]; 
+    },
 
-/**
- * @class Roo.data.DataReader
- * 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.
- */
+    // private
+    beginEdit : function(){
+        this.editing = true;
+        this.modified = {}; 
+    },
 
-Roo.data.DataReader = function(meta, recordType){
-    
-    this.meta = meta;
-    
-    this.recordType = recordType instanceof Array ? 
-        Roo.data.Record.create(recordType) : recordType;
-};
+    // private
+    cancelEdit : function(){
+        this.editing = false;
+        delete this.modified;
+    },
 
-Roo.data.DataReader.prototype = {
-     /**
-     * Create an empty record
-     * @param {Object} data (optional) - overlay some values
-     * @return {Roo.data.Record} record created.
+    // private
+    endEdit : function(){
+        this.editing = false;
+        if(this.dirty && this.store){
+            this.store.afterEdit(this);
+        }
+    },
+
+    /**
+     * Usually called by the {@link Roo.data.Store} which owns the Record.
+     * Rejects all changes made to the Record since either creation, or the last commit operation.
+     * Modified fields are reverted to their original values.
+     * <p>
+     * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
+     * of reject operations.
      */
-    newRow :  function(d) {
-        var da =  {};
-        this.recordType.prototype.fields.each(function(c) {
-            switch( c.type) {
-                case 'int' : da[c.name] = 0; break;
-                case 'date' : da[c.name] = new Date(); break;
-                case 'float' : da[c.name] = 0.0; break;
-                case 'boolean' : da[c.name] = false; break;
-                default : da[c.name] = ""; break;
+    reject : function(){
+        var m = this.modified;
+        for(var n in m){
+            if(typeof m[n] != "function"){
+                this.data[n] = m[n];
             }
-            
-        });
-        return new this.recordType(Roo.apply(da, d));
+        }
+        this.dirty = false;
+        delete this.modified;
+        this.editing = false;
+        if(this.store){
+            this.store.afterReject(this);
+        }
+    },
+
+    /**
+     * Usually called by the {@link Roo.data.Store} which owns the Record.
+     * Commits all changes made to the Record since either creation, or the last commit operation.
+     * <p>
+     * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
+     * of commit operations.
+     */
+    commit : function(){
+        this.dirty = false;
+        delete this.modified;
+        this.editing = false;
+        if(this.store){
+            this.store.afterCommit(this);
+        }
+    },
+
+    // private
+    hasError : function(){
+        return this.error != null;
+    },
+
+    // private
+    clearError : function(){
+        this.error = null;
+    },
+
+    /**
+     * Creates a copy of this record.
+     * @param {String} id (optional) A new record id if you don't want to use this record's id
+     * @return {Record}
+     */
+    copy : function(newId) {
+        return new this.constructor(Roo.apply({}, this.data), newId || this.id);
     }
-    
 };/*
  * Based on:
  * Ext JS Library 1.1.1
@@ -22113,462 +24214,744 @@ Roo.data.DataReader.prototype = {
  * <script type="text/javascript">
  */
 
+
+
 /**
- * @class Roo.data.DataProxy
- * @extends Roo.data.Observable
- * This class is an abstract base class for implementations which provide retrieval of
- * unformatted data objects.<br>
+ * @class Roo.data.Store
+ * @extends Roo.util.Observable
+ * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
+ * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
  * <p>
- * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
- * (of the appropriate type which knows how to parse the data object) to provide a block of
- * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
+ * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
+ * has no knowledge of the format of the data returned by the Proxy.<br>
  * <p>
- * Custom implementations must implement the load method as described in
- * {@link Roo.data.HttpProxy#load}.
+ * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
+ * instances from the data object. These records are cached and made available through accessor functions.
+ * @constructor
+ * Creates a new Store.
+ * @param {Object} config A config object containing the objects needed for the Store to access data,
+ * and read the data into Records.
  */
-Roo.data.DataProxy = function(){
+Roo.data.Store = function(config){
+    this.data = new Roo.util.MixedCollection(false);
+    this.data.getKey = function(o){
+        return o.id;
+    };
+    this.baseParams = {};
+    // private
+    this.paramNames = {
+        "start" : "start",
+        "limit" : "limit",
+        "sort" : "sort",
+        "dir" : "dir",
+        "multisort" : "_multisort"
+    };
+
+    if(config && config.data){
+        this.inlineData = config.data;
+        delete config.data;
+    }
+
+    Roo.apply(this, config);
+    
+    if(this.reader){ // reader passed
+        this.reader = Roo.factory(this.reader, Roo.data);
+        this.reader.xmodule = this.xmodule || false;
+        if(!this.recordType){
+            this.recordType = this.reader.recordType;
+        }
+        if(this.reader.onMetaChange){
+            this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
+        }
+    }
+
+    if(this.recordType){
+        this.fields = this.recordType.prototype.fields;
+    }
+    this.modified = [];
+
     this.addEvents({
+        /**
+         * @event datachanged
+         * Fires when the data cache has changed, and a widget which is using this Store
+         * as a Record cache should refresh its view.
+         * @param {Store} this
+         */
+        datachanged : true,
+        /**
+         * @event metachange
+         * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
+         * @param {Store} this
+         * @param {Object} meta The JSON metadata
+         */
+        metachange : true,
+        /**
+         * @event add
+         * Fires when Records have been added to the Store
+         * @param {Store} this
+         * @param {Roo.data.Record[]} records The array of Records added
+         * @param {Number} index The index at which the record(s) were added
+         */
+        add : true,
+        /**
+         * @event remove
+         * Fires when a Record has been removed from the Store
+         * @param {Store} this
+         * @param {Roo.data.Record} record The Record that was removed
+         * @param {Number} index The index at which the record was removed
+         */
+        remove : true,
+        /**
+         * @event update
+         * Fires when a Record has been updated
+         * @param {Store} this
+         * @param {Roo.data.Record} record The Record that was updated
+         * @param {String} operation The update operation being performed.  Value may be one of:
+         * <pre><code>
+ Roo.data.Record.EDIT
+ Roo.data.Record.REJECT
+ Roo.data.Record.COMMIT
+         * </code></pre>
+         */
+        update : true,
+        /**
+         * @event clear
+         * Fires when the data cache has been cleared.
+         * @param {Store} this
+         */
+        clear : true,
         /**
          * @event beforeload
-         * Fires before a network request is made to retrieve a data object.
-         * @param {Object} This DataProxy object.
-         * @param {Object} params The params parameter to the load function.
+         * Fires before a request is made for a new data object.  If the beforeload handler returns false
+         * the load action will be canceled.
+         * @param {Store} this
+         * @param {Object} options The loading options that were specified (see {@link #load} for details)
          */
         beforeload : true,
+        /**
+         * @event beforeloadadd
+         * Fires after a new set of Records has been loaded.
+         * @param {Store} this
+         * @param {Roo.data.Record[]} records The Records that were loaded
+         * @param {Object} options The loading options that were specified (see {@link #load} for details)
+         */
+        beforeloadadd : true,
         /**
          * @event load
-         * Fires before the load method's callback is called.
-         * @param {Object} This DataProxy object.
-         * @param {Object} o The data object.
-         * @param {Object} arg The callback argument object passed to the load function.
+         * Fires after a new set of Records has been loaded, before they are added to the store.
+         * @param {Store} this
+         * @param {Roo.data.Record[]} records The Records that were loaded
+         * @param {Object} options The loading options that were specified (see {@link #load} for details)
+         * @params {Object} return from reader
          */
         load : true,
         /**
          * @event loadexception
-         * Fires if an Exception occurs during data retrieval.
-         * @param {Object} This DataProxy object.
-         * @param {Object} o The data object.
-         * @param {Object} arg The callback argument object passed to the load function.
-         * @param {Object} e The Exception.
+         * Fires if an exception occurs in the Proxy during loading.
+         * Called with the signature of the Proxy's "loadexception" event.
+         * 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} jsonData from your request (normally this contains the Exception)
          */
         loadexception : true
     });
-    Roo.data.DataProxy.superclass.constructor.call(this);
+    
+    if(this.proxy){
+        this.proxy = Roo.factory(this.proxy, Roo.data);
+        this.proxy.xmodule = this.xmodule || false;
+        this.relayEvents(this.proxy,  ["loadexception"]);
+    }
+    this.sortToggle = {};
+    this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
+
+    Roo.data.Store.superclass.constructor.call(this);
+
+    if(this.inlineData){
+        this.loadData(this.inlineData);
+        delete this.inlineData;
+    }
 };
 
-Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
+Roo.extend(Roo.data.Store, Roo.util.Observable, {
+     /**
+    * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
+    * without a remote query - used by combo/forms at present.
+    */
+    
+    /**
+    * @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.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.
+    */
+    /**
+    * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
+    * on any HTTP request
+    */
+    /**
+    * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
+    */
+    /**
+    * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
+    */
+    multiSort: false,
+    /**
+    * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
+    * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
+    */
+    remoteSort : false,
 
     /**
-     * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
+    * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
+     * loaded or when a record is removed. (defaults to false).
+    */
+    pruneModifiedRecords : false,
+
+    // private
+    lastOptions : null,
+
+    /**
+     * Add Records to the Store and fires the add event.
+     * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
      */
-/*
- * 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.data.MemoryProxy
- * 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.
- */
-Roo.data.MemoryProxy = function(data){
-    if (data.data) {
-        data = data.data;
-    }
-    Roo.data.MemoryProxy.superclass.constructor.call(this);
-    this.data = data;
-};
+    add : function(records){
+        records = [].concat(records);
+        for(var i = 0, len = records.length; i < len; i++){
+            records[i].join(this);
+        }
+        var index = this.data.length;
+        this.data.addAll(records);
+        this.fireEvent("add", this, records, index);
+    },
 
-Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
     /**
-     * Load data from the requested source (in this case an in-memory
-     * data object passed to the constructor), read the data object into
-     * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
-     * process that block using the passed callback.
-     * @param {Object} params This parameter is not used by the MemoryProxy class.
-     * @param {Roo.data.DataReader} reader The Reader object which converts the data
-     * object into a block of Roo.data.Records.
-     * @param {Function} callback The function into which to pass the block of Roo.data.records.
-     * The function must be passed <ul>
-     * <li>The Record block object</li>
-     * <li>The "arg" argument from the load function</li>
-     * <li>A boolean success indicator</li>
+     * Remove a Record from the Store and fires the remove event.
+     * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
+     */
+    remove : function(record){
+        var index = this.data.indexOf(record);
+        this.data.removeAt(index);
+        if(this.pruneModifiedRecords){
+            this.modified.remove(record);
+        }
+        this.fireEvent("remove", this, record, index);
+    },
+
+    /**
+     * Remove all Records from the Store and fires the clear event.
+     */
+    removeAll : function(){
+        this.data.clear();
+        if(this.pruneModifiedRecords){
+            this.modified = [];
+        }
+        this.fireEvent("clear", this);
+    },
+
+    /**
+     * Inserts Records to the Store at the given index and fires the add event.
+     * @param {Number} index The start index at which to insert the passed Records.
+     * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
+     */
+    insert : function(index, records){
+        records = [].concat(records);
+        for(var i = 0, len = records.length; i < len; i++){
+            this.data.insert(index, records[i]);
+            records[i].join(this);
+        }
+        this.fireEvent("add", this, records, index);
+    },
+
+    /**
+     * Get the index within the cache of the passed Record.
+     * @param {Roo.data.Record} record The Roo.data.Record object to to find.
+     * @return {Number} The index of the passed Record. Returns -1 if not found.
+     */
+    indexOf : function(record){
+        return this.data.indexOf(record);
+    },
+
+    /**
+     * Get the index within the cache of the Record with the passed id.
+     * @param {String} id The id of the Record to find.
+     * @return {Number} The index of the Record. Returns -1 if not found.
+     */
+    indexOfId : function(id){
+        return this.data.indexOfKey(id);
+    },
+
+    /**
+     * Get the Record with the specified id.
+     * @param {String} id The id of the Record to find.
+     * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
+     */
+    getById : function(id){
+        return this.data.key(id);
+    },
+
+    /**
+     * Get the Record at the specified index.
+     * @param {Number} index The index of the Record to find.
+     * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
+     */
+    getAt : function(index){
+        return this.data.itemAt(index);
+    },
+
+    /**
+     * Returns a range of Records between specified indices.
+     * @param {Number} startIndex (optional) The starting index (defaults to 0)
+     * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
+     * @return {Roo.data.Record[]} An array of Records
+     */
+    getRange : function(start, end){
+        return this.data.getRange(start, end);
+    },
+
+    // private
+    storeOptions : function(o){
+        o = Roo.apply({}, o);
+        delete o.callback;
+        delete o.scope;
+        this.lastOptions = o;
+    },
+
+    /**
+     * Loads the Record cache from the configured Proxy using the configured Reader.
+     * <p>
+     * If using remote paging, then the first load call must specify the <em>start</em>
+     * and <em>limit</em> properties in the options.params property to establish the initial
+     * position within the dataset, and the number of Records to cache on each read from the Proxy.
+     * <p>
+     * <strong>It is important to note that for remote data sources, loading is asynchronous,
+     * and this call will return before the new data has been loaded. Perform any post-processing
+     * in a callback function, or in a "load" event handler.</strong>
+     * <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>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>
+     * <li>options: Options object from the load call</li>
+     * <li>success: Boolean success indicator</li></ul></li>
+     * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
+     * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
      * </ul>
-     * @param {Object} scope The scope in which to call the callback
-     * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
      */
-    load : function(params, reader, callback, scope, arg){
-        params = params || {};
-        var result;
-        try {
-            result = reader.readRecords(this.data);
-        }catch(e){
-            this.fireEvent("loadexception", this, arg, null, e);
-            callback.call(scope, null, arg, false);
-            return;
+    load : function(options){
+        options = options || {};
+        if(this.fireEvent("beforeload", this, options) !== false){
+            this.storeOptions(options);
+            var p = Roo.apply(options.params || {}, this.baseParams);
+            // if meta was not loaded from remote source.. try requesting it.
+            if (!this.reader.metaFromRemote) {
+                p._requestMeta = 1;
+            }
+            if(this.sortInfo && this.remoteSort){
+                var pn = this.paramNames;
+                p[pn["sort"]] = this.sortInfo.field;
+                p[pn["dir"]] = this.sortInfo.direction;
+            }
+            if (this.multiSort) {
+                var pn = this.paramNames;
+                p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
+            }
+            
+            this.proxy.load(p, this.reader, this.loadRecords, this, options);
         }
-        callback.call(scope, result, arg, true);
     },
-    
+
+    /**
+     * Reloads the Record cache from the configured Proxy using the configured Reader and
+     * the options from the last load operation performed.
+     * @param {Object} options (optional) An object containing properties which may override the options
+     * used in the last load operation. See {@link #load} for details (defaults to null, in which case
+     * the most recently used options are reused).
+     */
+    reload : function(options){
+        this.load(Roo.applyIf(options||{}, this.lastOptions));
+    },
+
     // private
-    update : function(params, records){
+    // Called as a callback by the Reader during a load operation.
+    loadRecords : function(o, options, success){
+         
+        if(!o){
+            if(success !== false){
+                this.fireEvent("load", this, [], options, o);
+            }
+            if(options.callback){
+                options.callback.call(options.scope || this, [], options, false);
+            }
+            return;
+        }
+        // if data returned failure - throw an exception.
+        if (o.success === false) {
+            // show a message if no listener is registered.
+            if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
+                    Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
+            }
+            // loadmask wil be hooked into this..
+            this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
+            return;
+        }
+        var r = o.records, t = o.totalRecords || r.length;
         
-    }
-});/*
- * 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.data.HttpProxy
- * @extends Roo.data.DataProxy
- * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
- * configured to reference a certain URL.<br><br>
- * <p>
- * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
- * from which the running page was served.<br><br>
- * <p>
- * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
- * <p>
- * Be aware that to enable the browser to parse an XML document, the server must set
- * the Content-Type header in the HTTP response to "text/xml".
- * @constructor
- * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
- * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
- * will be used to make the request.
- */
-Roo.data.HttpProxy = function(conn){
-    Roo.data.HttpProxy.superclass.constructor.call(this);
-    // is conn a conn config or a real conn?
-    this.conn = conn;
-    this.useAjax = !conn || !conn.events;
-  
-};
+        this.fireEvent("beforeloadadd", this, r, options, o);
+        
+        if(!options || options.add !== true){
+            if(this.pruneModifiedRecords){
+                this.modified = [];
+            }
+            for(var i = 0, len = r.length; i < len; i++){
+                r[i].join(this);
+            }
+            if(this.snapshot){
+                this.data = this.snapshot;
+                delete this.snapshot;
+            }
+            this.data.clear();
+            this.data.addAll(r);
+            this.totalLength = t;
+            this.applySort();
+            this.fireEvent("datachanged", this);
+        }else{
+            this.totalLength = Math.max(t, this.data.length+r.length);
+            this.add(r);
+        }
+        
+        if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
+                
+            var e = new Roo.data.Record({});
+
+            e.set(this.parent.displayField, this.parent.emptyTitle);
+            e.set(this.parent.valueField, '');
+
+            this.insert(0, e);
+        }
+            
+        this.fireEvent("load", this, r, options, o);
+        if(options.callback){
+            options.callback.call(options.scope || this, r, options, true);
+        }
+    },
+
 
-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 {Object} extraParams (Optional) An object containing properties which are used as
-     * extra parameters to each request made by this object. (defaults to undefined)
+     * Loads data from a passed data block. A Reader which understands the format of the data
+     * must have been configured in the constructor.
+     * @param {Object} data The data block from which to read the Records.  The format of the data expected
+     * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
+     * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
      */
-    /**
-     * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
-     *  to each request made by this object. (defaults to undefined)
+    loadData : function(o, append){
+        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));
+    },
+    
+
     /**
-     * @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)
+     * Gets the number of cached records.
+     * <p>
+     * <em>If using paging, this may not be the total size of the dataset. If the data object
+     * used by the Reader contains the dataset size, then the getTotalCount() function returns
+     * the data set size</em>
      */
+    getCount : function(){
+        return this.data.length || 0;
+    },
+
     /**
-     * @cfg {Number} timeout (Optional) 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)
-     * @type Boolean
+     * Gets the total number of records in the dataset as returned by the server.
+     * <p>
+     * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
+     * the dataset size</em>
      */
-  
+    getTotalCount : function(){
+        return this.totalLength || 0;
+    },
 
     /**
-     * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
-     * @type Boolean
+     * Returns the sort state of the Store as an object with two properties:
+     * <pre><code>
+ field {String} The name of the field by which the Records are sorted
+ direction {String} The sort order, "ASC" or "DESC"
+     * </code></pre>
      */
+    getSortState : function(){
+        return this.sortInfo;
+    },
+
+    // private
+    applySort : function(){
+        if(this.sortInfo && !this.remoteSort){
+            var s = this.sortInfo, f = s.field;
+            var st = this.fields.get(f).sortType;
+            var fn = function(r1, r2){
+                var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
+                return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
+            };
+            this.data.sort(s.direction, fn);
+            if(this.snapshot && this.snapshot != this.data){
+                this.snapshot.sort(s.direction, fn);
+            }
+        }
+    },
+
     /**
-     * Return the {@link Roo.data.Connection} object being used by this Proxy.
-     * @return {Connection} The Connection object. This object may be used to subscribe to events on
-     * a finer-grained basis than the DataProxy events.
+     * Sets the default sort column and order to be used by the next load operation.
+     * @param {String} fieldName The name of the field to sort by.
+     * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
      */
-    getConnection : function(){
-        return this.useAjax ? Roo.Ajax : this.conn;
+    setDefaultSort : function(field, dir){
+        this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
     },
 
     /**
-     * Load data from the configured {@link Roo.data.Connection}, read the data object into
-     * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
-     * process that block using the passed callback.
-     * @param {Object} params An object containing properties which are to be used as HTTP parameters
-     * for the request to the remote server.
-     * @param {Roo.data.DataReader} reader The Reader object which converts the data
-     * object into a block of Roo.data.Records.
-     * @param {Function} callback The function into which to pass the block of Roo.data.Records.
-     * The function must be passed <ul>
-     * <li>The Record block object</li>
-     * <li>The "arg" argument from the load function</li>
-     * <li>A boolean success indicator</li>
-     * </ul>
-     * @param {Object} scope The scope in which to call the callback
-     * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
+     * Sort the Records.
+     * If remote sorting is used, the sort is performed on the server, and the cache is
+     * reloaded. If local sorting is used, the cache is sorted internally.
+     * @param {String} fieldName The name of the field to sort by.
+     * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
      */
-    load : function(params, reader, callback, scope, arg){
-        if(this.fireEvent("beforeload", this, params) !== false){
-            var  o = {
-                params : params || {},
-                request: {
-                    callback : callback,
-                    scope : scope,
-                    arg : arg
-                },
-                reader: reader,
-                callback : this.loadResponse,
-                scope: this
-            };
-            if(this.useAjax){
-                Roo.applyIf(o, this.conn);
-                if(this.activeRequest){
-                    Roo.Ajax.abort(this.activeRequest);
-                }
-                this.activeRequest = Roo.Ajax.request(o);
+    sort : function(fieldName, dir){
+        var f = this.fields.get(fieldName);
+        if(!dir){
+            this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
+            
+            if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
+                dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
             }else{
-                this.conn.request(o);
+                dir = f.sortDir;
             }
+        }
+        this.sortToggle[f.name] = dir;
+        this.sortInfo = {field: f.name, direction: dir};
+        if(!this.remoteSort){
+            this.applySort();
+            this.fireEvent("datachanged", this);
         }else{
-            callback.call(scope||this, null, arg, false);
+            this.load(this.lastOptions);
         }
     },
 
-    // private
-    loadResponse : function(o, success, 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){
-            this.fireEvent("loadexception", this, o, response, e);
-            o.request.callback.call(o.request.scope, null, o.request.arg, false);
-            return;
-        }
-        
-        this.fireEvent("load", this, o, o.request.arg);
-        o.request.callback.call(o.request.scope, result, o.request.arg, true);
+    /**
+     * Calls the specified function for each of the Records in the cache.
+     * @param {Function} fn The function to call. The Record is passed as the first parameter.
+     * Returning <em>false</em> aborts and exits the iteration.
+     * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
+     */
+    each : function(fn, scope){
+        this.data.each(fn, scope);
     },
 
-    // private
-    update : function(dataSet){
-
+    /**
+     * Gets all records modified since the last commit.  Modified records are persisted across load operations
+     * (e.g., during paging).
+     * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
+     */
+    getModifiedRecords : function(){
+        return this.modified;
     },
 
     // private
-    updateResponse : function(dataSet){
-
-    }
-});/*
- * 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.data.ScriptTagProxy
- * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
- * other than the originating domain of the running page.<br><br>
- * <p>
- * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
- * of the running page, you must use this class, rather than DataProxy.</em><br><br>
- * <p>
- * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
- * source code that is used as the source inside a &lt;script> tag.<br><br>
- * <p>
- * In order for the browser to process the returned data, the server must wrap the data object
- * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
- * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
- * depending on whether the callback name was passed:
- * <p>
- * <pre><code>
-boolean scriptTag = false;
-String cb = request.getParameter("callback");
-if (cb != null) {
-    scriptTag = true;
-    response.setContentType("text/javascript");
-} else {
-    response.setContentType("application/x-json");
-}
-Writer out = response.getWriter();
-if (scriptTag) {
-    out.write(cb + "(");
-}
-out.print(dataBlock.toJsonString());
-if (scriptTag) {
-    out.write(");");
-}
-</pre></code>
- *
- * @constructor
- * @param {Object} config A configuration object.
- */
-Roo.data.ScriptTagProxy = function(config){
-    Roo.data.ScriptTagProxy.superclass.constructor.call(this);
-    Roo.apply(this, config);
-    this.head = document.getElementsByTagName("head")[0];
-};
-
-Roo.data.ScriptTagProxy.TRANS_ID = 1000;
+    createFilterFn : function(property, value, anyMatch){
+        if(!value.exec){ // not a regex
+            value = String(value);
+            if(value.length == 0){
+                return false;
+            }
+            value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
+        }
+        return function(r){
+            return value.test(r.data[property]);
+        };
+    },
 
-Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
-    /**
-     * @cfg {String} url The URL from which to request the data object.
-     */
     /**
-     * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
+     * Sums the value of <i>property</i> for each record between start and end and returns the result.
+     * @param {String} property A field on your records
+     * @param {Number} start The record index to start at (defaults to 0)
+     * @param {Number} end The last record index to include (defaults to length - 1)
+     * @return {Number} The sum
      */
-    timeout : 30000,
+    sum : function(property, start, end){
+        var rs = this.data.items, v = 0;
+        start = start || 0;
+        end = (end || end === 0) ? end : rs.length-1;
+
+        for(var i = start; i <= end; i++){
+            v += (rs[i].data[property] || 0);
+        }
+        return v;
+    },
+
     /**
-     * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
-     * the server the name of the callback function set up by the load call to process the returned data object.
-     * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
-     * javascript output which calls this named function passing the data object as its only parameter.
+     * Filter the records by a specified property.
+     * @param {String} field A field on your records
+     * @param {String/RegExp} value Either a string that the field
+     * should start with or a RegExp to test against the field
+     * @param {Boolean} anyMatch True to match any part not just the beginning
      */
-    callbackParam : "callback",
+    filter : function(property, value, anyMatch){
+        var fn = this.createFilterFn(property, value, anyMatch);
+        return fn ? this.filterBy(fn) : this.clearFilter();
+    },
+
     /**
-     *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
-     * name to the request.
+     * Filter by a function. The specified function will be called with each
+     * record in this data source. If the function returns true the record is included,
+     * otherwise it is filtered.
+     * @param {Function} fn The function to be called, it will receive 2 args (record, id)
+     * @param {Object} scope (optional) The scope of the function (defaults to this)
      */
-    nocache : true,
+    filterBy : function(fn, scope){
+        this.snapshot = this.snapshot || this.data;
+        this.data = this.queryBy(fn, scope||this);
+        this.fireEvent("datachanged", this);
+    },
 
     /**
-     * Load data from the configured URL, read the data object into
-     * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
-     * process that block using the passed callback.
-     * @param {Object} params An object containing properties which are to be used as HTTP parameters
-     * for the request to the remote server.
-     * @param {Roo.data.DataReader} reader The Reader object which converts the data
-     * object into a block of Roo.data.Records.
-     * @param {Function} callback The function into which to pass the block of Roo.data.Records.
-     * The function must be passed <ul>
-     * <li>The Record block object</li>
-     * <li>The "arg" argument from the load function</li>
-     * <li>A boolean success indicator</li>
-     * </ul>
-     * @param {Object} scope The scope in which to call the callback
-     * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
+     * Query the records by a specified property.
+     * @param {String} field A field on your records
+     * @param {String/RegExp} value Either a string that the field
+     * should start with or a RegExp to test against the field
+     * @param {Boolean} anyMatch True to match any part not just the beginning
+     * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
      */
-    load : function(params, reader, callback, scope, arg){
-        if(this.fireEvent("beforeload", this, params) !== false){
+    query : function(property, value, anyMatch){
+        var fn = this.createFilterFn(property, value, anyMatch);
+        return fn ? this.queryBy(fn) : this.data.clone();
+    },
 
-            var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
+    /**
+     * Query by a function. The specified function will be called with each
+     * record in this data source. If the function returns true the record is included
+     * in the results.
+     * @param {Function} fn The function to be called, it will receive 2 args (record, id)
+     * @param {Object} scope (optional) The scope of the function (defaults to this)
+      @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
+     **/
+    queryBy : function(fn, scope){
+        var data = this.snapshot || this.data;
+        return data.filterBy(fn, scope||this);
+    },
 
-            var url = this.url;
-            url += (url.indexOf("?") != -1 ? "&" : "?") + p;
-            if(this.nocache){
-                url += "&_dc=" + (new Date().getTime());
+    /**
+     * Collects unique values for a particular dataIndex from this store.
+     * @param {String} dataIndex The property to collect
+     * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
+     * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
+     * @return {Array} An array of the unique values
+     **/
+    collect : function(dataIndex, allowNull, bypassFilter){
+        var d = (bypassFilter === true && this.snapshot) ?
+                this.snapshot.items : this.data.items;
+        var v, sv, r = [], l = {};
+        for(var i = 0, len = d.length; i < len; i++){
+            v = d[i].data[dataIndex];
+            sv = String(v);
+            if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
+                l[sv] = true;
+                r[r.length] = v;
             }
-            var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
-            var trans = {
-                id : transId,
-                cb : "stcCallback"+transId,
-                scriptId : "stcScript"+transId,
-                params : params,
-                arg : arg,
-                url : url,
-                callback : callback,
-                scope : scope,
-                reader : reader
-            };
-            var conn = this;
-
-            window[trans.cb] = function(o){
-                conn.handleResponse(o, trans);
-            };
-
-            url += String.format("&{0}={1}", this.callbackParam, trans.cb);
+        }
+        return r;
+    },
 
-            if(this.autoAbort !== false){
-                this.abort();
+    /**
+     * Revert to a view of the Record cache with no filtering applied.
+     * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
+     */
+    clearFilter : function(suppressEvent){
+        if(this.snapshot && this.snapshot != this.data){
+            this.data = this.snapshot;
+            delete this.snapshot;
+            if(suppressEvent !== true){
+                this.fireEvent("datachanged", this);
             }
+        }
+    },
 
-            trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
-
-            var script = document.createElement("script");
-            script.setAttribute("src", url);
-            script.setAttribute("type", "text/javascript");
-            script.setAttribute("id", trans.scriptId);
-            this.head.appendChild(script);
-
-            this.trans = trans;
-        }else{
-            callback.call(scope||this, null, arg, false);
+    // private
+    afterEdit : function(record){
+        if(this.modified.indexOf(record) == -1){
+            this.modified.push(record);
         }
+        this.fireEvent("update", this, record, Roo.data.Record.EDIT);
+    },
+    
+    // private
+    afterReject : function(record){
+        this.modified.remove(record);
+        this.fireEvent("update", this, record, Roo.data.Record.REJECT);
     },
 
     // private
-    isLoading : function(){
-        return this.trans ? true : false;
+    afterCommit : function(record){
+        this.modified.remove(record);
+        this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
     },
 
     /**
-     * Abort the current server request.
+     * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
+     * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
      */
-    abort : function(){
-        if(this.isLoading()){
-            this.destroyTrans(this.trans);
+    commitChanges : function(){
+        var m = this.modified.slice(0);
+        this.modified = [];
+        for(var i = 0, len = m.length; i < len; i++){
+            m[i].commit();
         }
     },
 
-    // private
-    destroyTrans : function(trans, isLoaded){
-        this.head.removeChild(document.getElementById(trans.scriptId));
-        clearTimeout(trans.timeoutId);
-        if(isLoaded){
-            window[trans.cb] = undefined;
-            try{
-                delete window[trans.cb];
-            }catch(e){}
-        }else{
-            // if hasn't been loaded, wait for load to remove it to prevent script error
-            window[trans.cb] = function(){
-                window[trans.cb] = undefined;
-                try{
-                    delete window[trans.cb];
-                }catch(e){}
-            };
+    /**
+     * Cancel outstanding changes on all changed records.
+     */
+    rejectChanges : function(){
+        var m = this.modified.slice(0);
+        this.modified = [];
+        for(var i = 0, len = m.length; i < len; i++){
+            m[i].reject();
         }
     },
 
-    // private
-    handleResponse : function(o, trans){
-        this.trans = false;
-        this.destroyTrans(trans, true);
-        var result;
-        try {
-            result = trans.reader.readRecords(o);
-        }catch(e){
-            this.fireEvent("loadexception", this, o, trans.arg, e);
-            trans.callback.call(trans.scope||window, null, trans.arg, false);
-            return;
-        }
-        this.fireEvent("load", this, o, trans.arg);
-        trans.callback.call(trans.scope||window, result, trans.arg, true);
+    onMetaChange : function(meta, rtype, o){
+        this.recordType = rtype;
+        this.fields = rtype.prototype.fields;
+        delete this.snapshot;
+        this.sortInfo = meta.sortInfo || this.sortInfo;
+        this.modified = [];
+        this.fireEvent('metachange', this, this.reader.meta);
     },
-
-    // private
-    handleFailure : function(trans){
-        this.trans = false;
-        this.destroyTrans(trans, false);
-        this.fireEvent("loadexception", this, null, trans.arg);
-        trans.callback.call(trans.scope||window, null, trans.arg, false);
+    
+    moveIndex : function(data, type)
+    {
+        var index = this.indexOf(data);
+        
+        var newIndex = index + type;
+        
+        this.remove(data);
+        
+        this.insert(newIndex, data);
+        
     }
 });/*
  * Based on:
@@ -22582,206 +24965,225 @@ Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
  */
 
 /**
- * @class Roo.data.JsonReader
- * @extends Roo.data.DataReader
- * Data reader class to create an Array of Roo.data.Record objects from a JSON response
- * based on mappings in a provided Roo.data.Record constructor.
- * 
- * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
- * in the reply previously. 
- * 
- * <p>
- * Example code:
- * <pre><code>
-var RecordDef = Roo.data.Record.create([
-    {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
-    {name: 'occupation'}                 // This field will use "occupation" as the mapping.
-]);
-var myReader = new Roo.data.JsonReader({
-    totalProperty: "results",    // The property which contains the total dataset size (optional)
-    root: "rows",                // The property which contains an Array of row objects
-    id: "id"                     // The property within each row object that provides an ID for the record (optional)
-}, RecordDef);
-</code></pre>
- * <p>
- * This would consume a JSON file like this:
- * <pre><code>
-{ 'results': 2, 'rows': [
-    { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
-    { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
-}
+ * @class Roo.data.SimpleStore
+ * @extends Roo.data.Store
+ * 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.superclass.constructor.call(this, {
+        isLocal : true,
+        reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
+                id: config.id
+            },
+            Roo.data.Record.create(config.fields)
+        ),
+        proxy : new Roo.data.MemoryProxy(config.data)
+    });
+    this.load();
+};
+Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
+ * 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.data.Store
+ * @class Roo.data.JsonStore
+ * Small helper class to make creating Stores for JSON data easier. <br/>
+<pre><code>
+var store = new Roo.data.JsonStore({
+    url: 'get-images.php',
+    root: 'images',
+    fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
+});
 </code></pre>
- * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
- * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
- * paged from the remote server.
- * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
- * @cfg {String} root name of the property which contains the Array of row objects.
- * @cfg {String} id Name of the property within a row object that contains a record identifier value.
- * @cfg {Array} fields Array of field definition objects
+ * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
+ * JsonReader and HttpProxy (unless inline data is provided).</b>
+ * @cfg {Array} fields An array of field definition objects, or field name strings.
  * @constructor
- * Create a new JsonReader
- * @param {Object} meta Metadata configuration options
- * @param {Object} recordType Either an Array of field definition objects,
- * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
+ * @param {Object} config
  */
-Roo.data.JsonReader = function(meta, recordType){
+Roo.data.JsonStore = function(c){
+    Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
+        proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
+        reader: new Roo.data.JsonReader(c, c.fields)
+    }));
+};
+Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
+ * 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.data.Field = function(config){
+    if(typeof config == "string"){
+        config = {name: config};
+    }
+    Roo.apply(this, config);
     
-    meta = meta || {};
-    // set some defaults:
-    Roo.applyIf(meta, {
-        totalProperty: 'total',
-        successProperty : 'success',
-        root : 'data',
-        id : 'id'
-    });
+    if(!this.type){
+        this.type = "auto";
+    }
     
-    Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
-};
-Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
+    var st = Roo.data.SortTypes;
+    // named sortTypes are supported, here we look them up
+    if(typeof this.sortType == "string"){
+        this.sortType = st[this.sortType];
+    }
     
-    /**
-     * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
-     * Used by Store query builder to append _requestMeta to params.
-     * 
-     */
-    metaFromRemote : false,
-    /**
-     * 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 JSON data in its responseText.
-     * @return {Object} data A data block which is used by an Roo.data.Store object as
-     * a cache of Roo.data.Records.
-     */
-    read : function(response){
-        var json = response.responseText;
-       
-        var o = /* eval:var:o */ eval("("+json+")");
-        if(!o) {
-            throw {message: "JsonReader.read: Json object not found"};
+    // set default sortType for strings and dates
+    if(!this.sortType){
+        switch(this.type){
+            case "string":
+                this.sortType = st.asUCString;
+                break;
+            case "date":
+                this.sortType = st.asDate;
+                break;
+            default:
+                this.sortType = st.none;
         }
-        
-        if(o.metaData){
+    }
+
+    // define once
+    var stripRe = /[\$,%]/g;
+
+    // prebuilt conversion function for this field, instead of
+    // switching every time we're reading a value
+    if(!this.convert){
+        var cv, dateFormat = this.dateFormat;
+        switch(this.type){
+            case "":
+            case "auto":
+            case undefined:
+                cv = function(v){ return v; };
+                break;
+            case "string":
+                cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
+                break;
+            case "int":
+                cv = function(v){
+                    return v !== undefined && v !== null && v !== '' ?
+                           parseInt(String(v).replace(stripRe, ""), 10) : '';
+                    };
+                break;
+            case "float":
+                cv = function(v){
+                    return v !== undefined && v !== null && v !== '' ?
+                           parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
+                    };
+                break;
+            case "bool":
+            case "boolean":
+                cv = function(v){ return v === true || v === "true" || v == 1; };
+                break;
+            case "date":
+                cv = function(v){
+                    if(!v){
+                        return '';
+                    }
+                    if(v instanceof Date){
+                        return v;
+                    }
+                    if(dateFormat){
+                        if(dateFormat == "timestamp"){
+                            return new Date(v*1000);
+                        }
+                        return Date.parseDate(v, dateFormat);
+                    }
+                    var parsed = Date.parse(v);
+                    return parsed ? new Date(parsed) : null;
+                };
+             break;
             
-            delete this.ef;
-            this.metaFromRemote = true;
-            this.meta = o.metaData;
-            this.recordType = Roo.data.Record.create(o.metaData.fields);
-            this.onMetaChange(this.meta, this.recordType, o);
         }
-        return this.readRecords(o);
-    },
-
-    // private function a store will implement
-    onMetaChange : function(meta, recordType, o){
+        this.convert = cv;
+    }
+};
 
-    },
+Roo.data.Field.prototype = {
+    dateFormat: null,
+    defaultValue: "",
+    mapping: null,
+    sortType : null,
+    sortDir : "ASC"
+};/*
+ * 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">
+ */
+// Base class for reading structured data from a data source.  This class is intended to be
+// extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
 
-    /**
-        * @ignore
-        */
-    simpleAccess: function(obj, subsc) {
-       return obj[subsc];
-    },
+/**
+ * @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.
+ */
 
-       /**
-        * @ignore
-        */
-    getJsonAccessor: function(){
-        var re = /[\[\.]/;
-        return function(expr) {
-            try {
-                return(re.test(expr))
-                    ? new Function("obj", "return obj." + expr)
-                    : function(obj){
-                        return obj[expr];
-                    };
-            } catch(e){}
-            return Roo.emptyFn;
-        };
-    }(),
+Roo.data.DataReader = function(meta, recordType){
+    
+    this.meta = meta;
+    
+    this.recordType = recordType instanceof Array ? 
+        Roo.data.Record.create(recordType) : recordType;
+};
 
-    /**
-     * Create a data block containing Roo.data.Records from an XML document.
-     * @param {Object} o An object which contains an Array of row objects in the property specified
-     * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
-     * which contains the total size of the dataset.
-     * @return {Object} data A data block which is used by an Roo.data.Store object as
-     * a cache of Roo.data.Records.
+Roo.data.DataReader.prototype = {
+    
+    
+    readerType : 'Data',
+     /**
+     * Create an empty record
+     * @param {Object} data (optional) - overlay some values
+     * @return {Roo.data.Record} record created.
      */
-    readRecords : function(o){
-        /**
-         * After any data loads, the raw JSON data is available for further custom processing.
-         * @type Object
-         */
-        this.o = o;
-        var s = this.meta, Record = this.recordType,
-            f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
-
-//      Generate extraction functions for the totalProperty, the root, the id, and for each field
-        if (!this.ef) {
-            if(s.totalProperty) {
-                   this.getTotal = this.getJsonAccessor(s.totalProperty);
-               }
-               if(s.successProperty) {
-                   this.getSuccess = this.getJsonAccessor(s.successProperty);
-               }
-               this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
-               if (s.id) {
-                       var g = this.getJsonAccessor(s.id);
-                       this.getId = function(rec) {
-                               var r = g(rec);  
-                               return (r === undefined || r === "") ? null : r;
-                       };
-               } else {
-                       this.getId = function(){return null;};
-               }
-            this.ef = [];
-            for(var jj = 0; jj < fl; jj++){
-                f = fi[jj];
-                var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
-                this.ef[jj] = this.getJsonAccessor(map);
-            }
-        }
-
-       var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
-       if(s.totalProperty){
-            var vt = parseInt(this.getTotal(o), 10);
-            if(!isNaN(vt)){
-                totalRecords = vt;
-            }
-        }
-        if(s.successProperty){
-            var vs = this.getSuccess(o);
-            if(vs === false || vs === 'false'){
-                success = false;
-            }
-        }
-        var records = [];
-        for(var i = 0; i < c; 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);
+    newRow :  function(d) {
+        var da =  {};
+        this.recordType.prototype.fields.each(function(c) {
+            switch( c.type) {
+                case 'int' : da[c.name] = 0; break;
+                case 'date' : da[c.name] = new Date(); break;
+                case 'float' : da[c.name] = 0.0; break;
+                case 'boolean' : da[c.name] = false; break;
+                default : da[c.name] = ""; break;
             }
-            var record = new Record(values, id);
-            record.json = n;
-            records[i] = record;
-        }
-        return {
-            raw : o,
-            success : success,
-            records : records,
-            totalRecords : totalRecords
-        };
+            
+        });
+        return new this.recordType(Roo.apply(da, d));
     }
-});/*
+    
+    
+};/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -22793,127 +25195,55 @@ Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
  */
 
 /**
- * @class Roo.data.XmlReader
- * @extends Roo.data.DataReader
- * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
- * based on mappings in a provided Roo.data.Record constructor.<br><br>
- * <p>
- * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
- * header in the HTTP response must be set to "text/xml".</em>
+ * @class Roo.data.DataProxy
+ * @extends Roo.util.Observable
+ * @abstract
+ * This class is an abstract base class for implementations which provide retrieval of
+ * unformatted data objects.<br>
  * <p>
- * Example code:
- * <pre><code>
-var RecordDef = Roo.data.Record.create([
-   {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
-   {name: 'occupation'}                 // This field will use "occupation" as the mapping.
-]);
-var myReader = new Roo.data.XmlReader({
-   totalRecords: "results", // The element which contains the total dataset size (optional)
-   record: "row",           // The repeated element which contains row information
-   id: "id"                 // The element within the row that provides an ID for the record (optional)
-}, RecordDef);
-</code></pre>
+ * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
+ * (of the appropriate type which knows how to parse the data object) to provide a block of
+ * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
  * <p>
- * This would consume an XML file like this:
- * <pre><code>
-&lt;?xml?>
-&lt;dataset>
- &lt;results>2&lt;/results>
- &lt;row>
-   &lt;id>1&lt;/id>
-   &lt;name>Bill&lt;/name>
-   &lt;occupation>Gardener&lt;/occupation>
- &lt;/row>
- &lt;row>
-   &lt;id>2&lt;/id>
-   &lt;name>Ben&lt;/name>
-   &lt;occupation>Horticulturalist&lt;/occupation>
- &lt;/row>
-&lt;/dataset>
-</code></pre>
- * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
- * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
- * paged from the remote server.
- * @cfg {String} record The DomQuery path to the repeated element which contains record information.
- * @cfg {String} success The DomQuery path to the success attribute used by forms.
- * @cfg {String} id The DomQuery path relative from the record element to the element that contains
- * a record identifier value.
- * @constructor
- * Create a new XmlReader
- * @param {Object} meta Metadata configuration options
- * @param {Mixed} recordType The definition of the data record type to produce.  This can be either a valid
- * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
- * Roo.data.Record.create.  See the {@link Roo.data.Record} class for more details.
+ * Custom implementations must implement the load method as described in
+ * {@link Roo.data.HttpProxy#load}.
  */
-Roo.data.XmlReader = function(meta, recordType){
-    meta = meta || {};
-    Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
-};
-Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
-    /**
-     * 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
-        * to contain a method called 'responseXML' that returns an XML document object.
-     * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
-     * a cache of Roo.data.Records.
-     */
-    read : function(response){
-        var doc = response.responseXML;
-        if(!doc) {
-            throw {message: "XmlReader.read: XML Document not available"};
-        }
-        return this.readRecords(doc);
-    },
-
-    /**
-     * Create a data block containing Roo.data.Records from an XML document.
-        * @param {Object} doc A parsed XML document.
-     * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
-     * a cache of Roo.data.Records.
-     */
-    readRecords : function(doc){
+Roo.data.DataProxy = function(){
+    this.addEvents({
         /**
-         * After any data loads/reads, the raw XML Document is available for further custom processing.
-         * @type XMLDocument
+         * @event beforeload
+         * Fires before a network request is made to retrieve a data object.
+         * @param {Object} This DataProxy object.
+         * @param {Object} params The params parameter to the load function.
          */
-        this.xmlData = doc;
-        var root = doc.documentElement || doc;
-       var q = Roo.DomQuery;
-       var recordType = this.recordType, fields = recordType.prototype.fields;
-       var sid = this.meta.id;
-       var totalRecords = 0, success = true;
-       if(this.meta.totalRecords){
-           totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
-       }
-        
-        if(this.meta.success){
-            var sv = q.selectValue(this.meta.success, root, true);
-            success = sv !== false && sv !== 'false';
-       }
-       var records = [];
-       var ns = q.select(this.meta.record, root);
-        for(var i = 0, len = ns.length; i < len; i++) {
-               var n = ns[i];
-               var values = {};
-               var id = sid ? q.selectValue(sid, n) : undefined;
-               for(var j = 0, jlen = fields.length; j < jlen; j++){
-                   var f = fields.items[j];
-                var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
-                   v = f.convert(v);
-                   values[f.name] = v;
-               }
-               var record = new recordType(values, id);
-               record.node = n;
-               records[records.length] = record;
-           }
-
-           return {
-               success : success,
-               records : records,
-               totalRecords : totalRecords || records.length
-           };
-    }
-});/*
+        beforeload : true,
+        /**
+         * @event load
+         * Fires before the load method's callback is called.
+         * @param {Object} This DataProxy object.
+         * @param {Object} o The data object.
+         * @param {Object} arg The callback argument object passed to the load function.
+         */
+        load : true,
+        /**
+         * @event loadexception
+         * Fires if an Exception occurs during data retrieval.
+         * @param {Object} This DataProxy object.
+         * @param {Object} o The data object.
+         * @param {Object} arg The callback argument object passed to the load function.
+         * @param {Object} e The Exception.
+         */
+        loadexception : true
+    });
+    Roo.data.DataProxy.superclass.constructor.call(this);
+};
+
+Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
+
+    /**
+     * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
+     */
+/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -22923,74 +25253,56 @@ Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
  * Fork - LGPL
  * <script type="text/javascript">
  */
-
 /**
- * @class Roo.data.ArrayReader
- * @extends Roo.data.DataReader
- * Data reader class to create an Array of Roo.data.Record objects from an Array.
- * Each element of that Array represents a row of data fields. The
- * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
- * of the field definition if it exists, or the field's ordinal position in the definition.<br>
- * <p>
- * Example code:.
- * <pre><code>
-var RecordDef = Roo.data.Record.create([
-    {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
-    {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
-]);
-var myReader = new Roo.data.ArrayReader({
-    id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
-}, RecordDef);
-</code></pre>
- * <p>
- * This would consume an Array like this:
- * <pre><code>
-[ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
-  </code></pre>
- * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
+ * @class Roo.data.MemoryProxy
+ * 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
- * Create a new JsonReader
- * @param {Object} meta Metadata configuration options.
- * @param {Object} recordType Either an Array of field definition objects
- * as specified to {@link Roo.data.Record#create},
- * or an {@link Roo.data.Record} object
- * created using {@link Roo.data.Record#create}.
+ * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
  */
-Roo.data.ArrayReader = function(meta, recordType){
-    Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
+Roo.data.MemoryProxy = function(data){
+    if (data.data) {
+        data = data.data;
+    }
+    Roo.data.MemoryProxy.superclass.constructor.call(this);
+    this.data = data;
 };
 
-Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
+Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
+    
     /**
-     * Create a data block containing Roo.data.Records from an XML document.
-     * @param {Object} o An Array of row objects which represents the dataset.
-     * @return {Object} data A data block which is used by an Roo.data.Store object as
-     * a cache 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
+     * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
+     * process that block using the passed callback.
+     * @param {Object} params This parameter is not used by the MemoryProxy class.
+     * @param {Roo.data.DataReader} reader The Reader object which converts the data
+     * object into a block of Roo.data.Records.
+     * @param {Function} callback The function into which to pass the block of Roo.data.records.
+     * The function must be passed <ul>
+     * <li>The Record block object</li>
+     * <li>The "arg" argument from the load function</li>
+     * <li>A boolean success indicator</li>
+     * </ul>
+     * @param {Object} scope The scope in which to call the callback
+     * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
      */
-    readRecords : function(o){
-        var sid = this.meta ? this.meta.id : null;
-       var recordType = this.recordType, fields = recordType.prototype.fields;
-       var records = [];
-       var root = o;
-           for(var i = 0; i < root.length; i++){
-                   var n = root[i];
-               var values = {};
-               var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
-               for(var j = 0, jlen = fields.length; j < jlen; j++){
-                var f = fields.items[j];
-                var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
-                var v = n[k] !== undefined ? n[k] : f.defaultValue;
-                v = f.convert(v);
-                values[f.name] = v;
-            }
-               var record = new recordType(values, id);
-               record.json = n;
-               records[records.length] = record;
-           }
-           return {
-               records : records,
-               totalRecords : records.length
-           };
+    load : function(params, reader, callback, scope, arg){
+        params = params || {};
+        var result;
+        try {
+            result = reader.readRecords(params.data ? params.data :this.data);
+        }catch(e){
+            this.fireEvent("loadexception", this, arg, null, e);
+            callback.call(scope, null, arg, false);
+            return;
+        }
+        callback.call(scope, result, arg, true);
+    },
+    
+    // private
+    update : function(params, records){
+        
     }
 });/*
  * Based on:
@@ -23002,735 +25314,710 @@ Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
  * Fork - LGPL
  * <script type="text/javascript">
  */
-
-
 /**
- * @class Roo.data.Tree
- * @extends Roo.util.Observable
- * Represents a tree data structure and bubbles all the events for its nodes. The nodes
- * in the tree have most standard DOM functionality.
+ * @class Roo.data.HttpProxy
+ * @extends Roo.data.DataProxy
+ * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
+ * configured to reference a certain URL.<br><br>
+ * <p>
+ * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
+ * from which the running page was served.<br><br>
+ * <p>
+ * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
+ * <p>
+ * Be aware that to enable the browser to parse an XML document, the server must set
+ * the Content-Type header in the HTTP response to "text/xml".
  * @constructor
- * @param {Node} root (optional) The root node
+ * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
+ * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
+ * will be used to make the request.
  */
-Roo.data.Tree = function(root){
-   this.nodeHash = {};
-   /**
-    * The root node for this tree
-    * @type Node
-    */
-   this.root = null;
-   if(root){
-       this.setRootNode(root);
-   }
-   this.addEvents({
-       /**
-        * @event append
-        * Fires when a new child node is appended to a node in this tree.
-        * @param {Tree} tree The owner tree
-        * @param {Node} parent The parent node
-        * @param {Node} node The newly appended node
-        * @param {Number} index The index of the newly appended node
-        */
-       "append" : true,
-       /**
-        * @event remove
-        * Fires when a child node is removed from a node in this tree.
-        * @param {Tree} tree The owner tree
-        * @param {Node} parent The parent node
-        * @param {Node} node The child node removed
-        */
-       "remove" : true,
-       /**
-        * @event move
-        * Fires when a node is moved to a new location in the tree
-        * @param {Tree} tree The owner tree
-        * @param {Node} node The node moved
-        * @param {Node} oldParent The old parent of this node
-        * @param {Node} newParent The new parent of this node
-        * @param {Number} index The index it was moved to
-        */
-       "move" : true,
-       /**
-        * @event insert
-        * Fires when a new child node is inserted in a node in this tree.
-        * @param {Tree} tree The owner tree
-        * @param {Node} parent The parent node
-        * @param {Node} node The child node inserted
-        * @param {Node} refNode The child node the node was inserted before
-        */
-       "insert" : true,
-       /**
-        * @event beforeappend
-        * Fires before a new child is appended to a node in this tree, return false to cancel the append.
-        * @param {Tree} tree The owner tree
-        * @param {Node} parent The parent node
-        * @param {Node} node The child node to be appended
-        */
-       "beforeappend" : true,
-       /**
-        * @event beforeremove
-        * Fires before a child is removed from a node in this tree, return false to cancel the remove.
-        * @param {Tree} tree The owner tree
-        * @param {Node} parent The parent node
-        * @param {Node} node The child node to be removed
-        */
-       "beforeremove" : true,
-       /**
-        * @event beforemove
-        * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
-        * @param {Tree} tree The owner tree
-        * @param {Node} node The node being moved
-        * @param {Node} oldParent The parent of the node
-        * @param {Node} newParent The new parent the node is moving to
-        * @param {Number} index The index it is being moved to
-        */
-       "beforemove" : true,
-       /**
-        * @event beforeinsert
-        * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
-        * @param {Tree} tree The owner tree
-        * @param {Node} parent The parent node
-        * @param {Node} node The child node to be inserted
-        * @param {Node} refNode The child node the node is being inserted before
-        */
-       "beforeinsert" : true
-   });
-
-    Roo.data.Tree.superclass.constructor.call(this);
+Roo.data.HttpProxy = function(conn){
+    Roo.data.HttpProxy.superclass.constructor.call(this);
+    // is conn a conn config or a real conn?
+    this.conn = conn;
+    this.useAjax = !conn || !conn.events;
+  
 };
 
-Roo.extend(Roo.data.Tree, Roo.util.Observable, {
-    pathSeparator: "/",
-
-    proxyNodeEvent : function(){
-        return this.fireEvent.apply(this, arguments);
-    },
-
-    /**
-     * Returns the root node for this tree.
-     * @return {Node}
-     */
-    getRootNode : function(){
-        return this.root;
-    },
-
-    /**
-     * Sets the root node for this tree.
-     * @param {Node} node
-     * @return {Node}
-     */
-    setRootNode : function(node){
-        this.root = node;
-        node.ownerTree = this;
-        node.isRoot = true;
-        this.registerNode(node);
-        return node;
-    },
-
-    /**
-     * Gets a node in this tree by its id.
-     * @param {String} id
-     * @return {Node}
-     */
-    getNodeById : function(id){
-        return this.nodeHash[id];
-    },
-
-    registerNode : function(node){
-        this.nodeHash[node.id] = node;
-    },
-
-    unregisterNode : function(node){
-        delete this.nodeHash[node.id];
-    },
-
-    toString : function(){
-        return "[Tree"+(this.id?" "+this.id:"")+"]";
-    }
-});
-
-/**
- * @class Roo.data.Node
- * @extends Roo.util.Observable
- * @cfg {Boolean} leaf true if this node is a leaf and does not have children
- * @cfg {String} id The id for this node. If one is not specified, one is generated.
- * @constructor
- * @param {Object} attributes The attributes/config for the node
- */
-Roo.data.Node = function(attributes){
-    /**
-     * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
-     * @type {Object}
-     */
-    this.attributes = attributes || {};
-    this.leaf = this.attributes.leaf;
-    /**
-     * The node id. @type String
-     */
-    this.id = this.attributes.id;
-    if(!this.id){
-        this.id = Roo.id(null, "ynode-");
-        this.attributes.id = this.id;
-    }
-     
+Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
+    // thse are take from connection...
     
     /**
-     * All child nodes of this node. @type Array
-     */
-    this.childNodes = [];
-    if(!this.childNodes.indexOf){ // indexOf is a must
-        this.childNodes.indexOf = function(o){
-            for(var i = 0, len = this.length; i < len; i++){
-                if(this[i] == o) {
-                    return i;
-                }
-            }
-            return -1;
-        };
-    }
-    /**
-     * The parent node for this node. @type Node
+     * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
      */
-    this.parentNode = null;
     /**
-     * The first direct child node of this node, or null if this node has no child nodes. @type Node
+     * @cfg {Object} extraParams (Optional) An object containing properties which are used as
+     * extra parameters to each request made by this object. (defaults to undefined)
      */
-    this.firstChild = null;
     /**
-     * The last direct child node of this node, or null if this node has no child nodes. @type Node
+     * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
+     *  to each request made by this object. (defaults to undefined)
      */
-    this.lastChild = null;
     /**
-     * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
+     * @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)
      */
-    this.previousSibling = null;
     /**
-     * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
+     * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
      */
-    this.nextSibling = null;
-
-    this.addEvents({
-       /**
-        * @event append
-        * Fires when a new child node is appended
-        * @param {Tree} tree The owner tree
-        * @param {Node} this This node
-        * @param {Node} node The newly appended node
-        * @param {Number} index The index of the newly appended node
-        */
-       "append" : true,
-       /**
-        * @event remove
-        * Fires when a child node is removed
-        * @param {Tree} tree The owner tree
-        * @param {Node} this This node
-        * @param {Node} node The removed node
-        */
-       "remove" : true,
-       /**
-        * @event move
-        * Fires when this node is moved to a new location in the tree
-        * @param {Tree} tree The owner tree
-        * @param {Node} this This node
-        * @param {Node} oldParent The old parent of this node
-        * @param {Node} newParent The new parent of this node
-        * @param {Number} index The index it was moved to
-        */
-       "move" : true,
-       /**
-        * @event insert
-        * Fires when a new child node is inserted.
-        * @param {Tree} tree The owner tree
-        * @param {Node} this This node
-        * @param {Node} node The child node inserted
-        * @param {Node} refNode The child node the node was inserted before
-        */
-       "insert" : true,
-       /**
-        * @event beforeappend
-        * Fires before a new child is appended, return false to cancel the append.
-        * @param {Tree} tree The owner tree
-        * @param {Node} this This node
-        * @param {Node} node The child node to be appended
-        */
-       "beforeappend" : true,
-       /**
-        * @event beforeremove
-        * Fires before a child is removed, return false to cancel the remove.
-        * @param {Tree} tree The owner tree
-        * @param {Node} this This node
-        * @param {Node} node The child node to be removed
-        */
-       "beforeremove" : true,
-       /**
-        * @event beforemove
-        * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
-        * @param {Tree} tree The owner tree
-        * @param {Node} this This node
-        * @param {Node} oldParent The parent of this node
-        * @param {Node} newParent The new parent this node is moving to
-        * @param {Number} index The index it is being moved to
-        */
-       "beforemove" : true,
-       /**
-        * @event beforeinsert
-        * Fires before a new child is inserted, return false to cancel the insert.
-        * @param {Tree} tree The owner tree
-        * @param {Node} this This node
-        * @param {Node} node The child node to be inserted
-        * @param {Node} refNode The child node the node is being inserted before
-        */
-       "beforeinsert" : true
-   });
-    this.listeners = this.attributes.listeners;
-    Roo.data.Node.superclass.constructor.call(this);
-};
-
-Roo.extend(Roo.data.Node, Roo.util.Observable, {
-    fireEvent : function(evtName){
-        // first do standard event for this node
-        if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
-            return false;
-        }
-        // then bubble it up to the tree if the event wasn't cancelled
-        var ot = this.getOwnerTree();
-        if(ot){
-            if(ot.proxyNodeEvent.apply(ot, arguments) === false){
-                return false;
-            }
-        }
-        return true;
-    },
-
-    /**
-     * Returns true if this node is a leaf
-     * @return {Boolean}
+     /**
+     * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
+     * @type Boolean
      */
-    isLeaf : function(){
-        return this.leaf === true;
-    },
-
-    // private
-    setFirstChild : function(node){
-        this.firstChild = node;
-    },
-
-    //private
-    setLastChild : function(node){
-        this.lastChild = node;
-    },
-
+  
 
     /**
-     * Returns true if this node is the last child of its parent
-     * @return {Boolean}
+     * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
+     * @type Boolean
      */
-    isLast : function(){
-       return (!this.parentNode ? true : this.parentNode.lastChild == this);
-    },
-
     /**
-     * Returns true if this node is the first child of its parent
-     * @return {Boolean}
+     * Return the {@link Roo.data.Connection} object being used by this Proxy.
+     * @return {Connection} The Connection object. This object may be used to subscribe to events on
+     * a finer-grained basis than the DataProxy events.
      */
-    isFirst : function(){
-       return (!this.parentNode ? true : this.parentNode.firstChild == this);
-    },
-
-    hasChildNodes : function(){
-        return !this.isLeaf() && this.childNodes.length > 0;
+    getConnection : function(){
+        return this.useAjax ? Roo.Ajax : this.conn;
     },
 
     /**
-     * Insert node(s) as the last child node of this node.
-     * @param {Node/Array} node The node or Array of nodes to append
-     * @return {Node} The appended node if single append, or null if an array was passed
+     * Load data from the configured {@link Roo.data.Connection}, read the data object into
+     * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
+     * process that block using the passed callback.
+     * @param {Object} params An object containing properties which are to be used as HTTP parameters
+     * for the request to the remote server.
+     * @param {Roo.data.DataReader} reader The Reader object which converts the data
+     * object into a block of Roo.data.Records.
+     * @param {Function} callback The function into which to pass the block of Roo.data.Records.
+     * The function must be passed <ul>
+     * <li>The Record block object</li>
+     * <li>The "arg" argument from the load function</li>
+     * <li>A boolean success indicator</li>
+     * </ul>
+     * @param {Object} scope The scope in which to call the callback
+     * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
      */
-    appendChild : function(node){
-        var multi = false;
-        if(node instanceof Array){
-            multi = node;
-        }else if(arguments.length > 1){
-            multi = arguments;
-        }
-        // if passed an array or multiple args do them one by one
-        if(multi){
-            for(var i = 0, len = multi.length; i < len; i++) {
-               this.appendChild(multi[i]);
-            }
-        }else{
-            if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
-                return false;
-            }
-            var index = this.childNodes.length;
-            var oldParent = node.parentNode;
-            // it's a move, make sure we move it cleanly
-            if(oldParent){
-                if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
-                    return false;
+    load : function(params, reader, callback, scope, arg){
+        if(this.fireEvent("beforeload", this, params) !== false){
+            var  o = {
+                params : params || {},
+                request: {
+                    callback : callback,
+                    scope : scope,
+                    arg : arg
+                },
+                reader: reader,
+                callback : this.loadResponse,
+                scope: this
+            };
+            if(this.useAjax){
+                Roo.applyIf(o, this.conn);
+                if(this.activeRequest){
+                    Roo.Ajax.abort(this.activeRequest);
                 }
-                oldParent.removeChild(node);
-            }
-            index = this.childNodes.length;
-            if(index == 0){
-                this.setFirstChild(node);
-            }
-            this.childNodes.push(node);
-            node.parentNode = this;
-            var ps = this.childNodes[index-1];
-            if(ps){
-                node.previousSibling = ps;
-                ps.nextSibling = node;
+                this.activeRequest = Roo.Ajax.request(o);
             }else{
-                node.previousSibling = null;
-            }
-            node.nextSibling = null;
-            this.setLastChild(node);
-            node.setOwnerTree(this.getOwnerTree());
-            this.fireEvent("append", this.ownerTree, this, node, index);
-            if(oldParent){
-                node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
+                this.conn.request(o);
             }
-            return node;
+        }else{
+            callback.call(scope||this, null, arg, false);
         }
     },
 
-    /**
-     * Removes a child node from this node.
-     * @param {Node} node The node to remove
-     * @return {Node} The removed node
-     */
-    removeChild : function(node){
-        var index = this.childNodes.indexOf(node);
-        if(index == -1){
-            return false;
-        }
-        if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
-            return false;
-        }
-
-        // remove it from childNodes collection
-        this.childNodes.splice(index, 1);
-
-        // update siblings
-        if(node.previousSibling){
-            node.previousSibling.nextSibling = node.nextSibling;
+    // private
+    loadResponse : function(o, success, 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;
         }
-        if(node.nextSibling){
-            node.nextSibling.previousSibling = node.previousSibling;
+        var result;
+        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, o, o.request.arg, false);
+            return;
         }
+        
+        this.fireEvent("load", this, o, o.request.arg);
+        o.request.callback.call(o.request.scope, result, o.request.arg, true);
+    },
 
-        // update child refs
-        if(this.firstChild == node){
-            this.setFirstChild(node.nextSibling);
-        }
-        if(this.lastChild == node){
-            this.setLastChild(node.previousSibling);
-        }
+    // private
+    update : function(dataSet){
 
-        node.setOwnerTree(null);
-        // clear any references from the node
-        node.parentNode = null;
-        node.previousSibling = null;
-        node.nextSibling = null;
-        this.fireEvent("remove", this.ownerTree, this, node);
-        return node;
     },
 
-    /**
-     * Inserts the first node before the second node in this nodes childNodes collection.
-     * @param {Node} node The node to insert
-     * @param {Node} refNode The node to insert before (if null the node is appended)
-     * @return {Node} The inserted node
-     */
-    insertBefore : function(node, refNode){
-        if(!refNode){ // like standard Dom, refNode can be null for append
-            return this.appendChild(node);
-        }
-        // nothing to do
-        if(node == refNode){
-            return false;
-        }
+    // private
+    updateResponse : function(dataSet){
 
-        if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
-            return false;
-        }
-        var index = this.childNodes.indexOf(refNode);
-        var oldParent = node.parentNode;
-        var refIndex = index;
+    }
+});/*
+ * 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">
+ */
 
-        // when moving internally, indexes will change after remove
-        if(oldParent == this && this.childNodes.indexOf(node) < index){
-            refIndex--;
-        }
+/**
+ * @class Roo.data.ScriptTagProxy
+ * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
+ * other than the originating domain of the running page.<br><br>
+ * <p>
+ * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
+ * of the running page, you must use this class, rather than DataProxy.</em><br><br>
+ * <p>
+ * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
+ * source code that is used as the source inside a &lt;script> tag.<br><br>
+ * <p>
+ * In order for the browser to process the returned data, the server must wrap the data object
+ * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
+ * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
+ * depending on whether the callback name was passed:
+ * <p>
+ * <pre><code>
+boolean scriptTag = false;
+String cb = request.getParameter("callback");
+if (cb != null) {
+    scriptTag = true;
+    response.setContentType("text/javascript");
+} else {
+    response.setContentType("application/x-json");
+}
+Writer out = response.getWriter();
+if (scriptTag) {
+    out.write(cb + "(");
+}
+out.print(dataBlock.toJsonString());
+if (scriptTag) {
+    out.write(");");
+}
+</pre></code>
+ *
+ * @constructor
+ * @param {Object} config A configuration object.
+ */
+Roo.data.ScriptTagProxy = function(config){
+    Roo.data.ScriptTagProxy.superclass.constructor.call(this);
+    Roo.apply(this, config);
+    this.head = document.getElementsByTagName("head")[0];
+};
 
-        // it's a move, make sure we move it cleanly
-        if(oldParent){
-            if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
-                return false;
-            }
-            oldParent.removeChild(node);
-        }
-        if(refIndex == 0){
-            this.setFirstChild(node);
-        }
-        this.childNodes.splice(refIndex, 0, node);
-        node.parentNode = this;
-        var ps = this.childNodes[refIndex-1];
-        if(ps){
-            node.previousSibling = ps;
-            ps.nextSibling = node;
-        }else{
-            node.previousSibling = null;
-        }
-        node.nextSibling = refNode;
-        refNode.previousSibling = node;
-        node.setOwnerTree(this.getOwnerTree());
-        this.fireEvent("insert", this.ownerTree, this, node, refNode);
-        if(oldParent){
-            node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
-        }
-        return node;
-    },
+Roo.data.ScriptTagProxy.TRANS_ID = 1000;
 
+Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
     /**
-     * Returns the child node at the specified index.
-     * @param {Number} index
-     * @return {Node}
+     * @cfg {String} url The URL from which to request the data object.
      */
-    item : function(index){
-        return this.childNodes[index];
-    },
-
     /**
-     * Replaces one child node in this node with another.
-     * @param {Node} newChild The replacement node
-     * @param {Node} oldChild The node to replace
-     * @return {Node} The replaced node
+     * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
      */
-    replaceChild : function(newChild, oldChild){
-        this.insertBefore(newChild, oldChild);
-        this.removeChild(oldChild);
-        return oldChild;
-    },
-
+    timeout : 30000,
     /**
-     * Returns the index of a child node
-     * @param {Node} node
-     * @return {Number} The index of the node or -1 if it was not found
+     * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
+     * the server the name of the callback function set up by the load call to process the returned data object.
+     * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
+     * javascript output which calls this named function passing the data object as its only parameter.
      */
-    indexOf : function(child){
-        return this.childNodes.indexOf(child);
-    },
-
+    callbackParam : "callback",
     /**
-     * Returns the tree this node is in.
-     * @return {Tree}
+     *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
+     * name to the request.
      */
-    getOwnerTree : function(){
-        // if it doesn't have one, look for one
-        if(!this.ownerTree){
-            var p = this;
-            while(p){
-                if(p.ownerTree){
-                    this.ownerTree = p.ownerTree;
-                    break;
-                }
-                p = p.parentNode;
-            }
-        }
-        return this.ownerTree;
-    },
+    nocache : true,
 
     /**
-     * Returns depth of this node (the root node has a depth of 0)
-     * @return {Number}
+     * Load data from the configured URL, read the data object into
+     * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
+     * process that block using the passed callback.
+     * @param {Object} params An object containing properties which are to be used as HTTP parameters
+     * for the request to the remote server.
+     * @param {Roo.data.DataReader} reader The Reader object which converts the data
+     * object into a block of Roo.data.Records.
+     * @param {Function} callback The function into which to pass the block of Roo.data.Records.
+     * The function must be passed <ul>
+     * <li>The Record block object</li>
+     * <li>The "arg" argument from the load function</li>
+     * <li>A boolean success indicator</li>
+     * </ul>
+     * @param {Object} scope The scope in which to call the callback
+     * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
      */
-    getDepth : function(){
-        var depth = 0;
-        var p = this;
-        while(p.parentNode){
-            ++depth;
-            p = p.parentNode;
-        }
-        return depth;
-    },
+    load : function(params, reader, callback, scope, arg){
+        if(this.fireEvent("beforeload", this, params) !== false){
 
-    // private
-    setOwnerTree : function(tree){
-        // if it's move, we need to update everyone
-        if(tree != this.ownerTree){
-            if(this.ownerTree){
-                this.ownerTree.unregisterNode(this);
-            }
-            this.ownerTree = tree;
-            var cs = this.childNodes;
-            for(var i = 0, len = cs.length; i < len; i++) {
-               cs[i].setOwnerTree(tree);
+            var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
+
+            var url = this.url;
+            url += (url.indexOf("?") != -1 ? "&" : "?") + p;
+            if(this.nocache){
+                url += "&_dc=" + (new Date().getTime());
             }
-            if(tree){
-                tree.registerNode(this);
+            var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
+            var trans = {
+                id : transId,
+                cb : "stcCallback"+transId,
+                scriptId : "stcScript"+transId,
+                params : params,
+                arg : arg,
+                url : url,
+                callback : callback,
+                scope : scope,
+                reader : reader
+            };
+            var conn = this;
+
+            window[trans.cb] = function(o){
+                conn.handleResponse(o, trans);
+            };
+
+            url += String.format("&{0}={1}", this.callbackParam, trans.cb);
+
+            if(this.autoAbort !== false){
+                this.abort();
             }
+
+            trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
+
+            var script = document.createElement("script");
+            script.setAttribute("src", url);
+            script.setAttribute("type", "text/javascript");
+            script.setAttribute("id", trans.scriptId);
+            this.head.appendChild(script);
+
+            this.trans = trans;
+        }else{
+            callback.call(scope||this, null, arg, false);
         }
     },
 
+    // private
+    isLoading : function(){
+        return this.trans ? true : false;
+    },
+
     /**
-     * Returns the path for this node. The path can be used to expand or select this node programmatically.
-     * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
-     * @return {String} The path
+     * Abort the current server request.
      */
-    getPath : function(attr){
-        attr = attr || "id";
-        var p = this.parentNode;
-        var b = [this.attributes[attr]];
-        while(p){
-            b.unshift(p.attributes[attr]);
-            p = p.parentNode;
+    abort : function(){
+        if(this.isLoading()){
+            this.destroyTrans(this.trans);
         }
-        var sep = this.getOwnerTree().pathSeparator;
-        return sep + b.join(sep);
     },
 
-    /**
-     * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
-     * function call will be the scope provided or the current node. The arguments to the function
-     * will be the args provided or the current node. If the function returns false at any point,
-     * the bubble is stopped.
-     * @param {Function} fn The function to call
-     * @param {Object} scope (optional) The scope of the function (defaults to current node)
-     * @param {Array} args (optional) The args to call the function with (default to passing the current node)
-     */
-    bubble : function(fn, scope, args){
-        var p = this;
-        while(p){
-            if(fn.call(scope || p, args || p) === false){
-                break;
-            }
-            p = p.parentNode;
+    // private
+    destroyTrans : function(trans, isLoaded){
+        this.head.removeChild(document.getElementById(trans.scriptId));
+        clearTimeout(trans.timeoutId);
+        if(isLoaded){
+            window[trans.cb] = undefined;
+            try{
+                delete window[trans.cb];
+            }catch(e){}
+        }else{
+            // if hasn't been loaded, wait for load to remove it to prevent script error
+            window[trans.cb] = function(){
+                window[trans.cb] = undefined;
+                try{
+                    delete window[trans.cb];
+                }catch(e){}
+            };
         }
     },
 
-    /**
-     * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
-     * function call will be the scope provided or the current node. The arguments to the function
-     * will be the args provided or the current node. If the function returns false at any point,
-     * the cascade is stopped on that branch.
-     * @param {Function} fn The function to call
-     * @param {Object} scope (optional) The scope of the function (defaults to current node)
-     * @param {Array} args (optional) The args to call the function with (default to passing the current node)
-     */
-    cascade : function(fn, scope, args){
-        if(fn.call(scope || this, args || this) !== false){
-            var cs = this.childNodes;
-            for(var i = 0, len = cs.length; i < len; i++) {
-               cs[i].cascade(fn, scope, args);
-            }
+    // private
+    handleResponse : function(o, trans){
+        this.trans = false;
+        this.destroyTrans(trans, true);
+        var result;
+        try {
+            result = trans.reader.readRecords(o);
+        }catch(e){
+            this.fireEvent("loadexception", this, o, trans.arg, e);
+            trans.callback.call(trans.scope||window, null, trans.arg, false);
+            return;
         }
+        this.fireEvent("load", this, o, trans.arg);
+        trans.callback.call(trans.scope||window, result, trans.arg, true);
     },
 
+    // private
+    handleFailure : function(trans){
+        this.trans = false;
+        this.destroyTrans(trans, false);
+        this.fireEvent("loadexception", this, null, trans.arg);
+        trans.callback.call(trans.scope||window, null, trans.arg, 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.data.JsonReader
+ * @extends Roo.data.DataReader
+ * Data reader class to create an Array of Roo.data.Record objects from a JSON response
+ * based on mappings in a provided Roo.data.Record constructor.
+ * 
+ * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
+ * in the reply previously. 
+ * 
+ * <p>
+ * Example code:
+ * <pre><code>
+var RecordDef = Roo.data.Record.create([
+    {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
+    {name: 'occupation'}                 // This field will use "occupation" as the mapping.
+]);
+var myReader = new Roo.data.JsonReader({
+    totalProperty: "results",    // The property which contains the total dataset size (optional)
+    root: "rows",                // The property which contains an Array of row objects
+    id: "id"                     // The property within each row object that provides an ID for the record (optional)
+}, RecordDef);
+</code></pre>
+ * <p>
+ * This would consume a JSON file like this:
+ * <pre><code>
+{ 'results': 2, 'rows': [
+    { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
+    { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
+}
+</code></pre>
+ * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
+ * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
+ * paged from the remote server.
+ * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
+ * @cfg {String} root name of the property which contains the Array of row objects.
+ * @cfg {String} id Name of the property within a row object that contains a record identifier value.
+ * @cfg {Array} fields Array of field definition objects
+ * @constructor
+ * Create a new JsonReader
+ * @param {Object} meta Metadata configuration options
+ * @param {Object} recordType Either an Array of field definition objects,
+ * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
+ */
+Roo.data.JsonReader = function(meta, recordType){
+    
+    meta = meta || {};
+    // set some defaults:
+    Roo.applyIf(meta, {
+        totalProperty: 'total',
+        successProperty : 'success',
+        root : 'data',
+        id : 'id'
+    });
+    
+    Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
+};
+Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
+    
+    readerType : 'Json',
+    
     /**
-     * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
-     * function call will be the scope provided or the current node. The arguments to the function
-     * will be the args provided or the current node. If the function returns false at any point,
-     * the iteration stops.
-     * @param {Function} fn The function to call
-     * @param {Object} scope (optional) The scope of the function (defaults to current node)
-     * @param {Array} args (optional) The args to call the function with (default to passing the current node)
+     * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
+     * Used by Store query builder to append _requestMeta to params.
+     * 
      */
-    eachChild : function(fn, scope, args){
-        var cs = this.childNodes;
-        for(var i = 0, len = cs.length; i < len; i++) {
-               if(fn.call(scope || this, args || cs[i]) === false){
-                   break;
-               }
+    metaFromRemote : false,
+    /**
+     * 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 JSON data in its responseText.
+     * @return {Object} data A data block which is used by an Roo.data.Store object as
+     * a cache of Roo.data.Records.
+     */
+    read : function(response){
+        var json = response.responseText;
+       
+        var o = /* eval:var:o */ eval("("+json+")");
+        if(!o) {
+            throw {message: "JsonReader.read: Json object not found"};
+        }
+        
+        if(o.metaData){
+            
+            delete this.ef;
+            this.metaFromRemote = true;
+            this.meta = o.metaData;
+            this.recordType = Roo.data.Record.create(o.metaData.fields);
+            this.onMetaChange(this.meta, this.recordType, o);
         }
+        return this.readRecords(o);
     },
 
-    /**
-     * Finds the first child that has the attribute with the specified value.
-     * @param {String} attribute The attribute name
-     * @param {Mixed} value The value to search for
-     * @return {Node} The found child or null if none was found
-     */
-    findChild : function(attribute, value){
-        var cs = this.childNodes;
-        for(var i = 0, len = cs.length; i < len; i++) {
-               if(cs[i].attributes[attribute] == value){
-                   return cs[i];
-               }
-        }
-        return null;
+    // private function a store will implement
+    onMetaChange : function(meta, recordType, o){
+
     },
 
     /**
-     * Finds the first child by a custom function. The child matches if the function passed
-     * returns true.
-     * @param {Function} fn
-     * @param {Object} scope (optional)
-     * @return {Node} The found child or null if none was found
-     */
-    findChildBy : function(fn, scope){
-        var cs = this.childNodes;
-        for(var i = 0, len = cs.length; i < len; i++) {
-               if(fn.call(scope||cs[i], cs[i]) === true){
-                   return cs[i];
-               }
-        }
-        return null;
+        * @ignore
+        */
+    simpleAccess: function(obj, subsc) {
+       return obj[subsc];
     },
 
+       /**
+        * @ignore
+        */
+    getJsonAccessor: function(){
+        var re = /[\[\.]/;
+        return function(expr) {
+            try {
+                return(re.test(expr))
+                    ? new Function("obj", "return obj." + expr)
+                    : function(obj){
+                        return obj[expr];
+                    };
+            } catch(e){}
+            return Roo.emptyFn;
+        };
+    }(),
+
     /**
-     * Sorts this nodes children using the supplied sort function
-     * @param {Function} fn
-     * @param {Object} scope (optional)
+     * Create a data block containing Roo.data.Records from an XML document.
+     * @param {Object} o An object which contains an Array of row objects in the property specified
+     * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
+     * which contains the total size of the dataset.
+     * @return {Object} data A data block which is used by an Roo.data.Store object as
+     * a cache of Roo.data.Records.
      */
-    sort : function(fn, scope){
-        var cs = this.childNodes;
-        var len = cs.length;
-        if(len > 0){
-            var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
-            cs.sort(sortFn);
-            for(var i = 0; i < len; i++){
-                var n = cs[i];
-                n.previousSibling = cs[i-1];
-                n.nextSibling = cs[i+1];
-                if(i == 0){
-                    this.setFirstChild(n);
-                }
-                if(i == len-1){
-                    this.setLastChild(n);
-                }
+    readRecords : function(o){
+        /**
+         * After any data loads, the raw JSON data is available for further custom processing.
+         * @type Object
+         */
+        this.o = o;
+        var s = this.meta, Record = this.recordType,
+            f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
+
+//      Generate extraction functions for the totalProperty, the root, the id, and for each field
+        if (!this.ef) {
+            if(s.totalProperty) {
+                   this.getTotal = this.getJsonAccessor(s.totalProperty);
+               }
+               if(s.successProperty) {
+                   this.getSuccess = this.getJsonAccessor(s.successProperty);
+               }
+               this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
+               if (s.id) {
+                       var g = this.getJsonAccessor(s.id);
+                       this.getId = function(rec) {
+                               var r = g(rec);  
+                               return (r === undefined || r === "") ? null : r;
+                       };
+               } else {
+                       this.getId = function(){return null;};
+               }
+            this.ef = [];
+            for(var jj = 0; jj < fl; jj++){
+                f = fi[jj];
+                var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
+                this.ef[jj] = this.getJsonAccessor(map);
+            }
+        }
+
+       var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
+       if(s.totalProperty){
+            var vt = parseInt(this.getTotal(o), 10);
+            if(!isNaN(vt)){
+                totalRecords = vt;
+            }
+        }
+        if(s.successProperty){
+            var vs = this.getSuccess(o);
+            if(vs === false || vs === 'false'){
+                success = false;
             }
         }
+        var records = [];
+        for(var i = 0; i < c; 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);
+            }
+                       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;
+        }
+        return {
+            raw : o,
+            success : success,
+            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:
+ * 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.data.XmlReader
+ * @extends Roo.data.DataReader
+ * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
+ * based on mappings in a provided Roo.data.Record constructor.<br><br>
+ * <p>
+ * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
+ * header in the HTTP response must be set to "text/xml".</em>
+ * <p>
+ * Example code:
+ * <pre><code>
+var RecordDef = Roo.data.Record.create([
+   {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
+   {name: 'occupation'}                 // This field will use "occupation" as the mapping.
+]);
+var myReader = new Roo.data.XmlReader({
+   totalRecords: "results", // The element which contains the total dataset size (optional)
+   record: "row",           // The repeated element which contains row information
+   id: "id"                 // The element within the row that provides an ID for the record (optional)
+}, RecordDef);
+</code></pre>
+ * <p>
+ * This would consume an XML file like this:
+ * <pre><code>
+&lt;?xml?>
+&lt;dataset>
+ &lt;results>2&lt;/results>
+ &lt;row>
+   &lt;id>1&lt;/id>
+   &lt;name>Bill&lt;/name>
+   &lt;occupation>Gardener&lt;/occupation>
+ &lt;/row>
+ &lt;row>
+   &lt;id>2&lt;/id>
+   &lt;name>Ben&lt;/name>
+   &lt;occupation>Horticulturalist&lt;/occupation>
+ &lt;/row>
+&lt;/dataset>
+</code></pre>
+ * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
+ * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
+ * paged from the remote server.
+ * @cfg {String} record The DomQuery path to the repeated element which contains record information.
+ * @cfg {String} success The DomQuery path to the success attribute used by forms.
+ * @cfg {String} id The DomQuery path relative from the record element to the element that contains
+ * a record identifier value.
+ * @constructor
+ * Create a new XmlReader
+ * @param {Object} meta Metadata configuration options
+ * @param {Mixed} recordType The definition of the data record type to produce.  This can be either a valid
+ * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
+ * Roo.data.Record.create.  See the {@link Roo.data.Record} class for more details.
+ */
+Roo.data.XmlReader = function(meta, recordType){
+    meta = meta || {};
+    Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
+};
+Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
+    
+    readerType : 'Xml',
+    
     /**
-     * Returns true if this node is an ancestor (at any point) of the passed node.
-     * @param {Node} node
-     * @return {Boolean}
+     * 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
+        * to contain a method called 'responseXML' that returns an XML document object.
+     * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
+     * a cache of Roo.data.Records.
      */
-    contains : function(node){
-        return node.isAncestor(this);
+    read : function(response){
+        var doc = response.responseXML;
+        if(!doc) {
+            throw {message: "XmlReader.read: XML Document not available"};
+        }
+        return this.readRecords(doc);
     },
 
     /**
-     * Returns true if the passed node is an ancestor (at any point) of this node.
-     * @param {Node} node
-     * @return {Boolean}
+     * Create a data block containing Roo.data.Records from an XML document.
+        * @param {Object} doc A parsed XML document.
+     * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
+     * a cache of Roo.data.Records.
      */
-    isAncestor : function(node){
-        var p = this.parentNode;
-        while(p){
-            if(p == node){
-                return true;
-            }
-            p = p.parentNode;
-        }
-        return false;
-    },
+    readRecords : function(doc){
+        /**
+         * After any data loads/reads, the raw XML Document is available for further custom processing.
+         * @type XMLDocument
+         */
+        this.xmlData = doc;
+        var root = doc.documentElement || doc;
+       var q = Roo.DomQuery;
+       var recordType = this.recordType, fields = recordType.prototype.fields;
+       var sid = this.meta.id;
+       var totalRecords = 0, success = true;
+       if(this.meta.totalRecords){
+           totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
+       }
+        
+        if(this.meta.success){
+            var sv = q.selectValue(this.meta.success, root, true);
+            success = sv !== false && sv !== 'false';
+       }
+       var records = [];
+       var ns = q.select(this.meta.record, root);
+        for(var i = 0, len = ns.length; i < len; i++) {
+               var n = ns[i];
+               var values = {};
+               var id = sid ? q.selectValue(sid, n) : undefined;
+               for(var j = 0, jlen = fields.length; j < jlen; j++){
+                   var f = fields.items[j];
+                var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
+                   v = f.convert(v);
+                   values[f.name] = v;
+               }
+               var record = new recordType(values, id);
+               record.node = n;
+               records[records.length] = record;
+           }
 
-    toString : function(){
-        return "[Node"+(this.id?" "+this.id:"")+"]";
+           return {
+               success : success,
+               records : records,
+               totalRecords : totalRecords || records.length
+           };
     }
 });/*
  * Based on:
@@ -23742,454 +26029,838 @@ 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)
+ * @class Roo.data.ArrayReader
+ * @extends Roo.data.DataReader
+ * Data reader class to create an Array of Roo.data.Record objects from an Array.
+ * Each element of that Array represents a row of data fields. The
+ * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
+ * of the field definition if it exists, or the field's ordinal position in the definition.<br>
+ * <p>
+ * Example code:.
+ * <pre><code>
+var RecordDef = Roo.data.Record.create([
+    {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
+    {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
+]);
+var myReader = new Roo.data.ArrayReader({
+    id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
+}, RecordDef);
+</code></pre>
+ * <p>
+ * This would consume an Array like this:
+ * <pre><code>
+[ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
+  </code></pre>
  * @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.
+ * Create a new JsonReader
+ * @param {Object} meta Metadata configuration options.
+ * @param {Object|Array} recordType Either an Array of field definition objects
+ * 
+ * @cfg {Array} fields Array of field definition objects
+ * @cfg {String} id Name of the property within a row object that contains a record identifier value.
+ * as specified to {@link Roo.data.Record#create},
+ * or an {@link Roo.data.Record} object
+ *
+ * 
+ * created using {@link Roo.data.Record#create}.
  */
+Roo.data.ArrayReader = function(meta, recordType)
+{    
+    Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
+};
 
-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;
+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)
+    {
+        var sid = this.meta ? this.meta.id : null;
+        var recordType = this.recordType, fields = recordType.prototype.fields;
+        var records = [];
+        var root = o;
+        for(var i = 0; i < root.length; i++){
+            var n = root[i];
+            var values = {};
+            var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
+            for(var j = 0, jlen = fields.length; j < jlen; j++){
+                var f = fields.items[j];
+                var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
+                var v = n[k] !== undefined ? n[k] : f.defaultValue;
+                v = f.convert(v);
+                values[f.name] = v;
+            }
+            var record = new recordType(values, id);
+            record.json = n;
+            records[records.length] = record;
+        }
+        return {
+            records : records,
+            totalRecords : records.length
+        };
+    },
+    // 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;
+        
     }
-    this.useShim = config.shim !== false && Roo.useShims;
-    this.useDisplay = config.useDisplay;
-    this.hide();
-};
+    
+    
+});/*
+ * 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 supr = Roo.Element.prototype;
 
-// shims are shared among layer to keep from having 100 iframes
-var shims = [];
+/**
+ * @class Roo.data.Tree
+ * @extends Roo.util.Observable
+ * Represents a tree data structure and bubbles all the events for its nodes. The nodes
+ * in the tree have most standard DOM functionality.
+ * @constructor
+ * @param {Node} root (optional) The root node
+ */
+Roo.data.Tree = function(root){
+   this.nodeHash = {};
+   /**
+    * The root node for this tree
+    * @type Node
+    */
+   this.root = null;
+   if(root){
+       this.setRootNode(root);
+   }
+   this.addEvents({
+       /**
+        * @event append
+        * Fires when a new child node is appended to a node in this tree.
+        * @param {Tree} tree The owner tree
+        * @param {Node} parent The parent node
+        * @param {Node} node The newly appended node
+        * @param {Number} index The index of the newly appended node
+        */
+       "append" : true,
+       /**
+        * @event remove
+        * Fires when a child node is removed from a node in this tree.
+        * @param {Tree} tree The owner tree
+        * @param {Node} parent The parent node
+        * @param {Node} node The child node removed
+        */
+       "remove" : true,
+       /**
+        * @event move
+        * Fires when a node is moved to a new location in the tree
+        * @param {Tree} tree The owner tree
+        * @param {Node} node The node moved
+        * @param {Node} oldParent The old parent of this node
+        * @param {Node} newParent The new parent of this node
+        * @param {Number} index The index it was moved to
+        */
+       "move" : true,
+       /**
+        * @event insert
+        * Fires when a new child node is inserted in a node in this tree.
+        * @param {Tree} tree The owner tree
+        * @param {Node} parent The parent node
+        * @param {Node} node The child node inserted
+        * @param {Node} refNode The child node the node was inserted before
+        */
+       "insert" : true,
+       /**
+        * @event beforeappend
+        * Fires before a new child is appended to a node in this tree, return false to cancel the append.
+        * @param {Tree} tree The owner tree
+        * @param {Node} parent The parent node
+        * @param {Node} node The child node to be appended
+        */
+       "beforeappend" : true,
+       /**
+        * @event beforeremove
+        * Fires before a child is removed from a node in this tree, return false to cancel the remove.
+        * @param {Tree} tree The owner tree
+        * @param {Node} parent The parent node
+        * @param {Node} node The child node to be removed
+        */
+       "beforeremove" : true,
+       /**
+        * @event beforemove
+        * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
+        * @param {Tree} tree The owner tree
+        * @param {Node} node The node being moved
+        * @param {Node} oldParent The parent of the node
+        * @param {Node} newParent The new parent the node is moving to
+        * @param {Number} index The index it is being moved to
+        */
+       "beforemove" : true,
+       /**
+        * @event beforeinsert
+        * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
+        * @param {Tree} tree The owner tree
+        * @param {Node} parent The parent node
+        * @param {Node} node The child node to be inserted
+        * @param {Node} refNode The child node the node is being inserted before
+        */
+       "beforeinsert" : true
+   });
+
+    Roo.data.Tree.superclass.constructor.call(this);
+};
 
-Roo.extend(Roo.Layer, Roo.Element, {
+Roo.extend(Roo.data.Tree, Roo.util.Observable, {
+    pathSeparator: "/",
 
-    getZIndex : function(){
-        return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
+    proxyNodeEvent : function(){
+        return this.fireEvent.apply(this, arguments);
     },
 
-    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;
+    /**
+     * Returns the root node for this tree.
+     * @return {Node}
+     */
+    getRootNode : function(){
+        return this.root;
     },
 
-    hideShim : function(){
-        if(this.shim){
-            this.shim.setDisplayed(false);
-            shims.push(this.shim);
-            delete this.shim;
-        }
+    /**
+     * Sets the root node for this tree.
+     * @param {Node} node
+     * @return {Node}
+     */
+    setRootNode : function(node){
+        this.root = node;
+        node.ownerTree = this;
+        node.isRoot = true;
+        this.registerNode(node);
+        return node;
     },
 
-    disableShadow : function(){
-        if(this.shadow){
-            this.shadowDisabled = true;
-            this.shadow.hide();
-            this.lastShadowOffset = this.shadowOffset;
-            this.shadowOffset = 0;
-        }
+    /**
+     * Gets a node in this tree by its id.
+     * @param {String} id
+     * @return {Node}
+     */
+    getNodeById : function(id){
+        return this.nodeHash[id];
     },
 
-    enableShadow : function(show){
-        if(this.shadow){
-            this.shadowDisabled = false;
-            this.shadowOffset = this.lastShadowOffset;
-            delete this.lastShadowOffset;
-            if(show){
-                this.sync(true);
-            }
-        }
+    registerNode : function(node){
+        this.nodeHash[node.id] = node;
     },
 
-    // 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();
+    unregisterNode : function(node){
+        delete this.nodeHash[node.id];
+    },
 
-            var l = this.getLeft(true),
-                t = this.getTop(true);
+    toString : function(){
+        return "[Tree"+(this.id?" "+this.id:"")+"]";
+    }
+});
 
-            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();
+/**
+ * @class Roo.data.Node
+ * @extends Roo.util.Observable
+ * @cfg {Boolean} leaf true if this node is a leaf and does not have children
+ * @cfg {String} id The id for this node. If one is not specified, one is generated.
+ * @constructor
+ * @param {Object} attributes The attributes/config for the node
+ */
+Roo.data.Node = function(attributes){
+    /**
+     * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
+     * @type {Object}
+     */
+    this.attributes = attributes || {};
+    this.leaf = this.attributes.leaf;
+    /**
+     * The node id. @type String
+     */
+    this.id = this.attributes.id;
+    if(!this.id){
+        this.id = Roo.id(null, "ynode-");
+        this.attributes.id = this.id;
+    }
+     
+    
+    /**
+     * All child nodes of this node. @type Array
+     */
+    this.childNodes = [];
+    if(!this.childNodes.indexOf){ // indexOf is a must
+        this.childNodes.indexOf = function(o){
+            for(var i = 0, len = this.length; i < len; i++){
+                if(this[i] == o) {
+                    return i;
                 }
-                sh.setSize(w, h);
-                sh.setLeftTop(l, t);
             }
-            
-        }
-    },
+            return -1;
+        };
+    }
+    /**
+     * The parent node for this node. @type Node
+     */
+    this.parentNode = null;
+    /**
+     * The first direct child node of this node, or null if this node has no child nodes. @type Node
+     */
+    this.firstChild = null;
+    /**
+     * The last direct child node of this node, or null if this node has no child nodes. @type Node
+     */
+    this.lastChild = null;
+    /**
+     * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
+     */
+    this.previousSibling = null;
+    /**
+     * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
+     */
+    this.nextSibling = null;
 
-    // private
-    destroy : function(){
-        this.hideShim();
-        if(this.shadow){
-            this.shadow.hide();
+    this.addEvents({
+       /**
+        * @event append
+        * Fires when a new child node is appended
+        * @param {Tree} tree The owner tree
+        * @param {Node} this This node
+        * @param {Node} node The newly appended node
+        * @param {Number} index The index of the newly appended node
+        */
+       "append" : true,
+       /**
+        * @event remove
+        * Fires when a child node is removed
+        * @param {Tree} tree The owner tree
+        * @param {Node} this This node
+        * @param {Node} node The removed node
+        */
+       "remove" : true,
+       /**
+        * @event move
+        * Fires when this node is moved to a new location in the tree
+        * @param {Tree} tree The owner tree
+        * @param {Node} this This node
+        * @param {Node} oldParent The old parent of this node
+        * @param {Node} newParent The new parent of this node
+        * @param {Number} index The index it was moved to
+        */
+       "move" : true,
+       /**
+        * @event insert
+        * Fires when a new child node is inserted.
+        * @param {Tree} tree The owner tree
+        * @param {Node} this This node
+        * @param {Node} node The child node inserted
+        * @param {Node} refNode The child node the node was inserted before
+        */
+       "insert" : true,
+       /**
+        * @event beforeappend
+        * Fires before a new child is appended, return false to cancel the append.
+        * @param {Tree} tree The owner tree
+        * @param {Node} this This node
+        * @param {Node} node The child node to be appended
+        */
+       "beforeappend" : true,
+       /**
+        * @event beforeremove
+        * Fires before a child is removed, return false to cancel the remove.
+        * @param {Tree} tree The owner tree
+        * @param {Node} this This node
+        * @param {Node} node The child node to be removed
+        */
+       "beforeremove" : true,
+       /**
+        * @event beforemove
+        * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
+        * @param {Tree} tree The owner tree
+        * @param {Node} this This node
+        * @param {Node} oldParent The parent of this node
+        * @param {Node} newParent The new parent this node is moving to
+        * @param {Number} index The index it is being moved to
+        */
+       "beforemove" : true,
+       /**
+        * @event beforeinsert
+        * Fires before a new child is inserted, return false to cancel the insert.
+        * @param {Tree} tree The owner tree
+        * @param {Node} this This node
+        * @param {Node} node The child node to be inserted
+        * @param {Node} refNode The child node the node is being inserted before
+        */
+       "beforeinsert" : true
+   });
+    this.listeners = this.attributes.listeners;
+    Roo.data.Node.superclass.constructor.call(this);
+};
+
+Roo.extend(Roo.data.Node, Roo.util.Observable, {
+    fireEvent : function(evtName){
+        // first do standard event for this node
+        if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
+            return false;
         }
-        this.removeAllListeners();
-        var pn = this.dom.parentNode;
-        if(pn){
-            pn.removeChild(this.dom);
+        // then bubble it up to the tree if the event wasn't cancelled
+        var ot = this.getOwnerTree();
+        if(ot){
+            if(ot.proxyNodeEvent.apply(ot, arguments) === false){
+                return false;
+            }
         }
-        Roo.Element.uncache(this.id);
+        return true;
     },
 
-    remove : function(){
-        this.destroy();
+    /**
+     * Returns true if this node is a leaf
+     * @return {Boolean}
+     */
+    isLeaf : function(){
+        return this.leaf === true;
     },
 
     // private
-    beginUpdate : function(){
-        this.updating = true;
+    setFirstChild : function(node){
+        this.firstChild = node;
     },
 
-    // private
-    endUpdate : function(){
-        this.updating = false;
-        this.sync(true);
+    //private
+    setLastChild : function(node){
+        this.lastChild = node;
     },
 
-    // private
-    hideUnders : function(negOffset){
-        if(this.shadow){
-            this.shadow.hide();
-        }
-        this.hideShim();
+
+    /**
+     * Returns true if this node is the last child of its parent
+     * @return {Boolean}
+     */
+    isLast : function(){
+       return (!this.parentNode ? true : this.parentNode.lastChild == this);
     },
 
-    // private
-    constrainXY : function(){
-        if(this.constrain){
-            var vw = Roo.lib.Dom.getViewWidth(),
-                vh = Roo.lib.Dom.getViewHeight();
-            var s = Roo.get(document).getScroll();
+    /**
+     * Returns true if this node is the first child of its parent
+     * @return {Boolean}
+     */
+    isFirst : function(){
+       return (!this.parentNode ? true : this.parentNode.firstChild == this);
+    },
 
-            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;
+    hasChildNodes : function(){
+        return !this.isLeaf() && this.childNodes.length > 0;
+    },
+
+    /**
+     * Insert node(s) as the last child node of this node.
+     * @param {Node/Array} node The node or Array of nodes to append
+     * @return {Node} The appended node if single append, or null if an array was passed
+     */
+    appendChild : function(node){
+        var multi = false;
+        if(node instanceof Array){
+            multi = node;
+        }else if(arguments.length > 1){
+            multi = arguments;
+        }
+        
+        // if passed an array or multiple args do them one by one
+        if(multi){
+            for(var i = 0, len = multi.length; i < len; i++) {
+               this.appendChild(multi[i]);
             }
-            if((y + h) > vh+s.top){
-                y = vh - h - this.shadowOffset;
-                moved = true;
+        }else{
+            if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
+                return false;
             }
-            // then make sure top/left isn't negative
-            if(x < s.left){
-                x = s.left;
-                moved = true;
+            var index = this.childNodes.length;
+            var oldParent = node.parentNode;
+            // it's a move, make sure we move it cleanly
+            if(oldParent){
+                if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
+                    return false;
+                }
+                oldParent.removeChild(node);
             }
-            if(y < s.top){
-                y = s.top;
-                moved = true;
+            
+            index = this.childNodes.length;
+            if(index == 0){
+                this.setFirstChild(node);
             }
-            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();
+            this.childNodes.push(node);
+            node.parentNode = this;
+            var ps = this.childNodes[index-1];
+            if(ps){
+                node.previousSibling = ps;
+                ps.nextSibling = node;
+            }else{
+                node.previousSibling = null;
+            }
+            node.nextSibling = null;
+            this.setLastChild(node);
+            node.setOwnerTree(this.getOwnerTree());
+            this.fireEvent("append", this.ownerTree, this, node, index);
+            if(this.ownerTree) {
+                this.ownerTree.fireEvent("appendnode", this, node, index);
             }
+            if(oldParent){
+                node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
+            }
+            return node;
         }
     },
 
-    isVisible : function(){
-        return this.visible;    
-    },
+    /**
+     * Removes a child node from this node.
+     * @param {Node} node The node to remove
+     * @return {Node} The removed node
+     */
+    removeChild : function(node){
+        var index = this.childNodes.indexOf(node);
+        if(index == -1){
+            return false;
+        }
+        if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
+            return false;
+        }
 
-    // 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]);
+        // remove it from childNodes collection
+        this.childNodes.splice(index, 1);
+
+        // update siblings
+        if(node.previousSibling){
+            node.previousSibling.nextSibling = node.nextSibling;
+        }
+        if(node.nextSibling){
+            node.nextSibling.previousSibling = node.previousSibling;
         }
-    },
 
-    // private
-    hideAction : function(){
-        this.visible = false;
-        if(this.useDisplay === true){
-            this.setDisplayed(false);
-        }else{
-            this.setLeftTop(-10000,-10000);
+        // update child refs
+        if(this.firstChild == node){
+            this.setFirstChild(node.nextSibling);
+        }
+        if(this.lastChild == node){
+            this.setLastChild(node.previousSibling);
         }
+
+        node.setOwnerTree(null);
+        // clear any references from the node
+        node.parentNode = null;
+        node.previousSibling = null;
+        node.nextSibling = null;
+        this.fireEvent("remove", this.ownerTree, this, node);
+        return node;
     },
 
-    // overridden Element method
-    setVisible : function(v, a, d, c, e){
-        if(v){
-            this.showAction();
+    /**
+     * Inserts the first node before the second node in this nodes childNodes collection.
+     * @param {Node} node The node to insert
+     * @param {Node} refNode The node to insert before (if null the node is appended)
+     * @return {Node} The inserted node
+     */
+    insertBefore : function(node, refNode){
+        if(!refNode){ // like standard Dom, refNode can be null for append
+            return this.appendChild(node);
         }
-        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();
-            }
+        // nothing to do
+        if(node == refNode){
+            return false;
+        }
+
+        if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
+            return false;
         }
-    },
+        var index = this.childNodes.indexOf(refNode);
+        var oldParent = node.parentNode;
+        var refIndex = index;
 
-    storeXY : function(xy){
-        delete this.lastLT;
-        this.lastXY = xy;
-    },
+        // when moving internally, indexes will change after remove
+        if(oldParent == this && this.childNodes.indexOf(node) < index){
+            refIndex--;
+        }
 
-    storeLeftTop : function(left, top){
-        delete this.lastXY;
-        this.lastLT = [left, top];
+        // it's a move, make sure we move it cleanly
+        if(oldParent){
+            if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
+                return false;
+            }
+            oldParent.removeChild(node);
+        }
+        if(refIndex == 0){
+            this.setFirstChild(node);
+        }
+        this.childNodes.splice(refIndex, 0, node);
+        node.parentNode = this;
+        var ps = this.childNodes[refIndex-1];
+        if(ps){
+            node.previousSibling = ps;
+            ps.nextSibling = node;
+        }else{
+            node.previousSibling = null;
+        }
+        node.nextSibling = refNode;
+        refNode.previousSibling = node;
+        node.setOwnerTree(this.getOwnerTree());
+        this.fireEvent("insert", this.ownerTree, this, node, refNode);
+        if(oldParent){
+            node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
+        }
+        return node;
     },
 
-    // private
-    beforeFx : function(){
-        this.beforeAction();
-        return Roo.Layer.superclass.beforeFx.apply(this, arguments);
+    /**
+     * Returns the child node at the specified index.
+     * @param {Number} index
+     * @return {Node}
+     */
+    item : function(index){
+        return this.childNodes[index];
     },
 
-    // private
-    afterFx : function(){
-        Roo.Layer.superclass.afterFx.apply(this, arguments);
-        this.sync(this.isVisible());
+    /**
+     * Replaces one child node in this node with another.
+     * @param {Node} newChild The replacement node
+     * @param {Node} oldChild The node to replace
+     * @return {Node} The replaced node
+     */
+    replaceChild : function(newChild, oldChild){
+        this.insertBefore(newChild, oldChild);
+        this.removeChild(oldChild);
+        return oldChild;
     },
 
-    // private
-    beforeAction : function(){
-        if(!this.updating && this.shadow){
-            this.shadow.hide();
-        }
+    /**
+     * Returns the index of a child node
+     * @param {Node} node
+     * @return {Number} The index of the node or -1 if it was not found
+     */
+    indexOf : function(child){
+        return this.childNodes.indexOf(child);
     },
 
-    // overridden Element method
-    setLeft : function(left){
-        this.storeLeftTop(left, this.getTop(true));
-        supr.setLeft.apply(this, arguments);
-        this.sync();
+    /**
+     * Returns the tree this node is in.
+     * @return {Tree}
+     */
+    getOwnerTree : function(){
+        // if it doesn't have one, look for one
+        if(!this.ownerTree){
+            var p = this;
+            while(p){
+                if(p.ownerTree){
+                    this.ownerTree = p.ownerTree;
+                    break;
+                }
+                p = p.parentNode;
+            }
+        }
+        return this.ownerTree;
     },
 
-    setTop : function(top){
-        this.storeLeftTop(this.getLeft(true), top);
-        supr.setTop.apply(this, arguments);
-        this.sync();
+    /**
+     * Returns depth of this node (the root node has a depth of 0)
+     * @return {Number}
+     */
+    getDepth : function(){
+        var depth = 0;
+        var p = this;
+        while(p.parentNode){
+            ++depth;
+            p = p.parentNode;
+        }
+        return depth;
     },
 
-    setLeftTop : function(left, top){
-        this.storeLeftTop(left, top);
-        supr.setLeftTop.apply(this, arguments);
-        this.sync();
+    // private
+    setOwnerTree : function(tree){
+        // if it's move, we need to update everyone
+        if(tree != this.ownerTree){
+            if(this.ownerTree){
+                this.ownerTree.unregisterNode(this);
+            }
+            this.ownerTree = tree;
+            var cs = this.childNodes;
+            for(var i = 0, len = cs.length; i < len; i++) {
+               cs[i].setOwnerTree(tree);
+            }
+            if(tree){
+                tree.registerNode(this);
+            }
+        }
     },
 
-    setXY : function(xy, a, d, c, e){
-        this.fixDisplay();
-        this.beforeAction();
-        this.storeXY(xy);
-        var cb = this.createCB(c);
-        supr.setXY.call(this, xy, a, d, cb, e);
-        if(!a){
-            cb();
+    /**
+     * Returns the path for this node. The path can be used to expand or select this node programmatically.
+     * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
+     * @return {String} The path
+     */
+    getPath : function(attr){
+        attr = attr || "id";
+        var p = this.parentNode;
+        var b = [this.attributes[attr]];
+        while(p){
+            b.unshift(p.attributes[attr]);
+            p = p.parentNode;
         }
+        var sep = this.getOwnerTree().pathSeparator;
+        return sep + b.join(sep);
     },
 
-    // private
-    createCB : function(c){
-        var el = this;
-        return function(){
-            el.constrainXY();
-            el.sync(true);
-            if(c){
-                c();
+    /**
+     * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
+     * function call will be the scope provided or the current node. The arguments to the function
+     * will be the args provided or the current node. If the function returns false at any point,
+     * the bubble is stopped.
+     * @param {Function} fn The function to call
+     * @param {Object} scope (optional) The scope of the function (defaults to current node)
+     * @param {Array} args (optional) The args to call the function with (default to passing the current node)
+     */
+    bubble : function(fn, scope, args){
+        var p = this;
+        while(p){
+            if(fn.call(scope || p, args || p) === false){
+                break;
             }
-        };
+            p = p.parentNode;
+        }
     },
 
-    // overridden Element method
-    setX : function(x, a, d, c, e){
-        this.setXY([x, this.getY()], a, d, c, e);
+    /**
+     * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
+     * function call will be the scope provided or the current node. The arguments to the function
+     * will be the args provided or the current node. If the function returns false at any point,
+     * the cascade is stopped on that branch.
+     * @param {Function} fn The function to call
+     * @param {Object} scope (optional) The scope of the function (defaults to current node)
+     * @param {Array} args (optional) The args to call the function with (default to passing the current node)
+     */
+    cascade : function(fn, scope, args){
+        if(fn.call(scope || this, args || this) !== false){
+            var cs = this.childNodes;
+            for(var i = 0, len = cs.length; i < len; i++) {
+               cs[i].cascade(fn, scope, args);
+            }
+        }
     },
 
-    // overridden Element method
-    setY : function(y, a, d, c, e){
-        this.setXY([this.getX(), y], a, d, c, e);
+    /**
+     * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
+     * function call will be the scope provided or the current node. The arguments to the function
+     * will be the args provided or the current node. If the function returns false at any point,
+     * the iteration stops.
+     * @param {Function} fn The function to call
+     * @param {Object} scope (optional) The scope of the function (defaults to current node)
+     * @param {Array} args (optional) The args to call the function with (default to passing the current node)
+     */
+    eachChild : function(fn, scope, args){
+        var cs = this.childNodes;
+        for(var i = 0, len = cs.length; i < len; i++) {
+               if(fn.call(scope || this, args || cs[i]) === false){
+                   break;
+               }
+        }
     },
 
-    // overridden Element method
-    setSize : function(w, h, a, d, c, e){
-        this.beforeAction();
-        var cb = this.createCB(c);
-        supr.setSize.call(this, w, h, a, d, cb, e);
-        if(!a){
-            cb();
+    /**
+     * Finds the first child that has the attribute with the specified value.
+     * @param {String} attribute The attribute name
+     * @param {Mixed} value The value to search for
+     * @return {Node} The found child or null if none was found
+     */
+    findChild : function(attribute, value){
+        var cs = this.childNodes;
+        for(var i = 0, len = cs.length; i < len; i++) {
+               if(cs[i].attributes[attribute] == value){
+                   return cs[i];
+               }
         }
+        return null;
     },
 
-    // overridden Element method
-    setWidth : function(w, a, d, c, e){
-        this.beforeAction();
-        var cb = this.createCB(c);
-        supr.setWidth.call(this, w, a, d, cb, e);
-        if(!a){
-            cb();
+    /**
+     * Finds the first child by a custom function. The child matches if the function passed
+     * returns true.
+     * @param {Function} fn
+     * @param {Object} scope (optional)
+     * @return {Node} The found child or null if none was found
+     */
+    findChildBy : function(fn, scope){
+        var cs = this.childNodes;
+        for(var i = 0, len = cs.length; i < len; i++) {
+               if(fn.call(scope||cs[i], cs[i]) === true){
+                   return cs[i];
+               }
         }
+        return null;
     },
 
-    // overridden Element method
-    setHeight : function(h, a, d, c, e){
-        this.beforeAction();
-        var cb = this.createCB(c);
-        supr.setHeight.call(this, h, a, d, cb, e);
-        if(!a){
-            cb();
+    /**
+     * Sorts this nodes children using the supplied sort function
+     * @param {Function} fn
+     * @param {Object} scope (optional)
+     */
+    sort : function(fn, scope){
+        var cs = this.childNodes;
+        var len = cs.length;
+        if(len > 0){
+            var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
+            cs.sort(sortFn);
+            for(var i = 0; i < len; i++){
+                var n = cs[i];
+                n.previousSibling = cs[i-1];
+                n.nextSibling = cs[i+1];
+                if(i == 0){
+                    this.setFirstChild(n);
+                }
+                if(i == len-1){
+                    this.setLastChild(n);
+                }
+            }
         }
     },
 
-    // overridden Element method
-    setBounds : function(x, y, w, h, a, d, c, e){
-        this.beforeAction();
-        var cb = this.createCB(c);
-        if(!a){
-            this.storeXY([x, y]);
-            supr.setXY.call(this, [x, y]);
-            supr.setSize.call(this, w, h, a, d, cb, e);
-            cb();
-        }else{
-            supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
-        }
-        return this;
+    /**
+     * Returns true if this node is an ancestor (at any point) of the passed node.
+     * @param {Node} node
+     * @return {Boolean}
+     */
+    contains : function(node){
+        return node.isAncestor(this);
     },
-    
+
     /**
-     * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
-     * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
-     * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
-     * @param {Number} zindex The new z-index to set
-     * @return {this} The Layer
+     * Returns true if the passed node is an ancestor (at any point) of this node.
+     * @param {Node} node
+     * @return {Boolean}
      */
-    setZIndex : function(zindex){
-        this.zindex = zindex;
-        this.setStyle("z-index", zindex + 2);
-        if(this.shadow){
-            this.shadow.setZIndex(zindex + 1);
-        }
-        if(this.shim){
-            this.shim.setStyle("z-index", zindex);
+    isAncestor : function(node){
+        var p = this.parentNode;
+        while(p){
+            if(p == node){
+                return true;
+            }
+            p = p.parentNode;
         }
+        return false;
+    },
+
+    toString : function(){
+        return "[Node"+(this.id?" "+this.id:"")+"]";
     }
-});
-})();/*
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -24270,6 +26941,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)
@@ -24990,7 +27662,7 @@ Roo.View = function(config, depreciated_tpl, depreciated_config){
            
          var fctr = this.wrapEl.appendChild(document.createElement("div"));
         
-        this.footer.dataSource = this.store
+        this.footer.dataSource = this.store;
         this.footer.container = fctr;
         this.footer = Roo.factory(this.footer, Roo);
         fctr.insertFirst(this.el);
@@ -25673,15 +28345,20 @@ Roo.extend(Roo.JsonView, Roo.View, {
         um.update.apply(um, arguments);
     },
 
+    // note - render is a standard framework call...
+    // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
     render : function(el, response){
+        
         this.clearSelections();
         this.el.update("");
         var o;
         try{
-            o = Roo.util.JSON.decode(response.responseText);
-            if(this.jsonRoot){
-                
-                o = o[this.jsonRoot];
+            if (response != '') {
+                o = Roo.util.JSON.decode(response.responseText);
+                if(this.jsonRoot){
+                    
+                    o = o[this.jsonRoot];
+                }
             }
         } catch(e){
         }
@@ -26033,7 +28710,9 @@ Roo.DatePicker = function(config){
         var re = "(?:";
         for(var i = 0; i < dd.length; i++){
             re += dd[i];
-            if(i != dd.length-1) re += "|";
+            if(i != dd.length-1) {
+                re += "|";
+            }
         }
         this.disabledDatesRE = new RegExp(re + ")");
     }
@@ -27012,7 +29691,9 @@ Roo.extend(Roo.TabPanel, Roo.util.Observable, {
     autoSizeTabs : function(){
         var count = this.items.length;
         var vcount = count - this.hiddenCount;
-        if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
+        if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
+            return;
+        }
         var w = Math.max(this.el.getWidth() - this.cpad, 10);
         var availWidth = Math.floor(w / vcount);
         var b = this.stripBody;
@@ -27048,7 +29729,9 @@ Roo.extend(Roo.TabPanel, Roo.util.Observable, {
     setTabWidth : function(width){
         this.currentTabWidth = width;
         for(var i = 0, len = this.items.length; i < len; i++) {
-               if(!this.items[i].isHidden())this.items[i].setWidth(width);
+               if(!this.items[i].isHidden()) {
+                this.items[i].setWidth(width);
+            }
         }
     },
 
@@ -27572,7 +30255,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,
@@ -28194,6 +30877,7 @@ Roo.MenuButton = Roo.SplitButton;/*
 
 /**
  * @class Roo.Toolbar
+ * @children   Roo.Toolbar.Item Roo.form.Field
  * Basic Toolbar class.
  * @constructor
  * Creates a new Toolbar
@@ -28235,7 +30919,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
@@ -28706,7 +31390,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 || "";
@@ -28743,7 +31427,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);
@@ -28849,6 +31536,7 @@ Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
 /**
  * @class Roo.PagingToolbar
  * @extends Roo.Toolbar
+ * @children   Roo.Toolbar.Item 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
@@ -28884,10 +31572,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
@@ -28896,6 +31581,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)
@@ -29069,8 +31756,9 @@ Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
         {
           var v = this.field.dom.value, pageNum; 
           var increment = (e.shiftKey) ? 10 : 1;
-          if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
+          if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
             increment *= -1;
+          }
           if(!v || isNaN(pageNum = parseInt(v, 10))) {
             this.field.dom.value = d.activePage;
             return;
@@ -29490,7 +32178,9 @@ Roo.extend(Roo.Resizable, Roo.util.Observable, {
 
     // private
     snap : function(value, inc, min){
-        if(!inc || !value) return value;
+        if(!inc || !value) {
+            return value;
+        }
         var newValue = value;
         var m = value % inc;
         if(m > 0){
@@ -31288,6 +33978,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):
@@ -31373,6 +34065,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
@@ -31454,7 +34168,7 @@ Roo.Msg.show({
    animEl: 'elId'
 });
 </code></pre>
- * @singleton
+ * @static
  */
 Roo.MessageBox = function(){
     var dlg, opt, mask, waitTimer;
@@ -31983,7 +34697,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;
@@ -32016,12 +34730,12 @@ Roo.QuickTips = function(){
             t.removeAttribute("title");
             e.preventDefault();
         }else{
-            ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
+            ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
         }
         if(ttp){
             showProc = show.defer(tm.showDelay, tm, [{
                 el: t, 
-                text: ttp
+                text: ttp.replace(/\\n/g,'<br/>'),
                 width: et.getAttributeNS(ns, cfg.width),
                 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
                 title: et.getAttributeNS(ns, cfg.title),
@@ -32357,7 +35071,8 @@ target      Element/String/Array   An Element, id or array of ids that this quic
 
         // private
        tagConfig : {
-           namespace : "ext",
+           namespace : "roo", // was ext?? this may break..
+           alt_namespace : "ext",
            attribute : "qtip",
            width : "width",
            target : "target",
@@ -32384,7 +35099,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
@@ -32401,8 +35116,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>
@@ -32610,7 +35325,15 @@ Roo.tree.TreePanel = function(el, config){
         * </ul>
         * @param {Object} dragOverEvent
         */
-       "nodedragover" : true
+       "nodedragover" : true,
+       /**
+        * @event appendnode
+        * Fires when append node to the tree
+        * @param {Roo.tree.TreePanel} this
+        * @param {Roo.tree.TreeNode} node
+        * @param {Number} index The index of the newly appended node
+        */
+       "appendnode" : true
         
     });
     if(this.singleExpand){
@@ -33188,7 +35911,7 @@ Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
  * @cfg {Boolean} allowDrop false if this node cannot be drop on
  * @cfg {Boolean} disabled true to start the node disabled
  * @cfg {String} icon The path to an icon for the node. The preferred way to do this
- * is to use the cls or iconCls attributes and add the icon via a CSS background image.
+ *    is to use the cls or iconCls attributes and add the icon via a CSS background image.
  * @cfg {String} cls A css class to be added to the node
  * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
  * @cfg {String} href URL of the link used for the node (defaults to #)
@@ -33471,7 +36194,8 @@ Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
                 this.renderChildren();
             }
             this.expanded = true;
-            if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
+            
+            if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
                 this.ui.animExpand(function(){
                     this.fireEvent("expand", this);
                     if(typeof callback == "function"){
@@ -33922,7 +36646,7 @@ Roo.tree.TreeNodeUI.prototype = {
             this.addClass("x-tree-node-disabled");
         }
         var ot = this.node.getOwnerTree();
-        var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
+        var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
         if(dd && (!this.node.isRoot || ot.rootVisible)){
             Roo.dd.Registry.register(this.elNode, {
                 node: this.node,
@@ -34165,11 +36889,11 @@ Roo.tree.TreeNodeUI.prototype = {
         // add some indent caching, this helps performance when rendering a large tree
         this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
         var t = n.getOwnerTree();
-        var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
+        var txt = t && t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
         if (typeof(n.attributes.html) != 'undefined') {
             txt = n.attributes.html;
         }
-        var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
+        var tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
         var cb = typeof a.checked == 'boolean';
         var href = a.href ? a.href : Roo.isGecko ? "" : "#";
         var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
@@ -34355,7 +37079,9 @@ Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
     myTreeLoader.on("beforeload", function(treeLoader, node) {
         this.baseParams.category = node.attributes.category;
     }, this);
-</code></pre><
+    
+</code></pre>
+ *
  * This would pass an HTTP parameter called "category" to the server containing
  * the value of the Node's "category" attribute.
  * @constructor
@@ -35136,7 +37862,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
  *
  * 
  */
@@ -35442,7 +38168,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
@@ -35553,6 +38279,7 @@ Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
 /**
  * @class Roo.menu.Menu
  * @extends Roo.util.Observable
+ * @children Roo.menu.BaseItem
  * 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
@@ -35560,7 +38287,9 @@ Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
  * @param {Object} config Configuration options
  */
 Roo.menu.Menu = function(config){
-    Roo.apply(this, config);
+    
+    Roo.menu.Menu.superclass.constructor.call(this, config);
+    
     this.id = this.id || Roo.id();
     this.addEvents({
         /**
@@ -35687,7 +38416,10 @@ Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
             tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
         });
         var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
-        ul.on(Roo.isTouch ? 'touchstart' : 'click'   , this.onClick, this);
+        //disabling touch- as it's causing issues ..
+        //ul.on(Roo.isTouch ? 'touchstart' : 'click'   , this.onClick, this);
+        ul.on('click'   , this.onClick, this);
+        
         
         ul.on("mouseover", this.onMouseOver, this);
         ul.on("mouseout", this.onMouseOut, this);
@@ -36117,7 +38849,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();
@@ -36305,6 +39037,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
@@ -36451,6 +39184,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
@@ -36530,7 +39264,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 : '',
     
@@ -36620,7 +39354,10 @@ 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.
@@ -37038,6 +39775,77 @@ Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
  * <script type="text/javascript">
  */
  
+/**
+ * @class Roo.form.TextItem
+ * @extends Roo.BoxComponent
+ * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
+ * @constructor
+ * Creates a new TextItem
+ * @param {Object} config Configuration options
+ */
+Roo.form.TextItem = function(config){
+    Roo.form.TextItem.superclass.constructor.call(this, config);
+};
+
+Roo.extend(Roo.form.TextItem, Roo.BoxComponent,  {
+    
+    /**
+     * @cfg {String} tag the tag for this item (default div)
+     */
+    tag : 'div',
+    /**
+     * @cfg {String} html the content for this item
+     */
+    html : '',
+    
+    getAutoCreate : function()
+    {
+        var cfg = {
+            id: this.id,
+            tag: this.tag,
+            html: this.html,
+            cls: 'x-form-item'
+        };
+        
+        return cfg;
+        
+    },
+    
+    onRender : function(ct, position)
+    {
+        Roo.form.TextItem.superclass.onRender.call(this, ct, position);
+        
+        if(!this.el){
+            var cfg = this.getAutoCreate();
+            if(!cfg.name){
+                cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
+            }
+            if (!cfg.name.length) {
+                delete cfg.name;
+            }
+            this.el = ct.createChild(cfg, position);
+        }
+    },
+    /*
+     * setHTML
+     * @param {String} html update the Contents of the element.
+     */
+    setHTML : function(html)
+    {
+        this.fieldEl.dom.innerHTML = html;
+    }
+    
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
 /**
  * @class Roo.form.Field
  * @extends Roo.BoxComponent
@@ -37150,7 +39958,10 @@ side          Add an error icon to the right of the field with a popup on hover
     /**
      * @cfg {String} cls A CSS class to apply to the field's underlying element.
      */
-
+    // private
+    loadedValue : false,
+     
+     
        // private ??
        initComponent : function(){
         Roo.form.Field.superclass.initComponent.call(this);
@@ -37271,6 +40082,7 @@ side          Add an error icon to the right of the field with a popup on hover
 
     /**
      * Returns true if this field has been changed since it was originally loaded and is not disabled.
+     * DEPRICATED  - it never worked well - use hasChanged/resetHasChanged.
      */
     isDirty : function() {
         if(this.disabled) {
@@ -37279,6 +40091,27 @@ side          Add an error icon to the right of the field with a popup on hover
         return String(this.getValue()) !== String(this.originalValue);
     },
 
+    /**
+     * stores the current value in loadedValue
+     */
+    resetHasChanged : function()
+    {
+        this.loadedValue = String(this.getValue());
+    },
+    /**
+     * checks the current value against the 'loaded' value.
+     * Note - will return false if 'resetHasChanged' has not been called first.
+     */
+    hasChanged : function()
+    {
+        if(this.disabled || this.readOnly) {
+            return false;
+        }
+        return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
+    },
+    
+    
+    
     // private
     afterRender : function(){
         Roo.form.Field.superclass.afterRender.call(this);
@@ -37298,6 +40131,7 @@ side          Add an error icon to the right of the field with a popup on hover
      */
     reset : function(){
         this.setValue(this.resetValue);
+        this.originalValue = this.getValue();
         this.clearInvalid();
     },
 
@@ -37667,6 +40501,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")
      */
@@ -37711,8 +40549,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);
         }
@@ -37748,7 +40589,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.
      *  
@@ -37756,9 +40605,7 @@ Roo.extend(Roo.form.TextField, Roo.form.Field,  {
     reset : function(){
         Roo.form.TextField.superclass.reset.call(this);
        
-    },
-
-    
+    }, 
     // private
     preFocus : function(){
         
@@ -38510,7 +41357,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({
@@ -38526,15 +41374,21 @@ Roo.form.DateField = function(config){
     });
     
     
-    if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
-    if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
+    if(typeof this.minValue == "string") {
+        this.minValue = this.parseDate(this.minValue);
+    }
+    if(typeof this.maxValue == "string") {
+        this.maxValue = this.parseDate(this.maxValue);
+    }
     this.ddMatch = null;
     if(this.disabledDates){
         var dd = this.disabledDates;
         var re = "(?:";
         for(var i = 0; i < dd.length; i++){
             re += dd[i];
-            if(i != dd.length-1) re += "|";
+            if(i != dd.length-1) {
+                re += "|";
+            }
         }
         this.ddMatch = new RegExp(re + ")");
     }
@@ -38852,7 +41706,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
@@ -38889,15 +41749,21 @@ Roo.form.MonthField = function(config){
     });
     
     
-    if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
-    if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
+    if(typeof this.minValue == "string") {
+        this.minValue = this.parseDate(this.minValue);
+    }
+    if(typeof this.maxValue == "string") {
+        this.maxValue = this.parseDate(this.maxValue);
+    }
     this.ddMatch = null;
     if(this.disabledDates){
         var dd = this.disabledDates;
         var re = "(?:";
         for(var i = 0; i < dd.length; i++){
             re += dd[i];
-            if(i != dd.length-1) re += "|";
+            if(i != dd.length-1) {
+                re += "|";
+            }
         }
         this.ddMatch = new RegExp(re + ")");
     }
@@ -39559,9 +42425,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 =
@@ -39573,6 +42441,7 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
              
              
         }
+       
         if(Roo.isGecko){
             this.el.dom.setAttribute('autocomplete', 'off');
         }
@@ -39633,7 +42502,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);
@@ -39982,6 +42853,7 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
     reset : function(){
         // overridden so that last data is reset..
         this.setValue(this.resetValue);
+        this.originalValue = this.getValue();
         this.clearInvalid();
         this.lastData = false;
         if (this.view) {
@@ -40317,9 +43189,9 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
         }
         // scroll to?
         this.view.select(match);
-        var sn = Roo.get(this.view.getSelectedNodes()[0])
+        var sn = Roo.get(this.view.getSelectedNodes()[0]);
         sn.scrollIntoView(sn.dom.parentNode, false);
-    }
+    } 
 
     /** 
     * @cfg {Boolean} grow 
@@ -40411,7 +43283,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,
@@ -40433,7 +43305,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,
@@ -40454,7 +43329,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);
@@ -40575,6 +43450,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;
@@ -40606,18 +43482,19 @@ 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();
     },
     
     reset : function()
     {
-        //Roo.form.ComboBoxArray.superclass.reset.call(this); 
-        this.items.each(function(f) {
-           f.remove(); 
+        this.items.clear();
+        
+        Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
+           el.remove();
         });
+        
         this.el.dom.value = '';
         if (this.hiddenEl) {
             this.hiddenEl.dom.value = '';
@@ -40630,17 +43507,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) {
@@ -40657,7 +43532,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);
              
         }
@@ -40679,10 +43560,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];
@@ -40730,7 +43610,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));
         
     }
     
@@ -40818,6 +43698,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
@@ -41032,6 +44340,11 @@ Roo.extend(Roo.form.Checkbox, Roo.form.Field,  {
         }
          
         Roo.form.Checkbox.superclass.onDestroy.call(this);
+    },
+    
+    setBoxLabel : function(str)
+    {
+        this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
     }
 
 });/*
@@ -41215,6 +44528,10 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
      */
     stylesheets: 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,
     
@@ -41234,7 +44551,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
     black: false,
     white: false,
      
-    
+    bodyCls : '',
 
     /**
      * Protected method that will not generally be called directly. It
@@ -41261,7 +44578,10 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                 st = '<style type="text/css">' +
                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
                    '</style>';
-        } else { 
+        } else {
+            for (var i in this.stylesheets) { 
+                st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
+            }
             
         }
         
@@ -41269,12 +44589,17 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             'IMG { cursor: pointer } ' +
         '</style>';
 
+        var cls = 'roo-htmleditor-body';
+        
+        if(this.bodyCls.length){
+            cls += ' ' + this.bodyCls;
+        }
         
         return '<html><head>' + st  +
             //<style type="text/css">' +
             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
             //'</style>' +
-            ' </head><body class="roo-htmleditor-body"></body></html>';
+            ' </head><body contenteditable="true" data-enable-grammerly="true" class="' +  cls + '"></body></html>';
     },
 
     // private
@@ -41429,17 +44754,32 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             html = this.cleanHtml(html);
             // fix up the special chars.. normaly like back quotes in word...
             // however we do not want to do this with chinese..
-            html = html.replace(/([\x80-\uffff])/g, function (a, b) {
-                var cc = b.charCodeAt();
-                if (
+            html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
+                
+                var cc = match.charCodeAt();
+
+                // Get the character value, handling surrogate pairs
+                if (match.length == 2) {
+                    // It's a surrogate pair, calculate the Unicode code point
+                    var high = match.charCodeAt(0) - 0xD800;
+                    var low  = match.charCodeAt(1) - 0xDC00;
+                    cc = (high * 0x400) + low + 0x10000;
+                }  else if (
                     (cc >= 0x4E00 && cc < 0xA000 ) ||
                     (cc >= 0x3400 && cc < 0x4E00 ) ||
                     (cc >= 0xf900 && cc < 0xfb00 )
                 ) {
-                        return b;
-                }
-                return "&#"+cc+";" 
+                        return match;
+                }  
+         
+                // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
+                return "&#" + cc + ";";
+                
+                
             });
+            
+            
+             
             if(this.owner.fireEvent('beforesync', this, html) !== false){
                 this.el.dom.value = html;
                 this.owner.fireEvent('sync', this, html);
@@ -41623,7 +44963,11 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
     insertTag : function(tg)
     {
         // could be a bit smarter... -> wrap the current selected tRoo..
-        if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
+        if (tg.toLowerCase() == 'span' ||
+            tg.toLowerCase() == 'code' ||
+            tg.toLowerCase() == 'sup' ||
+            tg.toLowerCase() == 'sub' 
+            ) {
             
             range = this.createRange(this.getSelection());
             var wrappingNode = this.doc.createElement(tg.toLowerCase());
@@ -41688,8 +45032,6 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
     insertAtCursor : function(text)
     {
         
-        
-        
         if(!this.activated){
             return;
         }
@@ -42040,13 +45382,16 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         var nodeIsBefore   =  ss == 1;
         var nodeIsAfter    = ee == -1;
         
-        if (nodeIsBefore && nodeIsAfter)
+        if (nodeIsBefore && nodeIsAfter) {
             return 0; // outer
-        if (!nodeIsBefore && nodeIsAfter)
+        }
+        if (!nodeIsBefore && nodeIsAfter) {
             return 1; //right trailed.
+        }
         
-        if (nodeIsBefore && !nodeIsAfter)
+        if (nodeIsBefore && !nodeIsAfter) {
             return 2;  // left trailed.
+        }
         // fully contined.
         return 3;
     },
@@ -42101,7 +45446,9 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             return; 
         }
         if (node.nodeName == "#comment") {
-            node.parentNode.removeChild(node);
+            if (!this.allowComments) {
+                node.parentNode.removeChild(node);
+            }
             // clean up silly Windows -- stuff?
             return; 
         }
@@ -42118,6 +45465,11 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         
         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
         
+        // spans with no attributes - just remove them..
+        if ((!node.attributes || !node.attributes.length) && lcname == 'span') { 
+            remove_keep_children = true;
+        }
+        
         // remove <a name=....> as rendering on yahoo mailer is borked with this.
         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
         
@@ -42138,6 +45490,10 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         }
         
         if (!node.attributes || !node.attributes.length) {
+            
+          
+            
+            
             this.cleanUpChildren(node);
             return;
         }
@@ -42148,12 +45504,15 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             if (v.match(/^\./) || v.match(/^\//)) {
                 return;
             }
-            if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
+            if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
                 return;
             }
             if (v.match(/^#/)) {
                 return;
             }
+            if (v.match(/^\{/)) { // allow template editing.
+                return;
+            }
 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
             node.removeAttribute(n);
             
@@ -42234,11 +45593,11 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             
             if (a.name == 'class') {
                 if (a.value.match(/^Mso/)) {
-                    node.className = '';
+                    node.removeAttribute('class');
                 }
                 
-                if (a.value.match(/body/)) {
-                    node.className = '';
+                if (a.value.match(/^body$/)) {
+                    node.removeAttribute('class');
                 }
                 continue;
             }
@@ -42259,12 +45618,29 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
      */
     cleanWord : function(node)
     {
-        
-        
         if (!node) {
             this.cleanWord(this.doc.body);
             return;
         }
+        
+        if(
+                node.nodeName == 'SPAN' &&
+                !node.hasAttributes() &&
+                node.childNodes.length == 1 &&
+                node.firstChild.nodeName == "#text"  
+        ) {
+            var textNode = node.firstChild;
+            node.removeChild(textNode);
+            if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
+                node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
+            }
+            node.parentNode.insertBefore(textNode, node);
+            if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
+                node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
+            }
+            node.parentNode.removeChild(node);
+        }
+        
         if (node.nodeName == "#text") {
             // clean up silly Windows -- stuff?
             return; 
@@ -42279,16 +45655,20 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             node.parentNode.removeChild(node);
             return;
         }
-        
+        //Roo.log(node.tagName);
         // remove - but keep children..
-        if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
+        if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
+            //Roo.log('-- removed');
             while (node.childNodes.length) {
                 var cn = node.childNodes[0];
                 node.removeChild(cn);
                 node.parentNode.insertBefore(cn, node);
+                // move node to parent - and clean it..
+                this.cleanWord(cn);
             }
             node.parentNode.removeChild(node);
-            this.iterateChildren(node, this.cleanWord);
+            /// no need to iterate chidlren = it's got none..
+            //this.iterateChildren(node, this.cleanWord);
             return;
         }
         // clean styles
@@ -42648,6 +46028,17 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
             s.remove();
         });
+    },
+    
+    setStyle : function(style)
+    {
+        Roo.get(this.iframe.contentDocument.head).createChild({
+            tag : 'style',
+            type : 'text/css',
+            html : style
+        });
+
+        return;
     }
     
     // hide stuff that is not compatible
@@ -42755,8 +46146,8 @@ Roo.HtmlEditorCore.cblack= [
 
 
 Roo.HtmlEditorCore.swapCodes   =[ 
-    [    8211, "--" ], 
-    [    8212, "--" ], 
+    [    8211, "&#8211;" ], 
+    [    8212, "&#8212;" ], 
     [    8216,  "'" ],  
     [    8217, "'" ],  
     [    8220, '"' ],  
@@ -42853,6 +46244,10 @@ Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
      * 
      */
     white: false,
+    /**
+     * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this.
+     */
+    allowComments: false,
     
     // id of frame..
     frameId: false,
@@ -43517,7 +46912,8 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
         ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"], 
         ["pre"],[ "code"], 
         ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
-        ['div'],['span']
+        ['div'],['span'],
+        ['sup'],['sub']
     ],
     
     cleanStyles : [
@@ -43623,7 +47019,8 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
             tb.add(
                 btn('bold'),
                 btn('italic'),
-                btn('underline')
+                btn('underline'),
+                btn('strikethrough')
             );
         };
         if(!this.disable.fontSize){
@@ -43810,6 +47207,22 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
                 },
                 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',
@@ -43927,6 +47340,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
             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.disable.alignments){
             btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
@@ -44052,6 +47466,11 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
             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.',
@@ -44379,7 +47798,7 @@ Roo.form.HtmlEditor.ToolbarContext.options = {
 // fixme - these need to be configurable..
  
 
-Roo.form.HtmlEditor.ToolbarContext.types
+//Roo.form.HtmlEditor.ToolbarContext.types
 
 
 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
@@ -44528,7 +47947,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
         
         tn = sel.tagName.toUpperCase();
         
-        var lastSel = this.tb.selectedNode
+        var lastSel = this.tb.selectedNode;
         
         this.tb.selectedNode = sel;
         
@@ -44769,6 +48188,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
                 listeners: {
                     'change' : function(f, nv, ov) {
                         tb.selectedNode.setAttribute(f.attrname, nv);
+                        editorcore.syncValue();
                     }
                 }
             }));
@@ -44989,6 +48409,8 @@ Roo.form.BasicForm = function(el, config){
         this.initEl(el);
     }
     Roo.form.BasicForm.superclass.constructor.call(this);
+    
+    Roo.form.BasicForm.popover.apply();
 };
 
 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
@@ -45054,6 +48476,21 @@ Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
      * @type Mixed
      */
     waitMsgTarget : false,
+    
+    /**
+     * @type Boolean
+     */
+    disableMask : false,
+    
+    /**
+     * @cfg {Boolean} errorMask (true|false) default false
+     */
+    errorMask : false,
+    
+    /**
+     * @cfg {Number} maskOffset Default 100
+     */
+    maskOffset : 100,
 
     // private
     initEl : function(el){
@@ -45074,16 +48511,47 @@ Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
      */
     isValid : function(){
         var valid = true;
+        var target = false;
         this.items.each(function(f){
-           if(!f.validate()){
-               valid = false;
-           }
+            if(f.validate()){
+                return;
+            }
+            
+            valid = false;
+                
+            if(!target && f.el.isVisible(true)){
+                target = f;
+            }
         });
+        
+        if(this.errorMask && !valid){
+            Roo.form.BasicForm.popover.mask(this, target);
+        }
+        
         return valid;
     },
-
     /**
-     * Returns true if any fields in this form have changed since their original load.
+     * Returns array of invalid form fields.
+     * @return Array
+     */
+    
+    invalidFields : function()
+    {
+        var ret = [];
+        this.items.each(function(f){
+            if(f.validate()){
+                return;
+            }
+            ret.push(f);
+            
+        });
+        
+        return ret;
+    },
+    
+    
+    /**
+     * DEPRICATED Returns true if any fields in this form have changed since their original load. 
      * @return Boolean
      */
     isDirty : function(){
@@ -45096,7 +48564,39 @@ Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
         });
         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;
+        
+    },
+    /**
+     * 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();
+        });
+        
+    },
+    
+    
     /**
      * Performs a predefined action (submit or load) or custom actions you define on this form.
      * @param {String} actionName The name of the action type
@@ -45177,15 +48677,17 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
     beforeAction : function(action){
         var o = action.options;
         
-       
-        if(this.waitMsgTarget === true){
-            this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
-        }else if(this.waitMsgTarget){
-            this.waitMsgTarget = Roo.get(this.waitMsgTarget);
-            this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
-        }else {
-            Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
+        if(!this.disableMask) {
+            if(this.waitMsgTarget === true){
+                this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
+            }else if(this.waitMsgTarget){
+                this.waitMsgTarget = Roo.get(this.waitMsgTarget);
+                this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
+            }else {
+                Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
+            }
         }
+        
          
     },
 
@@ -45194,15 +48696,17 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
         this.activeAction = null;
         var o = action.options;
         
-        if(this.waitMsgTarget === true){
-            this.el.unmask();
-        }else if(this.waitMsgTarget){
-            this.waitMsgTarget.unmask();
-        }else{
-            Roo.MessageBox.updateProgress(1);
-            Roo.MessageBox.hide();
+        if(!this.disableMask) {
+            if(this.waitMsgTarget === true){
+                this.el.unmask();
+            }else if(this.waitMsgTarget){
+                this.waitMsgTarget.unmask();
+            }else{
+                Roo.MessageBox.updateProgress(1);
+                Roo.MessageBox.hide();
+            }
         }
-         
+        
         if(success){
             if(o.reset){
                 this.reset();
@@ -45380,14 +48884,17 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
                 }
             }
         }
-         
+        this.resetHasChanged();
+        
+        
         Roo.each(this.childForms || [], function (f) {
             f.setValues(values);
+            f.resetHasChanged();
         });
                 
         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.
@@ -45402,6 +48909,23 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
             }, this);
         }
         
+        // use formdata
+        if (typeof(FormData) != 'undefined' && asString !== true) {
+            // this relies on a 'recent' version of chrome apparently...
+            try {
+                var fd = (new FormData(this.el.dom)).entries();
+                var ret = {};
+                var ent = fd.next();
+                while (!ent.done) {
+                    ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
+                    ent = fd.next();
+                };
+                return ret;
+            } catch(e) {
+                
+            }
+            
+        }
         
         
         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
@@ -45489,7 +49013,7 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
         Roo.each(this.childForms || [], function (f) {
             f.reset();
         });
-       
+        this.resetHasChanged();
         
         return this;
     },
@@ -45557,7 +49081,153 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
 });
 
 // back compat
-Roo.BasicForm = Roo.form.BasicForm;/*
+Roo.BasicForm = Roo.form.BasicForm;
+
+Roo.apply(Roo.form.BasicForm, {
+    
+    popover : {
+        
+        padding : 5,
+        
+        isApplied : false,
+        
+        isMasked : false,
+        
+        form : false,
+        
+        target : false,
+        
+        intervalID : false,
+        
+        maskEl : false,
+        
+        apply : function()
+        {
+            if(this.isApplied){
+                return;
+            }
+            
+            this.maskEl = {
+                top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
+                left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
+                bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
+                right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
+            };
+            
+            this.maskEl.top.enableDisplayMode("block");
+            this.maskEl.left.enableDisplayMode("block");
+            this.maskEl.bottom.enableDisplayMode("block");
+            this.maskEl.right.enableDisplayMode("block");
+            
+            Roo.get(document.body).on('click', function(){
+                this.unmask();
+            }, this);
+            
+            Roo.get(document.body).on('touchstart', function(){
+                this.unmask();
+            }, this);
+            
+            this.isApplied = true
+        },
+        
+        mask : function(form, target)
+        {
+            this.form = form;
+            
+            this.target = target;
+            
+            if(!this.form.errorMask || !target.el){
+                return;
+            }
+            
+            var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
+            
+            var ot = this.target.el.calcOffsetsTo(scrollable);
+            
+            var scrollTo = ot[1] - this.form.maskOffset;
+            
+            scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
+            
+            scrollable.scrollTo('top', scrollTo);
+            
+            var el = this.target.wrap || this.target.el;
+            
+            var box = el.getBox();
+            
+            this.maskEl.top.setStyle('position', 'absolute');
+            this.maskEl.top.setStyle('z-index', 10000);
+            this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
+            this.maskEl.top.setLeft(0);
+            this.maskEl.top.setTop(0);
+            this.maskEl.top.show();
+            
+            this.maskEl.left.setStyle('position', 'absolute');
+            this.maskEl.left.setStyle('z-index', 10000);
+            this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
+            this.maskEl.left.setLeft(0);
+            this.maskEl.left.setTop(box.y - this.padding);
+            this.maskEl.left.show();
+
+            this.maskEl.bottom.setStyle('position', 'absolute');
+            this.maskEl.bottom.setStyle('z-index', 10000);
+            this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
+            this.maskEl.bottom.setLeft(0);
+            this.maskEl.bottom.setTop(box.bottom + this.padding);
+            this.maskEl.bottom.show();
+
+            this.maskEl.right.setStyle('position', 'absolute');
+            this.maskEl.right.setStyle('z-index', 10000);
+            this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
+            this.maskEl.right.setLeft(box.right + this.padding);
+            this.maskEl.right.setTop(box.y - this.padding);
+            this.maskEl.right.show();
+
+            this.intervalID = window.setInterval(function() {
+                Roo.form.BasicForm.popover.unmask();
+            }, 10000);
+
+            window.onwheel = function(){ return false;};
+            
+            (function(){ this.isMasked = true; }).defer(500, this);
+            
+        },
+        
+        unmask : function()
+        {
+            if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
+                return;
+            }
+            
+            this.maskEl.top.setStyle('position', 'absolute');
+            this.maskEl.top.setSize(0, 0).setXY([0, 0]);
+            this.maskEl.top.hide();
+
+            this.maskEl.left.setStyle('position', 'absolute');
+            this.maskEl.left.setSize(0, 0).setXY([0, 0]);
+            this.maskEl.left.hide();
+
+            this.maskEl.bottom.setStyle('position', 'absolute');
+            this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
+            this.maskEl.bottom.hide();
+
+            this.maskEl.right.setStyle('position', 'absolute');
+            this.maskEl.right.setSize(0, 0).setXY([0, 0]);
+            this.maskEl.right.hide();
+            
+            window.onwheel = function(){ return true;};
+            
+            if(this.intervalID){
+                window.clearInterval(this.intervalID);
+                this.intervalID = false;
+            }
+            
+            this.isMasked = false;
+            
+        }
+        
+    }
+    
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -45571,6 +49241,7 @@ Roo.BasicForm = Roo.form.BasicForm;/*
 /**
  * @class Roo.form.Form
  * @extends Roo.form.BasicForm
+ * @children Roo.form.Column Roo.form.FieldSet Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
  * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
  * @constructor
  * @param {Object} config Configuration options
@@ -45625,11 +49296,13 @@ Roo.form.Form = function(config){
     
     Roo.each(xitems, this.addxtype, this);
     
-    
-    
 };
 
 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
+     /**
+     * @cfg {Roo.Button} buttons[] buttons at bottom of form
+     */
+    
     /**
      * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
      */
@@ -45669,7 +49342,13 @@ Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
      */
     
     progressUrl : false,
-  
+    /**
+     * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
+     * sending a formdata with extra parameters - eg uploaded elements.
+     */
+    
+    formData : false,
+    
     /**
      * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
      * fields are added and the column is closed. If no fields are passed the column remains open
@@ -46225,7 +49904,8 @@ Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
                 url:this.getUrl(!isPost),
                 method: method,
                 params:isPost ? this.getParams() : null,
-                isUpload: this.form.fileUpload
+                isUpload: this.form.fileUpload,
+                formData : this.form.formData
             }));
             
             this.uploadProgress();
@@ -46362,6 +50042,7 @@ Roo.form.Action.ACTION_TYPES = {
 /**
  * @class Roo.form.Layout
  * @extends Roo.Component
+ * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
  * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
  * @constructor
  * @param {Object} config Configuration options
@@ -46546,6 +50227,7 @@ Roo.extend(Roo.form.Column, Roo.form.Layout, {
 /**
  * @class Roo.form.Row
  * @extends Roo.form.Layout
+ * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
  * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
  * @constructor
  * @param {Object} config Configuration options
@@ -46622,6 +50304,7 @@ Roo.extend(Roo.form.Row, Roo.form.Layout, {
 /**
  * @class Roo.form.FieldSet
  * @extends Roo.form.Layout
+ * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
  * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
  * @constructor
  * @param {Object} config Configuration options
@@ -46670,13 +50353,13 @@ Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
 /**
  * @class Roo.form.VTypes
  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
- * @singleton
+ * @static
  */
 Roo.form.VTypes = function(){
     // closure these in so they are only created once.
     var alpha = /^[a-zA-Z_]+$/;
     var alphanum = /^[a-zA-Z0-9_]+$/;
-    var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
+    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
@@ -46978,8 +50661,9 @@ Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
     
     replaceTextarea : function()
     {
-        if ( document.getElementById( this.getId() + '___Frame' ) )
+        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.
@@ -47238,6 +50922,7 @@ Roo.extend(Roo.form.GridField, Roo.form.Field,  {
  * @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
@@ -47245,6 +50930,14 @@ Roo.extend(Roo.form.GridField, Roo.form.Field,  {
 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,  {
@@ -47274,7 +50967,9 @@ Roo.extend(Roo.form.DisplayField, Roo.form.TextField,  {
      */
      
  //   defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
-
+    closable : false,
+    
     onResize : function(){
         Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
         
@@ -47283,6 +50978,10 @@ Roo.extend(Roo.form.DisplayField, Roo.form.TextField,  {
     initEvents : function(){
         // Roo.form.Checkbox.superclass.initEvents.call(this);
         // has no events...
+        
+        if(this.closable){
+            this.closeEl.on('click', this.onClose, this);
+        }
        
     },
 
@@ -47304,6 +51003,10 @@ Roo.extend(Roo.form.DisplayField, Roo.form.TextField,  {
         
         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'});
+        }
+        
         if (this.bodyStyle) {
             this.viewEl.applyStyles(this.bodyStyle);
         }
@@ -47337,6 +51040,13 @@ Roo.extend(Roo.form.DisplayField, Roo.form.TextField,  {
         this.viewEl.dom.innerHTML = html;
         Roo.form.DisplayField.superclass.setValue.call(this, v);
 
+    },
+    
+    onClose : function(e)
+    {
+        e.preventDefault();
+        
+        this.fireEvent('close', this);
     }
 });/*
  * 
@@ -47874,7 +51584,7 @@ Roo.extend(Roo.form.Signature, Roo.form.Field,  {
         pt.x = e.clientX; 
         pt.y = e.clientY;
         if (this.isTouchEvent(e)) {
-            pt.x =  e.targetTouches[0].clientX 
+            pt.x =  e.targetTouches[0].clientX;
             pt.y = e.targetTouches[0].clientY;
         }
         var a = this.svgEl.dom.getScreenCTM();
@@ -48695,10 +52405,10 @@ Roo.DDView = function(container, tpl, config) {
     this.getEl().setStyle("outline", "0px none");
     this.getEl().unselectable();
     if (this.dragGroup) {
-               this.setDraggable(this.dragGroup.split(","));
+       this.setDraggable(this.dragGroup.split(","));
     }
     if (this.dropGroup) {
-               this.setDroppable(this.dropGroup.split(","));
+       this.setDroppable(this.dropGroup.split(","));
     }
     if (this.deletable) {
        this.setDeletable();
@@ -49240,6 +52950,7 @@ Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
 /**
  * @class Roo.BorderLayout
  * @extends Roo.LayoutManager
+ * @children Roo.ContentPanel
  * This class represents a common layout manager used in desktop applications. For screenshots and more details,
  * please see: <br><br>
  * <a href="http://www.jackslocum.com/yui/2006/10/19/cross-browser-web-20-layouts-with-yahoo-ui/">Cross Browser Layouts - Part 1</a><br>
@@ -49321,6 +53032,22 @@ Roo.BorderLayout = function(container, config){
 };
 
 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
+       
+       /**
+        * @cfg {Roo.LayoutRegion} east
+        */
+       /**
+        * @cfg {Roo.LayoutRegion} west
+        */
+       /**
+        * @cfg {Roo.LayoutRegion} north
+        */
+       /**
+        * @cfg {Roo.LayoutRegion} south
+        */
+       /**
+        * @cfg {Roo.LayoutRegion} center
+        */
     /**
      * Creates and adds a new region if it doesn't already exist.
      * @param {String} target The target region key (north, south, east, west or center).
@@ -49351,7 +53078,9 @@ Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
      * Performs a layout update.
      */
     layout : function(){
-        if(this.updating) return;
+        if(this.updating) {
+            return;
+        }
         var size = this.getViewSize();
         var w = size.width;
         var h = size.height;
@@ -49913,6 +53642,12 @@ Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
          * @param {Roo.ContentPanel} panel The panel
          */
         "panelremoved" : true,
+        /**
+         * @event beforecollapse
+         * Fires when this region before collapse.
+         * @param {Roo.LayoutRegion} this
+         */
+        "beforecollapse" : true,
         /**
          * @event collapsed
          * Fires when this region is collapsed.
@@ -50464,22 +54199,29 @@ Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
      * Collapses this region.
      * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
      */
-    collapse : function(skipAnim){
-        if(this.collapsed) return;
-        this.collapsed = true;
-        if(this.split){
-            this.split.el.hide();
+    collapse : function(skipAnim, skipCheck){
+        if(this.collapsed) {
+            return;
         }
-        if(this.config.animate && skipAnim !== true){
-            this.fireEvent("invalidated", this);
-            this.animateCollapse();
-        }else{
-            this.el.setLocation(-20000,-20000);
-            this.el.hide();
-            this.collapsedEl.show();
-            this.fireEvent("collapsed", this);
-            this.fireEvent("invalidated", this);
+        
+        if(skipCheck || this.fireEvent("beforecollapse", this) != false){
+            
+            this.collapsed = true;
+            if(this.split){
+                this.split.el.hide();
+            }
+            if(this.config.animate && skipAnim !== true){
+                this.fireEvent("invalidated", this);
+                this.animateCollapse();
+            }else{
+                this.el.setLocation(-20000,-20000);
+                this.el.hide();
+                this.collapsedEl.show();
+                this.fireEvent("collapsed", this);
+                this.fireEvent("invalidated", this);
+            }
         }
+        
     },
 
     animateCollapse : function(){
@@ -50492,8 +54234,12 @@ Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
      * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
      */
     expand : function(e, skipAnim){
-        if(e) e.stopPropagation();
-        if(!this.collapsed || this.el.hasActiveFx()) return;
+        if(e) {
+            e.stopPropagation();
+        }
+        if(!this.collapsed || this.el.hasActiveFx()) {
+            return;
+        }
         if(this.isSlid){
             this.afterSlideIn();
             skipAnim = true;
@@ -50874,7 +54620,9 @@ Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
     beforeSlide: function(){
         if(Roo.isGecko){// firefox overflow auto bug workaround
             this.bodyEl.clip();
-            if(this.tabs) this.tabs.bodyEl.clip();
+            if(this.tabs) {
+                this.tabs.bodyEl.clip();
+            }
             if(this.activePanel){
                 this.activePanel.getEl().clip();
                 
@@ -50888,7 +54636,9 @@ Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
     afterSlide : function(){
         if(Roo.isGecko){// firefox overflow auto bug workaround
             this.bodyEl.unclip();
-            if(this.tabs) this.tabs.bodyEl.unclip();
+            if(this.tabs) {
+                this.tabs.bodyEl.unclip();
+            }
             if(this.activePanel){
                 this.activePanel.getEl().unclip();
                 if(this.activePanel.afterSlide){
@@ -51402,22 +55152,26 @@ Roo.LayoutStateManager.prototype = {
 /**
  * @class Roo.ContentPanel
  * @extends Roo.util.Observable
+ * @children Roo.form.Form Roo.JsonView Roo.View
+ * @parent Roo.BorderLayout Roo.LayoutDialog builder-top
  * A basic ContentPanel element.
  * @cfg {Boolean}   fitToFrame    True for this panel to adjust its size to fit when the region resizes  (defaults to false)
  * @cfg {Boolean}   fitContainer   When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container  (defaults to false)
- * @cfg {Boolean/Object} autoCreate True to auto generate the DOM element for this panel, or a {@link Roo.DomHelper} config of the element to create
+ * @cfg {Boolean|Object} autoCreate True to auto generate the DOM element for this panel, or a {@link Roo.DomHelper} config of the element to create
  * @cfg {Boolean}   closable      True if the panel can be closed/removed
  * @cfg {Boolean}   background    True if the panel should not be activated when it is added (defaults to false)
- * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
- * @cfg {Toolbar}   toolbar       A toolbar for this panel
+ * @cfg {String|HTMLElement|Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
+ * @cfg {Roo.Toolbar}   toolbar       A toolbar for this panel
  * @cfg {Boolean} autoScroll    True to scroll overflow in this panel (use with {@link #fitToFrame})
  * @cfg {String} title          The title for this panel
  * @cfg {Array} adjustments     Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
  * @cfg {String} url            Calls {@link #setUrl} with this value
- * @cfg {String} region         (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
- * @cfg {String/Object} params  When used with {@link #url}, calls {@link #setUrl} with this value
+ * @cfg {String} region [required]   (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.)
+ * @cfg {String}    style  Extra style to add to the content panel
+ * @cfg {Roo.menu.Menu} menu  popup menu
 
  * @constructor
  * Create a new ContentPanel.
@@ -51455,6 +55209,8 @@ Roo.ContentPanel = function(el, config, content){
                         {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
         }
     }
+    
+    
     this.closable = false;
     this.loaded = false;
     this.active = false;
@@ -51521,8 +55277,7 @@ Roo.ContentPanel = function(el, config, content){
          * @param {Roo.ContentPanel} this
          */
         "render" : true
-        
-        
+         
         
     });
     
@@ -51698,7 +55453,7 @@ panel.load({
         }
         if(this.footer){
             var te = this.footer.getEl();
-            Roo.log("footer:" + te.getHeight());
+            //Roo.log("footer:" + te.getHeight());
             
             height -= te.getHeight();
             te.setWidth(width);
@@ -51824,7 +55579,9 @@ layout.addxtype({
             this.form = new  Roo.form.Form(cfg);
             
             
-            if ( this.form.allItems.length) this.form.render(el.dom);
+            if ( this.form.allItems.length) {
+                this.form.render(el.dom);
+            }
             return this.form;
         }
         // should only have one of theses..
@@ -51926,7 +55683,7 @@ Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
  * Create a new NestedLayoutPanel.
  * 
  * 
- * @param {Roo.BorderLayout} layout The layout for this panel
+ * @param {Roo.BorderLayout} layout [required] The layout for this panel
  * @param {String/Object} config A string to set only the title or a config object
  */
 Roo.NestedLayoutPanel = function(layout, config)
@@ -52107,19 +55864,14 @@ Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
 
 
 
-
-
-
-
-
-
 /**
  * @class Roo.TreePanel
  * @extends Roo.ContentPanel
+ * Treepanel component
+ * 
  * @constructor
  * Create a new TreePanel. - defaults to fit/scoll contents.
  * @param {String/Object} config A string to set only the panel's title, or a config object
- * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
  */
 Roo.TreePanel = function(config){
     var el = config.el;
@@ -52162,7 +55914,12 @@ Roo.TreePanel = function(config){
 
 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {   
     fitToFrame : true,
-    autoScroll : true
+    autoScroll : true,
+    /*
+     * @cfg {Roo.tree.TreePanel} tree [required] The tree TreePanel, with config etc.
+     */
+    tree : false
+
 });
 
 
@@ -52603,8 +56360,26 @@ Roo.grid.Grid = function(container, config){
 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
     
     /**
+        * @cfg {Roo.grid.AbstractSelectionModel} sm The selection Model (default = Roo.grid.RowSelectionModel)
+        */
+       /**
+        * @cfg {Roo.grid.GridView} view  The view that renders the grid (default = Roo.grid.GridView)
+        */
+       /**
+        * @cfg {Roo.grid.ColumnModel} cm[] The columns of the grid
+        */
+       /**
+        * @cfg {Roo.grid.Store} ds The data store for the grid
+        */
+       /**
+        * @cfg {Roo.Toolbar} toolbar a toolbar for buttons etc.
+        */
+       /**
      * @cfg {String} ddGroup - drag drop group.
      */
+      /**
+     * @cfg {String} dragGroup - drag group (?? not sure if needed.)
+     */
 
     /**
      * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
@@ -52641,6 +56416,9 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
 
     /**
     * @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?)
     */
     
     /**
@@ -52715,6 +56493,15 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
     /**
     * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
     */
+    
+    
+    /**
+    * @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}",
+    
+    
     /**
      * Called once after all setup has been completed and the grid is ready to be rendered.
      * @return {Roo.grid.Grid} this
@@ -52769,12 +56556,12 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
         return this;
     },
 
-       /**
-        * Reconfigures the grid to use a different Store and Column Model.
-        * The View will be bound to the new objects and refreshed.
-        * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
-        * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
-        */
+    /**
+     * Reconfigures the grid to use a different Store and Column Model.
+     * The View will be bound to the new objects and refreshed.
+     * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
+     * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
+     */
     reconfigure : function(dataSource, colModel){
         if(this.loadMask){
             this.loadMask.destroy();
@@ -52786,7 +56573,41 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
         this.colModel = colModel;
         this.view.refresh(true);
     },
-
+    /**
+     * addColumns
+     * Add's a column, default at the end..
+     
+     * @param {int} position to add (default end)
+     * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel} 
+     */
+    addColumns : function(pos, ar)
+    {
+        
+        for (var i =0;i< ar.length;i++) {
+            var cfg = ar[i];
+            cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
+            this.cm.lookup[cfg.id] = cfg;
+        }
+        
+        
+        if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
+            pos = this.cm.config.length; //this.cm.config.push(cfg);
+        } 
+        pos = Math.max(0,pos);
+        ar.unshift(0);
+        ar.unshift(pos);
+        this.cm.config.splice.apply(this.cm.config, ar);
+        
+        
+        
+        this.view.generateRules(this.cm);
+        this.view.refresh(true);
+        
+    },
+    
+    
+    
+    
     // private
     onKeyDown : function(e){
         this.fireEvent("keydown", e);
@@ -52991,11 +56812,17 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
     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;
     },
     /**
      * 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}
      */
     getDragDropText : function(){
@@ -53003,12 +56830,7 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
         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.
@@ -53018,7 +56840,13 @@ Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
  * Fork - LGPL
  * <script type="text/javascript">
  */
+ /**
+ * @class Roo.grid.AbstractGridView
+ * @extends Roo.util.Observable
+ * @abstract
+ * Abstract base class for grid Views
+ * @constructor
+ */
 Roo.grid.AbstractGridView = function(){
        this.grid = null;
        
@@ -53822,8 +57650,8 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
             p.cellId = "x-grid-hd-0-" + i;
             p.splitId = "x-grid-csplit-0-" + i;
             p.id = cm.getColumnId(i);
-            p.title = cm.getColumnTooltip(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);
@@ -53923,7 +57751,7 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
                 );
         */
         if(ctop < stop){
-             c.scrollTop = ctop;
+            c.scrollTop = ctop;
             //Roo.log("set scrolltop to ctop DISABLE?");
         }else if(cbot > sbot){
             //Roo.log("set scrolltop to cbot-ch");
@@ -53983,7 +57811,9 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
         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;
+                if(cm.isHidden(i)) {
+                    continue;
+                }
                 var w = cm.getColumnWidth(i); // make sure it's a number
                 if(!cm.isLocked(i) && locked){
                     pos = 0;
@@ -54180,7 +58010,8 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
                 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
                 renderer : cm.getRenderer(i),
                 id : cm.getColumnId(i),
-                locked : cm.isLocked(i)
+                locked : cm.isLocked(i),
+                has_editor : cm.isCellEditable(i)
             };
         }
 
@@ -54212,9 +58043,14 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
                         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(r.dirty && typeof r.modified[c.name] !== 'undefined'){
-                            p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
+                        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){
@@ -54240,7 +58076,7 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
                             record: r,
                             rowIndex : rowIndex,
                             rowClass : ''
-                        }
+                        };
                         this.grid.fireEvent('rowclass', this, rowcfg);
                         alt.push(rowcfg.rowClass);
                     }
@@ -54266,9 +58102,15 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
                         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(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 += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
+                            p.css += ' x-grid-dirty-cell' 
                         }
                         
                         var markup = ct.apply(p);
@@ -54295,10 +58137,11 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
                             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);
@@ -54385,7 +58228,9 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
         };
         var renderer = cm.getRenderer(colIndex);
         var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
-        if(typeof val == "undefined" || val === "") val = "&#160;";
+        if(typeof val == "undefined" || val === "") {
+            val = "&#160;";
+        }
         cellText.innerHTML = val;
         cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
         this.syncRowHeights(rowIndex, rowIndex);
@@ -54901,7 +58746,8 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
         }
     },
 
-    layout : function(initialRender, is2ndPass){
+    layout : function(initialRender, is2ndPass)
+    {
         var g = this.grid;
         var auto = g.autoHeight;
         var scrollOffset = 16;
@@ -54952,6 +58798,11 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
         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;
 
@@ -55053,19 +58904,34 @@ Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
  * Fork - LGPL
  * <script type="text/javascript">
  */
+ /**
+ * @extends Roo.dd.DDProxy
+ * @class Roo.grid.SplitDragZone
+ * Support for Column Header resizing
+ * @constructor
+ * @param {Object} config
+ */
 // private
 // This is a support class used internally by the Grid components
 Roo.grid.SplitDragZone = function(grid, hd, hd2){
     this.grid = grid;
     this.view = grid.getView();
     this.proxy = this.view.resizeProxy;
-    Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
-        "gridSplitters" + this.grid.getGridEl().id, {
-        dragElId : Roo.id(this.proxy.dom), resizeFrame:false
-    });
+    Roo.grid.SplitDragZone.superclass.constructor.call(
+        this,
+        hd, // ID
+        "gridSplitters" + this.grid.getGridEl().id, // SGROUP
+        {  // CONFIG
+            dragElId : Roo.id(this.proxy.dom),
+            resizeFrame:false
+        }
+    );
+    
     this.setHandleElId(Roo.id(hd));
-    this.setOuterHandleElId(Roo.id(hd2));
+    if (hd2 !== false) {
+        this.setOuterHandleElId(Roo.id(hd2));
+    }
+    
     this.scroll = false;
 };
 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
@@ -55073,8 +58939,25 @@ Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
 
     b4StartDrag : function(x, y){
         this.view.headersDisabled = true;
-        this.proxy.setHeight(this.view.mainWrap.getHeight());
+        var h = this.view.mainWrap ? this.view.mainWrap.getHeight() : (
+                    this.view.headEl.getHeight() + this.view.bodyEl.getHeight()
+        );
+        this.proxy.setHeight(h);
+        
+        // for old system colWidth really stored the actual width?
+        // in bootstrap we tried using xs/ms/etc.. to do % sizing?
+        // which in reality did not work.. - it worked only for fixed sizes
+        // for resizable we need to use actual sizes.
         var w = this.cm.getColumnWidth(this.cellIndex);
+        if (!this.view.mainWrap) {
+            // bootstrap.
+            w = this.view.getHeaderIndex(this.cellIndex).getWidth();
+        }
+        
+        
+        
+        // this was w-this.grid.minColumnWidth;
+        // doesnt really make sense? - w = thie curren width or the rendered one?
         var minw = Math.max(w-this.grid.minColumnWidth, 0);
         this.resetConstraints();
         this.setXConstraint(minw, 1000);
@@ -55082,6 +58965,10 @@ Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
         this.minX = x - minw;
         this.maxX = x + 1000;
         this.startPos = x;
+        if (!this.view.mainWrap) { // this is Bootstrap code..
+            this.getDragEl().style.display='block';
+        }
+        
         Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
     },
 
@@ -55103,7 +58990,12 @@ Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
         this.view.headersDisabled = false;
         var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
         var diff = endX - this.startPos;
-        this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
+        // 
+        var w = this.cm.getColumnWidth(this.cellIndex);
+        if (!this.view.mainWrap) {
+            w = 0;
+        }
+        this.view.onColumnSplitterMoved(this.cellIndex, w+diff);
     },
 
     autoOffset : function(){
@@ -55155,7 +59047,12 @@ Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
             }
         
         }
+        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.. 
@@ -55176,14 +59073,14 @@ Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
                 grid: this.grid,
                 ddel: this.ddel,
                 rowIndex: rowIndex,
-                selections:sm.getSelections ? sm.getSelections() : (
-                    sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
-                )
+                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();
@@ -55251,30 +59148,15 @@ Roo.grid.ColumnModel = function(config){
        /**
      * The config passed into the constructor
      */
-    this.config = config;
+    this.config = []; //config;
     this.lookup = {};
 
     // if no id, create one
     // if the column does not have a dataIndex mapping,
     // map it to the order it is in the config
     for(var i = 0, len = config.length; i < len; i++){
-        var c = config[i];
-        if(typeof c.dataIndex == "undefined"){
-            c.dataIndex = i;
-        }
-        if(typeof c.renderer == "string"){
-            c.renderer = Roo.util.Format[c.renderer];
-        }
-        if(typeof c.id == "undefined"){
-            c.id = Roo.id();
-        }
-        if(c.editor && c.editor.xtype){
-            c.editor  = Roo.factory(c.editor, Roo.grid);
-        }
-        if(c.editor && c.editor.isFormField){
-            c.editor = new Roo.grid.GridEditor(c.editor);
-        }
-        this.lookup[c.id] = c;
+       this.addColumn(config[i]);
+       
     }
 
     /**
@@ -55336,6 +59218,21 @@ Roo.grid.ColumnModel = function(config){
 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     /**
      * @cfg {String} header The header text to display in the Grid view.
+     */
+       /**
+     * @cfg {String} xsHeader Header at Bootsrap Extra Small width (default for all)
+     */
+       /**
+     * @cfg {String} smHeader Header at Bootsrap Small width
+     */
+       /**
+     * @cfg {String} mdHeader Header at Bootsrap Medium width
+     */
+       /**
+     * @cfg {String} lgHeader Header at Bootsrap Large width
+     */
+       /**
+     * @cfg {String} xlHeader Header at Bootsrap extra Large width
      */
     /**
      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
@@ -55366,7 +59263,7 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     /**
      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
      * given the cell's data value. See {@link #setRenderer}. If not specified, the
-     * default renderer uses the raw data value. If an object is returned (bootstrap only)
+     * default renderer returns the escaped data value. If an object is returned (bootstrap only)
      * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
      */
        /**
@@ -55375,12 +59272,30 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     /**
      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
      */
+    /**
+     * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc).  Defaults to undefined.
+     */
     /**
      * @cfg {String} cursor (Optional)
      */
     /**
      * @cfg {String} tooltip (Optional)
      */
+    /**
+     * @cfg {Number} xs (Optional) can be '0' for hidden at this size (number less than 12)
+     */
+    /**
+     * @cfg {Number} sm (Optional) can be '0' for hidden at this size (number less than 12)
+     */
+    /**
+     * @cfg {Number} md (Optional) can be '0' for hidden at this size (number less than 12)
+     */
+    /**
+     * @cfg {Number} lg (Optional) can be '0' for hidden at this size (number less than 12)
+     */
+       /**
+     * @cfg {Number} xl (Optional) can be '0' for hidden at this size (number less than 12)
+     */
     /**
      * Returns the id of the column at the specified index.
      * @param {Number} index The column index
@@ -55401,7 +59316,7 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
 
     
     /**
-     * Returns the column for a specified dataIndex.
+     * Returns the column Object for a specified dataIndex.
      * @param {String} dataIndex The column dataIndex
      * @return {Object|Boolean} the column or false if not found
      */
@@ -55478,6 +59393,8 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
                 return i;
             }
         }
+        
+        return this.config.length;
     },
 
     /**
@@ -55560,10 +59477,29 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     /**
      * Returns the width for the specified column.
      * @param {Number} col The column index
+     * @param (optional) {String} gridSize bootstrap width size.
      * @return {Number}
      */
-    getColumnWidth : function(col){
-        return this.config[col].width * 1 || this.defaultWidth;
+    getColumnWidth : function(col, gridSize)
+       {
+               var cfg = this.config[col];
+               
+               if (typeof(gridSize) == 'undefined') {
+                       return cfg.width * 1 || this.defaultWidth;
+               }
+               if (gridSize === false) { // if we set it..
+                       return cfg.width || false;
+               }
+               var sizes = ['xl', 'lg', 'md', 'sm', 'xs'];
+               
+               for(var i = sizes.indexOf(gridSize); i < sizes.length; i++) {
+                       if (typeof(cfg[ sizes[i] ] ) == 'undefined') {
+                               continue;
+                       }
+                       return cfg[ sizes[i] ];
+               }
+               return 1;
+               
     },
 
     /**
@@ -55655,7 +59591,7 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     /**
      * Returns true if the cell is editable.
      * @param {Number} colIndex The column index
-     * @param {Number} rowIndex The row index
+     * @param {Number} rowIndex The row index - this is nto actually used..?
      * @return {Boolean}
      */
     isCellEditable : function(colIndex, rowIndex){
@@ -55725,14 +59661,47 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
      */
     setEditor : function(col, editor){
         this.config[col].editor = editor;
+    },
+    /**
+     * Add a column (experimental...) - defaults to adding to the end..
+     * @param {Object} config 
+    */
+    addColumn : function(c)
+    {
+    
+       var i = this.config.length;
+       this.config[i] = c;
+       
+       if(typeof c.dataIndex == "undefined"){
+            c.dataIndex = i;
+        }
+        if(typeof c.renderer == "string"){
+            c.renderer = Roo.util.Format[c.renderer];
+        }
+        if(typeof c.id == "undefined"){
+            c.id = Roo.id();
+        }
+        if(c.editor && c.editor.xtype){
+            c.editor  = Roo.factory(c.editor, Roo.grid);
+        }
+        if(c.editor && c.editor.isFormField){
+            c.editor = new Roo.grid.GridEditor(c.editor);
+        }
+        this.lookup[c.id] = c;
     }
+    
 });
 
-Roo.grid.ColumnModel.defaultRenderer = function(value){
+Roo.grid.ColumnModel.defaultRenderer = function(value)
+{
+    if(typeof value == "object") {
+        return value;
+    }
        if(typeof value == "string" && value.length < 1){
            return "&#160;";
        }
-       return value;
+    
+       return String.format("{0}", value);
 };
 
 // Alias for backwards compatibility
@@ -55751,6 +59720,7 @@ Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
 /**
  * @class Roo.grid.AbstractSelectionModel
  * @extends Roo.util.Observable
+ * @abstract
  * Abstract base class for grid SelectionModels.  It provides the interface that should be
  * implemented by descendant classes.  This class should not be directly instantiated.
  * @constructor
@@ -55817,39 +59787,39 @@ Roo.grid.RowSelectionModel = function(config){
 
     this.addEvents({
         /**
-            * @event selectionchange
-            * Fires when the selection changes
-            * @param {SelectionModel} this
-            */
-           "selectionchange" : true,
-        /**
-            * @event afterselectionchange
-            * Fires after the selection changes (eg. by key press or clicking)
-            * @param {SelectionModel} this
-            */
-           "afterselectionchange" : true,
-        /**
-            * @event beforerowselect
-            * Fires when a row is selected being selected, return false to cancel.
-            * @param {SelectionModel} this
-            * @param {Number} rowIndex The selected index
-            * @param {Boolean} keepExisting False if other selections will be cleared
-            */
-           "beforerowselect" : true,
-        /**
-            * @event rowselect
-            * Fires when a row is selected.
-            * @param {SelectionModel} this
-            * @param {Number} rowIndex The selected index
-            * @param {Roo.data.Record} r The record
-            */
-           "rowselect" : true,
-        /**
-            * @event rowdeselect
-            * Fires when a row is deselected.
-            * @param {SelectionModel} this
-            * @param {Number} rowIndex The selected index
-            */
+        * @event selectionchange
+        * Fires when the selection changes
+        * @param {SelectionModel} this
+        */
+       "selectionchange" : true,
+       /**
+        * @event afterselectionchange
+        * Fires after the selection changes (eg. by key press or clicking)
+        * @param {SelectionModel} this
+        */
+       "afterselectionchange" : true,
+       /**
+        * @event beforerowselect
+        * Fires when a row is selected being selected, return false to cancel.
+        * @param {SelectionModel} this
+        * @param {Number} rowIndex The selected index
+        * @param {Boolean} keepExisting False if other selections will be cleared
+        */
+       "beforerowselect" : true,
+       /**
+        * @event rowselect
+        * Fires when a row is selected.
+        * @param {SelectionModel} this
+        * @param {Number} rowIndex The selected index
+        * @param {Roo.data.Record} r The record
+        */
+       "rowselect" : true,
+       /**
+        * @event rowdeselect
+        * Fires when a row is deselected.
+        * @param {SelectionModel} this
+        * @param {Number} rowIndex The selected index
+        */
         "rowdeselect" : true
     });
     Roo.grid.RowSelectionModel.superclass.constructor.call(this);
@@ -55871,7 +59841,8 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
         }else{ // allow click to work like normal
             this.grid.on("rowclick", this.handleDragableRowClick, this);
         }
-
+        // bootstrap does not have a view..
+        var view = this.grid.view ? this.grid.view : this.grid;
         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
             "up" : function(e){
                 if(!e.shiftKey){
@@ -55879,7 +59850,7 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
                 }else if(this.last !== false && this.lastActive !== false){
                     var last = this.last;
                     this.selectRange(this.last,  this.lastActive-1);
-                    this.grid.getView().focusRow(this.lastActive);
+                    view.focusRow(this.lastActive);
                     if(last !== false){
                         this.last = last;
                     }
@@ -55894,7 +59865,7 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
                 }else if(this.last !== false && this.lastActive !== false){
                     var last = this.last;
                     this.selectRange(this.last,  this.lastActive+1);
-                    this.grid.getView().focusRow(this.lastActive);
+                    view.focusRow(this.lastActive);
                     if(last !== false){
                         this.last = last;
                     }
@@ -55906,7 +59877,7 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
             scope: this
         });
 
-        var view = this.grid.view;
+         
         view.on("refresh", this.onRefresh, this);
         view.on("rowupdated", this.onRowUpdated, this);
         view.on("rowremoved", this.onRemove, this);
@@ -55914,11 +59885,12 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
 
     // private
     onRefresh : function(){
-        var ds = this.grid.dataSource, i, v = this.grid.view;
+        var ds = this.grid.ds, i, v = this.grid.view;
         var s = this.selections;
         s.each(function(r){
             if((i = ds.indexOfId(r.id)) != -1){
                 v.onRowSelect(i);
+                s.add(ds.getAt(i)); // updating the selection relate data
             }else{
                 s.remove(r);
             }
@@ -55946,7 +59918,7 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
         if(!keepExisting){
             this.clearSelections();
         }
-        var ds = this.grid.dataSource;
+        var ds = this.grid.ds;
         for(var i = 0, len = records.length; i < len; i++){
             this.selectRow(ds.indexOf(records[i]), true);
         }
@@ -55972,7 +59944,7 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
      * @param {Boolean} keepExisting (optional) True to keep existing selections
      */
     selectLastRow : function(keepExisting){
-        this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
+        this.selectRow(this.grid.ds.getCount() - 1, keepExisting);
     },
 
     /**
@@ -55980,9 +59952,10 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
      * @param {Boolean} keepExisting (optional) True to keep existing selections
      */
     selectNext : function(keepExisting){
-        if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
+        if(this.last !== false && (this.last+1) < this.grid.ds.getCount()){
             this.selectRow(this.last+1, keepExisting);
-            this.grid.getView().focusRow(this.last);
+            var view = this.grid.view ? this.grid.view : this.grid;
+            view.focusRow(this.last);
         }
     },
 
@@ -55993,7 +59966,8 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
     selectPrevious : function(keepExisting){
         if(this.last){
             this.selectRow(this.last-1, keepExisting);
-            this.grid.getView().focusRow(this.last);
+            var view = this.grid.view ? this.grid.view : this.grid;
+            view.focusRow(this.last);
         }
     },
 
@@ -56018,9 +59992,11 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
      * Clears all selections.
      */
     clearSelections : function(fast){
-        if(this.locked) return;
+        if(this.locked) {
+            return;
+        }
         if(fast !== true){
-            var ds = this.grid.dataSource;
+            var ds = this.grid.ds;
             var s = this.selections;
             s.each(function(r){
                 this.deselectRow(ds.indexOfId(r.id));
@@ -56037,9 +60013,11 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
      * Selects all rows.
      */
     selectAll : function(){
-        if(this.locked) return;
+        if(this.locked) {
+            return;
+        }
         this.selections.clear();
-        for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
+        for(var i = 0, len = this.grid.ds.getCount(); i < len; i++){
             this.selectRow(i, true);
         }
     },
@@ -56058,7 +60036,7 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
      * @return {Boolean}
      */
     isSelected : function(index){
-        var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
+        var r = typeof index == "number" ? this.grid.ds.getAt(index) : index;
         return (r && this.selections.key(r.id) ? true : false);
     },
 
@@ -56072,8 +60050,10 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
     },
 
     // private
-    handleMouseDown : function(e, t){
-        var view = this.grid.getView(), rowIndex;
+    handleMouseDown : function(e, t)
+    {
+        var view = this.grid.view ? this.grid.view : this.grid;
+        var rowIndex;
         if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
             return;
         };
@@ -56100,7 +60080,8 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
     {
         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
             this.selectRow(rowIndex, false);
-            grid.view.focusRow(rowIndex);
+            var view = this.grid.view ? this.grid.view : this.grid;
+            view.focusRow(rowIndex);
              this.fireEvent("afterselectionchange", this);
         }
     },
@@ -56126,7 +60107,9 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
      * @param {Boolean} keepExisting (optional) True to retain existing selections
      */
     selectRange : function(startRow, endRow, keepExisting){
-        if(this.locked) return;
+        if(this.locked) {
+            return;
+        }
         if(!keepExisting){
             this.clearSelections();
         }
@@ -56147,7 +60130,9 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
      * @param {Number} endRow The index of the last row in the range
      */
     deselectRange : function(startRow, endRow, preventViewNotify){
-        if(this.locked) return;
+        if(this.locked) {
+            return;
+        }
         for(var i = startRow; i <= endRow; i++){
             this.deselectRow(i, preventViewNotify);
         }
@@ -56159,16 +60144,19 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
      * @param {Boolean} keepExisting (optional) True to keep existing selections
      */
     selectRow : function(index, keepExisting, preventViewNotify){
-        if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
+        if(this.locked || (index < 0 || index >= this.grid.ds.getCount())) {
+            return;
+        }
         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
             if(!keepExisting || this.singleSelect){
                 this.clearSelections();
             }
-            var r = this.grid.dataSource.getAt(index);
+            var r = this.grid.ds.getAt(index);
             this.selections.add(r);
             this.last = this.lastActive = index;
             if(!preventViewNotify){
-                this.grid.getView().onRowSelect(index);
+                var view = this.grid.view ? this.grid.view : this.grid;
+                view.onRowSelect(index);
             }
             this.fireEvent("rowselect", this, index, r);
             this.fireEvent("selectionchange", this);
@@ -56180,17 +60168,20 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
      * @param {Number} row The index of the row to deselect
      */
     deselectRow : function(index, preventViewNotify){
-        if(this.locked) return;
+        if(this.locked) {
+            return;
+        }
         if(this.last == index){
             this.last = false;
         }
         if(this.lastActive == index){
             this.lastActive = false;
         }
-        var r = this.grid.dataSource.getAt(index);
+        var r = this.grid.ds.getAt(index);
         this.selections.remove(r);
         if(!preventViewNotify){
-            this.grid.getView().onRowDeselect(index);
+            var view = this.grid.view ? this.grid.view : this.grid;
+            view.onRowDeselect(index);
         }
         this.fireEvent("rowdeselect", this, index);
         this.fireEvent("selectionchange", this);
@@ -56664,7 +60655,7 @@ Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
             cancel:false,
             editor: ed
         };
-        var cell = Roo.get(this.view.getCell(ed.row,ed.col))
+        var cell = Roo.get(this.view.getCell(ed.row,ed.col));
         cell.show();
           
         if(String(value) !== String(startValue)){
@@ -57089,7 +61080,7 @@ Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
  
 /**
  * @class Roo.grid.Calendar
- * @extends Roo.util.Grid
+ * @extends Roo.grid.Grid
  * This class extends the Grid to provide a calendar widget
  * <br><br>Usage:<pre><code>
  var grid = new Roo.grid.Calendar("my-container-id", {
@@ -58404,6 +62395,7 @@ Roo.LoadMask.prototype = {
      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
      */
+    removeMask : false,
     /**
      * @cfg {String} msg
      * The text to display in a centered loading message box (defaults to 'Loading...')
@@ -58452,20 +62444,18 @@ Roo.LoadMask.prototype = {
         }
         */
     
-        
-        
-        this.el.unmask(this.removeMask);
+        (function() { this.el.unmask(this.removeMask); }).defer(50, this);
     },
     // private
     onLoad : function()
     {
-        this.el.unmask(this.removeMask);
+        (function() { this.el.unmask(this.removeMask); }).defer(50, this);
     },
 
     // private
     onBeforeLoad : function(){
         if(!this.disabled){
-            this.el.mask(this.msg, this.msgCls);
+            (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
         }
     },