Roo/form/ComboBoxArray.js
[roojs1] / roojs-debug.js
index 0efc521..d05614a 100644 (file)
@@ -60,8 +60,8 @@ Roo.apply = function(o, c, defaults){
         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;
-
+        isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
+        isTouch =  'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
     // remove css image flicker
        if(isIE && !isIE7){
         try{
@@ -120,7 +120,7 @@ Roo.apply = function(o, c, defaults){
         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
 
         emptyFn : function(){},
-
+        
         /**
          * Copies all the properties of config to obj if they don't already exist.
          * @param {Object} obj The receiver of the properties
@@ -615,6 +615,8 @@ Roo.factory(conf, Roo.data);
         isLinux : isLinux,
         /** @type Boolean */
         isMac : isMac,
+        /** @type Boolean */
+        isTouch : isTouch,
 
         /**
          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
@@ -2096,6 +2098,7 @@ Roo.lib.Event = function() {
 
         getTarget: function(ev, resolveTextNode) {
             ev = ev.browserEvent || ev;
+            ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
             var t = ev.target || ev.srcElement;
             return this.resolveTextNode(t);
         },
@@ -2112,6 +2115,7 @@ Roo.lib.Event = function() {
 
         getPageX: function(ev) {
             ev = ev.browserEvent || ev;
+            ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
             var x = ev.pageX;
             if (!x && 0 !== x) {
                 x = ev.clientX || 0;
@@ -2127,6 +2131,7 @@ Roo.lib.Event = function() {
 
         getPageY: function(ev) {
             ev = ev.browserEvent || ev;
+            ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
             var y = ev.pageY;
             if (!y && 0 !== y) {
                 y = ev.clientY || 0;
@@ -2143,12 +2148,14 @@ Roo.lib.Event = function() {
 
         getXY: function(ev) {
             ev = ev.browserEvent || ev;
+            ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
             return [this.getPageX(ev), this.getPageY(ev)];
         },
 
 
         getRelatedTarget: function(ev) {
             ev = ev.browserEvent || ev;
+            ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
             var t = ev.relatedTarget;
             if (!t) {
                 if (ev.type == "mouseout") {
@@ -2164,6 +2171,7 @@ Roo.lib.Event = function() {
 
         getTime: function(ev) {
             ev = ev.browserEvent || ev;
+            ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
             if (!ev.time) {
                 var t = new Date().getTime();
                 try {
@@ -3393,123 +3401,125 @@ Roo.lib.Point.prototype = new Roo.lib.Region();
 
 Roo.lib.AnimMgr = new function() {
 
-        var thread = null;
+    var thread = null;
 
 
-        var queue = [];
+    var queue = [];
 
 
-        var tweenCount = 0;
+    var tweenCount = 0;
 
 
-        this.fps = 1000;
+    this.fps = 1000;
 
 
-        this.delay = 1;
+    this.delay = 1;
 
 
-        this.registerElement = function(tween) {
-            queue[queue.length] = tween;
-            tweenCount += 1;
-            tween._onStart.fire();
-            this.start();
-        };
+    this.registerElement = function(tween) {
+        queue[queue.length] = tween;
+        tweenCount += 1;
+        tween._onStart.fire();
+        this.start();
+    };
 
 
-        this.unRegister = function(tween, index) {
-            tween._onComplete.fire();
-            index = index || getIndex(tween);
-            if (index != -1) {
-                queue.splice(index, 1);
-            }
+    this.unRegister = function(tween, index) {
+        tween._onComplete.fire();
+        index = index || getIndex(tween);
+        if (index != -1) {
+            queue.splice(index, 1);
+        }
 
-            tweenCount -= 1;
-            if (tweenCount <= 0) {
-                this.stop();
-            }
-        };
+        tweenCount -= 1;
+        if (tweenCount <= 0) {
+            this.stop();
+        }
+    };
 
 
-        this.start = function() {
-            if (thread === null) {
-                thread = setInterval(this.run, this.delay);
-            }
-        };
+    this.start = function() {
+        if (thread === null) {
+            thread = setInterval(this.run, this.delay);
+        }
+    };
 
 
-        this.stop = function(tween) {
-            if (!tween) {
-                clearInterval(thread);
+    this.stop = function(tween) {
+        if (!tween) {
+            clearInterval(thread);
 
-                for (var i = 0, len = queue.length; i < len; ++i) {
-                    if (queue[0].isAnimated()) {
-                        this.unRegister(queue[0], 0);
-                    }
+            for (var i = 0, len = queue.length; i < len; ++i) {
+                if (queue[0].isAnimated()) {
+                    this.unRegister(queue[0], 0);
                 }
-
-                queue = [];
-                thread = null;
-                tweenCount = 0;
-            }
-            else {
-                this.unRegister(tween);
             }
-        };
 
+            queue = [];
+            thread = null;
+            tweenCount = 0;
+        }
+        else {
+            this.unRegister(tween);
+        }
+    };
 
-        this.run = function() {
-            for (var i = 0, len = queue.length; i < len; ++i) {
-                var tween = queue[i];
-                if (!tween || !tween.isAnimated()) {
-                    continue;
-                }
 
-                if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
-                {
-                    tween.currentFrame += 1;
+    this.run = function() {
+        for (var i = 0, len = queue.length; i < len; ++i) {
+            var tween = queue[i];
+            if (!tween || !tween.isAnimated()) {
+                continue;
+            }
 
-                    if (tween.useSeconds) {
-                        correctFrame(tween);
-                    }
-                    tween._onTween.fire();
-                }
-                else {
-                    Roo.lib.AnimMgr.stop(tween, i);
+            if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
+            {
+                tween.currentFrame += 1;
+
+                if (tween.useSeconds) {
+                    correctFrame(tween);
                 }
+                tween._onTween.fire();
             }
-        };
+            else {
+                Roo.lib.AnimMgr.stop(tween, i);
+            }
+        }
+    };
 
-        var getIndex = function(anim) {
-            for (var i = 0, len = queue.length; i < len; ++i) {
-                if (queue[i] == anim) {
-                    return i;
-                }
+    var getIndex = function(anim) {
+        for (var i = 0, len = queue.length; i < len; ++i) {
+            if (queue[i] == anim) {
+                return i;
             }
-            return -1;
-        };
+        }
+        return -1;
+    };
 
 
-        var correctFrame = function(tween) {
-            var frames = tween.totalFrames;
-            var frame = tween.currentFrame;
-            var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
-            var elapsed = (new Date() - tween.getStartTime());
-            var tweak = 0;
+    var correctFrame = function(tween) {
+        var frames = tween.totalFrames;
+        var frame = tween.currentFrame;
+        var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
+        var elapsed = (new Date() - tween.getStartTime());
+        var tweak = 0;
 
-            if (elapsed < tween.duration * 1000) {
-                tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
-            } else {
+        if (elapsed < tween.duration * 1000) {
+            tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
+        } else {
+            tweak = frames - (frame + 1);
+        }
+        if (tweak > 0 && isFinite(tweak)) {
+            if (tween.currentFrame + tweak >= frames) {
                 tweak = frames - (frame + 1);
             }
-            if (tweak > 0 && isFinite(tweak)) {
-                if (tween.currentFrame + tweak >= frames) {
-                    tweak = frames - (frame + 1);
-                }
 
-                tween.currentFrame += tweak;
-            }
-        };
-    };/*
+            tween.currentFrame += tweak;
+        }
+    };
+};
+
+    /*
  * 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:
@@ -14955,3333 +14965,3813 @@ Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
  * 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
+/**
+ * @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
  */
+Roo.ComponentMgr = function(){
+    var all = new Roo.util.MixedCollection();
 
-(function() {
+    return {
+        /**
+         * Registers a component.
+         * @param {Roo.Component} c The component
+         */
+        register : function(c){
+            all.add(c);
+        },
 
-var Event=Roo.EventManager;
-var Dom=Roo.lib.Dom;
+        /**
+         * Unregisters a component.
+         * @param {Roo.Component} c The component
+         */
+        unregister : function(c){
+            all.remove(c);
+        },
 
+        /**
+         * Returns a component by id
+         * @param {String} id The component id
+         */
+        get : function(id){
+            return all.get(id);
+        },
+
+        /**
+         * Registers a function that will be called when a specified component is added to ComponentMgr
+         * @param {String} id The component id
+         * @param {Funtction} fn The callback function
+         * @param {Object} scope The scope of the callback
+         */
+        onAvailable : function(id, fn, scope){
+            all.on("add", function(index, o){
+                if(o.id == id){
+                    fn.call(scope || o, o);
+                    all.un("add", fn, scope);
+                }
+            });
+        }
+    };
+}();/*
+ * 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.DragDrop
+ * @class Roo.Component
  * @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>
+ * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
+ * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
+ * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
+ * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
+ * All visual components (widgets) that require rendering into a layout should subclass Component.
  * @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
+ * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
+ * element and its id used as the component id.  If a string is passed, it is assumed to be the id of an existing element
+ * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
  */
-Roo.dd.DragDrop = function(id, sGroup, config) {
-    if (id) {
-        this.init(id, sGroup, config);
+Roo.Component = function(config){
+    config = config || {};
+    if(config.tagName || config.dom || typeof config == "string"){ // element object
+        config = {el: config, id: config.id || config};
+    }
+    this.initialConfig = config;
+
+    Roo.apply(this, config);
+    this.addEvents({
+        /**
+         * @event disable
+         * Fires after the component is disabled.
+            * @param {Roo.Component} this
+            */
+        disable : true,
+        /**
+         * @event enable
+         * Fires after the component is enabled.
+            * @param {Roo.Component} this
+            */
+        enable : true,
+        /**
+         * @event beforeshow
+         * Fires before the component is shown.  Return false to stop the show.
+            * @param {Roo.Component} this
+            */
+        beforeshow : true,
+        /**
+         * @event show
+         * Fires after the component is shown.
+            * @param {Roo.Component} this
+            */
+        show : true,
+        /**
+         * @event beforehide
+         * Fires before the component is hidden. Return false to stop the hide.
+            * @param {Roo.Component} this
+            */
+        beforehide : true,
+        /**
+         * @event hide
+         * Fires after the component is hidden.
+            * @param {Roo.Component} this
+            */
+        hide : true,
+        /**
+         * @event beforerender
+         * Fires before the component is rendered. Return false to stop the render.
+            * @param {Roo.Component} this
+            */
+        beforerender : true,
+        /**
+         * @event render
+         * Fires after the component is rendered.
+            * @param {Roo.Component} this
+            */
+        render : true,
+        /**
+         * @event beforedestroy
+         * Fires before the component is destroyed. Return false to stop the destroy.
+            * @param {Roo.Component} this
+            */
+        beforedestroy : true,
+        /**
+         * @event destroy
+         * Fires after the component is destroyed.
+            * @param {Roo.Component} this
+            */
+        destroy : true
+    });
+    if(!this.id){
+        this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
+    }
+    Roo.ComponentMgr.register(this);
+    Roo.Component.superclass.constructor.call(this);
+    this.initComponent();
+    if(this.renderTo){ // not supported by all components yet. use at your own risk!
+        this.render(this.renderTo);
+        delete this.renderTo;
     }
-    
 };
 
-Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
+/** @private */
+Roo.Component.AUTO_ID = 1000;
 
+Roo.extend(Roo.Component, 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
+     * @scope Roo.Component.prototype
+     * @type {Boolean}
+     * true if this component is hidden. Read-only.
      */
-    id: null,
-
+    hidden : false,
     /**
-     * Configuration attributes passed into the constructor
-     * @property config
-     * @type object
+     * @type {Boolean}
+     * true if this component is disabled. Read-only.
      */
-    config: null,
-
+    disabled : false,
     /**
-     * The id of the element that will be dragged.  By default this is same
-     * as the linked element , but could be changed to another element. Ex:
-     * Roo.dd.DDProxy
-     * @property dragElId
-     * @type String
-     * @private
+     * @type {Boolean}
+     * true if this component has been rendered. Read-only.
      */
-    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
+    rendered : false,
+    
+    /** @cfg {String} disableClass
+     * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
      */
-    handleElId: null,
-
-    /**
-     * An associative array of HTML tags that will be ignored if clicked.
-     * @property invalidHandleTypes
-     * @type {string: string}
+    disabledClass : "x-item-disabled",
+       /** @cfg {Boolean} allowDomMove
+        * Whether the component can move the Dom node when rendering (defaults to true).
+        */
+    allowDomMove : true,
+    /** @cfg {String} hideMode
+     * How this component should hidden. Supported values are
+     * "visibility" (css visibility), "offsets" (negative offset position) and
+     * "display" (css display) - defaults to "display".
      */
-    invalidHandleTypes: null,
+    hideMode: 'display',
 
-    /**
-     * An associative array of ids for elements that will be ignored if clicked
-     * @property invalidHandleIds
-     * @type {string: string}
-     */
-    invalidHandleIds: null,
+    /** @private */
+    ctype : "Roo.Component",
 
     /**
-     * An indexted array of css class names for elements that will be ignored
-     * if clicked.
-     * @property invalidHandleClasses
-     * @type string[]
+     * @cfg {String} actionMode 
+     * which property holds the element that used for  hide() / show() / disable() / enable()
+     * default is 'el' 
      */
-    invalidHandleClasses: null,
+    actionMode : "el",
 
-    /**
-     * The linked element's absolute X position at the time the drag was
-     * started
-     * @property startPageX
-     * @type int
-     * @private
-     */
-    startPageX: 0,
+    /** @private */
+    getActionEl : function(){
+        return this[this.actionMode];
+    },
 
+    initComponent : Roo.emptyFn,
     /**
-     * The linked element's absolute X position at the time the drag was
-     * started
-     * @property startPageY
-     * @type int
-     * @private
+     * If this is a lazy rendering component, render it to its container element.
+     * @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.
      */
-    startPageY: 0,
+    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();
+            }
+        }
+        return this;
+    },
 
-    /**
-     * 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,
+    /** @private */
+    // default function is not really useful
+    onRender : function(ct, position){
+        if(this.el){
+            this.el = Roo.get(this.el);
+            if(this.allowDomMove !== false){
+                ct.dom.insertBefore(this.el.dom, position);
+            }
+        }
+    },
 
-    /**
-     * Individual drag/drop instances can be locked.  This will prevent
-     * onmousedown start drag.
-     * @property locked
-     * @type boolean
-     * @private
-     */
-    locked: false,
+    /** @private */
+    getAutoCreate : function(){
+        var cfg = typeof this.autoCreate == "object" ?
+                      this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
+        if(this.id && !cfg.id){
+            cfg.id = this.id;
+        }
+        return cfg;
+    },
 
-    /**
-     * Lock this instance
-     * @method lock
-     */
-    lock: function() { this.locked = true; },
+    /** @private */
+    afterRender : Roo.emptyFn,
 
     /**
-     * Unlock this instace
-     * @method unlock
+     * Destroys this component by purging any event listeners, removing the component's element from the DOM,
+     * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
      */
-    unlock: function() { this.locked = false; },
+    destroy : function(){
+        if(this.fireEvent("beforedestroy", this) !== false){
+            this.purgeListeners();
+            this.beforeDestroy();
+            if(this.rendered){
+                this.el.removeAllListeners();
+                this.el.remove();
+                if(this.actionMode == "container"){
+                    this.container.remove();
+                }
+            }
+            this.onDestroy();
+            Roo.ComponentMgr.unregister(this);
+            this.fireEvent("destroy", this);
+        }
+    },
 
-    /**
-     * By default, all insances can be a drop target.  This can be disabled by
-     * setting isTarget to false.
-     * @method isTarget
-     * @type boolean
-     */
-    isTarget: true,
+       /** @private */
+    beforeDestroy : function(){
 
-    /**
-     * 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,
+       /** @private */
+       onDestroy : function(){
+
+    },
 
     /**
-     * Internal typeof flag
-     * @property __ygDragDrop
-     * @private
+     * Returns the underlying {@link Roo.Element}.
+     * @return {Roo.Element} The element
      */
-    __ygDragDrop: true,
+    getEl : function(){
+        return this.el;
+    },
 
     /**
-     * Set to true when horizontal contraints are applied
-     * @property constrainX
-     * @type boolean
-     * @private
+     * Returns the id of this component.
+     * @return {String}
      */
-    constrainX: false,
+    getId : function(){
+        return this.id;
+    },
 
     /**
-     * Set to true when vertical contraints are applied
-     * @property constrainY
-     * @type boolean
-     * @private
+     * Try to focus this component.
+     * @param {Boolean} selectText True to also select the text in this component (if applicable)
+     * @return {Roo.Component} this
      */
-    constrainY: false,
+    focus : function(selectText){
+        if(this.rendered){
+            this.el.focus();
+            if(selectText === true){
+                this.el.dom.select();
+            }
+        }
+        return this;
+    },
 
-    /**
-     * The left constraint
-     * @property minX
-     * @type int
-     * @private
-     */
-    minX: 0,
+    /** @private */
+    blur : function(){
+        if(this.rendered){
+            this.el.blur();
+        }
+        return this;
+    },
 
     /**
-     * The right constraint
-     * @property maxX
-     * @type int
-     * @private
+     * Disable this component.
+     * @return {Roo.Component} this
      */
-    maxX: 0,
+    disable : function(){
+        if(this.rendered){
+            this.onDisable();
+        }
+        this.disabled = true;
+        this.fireEvent("disable", this);
+        return this;
+    },
 
-    /**
-     * The up constraint
-     * @property minY
-     * @type int
-     * @type int
-     * @private
-     */
-    minY: 0,
+       // private
+    onDisable : function(){
+        this.getActionEl().addClass(this.disabledClass);
+        this.el.dom.disabled = true;
+    },
 
     /**
-     * The down constraint
-     * @property maxY
-     * @type int
-     * @private
+     * Enable this component.
+     * @return {Roo.Component} this
      */
-    maxY: 0,
+    enable : function(){
+        if(this.rendered){
+            this.onEnable();
+        }
+        this.disabled = false;
+        this.fireEvent("enable", this);
+        return this;
+    },
 
-    /**
-     * 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,
+       // private
+    onEnable : function(){
+        this.getActionEl().removeClass(this.disabledClass);
+        this.el.dom.disabled = 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[]
+     * Convenience function for setting disabled/enabled by boolean.
+     * @param {Boolean} disabled
      */
-    xTicks: null,
+    setDisabled : function(disabled){
+        this[disabled ? "disable" : "enable"]();
+    },
 
     /**
-     * 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[]
+     * Show this component.
+     * @return {Roo.Component} this
      */
-    yTicks: null,
+    show: function(){
+        if(this.fireEvent("beforeshow", this) !== false){
+            this.hidden = false;
+            if(this.rendered){
+                this.onShow();
+            }
+            this.fireEvent("show", this);
+        }
+        return this;
+    },
 
-    /**
-     * 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,
+    // private
+    onShow : function(){
+        var ae = this.getActionEl();
+        if(this.hideMode == 'visibility'){
+            ae.dom.style.visibility = "visible";
+        }else if(this.hideMode == 'offsets'){
+            ae.removeClass('x-hidden');
+        }else{
+            ae.dom.style.display = "";
+        }
+    },
 
     /**
-     * The availabe property is false until the linked dom element is accessible.
-     * @property available
-     * @type boolean
+     * Hide this component.
+     * @return {Roo.Component} this
      */
-    available: false,
+    hide: function(){
+        if(this.fireEvent("beforehide", this) !== false){
+            this.hidden = true;
+            if(this.rendered){
+                this.onHide();
+            }
+            this.fireEvent("hide", this);
+        }
+        return this;
+    },
 
-    /**
-     * 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,
+    // private
+    onHide : function(){
+        var ae = this.getActionEl();
+        if(this.hideMode == 'visibility'){
+            ae.dom.style.visibility = "hidden";
+        }else if(this.hideMode == 'offsets'){
+            ae.addClass('x-hidden');
+        }else{
+            ae.dom.style.display = "none";
+        }
+    },
 
     /**
-     * Code that executes immediately before the startDrag event
-     * @method b4StartDrag
-     * @private
+     * Convenience function to hide or show this component by boolean.
+     * @param {Boolean} visible True to show, false to hide
+     * @return {Roo.Component} this
      */
-    b4StartDrag: function(x, y) { },
+    setVisible: function(visible){
+        if(visible) {
+            this.show();
+        }else{
+            this.hide();
+        }
+        return 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
+     * Returns true if this component is visible.
      */
-    startDrag: function(x, y) { /* override this */ },
+    isVisible : function(){
+        return this.getActionEl().isVisible();
+    },
 
-    /**
-     * Code that executes immediately before the onDrag event
-     * @method b4Drag
-     * @private
-     */
-    b4Drag: function(e) { },
+    cloneConfig : function(overrides){
+        overrides = overrides || {};
+        var id = overrides.id || Roo.id();
+        var cfg = Roo.applyIf(overrides, this.initialConfig);
+        cfg.id = id; // prevent dup id
+        return new this.constructor(cfg);
+    }
+});/*
+ * 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">
+ */
 
-    /**
-     * Abstract method called during the onMouseMove event while dragging an
-     * object.
-     * @method onDrag
-     * @param {Event} e the mousemove event
-     */
-    onDrag: function(e) { /* override this */ },
+/**
+ * @class Roo.BoxComponent
+ * @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
+ * layout containers.
+ * @constructor
+ * @param {Roo.Element/String/Object} config The configuration options.
+ */
+Roo.BoxComponent = function(config){
+    Roo.Component.call(this, config);
+    this.addEvents({
+        /**
+         * @event resize
+         * Fires after the component is resized.
+            * @param {Roo.Component} this
+            * @param {Number} adjWidth The box-adjusted width that was set
+            * @param {Number} adjHeight The box-adjusted height that was set
+            * @param {Number} rawWidth The width that was originally specified
+            * @param {Number} rawHeight The height that was originally specified
+            */
+        resize : true,
+        /**
+         * @event move
+         * Fires after the component is moved.
+            * @param {Roo.Component} this
+            * @param {Number} x The new x position
+            * @param {Number} y The new y position
+            */
+        move : 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.
+Roo.extend(Roo.BoxComponent, Roo.Component, {
+    // private, set in afterRender to signify that the component has been rendered
+    boxReady : false,
+    // private, used to defer height settings to subclasses
+    deferHeight: false,
+    /** @cfg {Number} width
+     * width (optional) size of component
      */
-    onDragEnter: function(e, id) { /* override this */ },
-
-    /**
-     * Code that executes immediately before the onDragOver event
-     * @method b4DragOver
-     * @private
+     /** @cfg {Number} height
+     * height (optional) size of component
      */
-    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.
+     * Sets the width and height of the component.  This method fires the resize event.  This method can accept
+     * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
+     * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
+     * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
+     * @return {Roo.BoxComponent} this
      */
-    onDragOver: function(e, id) { /* override this */ },
+    setSize : function(w, h){
+        // support for standard size objects
+        if(typeof w == 'object'){
+            h = w.height;
+            w = w.width;
+        }
+        // not rendered
+        if(!this.boxReady){
+            this.width = w;
+            this.height = h;
+            return this;
+        }
 
-    /**
-     * Code that executes immediately before the onDragOut event
-     * @method b4DragOut
-     * @private
-     */
-    b4DragOut: function(e) { },
+        // prevent recalcs when not needed
+        if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
+            return this;
+        }
+        this.lastSize = {width: w, height: h};
 
-    /**
-     * 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 */ },
+        var adj = this.adjustSize(w, h);
+        var aw = adj.width, ah = adj.height;
+        if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
+            var rz = this.getResizeEl();
+            if(!this.deferHeight && aw !== undefined && ah !== undefined){
+                rz.setSize(aw, ah);
+            }else if(!this.deferHeight && ah !== undefined){
+                rz.setHeight(ah);
+            }else if(aw !== undefined){
+                rz.setWidth(aw);
+            }
+            this.onResize(aw, ah, w, h);
+            this.fireEvent('resize', this, aw, ah, w, h);
+        }
+        return this;
+    },
 
     /**
-     * Code that executes immediately before the onDragDrop event
-     * @method b4DragDrop
-     * @private
+     * Gets the current size of the component's underlying element.
+     * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
      */
-    b4DragDrop: function(e) { },
+    getSize : function(){
+        return this.el.getSize();
+    },
 
     /**
-     * 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.
+     * Gets the current XY position of the component's underlying element.
+     * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
+     * @return {Array} The XY position of the element (e.g., [100, 200])
      */
-    onDragDrop: function(e, id) { /* override this */ },
+    getPosition : function(local){
+        if(local === true){
+            return [this.el.getLeft(true), this.el.getTop(true)];
+        }
+        return this.xy || this.el.getXY();
+    },
 
     /**
-     * Abstract method called when this item is dropped on an area with no
-     * drop target
-     * @method onInvalidDrop
-     * @param {Event} e the mouseup event
+     * Gets the current box measurements of the component's underlying element.
+     * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
+     * @returns {Object} box An object in the format {x, y, width, height}
      */
-    onInvalidDrop: function(e) { /* override this */ },
+    getBox : function(local){
+        var s = this.el.getSize();
+        if(local){
+            s.x = this.el.getLeft(true);
+            s.y = this.el.getTop(true);
+        }else{
+            var xy = this.xy || this.el.getXY();
+            s.x = xy[0];
+            s.y = xy[1];
+        }
+        return s;
+    },
 
     /**
-     * Code that executes immediately before the endDrag event
-     * @method b4EndDrag
-     * @private
+     * Sets the current box measurements of the component's underlying element.
+     * @param {Object} box An object in the format {x, y, width, height}
+     * @returns {Roo.BoxComponent} this
      */
-    b4EndDrag: function(e) { },
+    updateBox : function(box){
+        this.setSize(box.width, box.height);
+        this.setPagePosition(box.x, box.y);
+        return this;
+    },
 
-    /**
-     * Fired when we are done dragging the object
-     * @method endDrag
-     * @param {Event} e the mouseup event
-     */
-    endDrag: function(e) { /* override this */ },
+    // protected
+    getResizeEl : function(){
+        return this.resizeEl || this.el;
+    },
 
-    /**
-     * Code executed immediately before the onMouseDown event
-     * @method b4MouseDown
-     * @param {Event} e the mousedown event
-     * @private
-     */
-    b4MouseDown: function(e) {  },
+    // protected
+    getPositionEl : function(){
+        return this.positionEl || this.el;
+    },
 
     /**
-     * Event handler that fires when a drag/drop obj gets a mousedown
-     * @method onMouseDown
-     * @param {Event} e the mousedown event
+     * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
+     * This method fires the move event.
+     * @param {Number} left The new left
+     * @param {Number} top The new top
+     * @returns {Roo.BoxComponent} this
      */
-    onMouseDown: function(e) { /* override this */ },
+    setPosition : function(x, y){
+        this.x = x;
+        this.y = y;
+        if(!this.boxReady){
+            return this;
+        }
+        var adj = this.adjustPosition(x, y);
+        var ax = adj.x, ay = adj.y;
 
-    /**
-     * 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 */ },
+        var el = this.getPositionEl();
+        if(ax !== undefined || ay !== undefined){
+            if(ax !== undefined && ay !== undefined){
+                el.setLeftTop(ax, ay);
+            }else if(ax !== undefined){
+                el.setLeft(ax);
+            }else if(ay !== undefined){
+                el.setTop(ay);
+            }
+            this.onPosition(ax, ay);
+            this.fireEvent('move', this, ax, ay);
+        }
+        return this;
+    },
 
     /**
-     * Override the onAvailable method to do what is needed after the initial
-     * position was determined.
-     * @method onAvailable
+     * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
+     * This method fires the move event.
+     * @param {Number} x The new x position
+     * @param {Number} y The new y position
+     * @returns {Roo.BoxComponent} this
      */
-    onAvailable: function () {
+    setPagePosition : function(x, y){
+        this.pageX = x;
+        this.pageY = y;
+        if(!this.boxReady){
+            return;
+        }
+        if(x === undefined || y === undefined){ // cannot translate undefined points
+            return;
+        }
+        var p = this.el.translatePoints(x, y);
+        this.setPosition(p.left, p.top);
+        return this;
     },
 
-    /*
-     * 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},
+    // private
+    onRender : function(ct, position){
+        Roo.BoxComponent.superclass.onRender.call(this, ct, position);
+        if(this.resizeEl){
+            this.resizeEl = Roo.get(this.resizeEl);
+        }
+        if(this.positionEl){
+            this.positionEl = Roo.get(this.positionEl);
+        }
+    },
 
-    /*
-     * 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};
+    // private
+    afterRender : function(){
+        Roo.BoxComponent.superclass.afterRender.call(this);
+        this.boxReady = true;
+        this.setSize(this.width, this.height);
+        if(this.x || this.y){
+            this.setPosition(this.x, this.y);
         }
-        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};
+        if(this.pageX || this.pageY){
+            this.setPagePosition(this.pageX, this.pageY);
         }
-
-
-        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
+     * Force the component's size to recalculate based on the underlying element's current height and width.
+     * @returns {Roo.BoxComponent} this
      */
-    getEl: function() {
-        if (!this._domRef) {
-            this._domRef = Roo.getDom(this.id);
-        }
-
-        return this._domRef;
+    syncSize : function(){
+        delete this.lastSize;
+        this.setSize(this.el.getWidth(), this.el.getHeight());
+        return this;
     },
 
     /**
-     * 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
+     * Called after the component is resized, this method is empty by default but can be implemented by any
+     * subclass that needs to perform custom logic after a resize occurs.
+     * @param {Number} adjWidth The box-adjusted width that was set
+     * @param {Number} adjHeight The box-adjusted height that was set
+     * @param {Number} rawWidth The width that was originally specified
+     * @param {Number} rawHeight The height that was originally specified
      */
-    getDragEl: function() {
-        return Roo.getDom(this.dragElId);
-    },
+    onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
 
-    /**
-     * 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);
-        Event.on(this.id, "mousedown", 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
+     * Called after the component is moved, this method is empty by default but can be implemented by any
+     * subclass that needs to perform custom logic after a move occurs.
+     * @param {Number} x The new x position
+     * @param {Number} y The new y position
      */
-    initTarget: function(id, sGroup, config) {
-
-        // configuration attributes
-        this.config = config || {};
+    onPosition : function(x, y){
 
-        // 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);
+    // private
+    adjustSize : function(w, h){
+        if(this.autoWidth){
+            w = 'auto';
         }
-
-        // 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();
+        if(this.autoHeight){
+            h = 'auto';
+        }
+        return {width : w, height: h};
     },
 
+    // private
+    adjustPosition : function(x, y){
+        return {x : x, y: y};
+    }
+});/*
+ * 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.
+ * 
+ * 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 )
+ * 
+ * @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, {
     /**
-     * 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
+     * @property el
+     * The created element (with Roo.factory())
+     * @type {Roo.Layout}
      */
-    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);
-
-    },
-
+    el  : false,
+    
     /**
-     * Executed when the linked element is available
-     * @method handleOnAvailable
-     * @private
+     * @property el
+     * for BC  - use el in new code
+     * @type {Roo.Layout}
      */
-    handleOnAvailable: function() {
-        this.available = true;
-        this.resetConstraints();
-        this.onAvailable();
-    },
-
+    panel : false,
+    
+    /**
+     * @property layout
+     * for BC  - use el in new code
+     * @type {Roo.Layout}
+     */
+    layout : false,
+    
      /**
-     * 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
+     * @cfg {Function|boolean} disabled
+     * If this module is disabled by some rule, return true from the funtion
      */
-    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];
-        }
-    },
-
+    disabled : false,
+    
     /**
-     * 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
+     * @cfg {String} parent 
+     * Name of parent element which it get xtype added to..
      */
-    setInitPosition: function(diffX, diffY) {
-        var el = this.getEl();
-
-        if (!this.DDM.verifyEl(el)) {
-            return;
-        }
-
-        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);
-    },
-
+    parent: false,
+    
     /**
-     * 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
+     * @cfg {String} order
+     * Used to set the order in which elements are created (usefull for multiple tabs)
      */
-    setStartPosition: function(pos) {
-        var p = pos || Dom.getXY( this.getEl() );
-        this.deltaSetXY = null;
-
-        this.startPageX = p[0];
-        this.startPageY = p[1];
-    },
-
+    
+    order : false,
     /**
-     * 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
+     * @cfg {String} name
+     * String to display while loading.
      */
-    addToGroup: function(sGroup) {
-        this.groups[sGroup] = true;
-        this.DDM.regDragDrop(this, sGroup);
-    },
-
+    name : false,
     /**
-     * Remove's this instance from the supplied interaction group
-     * @method removeFromGroup
-     * @param {string}  sGroup  The group to drop
+     * @cfg {String} region
+     * Region to render component to (defaults to center)
      */
-    removeFromGroup: function(sGroup) {
-        if (this.groups[sGroup]) {
-            delete this.groups[sGroup];
-        }
-
-        this.DDM.removeDDFromGroup(this, sGroup);
-    },
-
+    region : 'center',
+    
     /**
-     * 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
+     * @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...
      */
-    setDragElId: function(id) {
-        this.dragElId = id;
-    },
-
+    items : false,
+    
     /**
-     * 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.
+     * @property _tree
+     * The method that retuns the tree of parts that make up this compoennt 
+     * @type {function}
      */
-    setHandleElId: function(id) {
-        if (typeof id !== "string") {
-            id = Roo.id(id);
+    _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;
+        
+        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 = (this.parent == '#bootstrap') ? { el : true}  : false; // flags it as a top module...
+            el = Roo.get(ename);
+            if (!el && !this.parent) {
+                Roo.log("Warning - element can not be found :#" + ename );
+                return;
+            }
         }
-        this.handleElId = id;
-        this.DDM.regHandle(this.id, id);
-    },
+        
+        
+        if (!this.parent) {
+            
+            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' 
+            
+        var tree = this._tree ? this._tree() : this.tree();
+        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.apply(Roo.XComponent, {
     /**
-     * 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
+     * @property  hideProgress
+     * true to disable the building progress bar.. usefull on single page renders.
+     * @type Boolean
      */
-    setOuterHandleElId: function(id) {
-        if (typeof id !== "string") {
-            id = Roo.id(id);
-        }
-        Event.on(id, "mousedown",
-                this.handleMouseDown, this);
-        this.setHandleElId(id);
-
-        this.hasOuterHandles = true;
-    },
-
+    hideProgress : false,
     /**
-     * Remove all drag and drop hooks for this element
-     * @method unreg
+     * @property  buildCompleted
+     * True when the builder has completed building the interface.
+     * @type Boolean
      */
-    unreg: function() {
-        Event.un(this.id, "mousedown",
-                this.handleMouseDown);
-        this._domRef = null;
-        this.DDM._remove(this);
-    },
-
-    destroy : function(){
-        this.unreg();
-    },
-
+    buildCompleted : false,
+     
     /**
-     * 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
+     * @property  topModule
+     * the upper most module - uses document.element as it's constructor.
+     * @type Object
      */
-    isLocked: function() {
-        return (this.DDM.isLocked() || this.locked);
-    },
-
+     
+    topModule  : false,
+      
     /**
-     * Fired when this object is clicked
-     * @method handleMouseDown
-     * @param {Event} e
-     * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
-     * @private
+     * @property  modules
+     * array of modules to be created by registration system.
+     * @type {Array} of Roo.XComponent
      */
-    handleMouseDown: function(e, oDD){
-        if (this.primaryButtonOnly && e.button != 0) {
-            return;
-        }
-
-        if (this.isLocked()) {
-            return;
-        }
-
-        this.DDM.refreshCache(this.groups);
-
-        var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
-        if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
-        } else {
-            if (this.clickValidator(e)) {
-
-                // set the initial element position
-                this.setStartPosition();
-
-
-                this.b4MouseDown(e);
-                this.onMouseDown(e);
-
-                this.DDM.handleMouseDown(e, this);
-
-                this.DDM.stopEvent(e);
-            } else {
-
-
-            }
-        }
-    },
-
-    clickValidator: function(e) {
-        var target = e.getTarget();
-        return ( this.isValidHandleChild(target) &&
-                    (this.id == this.handleElId ||
-                        this.DDM.handleWasClicked(target, this.id)) );
-    },
-
+    
+    modules : [],
     /**
-     * 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
+     * @property  elmodules
+     * array of modules to be created by which use #ID 
+     * @type {Array} of Roo.XComponent
      */
-    addInvalidHandleType: function(tagName) {
-        var type = tagName.toUpperCase();
-        this.invalidHandleTypes[type] = type;
-    },
+     
+    elmodules : [],
 
+    
     /**
-     * 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
+     * Register components to be built later.
+     *
+     * This solves the following issues
+     * - Building is not done on page load, but after an authentication process has occured.
+     * - Interface elements are registered on page load
+     * - Parent Interface elements may not be loaded before child, so this handles that..
+     * 
+     *
+     * example:
+     * 
+     * MyApp.register({
+          order : '000001',
+          module : 'Pman.Tab.projectMgr',
+          region : 'center',
+          parent : 'Pman.layout',
+          disabled : false,  // or use a function..
+        })
+     
+     * * @param {Object} details about module
      */
-    addInvalidHandleId: function(id) {
-        if (typeof id !== "string") {
-            id = Roo.id(id);
+    register : function(obj) {
+               
+        Roo.XComponent.event.fireEvent('register', obj);
+        switch(typeof(obj.disabled) ) {
+                
+            case 'undefined':
+                break;
+            
+            case 'function':
+                if ( obj.disabled() ) {
+                        return;
+                }
+                break;
+            
+            default:
+                if (obj.disabled) {
+                        return;
+                }
+                break;
         }
-        this.invalidHandleIds[id] = id;
-    },
-
-    /**
-     * 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);
+               
+        this.modules.push(obj);
+         
     },
-
     /**
-     * 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];
-    },
+     * convert a string to an object..
+     * eg. 'AAA.BBB' -> finds AAA.BBB
 
-    /**
-     * 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);
+    
+    toObject : function(str)
+    {
+        if (!str || typeof(str) == 'object') {
+            return str;
         }
-        delete this.invalidHandleIds[id];
-    },
-
-    /**
-     * 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];
-            }
+        if (str.substring(0,1) == '#') {
+            return str;
         }
-    },
-
-    /**
-     * 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) {
 
-        var valid = true;
-        // var n = (node.nodeName == "#text") ? node.parentNode : node;
-        var nodeName;
+        var ar = str.split('.');
+        var rt, o;
+        rt = ar.shift();
+            /** eval:var:o */
         try {
-            nodeName = node.nodeName.toUpperCase();
-        } catch(e) {
-            nodeName = node.nodeName;
+            eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
+        } catch (e) {
+            throw "Module not found : " + str;
         }
-        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]);
+        
+        if (o === false) {
+            throw "Module not found : " + str;
         }
-
-
-        return valid;
-
+        Roo.each(ar, function(e) {
+            if (typeof(o[e]) == 'undefined') {
+                throw "Module not found : " + str;
+            }
+            o = o[e];
+        });
+        
+        return o;
+        
     },
-
+    
+    
     /**
-     * Create the array of horizontal tick marks if an interval was specified
-     * in setXConstraint().
-     * @method setXTicks
-     * @private
+     * move modules into their correct place in the tree..
+     * 
      */
-    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;
+    preBuild : function ()
+    {
+        var _t = this;
+        Roo.each(this.modules , function (obj)
+        {
+            Roo.XComponent.event.fireEvent('beforebuild', obj);
+            
+            var opar = obj.parent;
+            try { 
+                obj.parent = this.toObject(opar);
+            } catch(e) {
+                Roo.log("parent:toObject failed: " + e.toString());
+                return;
+            }
+            
+            if (!obj.parent) {
+                Roo.debug && Roo.log("GOT top level module");
+                Roo.debug && Roo.log(obj);
+                obj.modules = new Roo.util.MixedCollection(false, 
+                    function(o) { return o.order + '' }
+                );
+                this.topModule = obj;
+                return;
+            }
+                       // parent is a string (usually a dom element name..)
+            if (typeof(obj.parent) == 'string') {
+                this.elmodules.push(obj);
+                return;
+            }
+            if (obj.parent.constructor != Roo.XComponent) {
+                Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
+            }
+            if (!obj.parent.modules) {
+                obj.parent.modules = new Roo.util.MixedCollection(false, 
+                    function(o) { return o.order + '' }
+                );
             }
+            if (obj.parent.disabled) {
+                obj.disabled = true;
+            }
+            obj.parent.modules.add(obj);
+        }, this);
+    },
+    
+     /**
+     * make a list of modules to build.
+     * @return {Array} list of modules. 
+     */ 
+    
+    buildOrder : function()
+    {
+        var _this = this;
+        var cmp = function(a,b) {   
+            return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
+        };
+        if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
+            throw "No top level modules to build";
         }
+        
+        // make a flat list in order of modules to build.
+        var mods = this.topModule ? [ this.topModule ] : [];
+               
+        
+       // elmodules (is a list of DOM based modules )
+        Roo.each(this.elmodules, function(e) {
+            mods.push(e);
+            if (!this.topModule &&
+                typeof(e.parent) == 'string' &&
+                e.parent.substring(0,1) == '#' &&
+                Roo.get(e.parent.substr(1))
+               ) {
+                
+                _this.topModule = e;
+            }
+            
+        });
 
-        for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
-            if (!tickMap[i]) {
-                this.xTicks[this.xTicks.length] = i;
-                tickMap[i] = true;
+        
+        // add modules to their parents..
+        var addMod = function(m) {
+            Roo.debug && Roo.log("build Order: add: " + m.name);
+                
+            mods.push(m);
+            if (m.modules && !m.disabled) {
+                Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
+                m.modules.keySort('ASC',  cmp );
+                Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
+    
+                m.modules.each(addMod);
+            } else {
+                Roo.debug && Roo.log("build Order: no child modules");
+            }
+            // not sure if this is used any more..
+            if (m.finalize) {
+                m.finalize.name = m.name + " (clean up) ";
+                mods.push(m.finalize);
             }
+            
         }
-
-        this.xTicks.sort(this.DDM.numericSort) ;
+        if (this.topModule && this.topModule.modules) { 
+            this.topModule.modules.keySort('ASC',  cmp );
+            this.topModule.modules.each(addMod);
+        } 
+        return mods;
     },
-
-    /**
-     * 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;
-
-        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;
-            }
+    
+     /**
+     * Build the registered modules.
+     * @param {Object} parent element.
+     * @param {Function} optional method to call after module has been added.
+     * 
+     */ 
+   
+    build : function() 
+    {
+        
+        this.preBuild();
+        var mods = this.buildOrder();
+      
+        //this.allmods = mods;
+        //Roo.debug && Roo.log(mods);
+        //return;
+        if (!mods.length) { // should not happen
+            throw "NO modules!!!";
         }
-
-        for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
-            if (!tickMap[i]) {
-                this.yTicks[this.yTicks.length] = i;
-                tickMap[i] = true;
+        
+        
+        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.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);
+             
         }
-
-        this.yTicks.sort(this.DDM.numericSort) ;
+        progressRun.defer(1, _this);
+     
+        
+        
     },
-
+       
+       
+       /**
+        * Event Object.
+        *
+        *
+        */
+       event: false, 
     /**
-     * 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;
+        * 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
+   
+    
+    
+});
 
-        this.minX = this.initPageX - iLeft;
-        this.maxX = this.initPageX + iRight;
-        if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
+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
+                       
+               }
+});
 
-        this.constrainX = 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">
+ */
 
-    /**
-     * 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();
-    },
 
-    /**
-     * Clears any tick interval defined for this instance
-     * @method clearTicks
-     */
-    clearTicks: function() {
-        this.xTicks = null;
-        this.yTicks = null;
-        this.xTickSize = 0;
-        this.yTickSize = 0;
-    },
 
-    /**
-     * 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;
+/*
+ * 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.minY = this.initPageY - iUp;
-        this.maxY = this.initPageY + iDown;
-        if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
+(function() {
 
-        this.constrainY = true;
+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 , {
 
     /**
-     * resetConstraints must be called if you manually reposition a dd element.
-     * @method resetConstraints
-     * @param {boolean} maintainOffset
+     * 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
      */
-    resetConstraints: function() {
+    id: null,
 
+    /**
+     * Configuration attributes passed into the constructor
+     * @property config
+     * @type object
+     */
+    config: 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;
+    /**
+     * 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,
 
-            this.setInitPosition(dx, dy);
+    /**
+     * 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,
 
-        // This is the first time we have detected the element's position
-        } else {
-            this.setInitPosition();
-        }
+    /**
+     * An associative array of HTML tags that will be ignored if clicked.
+     * @property invalidHandleTypes
+     * @type {string: string}
+     */
+    invalidHandleTypes: null,
 
-        if (this.constrainX) {
-            this.setXConstraint( this.leftConstraint,
-                                 this.rightConstraint,
-                                 this.xTickSize        );
-        }
+    /**
+     * An associative array of ids for elements that will be ignored if clicked
+     * @property invalidHandleIds
+     * @type {string: string}
+     */
+    invalidHandleIds: null,
 
-        if (this.constrainY) {
-            this.setYConstraint( this.topConstraint,
-                                 this.bottomConstraint,
-                                 this.yTickSize         );
-        }
-    },
+    /**
+     * An indexted array of css class names for elements that will be ignored
+     * if clicked.
+     * @property invalidHandleClasses
+     * @type string[]
+     */
+    invalidHandleClasses: 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
+     * The linked element's absolute X position at the time the drag was
+     * started
+     * @property startPageX
+     * @type int
      * @private
      */
-    getTick: function(val, tickArray) {
+    startPageX: 0,
 
-        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];
-                }
-            }
+    /**
+     * The linked element's absolute X position at the time the drag was
+     * started
+     * @property startPageY
+     * @type int
+     * @private
+     */
+    startPageY: 0,
 
-            // The value is larger than the last tick, so we return the last
-            // tick.
-            return tickArray[tickArray.length - 1];
-        }
-    },
+    /**
+     * 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,
 
     /**
-     * toString method
-     * @method toString
-     * @return {string} string representation of the dd obj
+     * Individual drag/drop instances can be locked.  This will prevent
+     * onmousedown start drag.
+     * @property locked
+     * @type boolean
+     * @private
      */
-    toString: function() {
-        return ("DragDrop " + this.id);
-    }
+    locked: false,
 
-});
+    /**
+     * Lock this instance
+     * @method lock
+     */
+    lock: function() { this.locked = true; },
 
-})();
-/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
+    /**
+     * 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 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 padding configured for this drag and drop object for calculating
+     * the drop zone intersection with this object.
+     * @method padding
+     * @type int[]
+     */
+    padding: null,
 
-// Only load the library once.  Rewriting the manager class would orphan
-// existing drag and drop instances.
-if (!Roo.dd.DragDropMgr) {
+    /**
+     * Cached reference to the linked element
+     * @property _domRef
+     * @private
+     */
+    _domRef: null,
 
-/**
- * @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() {
+    /**
+     * Internal typeof flag
+     * @property __ygDragDrop
+     * @private
+     */
+    __ygDragDrop: true,
 
-    var Event = Roo.EventManager;
+    /**
+     * Set to true when horizontal contraints are applied
+     * @property constrainX
+     * @type boolean
+     * @private
+     */
+    constrainX: false,
 
-    return {
+    /**
+     * Set to true when vertical contraints are applied
+     * @property constrainY
+     * @type boolean
+     * @private
+     */
+    constrainY: false,
 
-        /**
-         * 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 left constraint
+     * @property minX
+     * @type int
+     * @private
+     */
+    minX: 0,
 
-        /**
-         * 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: {},
+    /**
+     * The right constraint
+     * @property maxX
+     * @type int
+     * @private
+     */
+    maxX: 0,
 
-        /**
-         * the DragDrop object that is currently being dragged
-         * @property dragCurrent
-         * @type DragDrop
-         * @private
-         * @static
-         **/
-        dragCurrent: null,
+    /**
+     * The up constraint
+     * @property minY
+     * @type int
+     * @type int
+     * @private
+     */
+    minY: 0,
 
-        /**
-         * the DragDrop object(s) that are being hovered over
-         * @property dragOvers
-         * @type Array
-         * @private
-         * @static
-         */
-        dragOvers: {},
+    /**
+     * The down constraint
+     * @property maxY
+     * @type int
+     * @private
+     */
+    maxY: 0,
 
-        /**
-         * the X distance between the cursor and the object being dragged
-         * @property deltaX
-         * @type int
-         * @private
-         * @static
-         */
-        deltaX: 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,
 
-        /**
-         * the Y distance between the cursor and the object being dragged
-         * @property deltaY
-         * @type int
-         * @private
-         * @static
-         */
-        deltaY: 0,
+    /**
+     * 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,
 
-        /**
-         * 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,
+    /**
+     * 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,
 
-        /**
-         * 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,
+    /**
+     * 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,
 
-        /**
-         * Internal flag that is set to true when drag and drop has been
-         * intialized
-         * @property initialized
-         * @private
-         * @static
-         */
-        initalized: false,
+    /**
+     * The availabe property is false until the linked dom element is accessible.
+     * @property available
+     * @type boolean
+     */
+    available: false,
 
-        /**
-         * All drag and drop can be disabled.
-         * @property locked
-         * @private
-         * @static
-         */
-        locked: 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,
 
-        /**
-         * Called the first time an element is registered.
-         * @method init
-         * @private
-         * @static
-         */
-        init: function() {
-            this.initialized = true;
-        },
+    /**
+     * Code that executes immediately before the startDrag event
+     * @method b4StartDrag
+     * @private
+     */
+    b4StartDrag: function(x, y) { },
 
-        /**
-         * 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,
+    /**
+     * 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 */ },
 
-        /**
-         * 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,
+    /**
+     * Code that executes immediately before the onDrag event
+     * @method b4Drag
+     * @private
+     */
+    b4Drag: function(e) { },
 
-        /**
-         * The current drag and drop mode.  Default: POINT
-         * @property mode
-         * @type int
-         * @static
-         */
-        mode: 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 */ },
 
-        /**
-         * 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);
-                }
-            }
-        },
+    /**
+     * 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 */ },
 
-        /**
-         * Drag and drop initialization.  Sets up the global event handlers
-         * @method _onLoad
-         * @private
-         * @static
-         */
-        _onLoad: function() {
+    /**
+     * Code that executes immediately before the onDragOver event
+     * @method b4DragOver
+     * @private
+     */
+    b4DragOver: function(e) { },
 
-            this.init();
+    /**
+     * 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 */ },
 
+    /**
+     * Code that executes immediately before the onDragOut event
+     * @method b4DragOut
+     * @private
+     */
+    b4DragOut: function(e) { },
 
-            Event.on(document, "mouseup",   this.handleMouseUp, this, true);
-            Event.on(document, "mousemove", 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);
+    /**
+     * 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 */ },
 
-        },
+    /**
+     * Code that executes immediately before the onDragDrop event
+     * @method b4DragDrop
+     * @private
+     */
+    b4DragDrop: function(e) { },
 
-        /**
-         * Reset constraints on all drag and drop objs
-         * @method _onResize
-         * @private
-         * @static
-         */
-        _onResize: function(e) {
-            this._execOnAll("resetConstraints", []);
-        },
+    /**
+     * 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 */ },
 
-        /**
-         * Lock all drag and drop functionality
-         * @method lock
-         * @static
-         */
-        lock: function() { this.locked = true; },
+    /**
+     * 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 */ },
 
-        /**
-         * Unlock all drag and drop functionality
-         * @method unlock
-         * @static
-         */
-        unlock: function() { this.locked = false; },
+    /**
+     * Code that executes immediately before the endDrag event
+     * @method b4EndDrag
+     * @private
+     */
+    b4EndDrag: function(e) { },
 
-        /**
-         * Is drag and drop locked?
-         * @method isLocked
-         * @return {boolean} True if drag and drop is locked, false otherwise.
-         * @static
-         */
-        isLocked: function() { return this.locked; },
+    /**
+     * Fired when we are done dragging the object
+     * @method endDrag
+     * @param {Event} e the mouseup event
+     */
+    endDrag: function(e) { /* override this */ },
 
-        /**
-         * 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: {},
+    /**
+     * Code executed immediately before the onMouseDown event
+     * @method b4MouseDown
+     * @param {Event} e the mousedown event
+     * @private
+     */
+    b4MouseDown: function(e) {  },
 
-        /**
-         * 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,
+    /**
+     * 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 */ },
 
-        /**
-         * 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,
+    /**
+     * 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 */ },
 
-        /**
-         * 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,
+    /**
+     * Override the onAvailable method to do what is needed after the initial
+     * position was determined.
+     * @method onAvailable
+     */
+    onAvailable: function () {
+    },
 
-        /**
-         * 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,
+    /*
+     * 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},
 
-        /**
-         * Timeout used for the click time threshold
-         * @property clickTimeout
-         * @type Object
-         * @private
-         * @static
-         */
-        clickTimeout: null,
+    /*
+     * 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};
+        }
 
-        /**
-         * 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 Y position of the mousedown event stored for later use when a
-         * drag threshold is met.
-         * @property startY
-         * @type int
-         * @private
-         * @static
-         */
-        startY: 0,
+        var topSpace = b.y - c.y;
+        var leftSpace = b.x - c.x;
 
-        /**
-         * 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(); }
+        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
+        );
+    },
 
-            if (!this.ids[sGroup]) {
-                this.ids[sGroup] = {};
-            }
-            this.ids[sGroup][oDD.id] = oDD;
-        },
+    /**
+     * 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);
+        }
 
-        /**
-         * 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] = {};
-            }
+        return this._domRef;
+    },
 
-            var obj = this.ids[sGroup];
-            if (obj && obj[oDD.id]) {
-                delete obj[oDD.id];
-            }
-        },
+    /**
+     * 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);
+    },
 
-        /**
-         * 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];
-        },
+    /**
+     * 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);
+    },
 
-        /**
-         * 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;
-        },
+    /**
+     * 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) {
 
-        /**
-         * 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;
-        },
+        // configuration attributes
+        this.config = config || {};
 
-        /**
-         * 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;
-                    }
-                }
-            }
+        // create a local reference to the drag and drop manager
+        this.DDM = Roo.dd.DDM;
+        // initialize the groups array
+        this.groups = {};
 
-            return oDDs;
-        },
+        // 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);
+        }
 
-        /**
-         * 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;
-                }
-            }
+        // set the id
+        this.id = id;
 
-            return false;
-        },
+        // add to an interaction group
+        this.addToGroup((sGroup) ? sGroup : "default");
 
-        /**
-         * 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);
-        },
+        // 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;
 
-        /**
-         * 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] );
-        },
+        // the linked element is the element that gets dragged by default
+        this.setDragElId(id);
 
-        /**
-         * 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;
-        },
+        // by default, clicked anchors will not start drag operations.
+        this.invalidHandleTypes = { A: "A" };
+        this.invalidHandleIds = {};
+        this.invalidHandleClasses = [];
 
-        /**
-         * 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();
+        this.applyConfig();
 
-            this.dragCurrent = oDD;
+        this.handleOnAvailable();
+    },
 
-            var el = oDD.getEl();
+    /**
+     * 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() {
 
-            // track start position
-            this.startX = e.getPageX();
-            this.startY = e.getPageY();
+        // 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);
 
-            this.deltaX = this.startX - el.offsetLeft;
-            this.deltaY = this.startY - el.offsetTop;
+    },
 
-            this.dragThreshMet = false;
+    /**
+     * Executed when the linked element is available
+     * @method handleOnAvailable
+     * @private
+     */
+    handleOnAvailable: function() {
+        this.available = true;
+        this.resetConstraints();
+        this.onAvailable();
+    },
 
-            this.clickTimeout = setTimeout(
-                    function() {
-                        var DDM = Roo.dd.DDM;
-                        DDM.startDrag(DDM.startX, DDM.startY);
-                    },
-                    this.clickTimeThresh );
-        },
+     /**
+     * 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 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;
-        },
+    /**
+     * 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();
 
-        /**
-         * 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) {
+        if (!this.DDM.verifyEl(el)) {
+            return;
+        }
 
-            if(Roo.QuickTips){
-                Roo.QuickTips.enable();
-            }
-            if (! this.dragCurrent) {
-                return;
-            }
+        var dx = diffX || 0;
+        var dy = diffY || 0;
 
-            clearTimeout(this.clickTimeout);
+        var p = Dom.getXY( el );
 
-            if (this.dragThreshMet) {
-                this.fireEvents(e, true);
-            } else {
-            }
+        this.initPageX = p[0] - dx;
+        this.initPageY = p[1] - dy;
 
-            this.stopDrag(e);
+        this.lastPageX = p[0];
+        this.lastPageY = p[1];
 
-            this.stopEvent(e);
-        },
 
-        /**
-         * 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();
-            }
+        this.setStartPosition(p);
+    },
 
-            if (this.preventDefault) {
-                e.preventDefault();
-            }
-        },
+    /**
+     * 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;
 
-        /**
-         * 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.startPageX = p[0];
+        this.startPageY = p[1];
+    },
 
-                this.dragCurrent.onMouseUp(e);
-            }
+    /**
+     * 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);
+    },
 
-            this.dragCurrent = null;
-            this.dragOvers = {};
-        },
+    /**
+     * 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];
+        }
 
-        /**
-         * 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;
-            }
+        this.DDM.removeDDFromGroup(this, sGroup);
+    },
 
-            // var button = e.which || e.button;
+    /**
+     * 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;
+    },
 
-            // 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);
-            }
+    /**
+     * 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.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);
-                }
-            }
+    /**
+     * 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);
 
-            if (this.dragThreshMet) {
-                this.dragCurrent.b4Drag(e);
-                this.dragCurrent.onDrag(e);
-                if(!this.dragCurrent.moveOnly){
-                    this.fireEvents(e, false);
-                }
-            }
+        this.hasOuterHandles = true;
+    },
 
-            this.stopEvent(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);
+    },
 
-            return true;
-        },
+    destroy : function(){
+        this.unreg();
+    },
 
-        /**
-         * 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;
+    /**
+     * 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);
+    },
 
-            // 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;
-            }
+    /**
+     * 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..
+        }
+        
 
-            var pt = e.getPoint();
+        if (this.isLocked()) {
+            //Roo.log('locked');
+            return;
+        }
 
-            // cache the previous dragOver array
-            var oldOvers = [];
+        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();
 
-            var outEvts   = [];
-            var overEvts  = [];
-            var dropEvts  = [];
-            var enterEvts = [];
 
-            // 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) {
+                this.b4MouseDown(e);
+                this.onMouseDown(e);
 
-                var ddo = this.dragOvers[i];
+                this.DDM.handleMouseDown(e, this);
 
-                if (! this.isTypeOfDD(ddo)) {
-                    continue;
-                }
+                this.DDM.stopEvent(e);
+            } else {
 
-                if (! this.isOverTarget(pt, ddo, this.mode)) {
-                    outEvts.push( ddo );
-                }
 
-                oldOvers[i] = true;
-                delete this.dragOvers[i];
             }
+        }
+    },
 
-            for (var sGroup in dc.groups) {
-
-                if ("string" != typeof sGroup) {
-                    continue;
-                }
+    clickValidator: function(e) {
+        var target = e.getTarget();
+        return ( this.isValidHandleChild(target) &&
+                    (this.id == this.handleElId ||
+                        this.DDM.handleWasClicked(target, this.id)) );
+    },
 
-                for (i in this.ids[sGroup]) {
-                    var oDD = this.ids[sGroup][i];
-                    if (! this.isTypeOfDD(oDD)) {
-                        continue;
-                    }
+    /**
+     * 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;
+    },
 
-                    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 {
+    /**
+     * 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;
+    },
 
-                                // initial drag over: dragEnter fires
-                                if (!oldOvers[oDD.id]) {
-                                    enterEvts.push( oDD );
-                                // subsequent drag overs: dragOver fires
-                                } else {
-                                    overEvts.push( oDD );
-                                }
+    /**
+     * 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);
+    },
 
-                                this.dragOvers[oDD.id] = oDD;
-                            }
-                        }
-                    }
-                }
-            }
+    /**
+     * 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.mode) {
-                if (outEvts.length) {
-                    dc.b4DragOut(e, outEvts);
-                    dc.onDragOut(e, outEvts);
-                }
+    /**
+     * 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];
+    },
 
-                if (enterEvts.length) {
-                    dc.onDragEnter(e, enterEvts);
-                }
+    /**
+     * 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];
+            }
+        }
+    },
 
-                if (overEvts.length) {
-                    dc.b4DragOver(e, overEvts);
-                    dc.onDragOver(e, overEvts);
-                }
+    /**
+     * 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) {
 
-                if (dropEvts.length) {
-                    dc.b4DragDrop(e, dropEvts);
-                    dc.onDragDrop(e, dropEvts);
-                }
+        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];
 
-            } 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 (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
+            valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
+        }
 
-                // fire enter events
-                for (i=0,len=enterEvts.length; i<len; ++i) {
-                    // dc.b4DragEnter(e, oDD.id);
-                    dc.onDragEnter(e, enterEvts[i].id);
-                }
 
-                // fire over events
-                for (i=0,len=overEvts.length; i<len; ++i) {
-                    dc.b4DragOver(e, overEvts[i].id);
-                    dc.onDragOver(e, overEvts[i].id);
-                }
+        return valid;
 
-                // fire drop events
-                for (i=0, len=dropEvts.length; i<len; ++i) {
-                    dc.b4DragDrop(e, dropEvts[i].id);
-                    dc.onDragDrop(e, dropEvts[i].id);
-                }
+    },
+
+    /**
+     * 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;
+
+        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;
             }
+        }
 
-            // notify about a drop that did not find a target
-            if (isDrop && !dropEvts.length) {
-                dc.onInvalidDrop(e);
+        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) ;
+    },
 
-        /**
-         * 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) {
+    /**
+     * 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;
 
-            var len = dds.length;
+        var tickMap = {};
 
-            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;
-                        }
-                    }
-                }
+        for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
+            if (!tickMap[i]) {
+                this.yTicks[this.yTicks.length] = i;
+                tickMap[i] = true;
             }
+        }
 
-            return winner;
-        },
+        for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
+            if (!tickMap[i]) {
+                this.yTicks[this.yTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
 
-        /**
-         * 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];
+        this.yTicks.sort(this.DDM.numericSort) ;
+    },
 
-                    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.  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;
 
-        /**
-         * 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.minX = this.initPageX - iLeft;
+        this.maxX = this.initPageX + iRight;
+        if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
 
-            return false;
-        },
+        this.constrainX = 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;
-            }
+    /**
+     * 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();
+    },
 
-            var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
+    /**
+     * Clears any tick interval defined for this instance
+     * @method clearTicks
+     */
+    clearTicks: function() {
+        this.xTicks = null;
+        this.yTicks = null;
+        this.xTickSize = 0;
+        this.yTickSize = 0;
+    },
 
-            try {
-                pos= Roo.lib.Dom.getXY(el);
-            } catch (e) { }
+    /**
+     * 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;
 
-            if (!pos) {
-                return null;
-            }
+        this.minY = this.initPageY - iUp;
+        this.maxY = this.initPageY + iDown;
+        if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
 
-            x1 = pos[0];
-            x2 = x1 + el.offsetWidth;
-            y1 = pos[1];
-            y2 = y1 + el.offsetHeight;
+        this.constrainY = true;
 
-            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 );
-        },
+    /**
+     * resetConstraints must be called if you manually reposition a dd element.
+     * @method resetConstraints
+     * @param {boolean} maintainOffset
+     */
+    resetConstraints: function() {
 
-        /**
-         * 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;
 
-            }
+        // 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;
 
-            if (!loc) {
-                return false;
-            }
+            this.setInitPosition(dx, dy);
 
-            oTarget.cursorIsOver = loc.contains( pt );
+        // This is the first time we have detected the element's position
+        } else {
+            this.setInitPosition();
+        }
 
-            // 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;
+        if (this.constrainX) {
+            this.setXConstraint( this.leftConstraint,
+                                 this.rightConstraint,
+                                 this.xTickSize        );
+        }
+
+        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 (!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.overlap = null;
+            // The value is larger than the last tick, so we return the last
+            // tick.
+            return tickArray[tickArray.length - 1];
+        }
+    },
 
-            // 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);
+    /**
+     * toString method
+     * @method toString
+     * @return {string} string representation of the dd obj
+     */
+    toString: function() {
+        return ("DragDrop " + this.id);
+    }
 
-            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);
+})();
+/*
+ * 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">
+ */
 
-            if (overlap) {
-                oTarget.overlap = overlap;
-                return (intersect) ? true : oTarget.cursorIsOver;
-            } else {
-                return false;
-            }
-        },
+
+/**
+ * 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.
+ */
+
+// Only load the library once.  Rewriting the manager class would orphan
+// existing drag and drop instances.
+if (!Roo.dd.DragDropMgr) {
+
+/**
+ * @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() {
+
+    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
+         * 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,
+
+        /**
+         * 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,
+
+        /**
+         * Internal flag that is set to true when drag and drop has been
+         * intialized
+         * @property initialized
          * @private
-         * @deprecated
+         * @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;
-            },
+        initalized: false,
 
         /**
-         * 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
+         * All drag and drop can be disabled.
+         * @property locked
+         * @private
          * @static
          */
-        getPosX: function(el) {
-            return Roo.lib.Dom.getX(el);
-        },
+        locked: 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
+         * Called the first time an element is registered.
+         * @method init
+         * @private
          * @static
          */
-        getPosY: function(el) {
-            return Roo.lib.Dom.getY(el);
+        init: function() {
+            this.initialized = true;
         },
 
         /**
-         * 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
+         * In point mode, drag and drop interaction is defined by the
+         * location of the cursor during the drag/drop
+         * @property POINT
+         * @type int
          * @static
          */
-        swapNode: function(n1, n2) {
-            if (n1.swapNode) {
-                n1.swapNode(n2);
-            } else {
-                var p = n2.parentNode;
-                var s = n2.nextSibling;
+        POINT: 0,
 
-                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);
+        /**
+         * 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,
+
+        /**
+         * The current drag and drop mode.  Default: POINT
+         * @property mode
+         * @type int
+         * @static
+         */
+        mode: 0,
+
+        /**
+         * 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);
                 }
             }
         },
 
         /**
-         * Returns the current scroll position
-         * @method getScroll
+         * Drag and drop initialization.  Sets up the global event handlers
+         * @method _onLoad
          * @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 {
+        _onLoad: function() {
+
+            this.init();
 
+            if (!Roo.isTouch) {
+                Event.on(document, "mouseup",   this.handleMouseUp, this, true);
+                Event.on(document, "mousemove", this.handleMouseMove, this, true);
             }
-            return { top: t, left: l };
+            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);
+
         },
 
         /**
-         * 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
+         * Reset constraints on all drag and drop objs
+         * @method _onResize
+         * @private
          * @static
          */
-        getStyle: function(el, styleProp) {
-            return Roo.fly(el).getStyle(styleProp);
+        _onResize: function(e) {
+            this._execOnAll("resetConstraints", []);
         },
 
         /**
-         * Gets the scrollTop
-         * @method getScrollTop
-         * @return {int} the document's scrollTop
+         * Lock all drag and drop functionality
+         * @method lock
          * @static
          */
-        getScrollTop: function () { return this.getScroll().top; },
+        lock: function() { this.locked = true; },
 
         /**
-         * Gets the scrollLeft
-         * @method getScrollLeft
-         * @return {int} the document's scrollTop
+         * Unlock all drag and drop functionality
+         * @method unlock
          * @static
          */
-        getScrollLeft: function () { return this.getScroll().left; },
+        unlock: function() { this.locked = false; },
 
         /**
-         * 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
+         * Is drag and drop locked?
+         * @method isLocked
+         * @return {boolean} True if drag and drop is locked, false otherwise.
          * @static
          */
-        moveToEl: function (moveEl, targetEl) {
-            var aCoord = Roo.lib.Dom.getXY(targetEl);
-            Roo.lib.Dom.setXY(moveEl, aCoord);
-        },
+        isLocked: function() { return this.locked; },
 
         /**
-         * Numeric array sort function
-         * @method numericSort
+         * 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
          */
-        numericSort: function(a, b) { return (a - b); },
+        locationCache: {},
 
         /**
-         * Internal counter
-         * @property _timeoutCount
+         * 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 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 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,
+
+        /**
+         * Flag that indicates that either the drag pixel threshold or the
+         * mousdown time threshold has been met
+         * @property dragThreshMet
+         * @type boolean
          * @private
          * @static
          */
-        _timeoutCount: 0,
+        dragThreshMet: false,
 
         /**
-         * 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
+         * Timeout used for the click time threshold
+         * @property clickTimeout
+         * @type Object
          * @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;
-                    }
-                }
+        clickTimeout: null,
+
+        /**
+         * 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 Y position of the mousedown event stored for later use when a
+         * drag threshold is met.
+         * @property startY
+         * @type int
+         * @private
+         * @static
+         */
+        startY: 0,
+
+        /**
+         * 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;
         },
 
         /**
-         * 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
+         * Removes the supplied dd instance from the supplied group. Executed
+         * by DragDrop.removeFromGroup, so don't call this function directly.
+         * @method removeDDFromGroup
+         * @private
          * @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;
+        removeDDFromGroup: function(oDD, sGroup) {
+            if (!this.ids[sGroup]) {
+                this.ids[sGroup] = {};
+            }
 
-                while (p) {
-                    if (this.isHandle(id, p.id)) {
-                        return true;
-                    } else {
-                        p = p.parentNode;
-                    }
+            var obj = this.ids[sGroup];
+            if (obj && obj[oDD.id]) {
+                delete obj[oDD.id];
+            }
+        },
+
+        /**
+         * 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];
+        },
 
-            return false;
-        }
+        /**
+         * 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;
+        },
 
-    };
+        /**
+         * 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;
+                    }
+                }
+            }
 
-// shorter alias, save a few bytes
-Roo.dd.DDM = Roo.dd.DragDropMgr;
-Roo.dd.DDM._addListeners();
+            return oDDs;
+        },
 
-}/*
- * 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">
- */
+        /**
+         * 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;
+                }
+            }
 
-/**
- * @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);
-    }
-};
+            return false;
+        },
 
-Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
+        /**
+         * 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);
+        },
 
-    /**
-     * 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,
+        /**
+         * 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] );
+        },
 
-    /**
-     * 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);
-    },
+        /**
+         * 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;
+        },
 
-    /**
-     * 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;
-    },
+        /**
+         * 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();
 
-    /**
-     * 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
+            this.dragCurrent = oDD;
 
-        var el = this.getDragEl();
-        this.alignElWithMouse(el, iPageX, iPageY);
-    },
+            var el = oDD.getEl();
 
-    /**
-     * 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]);
-        }
+            // track start position
+            this.startX = e.getPageX();
+            this.startY = e.getPageY();
 
-        this.cachePosition(oCoord.x, oCoord.y);
-        this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
-        return oCoord;
-    },
+            this.deltaX = this.startX - el.offsetLeft;
+            this.deltaY = this.startY - el.offsetTop;
 
-    /**
-     * 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];
-        }
-    },
+            this.dragThreshMet = false;
 
-    /**
-     * 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) {
+            this.clickTimeout = setTimeout(
+                    function() {
+                        var DDM = Roo.dd.DDM;
+                        DDM.startDrag(DDM.startX, DDM.startY);
+                    },
+                    this.clickTimeThresh );
+        },
 
-        if (this.scroll) {
-            // The client height
-            var clientH = Roo.lib.Dom.getViewWidth();
+        /**
+         * 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;
+        },
 
-            // The client width
-            var clientW = Roo.lib.Dom.getViewHeight();
+        /**
+         * 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) {
 
-            // The amt scrolled down
-            var st = this.DDM.getScrollTop();
+            if(Roo.QuickTips){
+                Roo.QuickTips.enable();
+            }
+            if (! this.dragCurrent) {
+                return;
+            }
 
-            // The amt scrolled right
-            var sl = this.DDM.getScrollLeft();
+            clearTimeout(this.clickTimeout);
 
-            // Location of the bottom of the element
-            var bot = h + y;
+            if (this.dragThreshMet) {
+                this.fireEvents(e, true);
+            } else {
+            }
 
-            // Location of the right of the element
-            var right = w + x;
+            this.stopDrag(e);
 
-            // 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);
+            this.stopEvent(e);
+        },
 
-            // The distance from the cursor to the right of the visible area
-            var toRight = (clientW + sl - x - this.deltaX);
+        /**
+         * 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();
+            }
 
+            if (this.preventDefault) {
+                e.preventDefault();
+            }
+        },
 
-            // How close to the edge the cursor must be before we scroll
-            // var thresh = (document.all) ? 100 : 40;
-            var thresh = 40;
+        /**
+         * 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);
+                }
 
-            // 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;
+                this.dragCurrent.onMouseUp(e);
+            }
 
-            // 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);
+            this.dragCurrent = null;
+            this.dragOvers = {};
+        },
+
+        /**
+         * 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;
             }
 
-            // 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);
+            // var button = e.which || e.button;
+
+            // 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);
             }
 
-            // 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);
+            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);
+                }
             }
 
-            // 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);
+            if (this.dragThreshMet) {
+                this.dragCurrent.b4Drag(e);
+                this.dragCurrent.onDrag(e);
+                if(!this.dragCurrent.moveOnly){
+                    this.fireEvents(e, false);
+                }
             }
-        }
-    },
 
-    /**
-     * 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) {
+            this.stopEvent(e);
 
+            return true;
+        },
 
-        var x = iPageX - this.deltaX;
-        var y = iPageY - this.deltaY;
+        /**
+         * 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;
 
-        if (this.constrainX) {
-            if (x < this.minX) { x = this.minX; }
-            if (x > this.maxX) { x = this.maxX; }
-        }
+            // 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;
+            }
 
-        if (this.constrainY) {
-            if (y < this.minY) { y = this.minY; }
-            if (y > this.maxY) { y = this.maxY; }
-        }
+            var pt = e.getPoint();
 
-        x = this.getTick(x, this.xTicks);
-        y = this.getTick(y, this.yTicks);
+            // cache the previous dragOver array
+            var oldOvers = [];
 
+            var outEvts   = [];
+            var overEvts  = [];
+            var dropEvts  = [];
+            var enterEvts = [];
 
-        return {x:x, y:y};
-    },
+            // 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) {
 
-    /*
-     * 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);
-    },
+                var ddo = this.dragOvers[i];
 
-    /*
-     * Event that fires prior to the onMouseDown event.  Overrides
-     * Roo.dd.DragDrop.
-     */
-    b4MouseDown: function(e) {
-        // this.resetConstraints();
-        this.autoOffset(e.getPageX(),
-                            e.getPageY());
-    },
+                if (! this.isTypeOfDD(ddo)) {
+                    continue;
+                }
 
-    /*
-     * Event that fires prior to the onDrag event.  Overrides
-     * Roo.dd.DragDrop.
-     */
-    b4Drag: function(e) {
-        this.setDragElPos(e.getPageX(),
-                            e.getPageY());
-    },
+                if (! this.isOverTarget(pt, ddo, this.mode)) {
+                    outEvts.push( ddo );
+                }
 
-    toString: function() {
-        return ("DD " + this.id);
-    }
+                oldOvers[i] = true;
+                delete this.dragOvers[i];
+            }
 
-    //////////////////////////////////////////////////////////////////////////
-    // Debugging ygDragDrop events that can be overridden
-    //////////////////////////////////////////////////////////////////////////
-    /*
-    startDrag: function(x, y) {
-    },
+            for (var sGroup in dc.groups) {
 
-    onDrag: function(e) {
-    },
+                if ("string" != typeof sGroup) {
+                    continue;
+                }
 
-    onDragEnter: function(e, id) {
-    },
+                for (i in this.ids[sGroup]) {
+                    var oDD = this.ids[sGroup][i];
+                    if (! this.isTypeOfDD(oDD)) {
+                        continue;
+                    }
 
-    onDragOver: function(e, 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 {
 
-    onDragOut: function(e, id) {
-    },
+                                // initial drag over: dragEnter fires
+                                if (!oldOvers[oDD.id]) {
+                                    enterEvts.push( oDD );
+                                // subsequent drag overs: dragOver fires
+                                } else {
+                                    overEvts.push( oDD );
+                                }
 
-    onDragDrop: function(e, id) {
-    },
+                                this.dragOvers[oDD.id] = oDD;
+                            }
+                        }
+                    }
+                }
+            }
 
-    endDrag: function(e) {
-    }
+            if (this.mode) {
+                if (outEvts.length) {
+                    dc.b4DragOut(e, outEvts);
+                    dc.onDragOut(e, outEvts);
+                }
 
-    */
+                if (enterEvts.length) {
+                    dc.onDragEnter(e, enterEvts);
+                }
 
-});/*
- * 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">
- */
+                if (overEvts.length) {
+                    dc.b4DragOver(e, overEvts);
+                    dc.onDragOver(e, overEvts);
+                }
 
-/**
- * @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();
-    }
-};
+                if (dropEvts.length) {
+                    dc.b4DragDrop(e, dropEvts);
+                    dc.onDragDrop(e, dropEvts);
+                }
 
-/**
- * The default drag frame div id
- * @property Roo.dd.DDProxy.dragElId
- * @type String
- * @static
- */
-Roo.dd.DDProxy.dragElId = "ygddfdiv";
+            } 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);
+                }
 
-Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
+                // fire enter events
+                for (i=0,len=enterEvts.length; i<len; ++i) {
+                    // dc.b4DragEnter(e, oDD.id);
+                    dc.onDragEnter(e, enterEvts[i].id);
+                }
 
-    /**
-     * 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,
+                // fire over events
+                for (i=0,len=overEvts.length; i<len; ++i) {
+                    dc.b4DragOver(e, overEvts[i].id);
+                    dc.onDragOver(e, overEvts[i].id);
+                }
 
-    /**
-     * 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,
-
-    /**
-     * Creates the proxy element if it does not yet exist
-     * @method createFrame
-     */
-    createFrame: function() {
-        var self = this;
-        var body = document.body;
+                // fire drop events
+                for (i=0, len=dropEvts.length; i<len; ++i) {
+                    dc.b4DragDrop(e, dropEvts[i].id);
+                    dc.onDragDrop(e, dropEvts[i].id);
+                }
 
-        if (!body || !body.firstChild) {
-            setTimeout( function() { self.createFrame(); }, 50 );
-            return;
-        }
+            }
 
-        var div = this.getDragEl();
+            // notify about a drop that did not find a target
+            if (isDrop && !dropEvts.length) {
+                dc.onInvalidDrop(e);
+            }
 
-        if (!div) {
-            div    = document.createElement("div");
-            div.id = this.dragElId;
-            var s  = div.style;
+        },
 
-            s.position   = "absolute";
-            s.visibility = "hidden";
-            s.cursor     = "move";
-            s.border     = "2px solid #aaa";
-            s.zIndex     = 999;
+        /**
+         * 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) {
 
-            // 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 len = dds.length;
 
-    /**
-     * Initialization for the drag frame element.  Must be called in the
-     * constructor of all subclasses
-     * @method initFrame
-     */
-    initFrame: function() {
-        this.createFrame();
-    },
+            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;
+                        }
+                    }
+                }
+            }
 
-    applyConfig: function() {
-        Roo.dd.DDProxy.superclass.applyConfig.call(this);
+            return winner;
+        },
 
-        this.resizeFrame = (this.config.resizeFrame !== false);
-        this.centerFrame = (this.config.centerFrame);
-        this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
-    },
+        /**
+         * 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];
 
-    /**
-     * 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;
+                    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();
+                        }
+                    }
+                }
+            }
+        },
 
-        this._resizeProxy();
+        /**
+         * 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;
+                }
+            }
 
-        if (this.centerFrame) {
-            this.setDelta( Math.round(parseInt(s.width,  10)/2),
-                           Math.round(parseInt(s.height, 10)/2) );
-        }
+            return false;
+        },
 
-        this.setDragElPos(iPageX, iPageY);
+        /**
+         * 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;
+            }
 
-        Roo.fly(dragEl).show();
-    },
+            var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
 
-    /**
-     * 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);
-        }
-    },
+            try {
+                pos= Roo.lib.Dom.getXY(el);
+            } catch (e) { }
 
-    // overrides Roo.dd.DragDrop
-    b4MouseDown: function(e) {
-        var x = e.getPageX();
-        var y = e.getPageY();
-        this.autoOffset(x, y);
-        this.setDragElPos(x, y);
-    },
+            if (!pos) {
+                return null;
+            }
 
-    // overrides Roo.dd.DragDrop
-    b4StartDrag: function(x, y) {
-        // show the drag frame
-        this.showFrame(x, y);
-    },
+            x1 = pos[0];
+            x2 = x1 + el.offsetWidth;
+            y1 = pos[1];
+            y2 = y1 + el.offsetHeight;
 
-    // overrides Roo.dd.DragDrop
-    b4EndDrag: function(e) {
-        Roo.fly(this.getDragEl()).hide();
-    },
+            t = y1 - oDD.padding[0];
+            r = x2 + oDD.padding[1];
+            b = y2 + oDD.padding[2];
+            l = x1 - oDD.padding[3];
 
-    // 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) {
+            return new Roo.lib.Region( t, r, b, l );
+        },
 
-        var lel = this.getEl();
-        var del = this.getDragEl();
+        /**
+         * 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;
 
-        // 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 = "";
+            if (!loc) {
+                return false;
+            }
 
-        this.afterDrag();
-    },
+            oTarget.cursorIsOver = loc.contains( pt );
 
-    beforeMove : function(){
+            // 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;
 
-    afterDrag : function(){
+            // 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 );
 
-    toString: function() {
-        return ("DDProxy " + this.id);
-    }
+            var overlap = curRegion.intersect(loc);
 
-});
-/*
- * 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">
- */
+            if (overlap) {
+                oTarget.overlap = overlap;
+                return (intersect) ? true : oTarget.cursorIsOver;
+            } else {
+                return false;
+            }
+        },
 
- /**
- * @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 || {} 
-        });    
-    }
-};
+        /**
+         * unload event handler
+         * @method _onUnload
+         * @private
+         * @static
+         */
+        _onUnload: function(e, me) {
+            Roo.dd.DragDropMgr.unregAll();
+        },
 
-// 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">
- */
+        /**
+         * Cleans up the drag and drop events and objects.
+         * @method unregAll
+         * @private
+         * @static
+         */
+        unregAll: function() {
 
-/**
- * @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();
-                }
-            }else{
-                proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
+            if (this.dragCurrent) {
+                this.stopDrag();
+                this.dragCurrent = null;
             }
-        }
-    };
-    
-    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;
-                }
+
+            this._execOnAll("unreg", []);
+
+            for (i in this.elementCache) {
+                delete this.elementCache[i];
             }
-        }
-        clearProc();
-    };
-    
-    ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
-    ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
-    
-    return {
+
+            this.elementCache = {};
+            this.ids = {};
+        },
+
         /**
-         * 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
+         * A cache of DOM elements
+         * @property elementCache
+         * @private
+         * @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;
-            }
-            Roo.dd.ScrollManager.els = els;
-        },
-        
+        elementCache: {},
+
         /**
-         * 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
+         * 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
          */
-        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];
+        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 number of pixels from the edge of a container the pointer needs to be to 
-         * trigger scrolling (defaults to 25)
-         * @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
          */
-        thresh : 25,
-        
+        getElement: function(id) {
+            return Roo.getDom(id);
+        },
+
         /**
-         * The number of pixels to scroll in each scroll increment (defaults to 50)
-         * @type Number
+         * 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
          */
-        increment : 100,
-        
+        getCss: function(id) {
+            var el = Roo.getDom(id);
+            return (el) ? el.style : null;
+        },
+
         /**
-         * The frequency of scrolls in milliseconds (defaults to 500)
-         * @type Number
+         * Inner class for cached elements
+         * @class DragDropMgr.ElementWrapper
+         * @for DragDropMgr
+         * @private
+         * @deprecated
          */
-        frequency : 500,
-        
+        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;
+            },
+
         /**
-         * True to animate the scroll (defaults to true)
-         * @type Boolean
+         * 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
          */
-        animate: true,
-        
+        getPosX: function(el) {
+            return Roo.lib.Dom.getX(el);
+        },
+
         /**
-         * The animation duration in seconds - 
-         * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
-         * @type Number
+         * 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
          */
-        animDuration: .4,
-        
+        getPosY: function(el) {
+            return Roo.lib.Dom.getY(el);
+        },
+
         /**
-         * Manually trigger a cache refresh.
+         * 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
          */
-        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">
- */
-
-/**
- * @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;
+        swapNode: function(n1, n2) {
+            if (n1.swapNode) {
+                n1.swapNode(n2);
+            } else {
+                var p = n2.parentNode;
+                var s = n2.nextSibling;
 
-    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;
+                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);
                 }
             }
         },
 
-    /**
-     * 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 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 { top: t, left: l };
         },
 
-    /**
-     * 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;
-            }
-            return handles[id];
+        /**
+         * 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 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;
+        /**
+         * 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);
         },
 
-    /**
-     * 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;
+        /**
+         * 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;
+                    }
+                }
             }
-            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;
+        /**
+         * 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 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.
@@ -18291,173 +18781,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 = {
-    /**
-     * @cfg {String} dropAllowed
-     * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
-     */
-    dropAllowed : "x-dd-drop-ok",
+Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
+
     /**
-     * @cfg {String} dropNotAllowed
-     * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
+     * 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
      */
-    dropNotAllowed : "x-dd-drop-nodrop",
+    scroll: true,
 
     /**
-     * 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 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
      */
-    setStatus : function(cssClass){
-        cssClass = cssClass || this.dropNotAllowed;
-        if(this.dropStatus != cssClass){
-            this.el.replaceClass(this.dropStatus, cssClass);
-            this.dropStatus = cssClass;
-        }
+    autoOffset: function(iPageX, iPageY) {
+        var x = iPageX - this.startPageX;
+        var y = iPageY - this.startPageY;
+        this.setDelta(x, y);
     },
 
     /**
-     * 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 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
      */
-    reset : function(clearGhost){
-        this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
-        this.dropStatus = this.dropNotAllowed;
-        if(clearGhost){
-            this.ghost.update("");
-        }
+    setDelta: function(iDeltaX, iDeltaY) {
+        this.deltaX = iDeltaX;
+        this.deltaY = iDeltaY;
     },
 
     /**
-     * Updates the contents of the ghost element
-     * @param {String} html The html that will replace the current innerHTML of the ghost element
+     * 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
      */
-    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');
-               }
-    },
-    
-    /**
-     * Returns the underlying proxy {@link Roo.Layer}
-     * @return {Roo.Layer} el
-    */
-    getEl : function(){
-        return this.el;
+    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);
     },
 
     /**
-     * Returns the ghost element
-     * @return {Roo.Element} el
+     * 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
      */
-    getGhost : function(){
-        return this.ghost;
+    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;
     },
 
     /**
-     * Hides the proxy
-     * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
+     * 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)
      */
-    hide : function(clear){
-        this.el.hide();
-        if(clear){
-            this.reset(true);
+    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];
         }
     },
 
     /**
-     * Stops the repair animation if it's currently running
+     * 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
      */
-    stop : function(){
-        if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
-            this.anim.stop();
+    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);
+            }
         }
     },
 
     /**
-     * Displays this proxy
+     * 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
      */
-    show : function(){
-        this.el.show();
+    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};
     },
 
-    /**
-     * Force the Layer to sync its shadow and shim positions to the element
+    /*
+     * Sets up config options specific to this class. Overrides
+     * Roo.dd.DragDrop, but all versions of this method through the
+     * inheritance chain are called
      */
-    sync : function(){
-        this.el.sync();
+    applyConfig: function() {
+        Roo.dd.DD.superclass.applyConfig.call(this);
+        this.scroll = (this.config.scroll !== false);
     },
 
-    /**
-     * 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 onMouseDown 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();
-        }
+    b4MouseDown: function(e) {
+        // this.resetConstraints();
+        this.autoOffset(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;
+    /*
+     * Event that fires prior to the onDrag event.  Overrides
+     * Roo.dd.DragDrop.
+     */
+    b4Drag: function(e) {
+        this.setDragElPos(e.getPageX(),
+                            e.getPageY());
+    },
+
+    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.
@@ -18469,358 +19082,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, {
+/**
+ * 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, {
+
     /**
-     * @cfg {String} dropAllowed
-     * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
+     * 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
      */
-    dropAllowed : "x-dd-drop-ok",
+    resizeFrame: true,
+
     /**
-     * @cfg {String} dropNotAllowed
-     * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
+     * 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
      */
-    dropNotAllowed : "x-dd-drop-nodrop",
+    centerFrame: false,
 
     /**
-     * Returns the data object associated with this drag source
-     * @return {Object} data An object containing arbitrary data
+     * Creates the proxy element if it does not yet exist
+     * @method createFrame
      */
-    getDragData : function(e){
-        return this.dragData;
-    },
+    createFrame: function() {
+        var self = this;
+        var body = document.body;
 
-    // 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);
-            }
+        if (!body || !body.firstChild) {
+            setTimeout( function() { self.createFrame(); }, 50 );
+            return;
         }
-    },
 
-    /**
-     * 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;
-    },
+        var div = this.getDragEl();
 
-    // private
-    alignElWithMouse: function() {
-        Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
-        this.proxy.sync();
-    },
+        if (!div) {
+            div    = document.createElement("div");
+            div.id = this.dragElId;
+            var s  = div.style;
 
-    // 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);
-            }
+            s.position   = "absolute";
+            s.visibility = "hidden";
+            s.cursor     = "move";
+            s.border     = "2px solid #aaa";
+            s.zIndex     = 999;
 
-            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);
-            }
+            // 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);
         }
     },
 
     /**
-     * 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
+     * Initialization for the drag frame element.  Must be called in the
+     * constructor of all subclasses
+     * @method initFrame
      */
-    beforeDragOver : function(target, e, id){
-        return true;
+    initFrame: function() {
+        this.createFrame();
     },
 
-    // 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;
+    applyConfig: function() {
+        Roo.dd.DDProxy.superclass.applyConfig.call(this);
+
+        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 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
+     * 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
      */
-    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);
-            }
+    showFrame: function(iPageX, iPageY) {
+        var el = this.getEl();
+        var dragEl = this.getDragEl();
+        var s = dragEl.style;
+
+        this._resizeProxy();
+
+        if (this.centerFrame) {
+            this.setDelta( Math.round(parseInt(s.width,  10)/2),
+                           Math.round(parseInt(s.height, 10)/2) );
         }
-        delete this.cachedTarget;
+
+        this.setDragElPos(iPageX, iPageY);
+
+        Roo.fly(dragEl).show();
     },
 
     /**
-     * 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
+     * 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
      */
-    beforeDragDrop : function(target, e, id){
-        return true;
+    _resizeProxy: function() {
+        if (this.resizeFrame) {
+            var el = this.getEl();
+            Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
+        }
     },
 
-    // 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);
-        }
-    },
-
-    // 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);
-        }
+    // overrides Roo.dd.DragDrop
+    b4MouseDown: function(e) {
+        var x = e.getPageX();
+        var y = e.getPageY();
+        this.autoOffset(x, y);
+        this.setDragElPos(x, y);
     },
 
-    // private
-    afterRepair : function(){
-        if(Roo.enableFx){
-            this.el.highlight(this.hlColor || "c3daf9");
-        }
-        this.dragging = false;
+    // overrides Roo.dd.DragDrop
+    b4StartDrag: function(x, y) {
+        // show the drag frame
+        this.showFrame(x, y);
     },
 
-    /**
-     * 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
-     */
-    beforeInvalidDrop : function(target, e, id){
-        return true;
+    // overrides Roo.dd.DragDrop
+    b4EndDrag: function(e) {
+        Roo.fly(this.getDragEl()).hide();
     },
 
-    // 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);
-        } 
-    },
+    // 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) {
 
-    /**
-     * 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;
-    },
+        var lel = this.getEl();
+        var del = this.getDragEl();
 
-    /**
-     * 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,
+        // Show the drag frame briefly so we can get its position
+        del.style.visibility = "";
 
-    // private - YUI override
-    startDrag : function(x, y){
-        this.proxy.reset();
-        this.dragging = true;
-        this.proxy.update("");
-        this.onInitDrag(x, y);
-        this.proxy.show();
-    },
+        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 = "";
 
-    // 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;
+        this.afterDrag();
     },
 
-    /**
-     * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
-     * @return {Roo.dd.StatusProxy} proxy The StatusProxy
-     */
-    getProxy : function(){
-        return this.proxy;  
-    },
+    beforeMove : function(){
 
-    /**
-     * Hides the drag source's {@link Roo.dd.StatusProxy}
-     */
-    hideProxy : function(){
-        this.proxy.hide();  
-        this.proxy.reset(true);
-        this.dragging = false;
     },
 
-    // private
-    triggerCacheRefresh : function(){
-        Roo.dd.DDM.refreshCache(this.groups);
-    },
+    afterDrag : function(){
 
-    // private - override to prevent hiding
-    b4EndDrag: function(e) {
     },
 
-    // private - override to prevent moving
-    endDrag : function(e){
-        this.onEndDrag(this.dragData, e);
-    },
+    toString: function() {
+        return ("DDProxy " + this.id);
+    }
 
-    // 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.
@@ -18831,188 +19289,40 @@ Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
  * <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.
+ /**
+ * @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/HTMLElement/Element} el The container element
- * @param {Object} config
+ * @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.DropTarget = function(el, config){
-    this.el = Roo.get(el);
-    
-    var listeners = false; ;
-    if (config && config.listeners) {
-        listeners= config.listeners;
-        delete config.listeners;
+Roo.dd.DDTarget = function(id, sGroup, config) {
+    if (id) {
+        this.initTarget(id, sGroup, config);
     }
-    Roo.apply(this, config);
-    
-    if(this.containerScroll){
-        Roo.dd.ScrollManager.register(this.el);
+    if (config.listeners || config.events) { 
+       Roo.dd.DragDrop.superclass.constructor.call(this,  { 
+            listeners : config.listeners || {}, 
+            events : config.events || {} 
+        });    
     }
-    this.addEvents( {
-         /**
-         * @scope Roo.dd.DropTarget
-         */
-         
-         /**
-         * @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
-         */
-        "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.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
-         
-         */
-        "over" : true,
-        /**
-         * @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
-         */
-         "out" : 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 || {} 
-           
-        
-        }
-    );
-
 };
 
-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)
-    {
-        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;
+// 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.
@@ -19022,288 +19332,315 @@ 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.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.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, {
-    /**
-     * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
-     * for auto scrolling during drag operations.
-     */
-    /**
-     * @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)
-     */
-
-    /**
-     * 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
-     */
-    getDragData : function(e){
-        return Roo.dd.Registry.getHandleFromEvent(e);
-    },
+Roo.dd.ScrollManager = function(){
+    var ddm = Roo.dd.DragDropMgr;
+    var els = {};
+    var dragEl = null;
+    var proc = {};
     
-    /**
-     * 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
-     */
-    onInitDrag : function(x, y){
-        this.proxy.update(this.dragData.ddel.cloneNode(true));
-        this.onStartDrag(x, y);
-        return true;
-    },
     
-    /**
-     * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
-     */
-    afterRepair : function(){
-        if(Roo.enableFx){
-            Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
+    
+    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();
         }
-        this.dragging = false;
-    },
-
-    /**
-     * 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])
-     */
-    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, {
-    /**
-     * 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
-     */
-    getTargetFromEvent : function(e){
-        return Roo.dd.Registry.getTargetFromEvent(e);
-    },
-
-    /**
-     * 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){
-        
-    },
-
-    /**
-     * 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
-     */
-    onNodeOver : function(n, dd, e, data){
-        return this.dropAllowed;
-    },
-
-    /**
-     * 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
-     */
-    onNodeOut : function(n, dd, e, data){
         
-    },
+        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
+         */
+        thresh : 25,
+        
+        /**
+         * The number of pixels to scroll in each scroll increment (defaults to 50)
+         * @type Number
+         */
+        increment : 100,
+        
+        /**
+         * The frequency of scrolls in milliseconds (defaults to 500)
+         * @type Number
+         */
+        frequency : 500,
+        
+        /**
+         * True to animate the scroll (defaults to true)
+         * @type Boolean
+         */
+        animate: true,
+        
+        /**
+         * 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();
+                }
+            }
+        }
+    };
+}();/*
+ * 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">
+ */
 
-    /**
-     * 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
-     */
-    onNodeDrop : function(n, dd, e, data){
-        return false;
-    },
+/**
+ * @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;
 
+    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 {
     /**
-     * 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
+     * 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>
      */
-    onContainerOver : function(dd, e, data){
-        return this.dropNotAllowed;
-    },
+        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;
+                }
+            }
+        },
 
     /**
-     * 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
+     * Unregister a drag drop element
+     * @param {String|HTMLElement}  element The id or DOM node to unregister
      */
-    onContainerDrop : function(dd, e, data){
-        return false;
-    },
+        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)];
+                    }
+                }
+            }
+        },
 
     /**
-     * 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
+     * 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
      */
-    notifyEnter : function(dd, e, data){
-        return this.dropNotAllowed;
-    },
+        getHandle : function(id){
+            if(typeof id != "string"){ // must be element?
+                id = id.id;
+            }
+            return handles[id];
+        },
 
     /**
-     * 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
+     * Returns the handle that is registered for the DOM node that is the target of the event
      * @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
+     * @return {Object} handle The custom handle data
      */
-    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;
-        }
-        return this.onNodeOver(n, dd, e, data);
-    },
+        getHandleFromEvent : function(e){
+            var t = Roo.lib.Event.getTarget(e);
+            return t ? handles[t.id] : null;
+        },
 
     /**
-     * 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
+     * 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
      */
-    notifyOut : function(dd, e, data){
-        if(this.lastOverNode){
-            this.onNodeOut(this.lastOverNode, dd, e, data);
-            this.lastOverNode = null;
-        }
-    },
+        getTarget : function(id){
+            if(typeof id != "string"){ // must be element?
+                id = id.id;
+            }
+            return elements[id];
+        },
 
     /**
-     * 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
+     * Returns a custom data object that is registered for the DOM node that is the target of the event
      * @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
+     * @return {Object} data The custom data
      */
-    notifyDrop : function(dd, e, data){
-        if(this.lastOverNode){
-            this.onNodeOut(this.lastOverNode, dd, e, data);
-            this.lastOverNode = null;
+        getTargetFromEvent : function(e){
+            var t = Roo.lib.Event.getTarget(e);
+            return t ? elements[t.id] || handles[t.id] : null;
         }
-        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);
-    }  
-});/*
+    };
+}();/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -19313,92 +19650,171 @@ Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
  * Fork - LGPL
  * <script type="text/javascript">
  */
-
 
 /**
- * @class Roo.data.SortTypes
- * @singleton
- * Defines the default sorting (casting?) comparison functions used when sorting data.
+ * @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 {Object} config
  */
-Roo.data.SortTypes = {
+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.StatusProxy.prototype = {
     /**
-     * Default sort that does nothing
-     * @param {Mixed} s The value being converted
-     * @return {Mixed} The comparison value
+     * @cfg {String} dropAllowed
+     * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
      */
-    none : function(s){
-        return s;
-    },
-    
+    dropAllowed : "x-dd-drop-ok",
     /**
-     * The regular expression used to strip tags
-     * @type {RegExp}
-     * @property
+     * @cfg {String} dropNotAllowed
+     * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
      */
-    stripTagsRE : /<\/?[^>]+>/gi,
-    
+    dropNotAllowed : "x-dd-drop-nodrop",
+
     /**
-     * Strips all HTML tags to sort on text only
-     * @param {Mixed} s The value being converted
-     * @return {String} The comparison value
+     * 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
      */
-    asText : function(s){
-        return String(s).replace(this.stripTagsRE, "");
+    setStatus : function(cssClass){
+        cssClass = cssClass || this.dropNotAllowed;
+        if(this.dropStatus != cssClass){
+            this.el.replaceClass(this.dropStatus, cssClass);
+            this.dropStatus = cssClass;
+        }
     },
-    
+
     /**
-     * Strips all HTML tags to sort on text only - Case insensitive
-     * @param {Mixed} s The value being converted
-     * @return {String} The comparison value
+     * 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
      */
-    asUCText : function(s){
-        return String(s).toUpperCase().replace(this.stripTagsRE, "");
+    reset : function(clearGhost){
+        this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
+        this.dropStatus = this.dropNotAllowed;
+        if(clearGhost){
+            this.ghost.update("");
+        }
     },
-    
+
     /**
-     * Case insensitive string
-     * @param {Mixed} s The value being converted
-     * @return {String} The comparison value
+     * Updates the contents of the ghost element
+     * @param {String} html The html that will replace the current innerHTML of the ghost element
      */
-    asUCString : function(s) {
-       return String(s).toUpperCase();
+    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');
+               }
     },
     
     /**
-     * Date sorting
-     * @param {Mixed} s The value being converted
-     * @return {Number} The comparison value
-     */
-    asDate : function(s) {
-        if(!s){
-            return 0;
-        }
-        if(s instanceof Date){
-            return s.getTime();
-        }
-       return Date.parse(String(s));
+     * Returns the underlying proxy {@link Roo.Layer}
+     * @return {Roo.Layer} el
+    */
+    getEl : function(){
+        return this.el;
     },
-    
+
     /**
-     * Float sorting
-     * @param {Mixed} s The value being converted
-     * @return {Float} The comparison value
+     * Returns the ghost element
+     * @return {Roo.Element} el
      */
-    asFloat : function(s) {
-       var val = parseFloat(String(s).replace(/,/g, ""));
-        if(isNaN(val)) val = 0;
-       return val;
+    getGhost : function(){
+        return this.ghost;
     },
-    
+
     /**
-     * Integer sorting
-     * @param {Mixed} s The value being converted
-     * @return {Number} The comparison value
+     * Hides the proxy
+     * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
      */
-    asInt : function(s) {
-        var val = parseInt(String(s).replace(/,/g, ""));
-        if(isNaN(val)) val = 0;
-       return val;
+    hide : function(clear){
+        this.el.hide();
+        if(clear){
+            this.reset(true);
+        }
+    },
+
+    /**
+     * Stops the repair animation if it's currently running
+     */
+    stop : function(){
+        if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
+            this.anim.stop();
+        }
+    },
+
+    /**
+     * Displays this proxy
+     */
+    show : function(){
+        this.el.show();
+    },
+
+    /**
+     * Force the Layer to sync its shadow and shim positions to the element
+     */
+    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();
+        }
+    },
+
+    // private
+    afterRepair : function(){
+        this.hide(true);
+        if(typeof this.callback == "function"){
+            this.callback.call(this.scope || this);
+        }
+        this.callback = null;
+        this.scope = null;
     }
 };/*
  * Based on:
@@ -19412,943 +19828,938 @@ Roo.data.SortTypes = {
  */
 
 /**
-* @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.
+ * @class Roo.dd.DragSource
+ * @extends Roo.dd.DDProxy
+ * A simple class that provides the basic implementation needed to make any element draggable.
  * @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'}
-);
-
-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
+ * @param {String/HTMLElement/Element} el The container element
+ * @param {Object} config
  */
-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]));
+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();
     }
-    f.getField = function(name){
-        return p.fields.get(name);  
-    };
-    return f;
-};
 
-Roo.data.Record.AUTO_ID = 1000;
-Roo.data.Record.EDIT = 'edit';
-Roo.data.Record.REJECT = 'reject';
-Roo.data.Record.COMMIT = 'commit';
+    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.data.Record.prototype = {
+Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
     /**
-     * Readonly flag - true if this record has been modified.
-     * @type Boolean
+     * @cfg {String} dropAllowed
+     * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
      */
-    dirty : false,
-    editing : false,
-    error: null,
-    modified: null,
-
-    // private
-    join : function(store){
-        this.store = store;
-    },
+    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",
 
     /**
-     * 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.
+     * Returns the data object associated with this drag source
+     * @return {Object} data An object containing arbitrary data
      */
-    set : function(name, value){
-        if(this.data[name] == value){
-            return;
-        }
-        this.dirty = true;
-        if(!this.modified){
-            this.modified = {};
-        }
-        if(typeof this.modified[name] == 'undefined'){
-            this.modified[name] = this.data[name];
+    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);
+            }
         }
-        this.data[name] = value;
-        if(!this.editing && this.store){
-            this.store.afterEdit(this);
-        }       
     },
 
     /**
-     * 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
+     * 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
      */
-    get : function(name){
-        return this.data[name]; 
+    beforeDragEnter : function(target, e, id){
+        return true;
     },
 
     // private
-    beginEdit : function(){
-        this.editing = true;
-        this.modified = {}; 
+    alignElWithMouse: function() {
+        Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
+        this.proxy.sync();
     },
 
     // private
-    cancelEdit : function(){
-        this.editing = false;
-        delete this.modified;
+    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);
+            }
+
+            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);
+            }
+        }
+    },
+
+    /**
+     * 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
+     */
+    beforeDragOver : function(target, e, id){
+        return true;
     },
 
     // private
-    endEdit : function(){
-        this.editing = false;
-        if(this.dirty && this.store){
-            this.store.afterEdit(this);
+    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;
     },
 
     /**
-     * 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.
+     * 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
      */
-    reject : function(){
-        var m = this.modified;
-        for(var n in m){
-            if(typeof m[n] != "function"){
-                this.data[n] = m[n];
+    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 = false;
-        delete this.modified;
-        this.editing = false;
-        if(this.store){
-            this.store.afterReject(this);
-        }
+        delete this.cachedTarget;
     },
 
     /**
-     * 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.
+     * 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
      */
-    commit : function(){
-        this.dirty = false;
-        delete this.modified;
-        this.editing = false;
-        if(this.store){
-            this.store.afterCommit(this);
+    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);
         }
     },
 
     // private
-    hasError : function(){
-        return this.error != null;
+    getRepairXY : function(e, data){
+        return this.el.getXY();  
     },
 
     // private
-    clearError : function(){
-        this.error = null;
+    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.dragging = false;
     },
 
     /**
-     * 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}
+     * 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
      */
-    copy : function(newId) {
-        return new this.constructor(Roo.apply({}, this.data), newId || 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">
- */
+    beforeInvalidDrop : function(target, e, id){
+        return true;
+    },
 
+    // 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);
+        } 
+    },
 
+    /**
+     * 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();
+    },
 
-/**
- * @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.
- * @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.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"
-    };
+    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(config && config.data){
-        this.inlineData = config.data;
-        delete config.data;
-    }
+    /**
+     * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
+     * @return {Roo.dd.StatusProxy} proxy The StatusProxy
+     */
+    getProxy : function(){
+        return this.proxy;  
+    },
 
-    Roo.apply(this, config);
+    /**
+     * Hides the drag source's {@link Roo.dd.StatusProxy}
+     */
+    hideProxy : function(){
+        this.proxy.hide();  
+        this.proxy.reset(true);
+        this.dragging = false;
+    },
+
+    // private
+    triggerCacheRefresh : function(){
+        Roo.dd.DDM.refreshCache(this.groups);
+    },
+
+    // private - override to prevent hiding
+    b4EndDrag: function(e) {
+    },
+
+    // private - override to prevent moving
+    endDrag : function(e){
+        this.onEndDrag(this.dragData, e);
+    },
+
+    // private
+    onEndDrag : function(data, e){
+    },
     
-    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);
-        }
-    }
+    // 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.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
 
-    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
+/**
+ * @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
+ */
+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.containerScroll){
+        Roo.dd.ScrollManager.register(this.el);
+    }
+    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.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
          */
-        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.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
+         
          */
-        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;
+    notifyDrop : function(dd, e, data){
+        if(this.lastOverNode){
+            this.onNodeOut(this.lastOverNode, dd, e, data);
+            this.lastOverNode = null;
+        }
+        var n = this.getTargetFromEvent(e);
+        return n ?
+            this.onNodeDrop(n, dd, e, data) :
+            this.onContainerDrop(dd, e, data);
     },
 
     // 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");
-        }
-        return function(r){
-            return value.test(r.data[property]);
-        };
-    },
+    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">
+ */
 
+
+/**
+ * @class Roo.data.SortTypes
+ * @singleton
+ * Defines the default sorting (casting?) comparison functions used when sorting data.
+ */
+Roo.data.SortTypes = {
     /**
-     * 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
+     * Default sort that does nothing
+     * @param {Mixed} s The value being converted
+     * @return {Mixed} The comparison value
      */
-    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;
+    none : function(s){
+        return s;
     },
-
+    
     /**
-     * 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
+     * The regular expression used to strip tags
+     * @type {RegExp}
+     * @property
      */
-    filter : function(property, value, anyMatch){
-        var fn = this.createFilterFn(property, value, anyMatch);
-        return fn ? this.filterBy(fn) : this.clearFilter();
-    },
-
+    stripTagsRE : /<\/?[^>]+>/gi,
+    
     /**
-     * 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)
+     * Strips all HTML tags to sort on text only
+     * @param {Mixed} s The value being converted
+     * @return {String} The comparison value
      */
-    filterBy : function(fn, scope){
-        this.snapshot = this.snapshot || this.data;
-        this.data = this.queryBy(fn, scope||this);
-        this.fireEvent("datachanged", this);
+    asText : function(s){
+        return String(s).replace(this.stripTagsRE, "");
     },
-
+    
     /**
-     * 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
+     * Strips all HTML tags to sort on text only - Case insensitive
+     * @param {Mixed} s The value being converted
+     * @return {String} The comparison value
      */
-    query : function(property, value, anyMatch){
-        var fn = this.createFilterFn(property, value, anyMatch);
-        return fn ? this.queryBy(fn) : this.data.clone();
+    asUCText : function(s){
+        return String(s).toUpperCase().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);
+     * Case insensitive string
+     * @param {Mixed} s The value being converted
+     * @return {String} The comparison value
+     */
+    asUCString : function(s) {
+       return String(s).toUpperCase();
     },
-
+    
     /**
-     * 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;
-            }
+     * Date sorting
+     * @param {Mixed} s The value being converted
+     * @return {Number} The comparison value
+     */
+    asDate : function(s) {
+        if(!s){
+            return 0;
         }
-        return r;
+        if(s instanceof Date){
+            return s.getTime();
+        }
+       return Date.parse(String(s));
     },
-
+    
     /**
-     * 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
+     * Float sorting
+     * @param {Mixed} s The value being converted
+     * @return {Float} 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);
-            }
-        }
-    },
-
-    // private
-    afterEdit : function(record){
-        if(this.modified.indexOf(record) == -1){
-            this.modified.push(record);
-        }
-        this.fireEvent("update", this, record, Roo.data.Record.EDIT);
+    asFloat : function(s) {
+       var val = parseFloat(String(s).replace(/,/g, ""));
+        if(isNaN(val)) val = 0;
+       return val;
     },
     
-    // 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.
-     */
-    commitChanges : function(){
-        var m = this.modified.slice(0);
-        this.modified = [];
-        for(var i = 0, len = m.length; i < len; i++){
-            m[i].commit();
-        }
-    },
-
     /**
-     * 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();
-        }
-    },
-
-    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);
+    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.
@@ -20360,215 +20771,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
@@ -20580,462 +21003,709 @@ 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(){
-    this.addEvents({
-        /**
-         * @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.
-         */
-        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.
- *
- * 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.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.data.MemoryProxy.superclass.constructor.call(this);
-    this.data = data;
-};
 
-Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
-    /**
-     * Load data from the requested source (in this case an in-memory
-     * data object passed to the constructor), read the data object into
-     * 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.
-     */
-    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;
+    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;
         }
-        callback.call(scope, result, arg, true);
-    },
+        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 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 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 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
+    });
     
-    // private
-    update : function(params, records){
-        
+    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;
     }
-});/*
- * 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;
-  
 };
 
-Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
-    // thse are take from connection...
+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 {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
-     */
+    * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
+    */
     /**
-     * @cfg {Object} extraParams (Optional) An object containing properties which are used as
-     * extra parameters to each request made by this object. (defaults to undefined)
-     */
+    * @cfg {Array} data Inline data to be loaded when the store is initialized.
+    */
     /**
-     * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
-     *  to each request made by this object. (defaults to undefined)
-     */
+    * @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.
+    */
     /**
-     * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
-     */
+    * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
+    * on any HTTP request
+    */
     /**
-     * @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
-     */
-  
+    * @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 {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
-     * @type Boolean
-     */
+    * @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,
+
     /**
-     * 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.
+     * 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.
      */
-    getConnection : function(){
-        return this.useAjax ? Roo.Ajax : this.conn;
+    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);
     },
 
     /**
-     * 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.
+     * 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.
      */
-    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);
-            }else{
-                this.conn.request(o);
-            }
-        }else{
-            callback.call(scope||this, null, arg, false);
+    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);
     },
 
-    // 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;
+    /**
+     * Remove all Records from the Store and fires the clear event.
+     */
+    removeAll : function(){
+        this.data.clear();
+        if(this.pruneModifiedRecords){
+            this.modified = [];
         }
-        
-        this.fireEvent("load", this, o, o.request.arg);
-        o.request.callback.call(o.request.scope, result, o.request.arg, true);
+        this.fireEvent("clear", this);
     },
 
-    // private
-    update : function(dataSet){
-
+    /**
+     * 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);
     },
 
-    // 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;
-
-Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
     /**
-     * @cfg {String} url The URL from which to request the data object.
+     * 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);
+    },
+
     /**
-     * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
+     * 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.
      */
-    timeout : 30000,
+    indexOfId : function(id){
+        return this.data.indexOfKey(id);
+    },
+
     /**
-     * @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.
+     * 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.
      */
-    callbackParam : "callback",
+    getById : function(id){
+        return this.data.key(id);
+    },
+
     /**
-     *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
-     * name to the request.
+     * 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.
      */
-    nocache : true,
+    getAt : function(index){
+        return this.data.itemAt(index);
+    },
 
     /**
-     * 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.
+     * 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
      */
-    load : function(params, reader, callback, scope, arg){
-        if(this.fireEvent("beforeload", this, params) !== false){
-
-            var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
+    getRange : function(start, end){
+        return this.data.getRange(start, end);
+    },
 
-            var url = this.url;
-            url += (url.indexOf("?") != -1 ? "&" : "?") + p;
-            if(this.nocache){
-                url += "&_dc=" + (new Date().getTime());
-            }
-            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;
+    // private
+    storeOptions : function(o){
+        o = Roo.apply({}, o);
+        delete o.callback;
+        delete o.scope;
+        this.lastOptions = o;
+    },
 
-            window[trans.cb] = function(o){
-                conn.handleResponse(o, trans);
-            };
+    /**
+     * 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>
+     */
+    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);
+        }
+    },
 
-            url += String.format("&{0}={1}", this.callbackParam, trans.cb);
+    /**
+     * 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));
+    },
 
-            if(this.autoAbort !== false){
-                this.abort();
+    // 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);
+        
+        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);
+        }
+    },
 
-            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);
+    /**
+     * 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.
+     */
+    loadData : function(o, append){
+        var r = this.reader.readRecords(o);
+        this.loadRecords(r, {add: append}, true);
+    },
 
-            this.trans = trans;
+    /**
+     * 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;
+    },
+
+    /**
+     * 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;
+    },
+
+    /**
+     * 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);
+            }
+        }
+    },
+
+    /**
+     * 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")
+     */
+    setDefaultSort : function(field, dir){
+        this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
+    },
+
+    /**
+     * 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")
+     */
+    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;
+            }
+        }
+        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);
         }
     },
 
+    /**
+     * 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);
+    },
+
+    /**
+     * 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
-    isLoading : function(){
-        return this.trans ? true : false;
+    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]);
+        };
     },
 
     /**
-     * Abort the current server request.
+     * 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
      */
-    abort : function(){
-        if(this.isLoading()){
-            this.destroyTrans(this.trans);
+    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;
     },
 
-    // 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){}
-            };
+    /**
+     * 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
+     */
+    filter : function(property, value, anyMatch){
+        var fn = this.createFilterFn(property, value, anyMatch);
+        return fn ? this.filterBy(fn) : this.clearFilter();
+    },
+
+    /**
+     * 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)
+     */
+    filterBy : function(fn, scope){
+        this.snapshot = this.snapshot || this.data;
+        this.data = this.queryBy(fn, scope||this);
+        this.fireEvent("datachanged", this);
+    },
+
+    /**
+     * 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();
+    },
+
+    /**
+     * 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);
+    },
+
+    /**
+     * 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;
+    },
+
+    /**
+     * 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);
+            }
         }
     },
 
     // 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;
+    afterEdit : function(record){
+        if(this.modified.indexOf(record) == -1){
+            this.modified.push(record);
         }
-        this.fireEvent("load", this, o, trans.arg);
-        trans.callback.call(trans.scope||window, result, trans.arg, true);
+        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
-    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);
+    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.
+     */
+    commitChanges : function(){
+        var m = this.modified.slice(0);
+        this.modified = [];
+        for(var i = 0, len = m.length; i < len; i++){
+            m[i].commit();
+        }
+    },
+
+    /**
+     * 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();
+        }
+    },
+
+    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);
     }
 });/*
  * Based on:
@@ -21049,205 +21719,28 @@ 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' } ]
-}
-</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.
+ * @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
  * @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){
-    
-    meta = meta || {};
-    // set some defaults:
-    Roo.applyIf(meta, {
-        totalProperty: 'total',
-        successProperty : 'success',
-        root : 'data',
-        id : 'id'
+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)
     });
-    
-    Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
+    this.load();
 };
-Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
-    
-    /**
-     * @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"};
-        }
-        
-        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);
-    },
-
-    // private function a store will implement
-    onMetaChange : function(meta, recordType, o){
-
-    },
-
-    /**
-        * @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;
-        };
-    }(),
-
-    /**
-     * 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.
-     */
-    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.prototype.fields, fi = f.items, fl = f.length;
-
-//      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);
-               }
-               var record = new Record(values, id);
-               record.json = n;
-               records[i] = record;
-           }
-           return {
-            raw : o,
-               success : success,
-               records : records,
-               totalRecords : totalRecords
-           };
-    }
-});/*
+Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -21259,127 +21752,134 @@ 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>
- * <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>
+/**
+ * @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} 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.
+ * <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 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.
+ * @param {Object} config
  */
-Roo.data.XmlReader = function(meta, recordType){
-    meta = meta || {};
-    Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
+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.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"};
+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;
         }
-        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){
-        /**
-         * 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;
-           }
+    // define once
+    var stripRe = /[\$,%]/g;
 
-           return {
-               success : success,
-               records : records,
-               totalRecords : totalRecords || records.length
-           };
+    // 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;
+            
+        }
+        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.
@@ -21389,76 +21889,46 @@ Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
  * 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.
 
 /**
- * @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
- * @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}.
+ * @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.
  */
-Roo.data.ArrayReader = function(meta, recordType){
-    Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
+
+Roo.data.DataReader = function(meta, recordType){
+    
+    this.meta = meta;
+    
+    this.recordType = recordType instanceof Array ? 
+        Roo.data.Record.create(recordType) : recordType;
 };
 
-Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
-    /**
-     * Create a data block containing Roo.data.Records from an XML document.
-     * @param {Object} o An Array of row objects which represents the dataset.
-     * @return {Object} data A data block which is used by an Roo.data.Store object as
-     * a cache of Roo.data.Records.
+Roo.data.DataReader.prototype = {
+     /**
+     * Create an empty record
+     * @param {Object} data (optional) - overlay some values
+     * @return {Roo.data.Record} record created.
      */
-    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;
+    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 recordType(values, id);
-               record.json = n;
-               records[records.length] = record;
-           }
-           return {
-               records : records,
-               totalRecords : records.length
-           };
+            
+        });
+        return new this.recordType(Roo.apply(da, d));
     }
-});/*
+    
+};/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -21469,734 +21939,462 @@ Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
  * <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.
- * @constructor
- * @param {Node} root (optional) The root node
+ * @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>
+ * <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>
+ * <p>
+ * Custom implementations must implement the load method as described in
+ * {@link Roo.data.HttpProxy#load}.
  */
-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.DataProxy = function(){
+    this.addEvents({
+        /**
+         * @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.
+         */
+        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.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;
-    },
+Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
 
     /**
-     * Sets the root node for this tree.
-     * @param {Node} node
-     * @return {Node}
+     * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
      */
-    setRootNode : function(node){
-        this.root = node;
-        node.ownerTree = this;
-        node.isRoot = true;
-        this.registerNode(node);
-        return node;
-    },
+/*
+ * 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;
+};
 
+Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
     /**
-     * Gets a node in this tree by its id.
-     * @param {String} id
-     * @return {Node}
+     * 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.
      */
-    getNodeById : function(id){
-        return this.nodeHash[id];
-    },
-
-    registerNode : function(node){
-        this.nodeHash[node.id] = node;
-    },
-
-    unregisterNode : function(node){
-        delete this.nodeHash[node.id];
+    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;
+        }
+        callback.call(scope, result, arg, true);
     },
-
-    toString : function(){
-        return "[Tree"+(this.id?" "+this.id:"")+"]";
+    
+    // private
+    update : function(params, records){
+        
     }
-});
-
+});/*
+ * 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.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.
+ * @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} attributes The attributes/config for the 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.Node = function(attributes){
+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.HttpProxy, Roo.data.DataProxy, {
+    // thse are take from connection...
+    
     /**
-     * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
-     * @type {Object}
+     * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
      */
-    this.attributes = attributes || {};
-    this.leaf = this.attributes.leaf;
     /**
-     * The node id. @type String
+     * @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.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
+     * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
+     *  to each request made by this object. (defaults to undefined)
      */
-    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} 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.parentNode = null;
     /**
-     * The first direct child node of this node, or null if this node has no child nodes. @type Node
+     * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
      */
-    this.firstChild = null;
-    /**
-     * The last direct child node of this node, or null if this node has no child nodes. @type Node
+     /**
+     * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
+     * @type Boolean
      */
-    this.lastChild = null;
+  
+
     /**
-     * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
+     * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
+     * @type Boolean
      */
-    this.previousSibling = null;
     /**
-     * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
+     * 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.
      */
-    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;
+    getConnection : function(){
+        return this.useAjax ? Roo.Ajax : this.conn;
     },
 
     /**
-     * Returns true if this node is a leaf
-     * @return {Boolean}
+     * 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.
      */
-    isLeaf : function(){
-        return this.leaf === true;
+    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);
+            }else{
+                this.conn.request(o);
+            }
+        }else{
+            callback.call(scope||this, null, arg, false);
+        }
     },
 
     // private
-    setFirstChild : function(node){
-        this.firstChild = node;
-    },
-
-    //private
-    setLastChild : function(node){
-        this.lastChild = node;
+    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);
     },
 
+    // private
+    update : function(dataSet){
 
-    /**
-     * Returns true if this node is the last child of its parent
-     * @return {Boolean}
-     */
-    isLast : function(){
-       return (!this.parentNode ? true : this.parentNode.lastChild == this);
     },
 
-    /**
-     * Returns true if this node is the first child of its parent
-     * @return {Boolean}
-     */
-    isFirst : function(){
-       return (!this.parentNode ? true : this.parentNode.firstChild == this);
-    },
+    // private
+    updateResponse : function(dataSet){
 
-    hasChildNodes : function(){
-        return !this.isLeaf() && this.childNodes.length > 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">
+ */
 
-    /**
-     * Insert node(s) as the last child node of this node.
-     * @param {Node/Array} node The node or Array of nodes to append
-     * @return {Node} The appended node if single append, or null if an array was passed
-     */
-    appendChild : function(node){
-        var multi = false;
-        if(node instanceof Array){
-            multi = node;
-        }else if(arguments.length > 1){
-            multi = arguments;
-        }
-        // if passed an array or multiple args do them one by one
-        if(multi){
-            for(var i = 0, len = multi.length; i < len; i++) {
-               this.appendChild(multi[i]);
-            }
-        }else{
-            if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
-                return false;
-            }
-            var index = this.childNodes.length;
-            var oldParent = node.parentNode;
-            // it's a move, make sure we move it cleanly
-            if(oldParent){
-                if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
-                    return false;
-                }
-                oldParent.removeChild(node);
-            }
-            index = this.childNodes.length;
-            if(index == 0){
-                this.setFirstChild(node);
-            }
-            this.childNodes.push(node);
-            node.parentNode = this;
-            var ps = this.childNodes[index-1];
-            if(ps){
-                node.previousSibling = ps;
-                ps.nextSibling = node;
-            }else{
-                node.previousSibling = null;
-            }
-            node.nextSibling = null;
-            this.setLastChild(node);
-            node.setOwnerTree(this.getOwnerTree());
-            this.fireEvent("append", this.ownerTree, this, node, index);
-            if(oldParent){
-                node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
-            }
-            return node;
-        }
-    },
-
-    /**
-     * Removes a child node from this node.
-     * @param {Node} node The node to remove
-     * @return {Node} The removed node
-     */
-    removeChild : function(node){
-        var index = this.childNodes.indexOf(node);
-        if(index == -1){
-            return false;
-        }
-        if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
-            return false;
-        }
-
-        // remove it from childNodes collection
-        this.childNodes.splice(index, 1);
-
-        // update siblings
-        if(node.previousSibling){
-            node.previousSibling.nextSibling = node.nextSibling;
-        }
-        if(node.nextSibling){
-            node.nextSibling.previousSibling = node.previousSibling;
-        }
-
-        // update child refs
-        if(this.firstChild == node){
-            this.setFirstChild(node.nextSibling);
-        }
-        if(this.lastChild == node){
-            this.setLastChild(node.previousSibling);
-        }
+/**
+ * @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];
+};
 
-        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;
-    },
+Roo.data.ScriptTagProxy.TRANS_ID = 1000;
 
+Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
     /**
-     * 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
+     * @cfg {String} url The URL from which to request the data object.
      */
-    insertBefore : function(node, refNode){
-        if(!refNode){ // like standard Dom, refNode can be null for append
-            return this.appendChild(node);
-        }
-        // nothing to do
-        if(node == refNode){
-            return false;
-        }
-
-        if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
-            return false;
-        }
-        var index = this.childNodes.indexOf(refNode);
-        var oldParent = node.parentNode;
-        var refIndex = index;
-
-        // when moving internally, indexes will change after remove
-        if(oldParent == this && this.childNodes.indexOf(node) < index){
-            refIndex--;
-        }
-
-        // it's a move, make sure we move it cleanly
-        if(oldParent){
-            if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
-                return false;
-            }
-            oldParent.removeChild(node);
-        }
-        if(refIndex == 0){
-            this.setFirstChild(node);
-        }
-        this.childNodes.splice(refIndex, 0, node);
-        node.parentNode = this;
-        var ps = this.childNodes[refIndex-1];
-        if(ps){
-            node.previousSibling = ps;
-            ps.nextSibling = node;
-        }else{
-            node.previousSibling = null;
-        }
-        node.nextSibling = refNode;
-        refNode.previousSibling = node;
-        node.setOwnerTree(this.getOwnerTree());
-        this.fireEvent("insert", this.ownerTree, this, node, refNode);
-        if(oldParent){
-            node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
-        }
-        return node;
-    },
-
     /**
-     * Returns the child node at the specified index.
-     * @param {Number} index
-     * @return {Node}
+     * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
      */
-    item : function(index){
-        return this.childNodes[index];
-    },
-
+    timeout : 30000,
     /**
-     * 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 {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.
      */
-    replaceChild : function(newChild, oldChild){
-        this.insertBefore(newChild, oldChild);
-        this.removeChild(oldChild);
-        return oldChild;
-    },
-
+    callbackParam : "callback",
     /**
-     * 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 {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
+     * name to the request.
      */
-    indexOf : function(child){
-        return this.childNodes.indexOf(child);
-    },
+    nocache : true,
 
     /**
-     * Returns the tree this node is in.
-     * @return {Tree}
+     * 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.
      */
-    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;
-    },
+    load : function(params, reader, callback, scope, arg){
+        if(this.fireEvent("beforeload", this, params) !== false){
 
-    /**
-     * 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;
-    },
+            var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
 
-    // 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);
+            var url = this.url;
+            url += (url.indexOf("?") != -1 ? "&" : "?") + p;
+            if(this.nocache){
+                url += "&_dc=" + (new Date().getTime());
             }
-        }
-    },
+            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;
 
-    /**
-     * 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);
-    },
+            window[trans.cb] = function(o){
+                conn.handleResponse(o, trans);
+            };
 
-    /**
-     * 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;
-        }
-    },
+            url += String.format("&{0}={1}", this.callbackParam, trans.cb);
 
-    /**
-     * 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);
+            if(this.autoAbort !== false){
+                this.abort();
             }
-        }
-    },
 
-    /**
-     * 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;
-               }
-        }
-    },
+            trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
 
-    /**
-     * 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];
-               }
+            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);
         }
-        return null;
     },
 
-    /**
-     * 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;
+    // private
+    isLoading : function(){
+        return this.trans ? true : false;
     },
 
     /**
-     * Sorts this nodes children using the supplied sort function
-     * @param {Function} fn
-     * @param {Object} scope (optional)
+     * Abort the current server request.
      */
-    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);
-                }
-            }
+    abort : function(){
+        if(this.isLoading()){
+            this.destroyTrans(this.trans);
         }
     },
 
-    /**
-     * 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);
+    // 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){}
+            };
+        }
     },
 
-    /**
-     * Returns true if the passed node is an ancestor (at any point) of this node.
-     * @param {Node} node
-     * @return {Boolean}
-     */
-    isAncestor : function(node){
-        var p = this.parentNode;
-        while(p){
-            if(p == node){
-                return true;
-            }
-            p = p.parentNode;
+    // 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;
         }
-        return false;
+        this.fireEvent("load", this, o, trans.arg);
+        trans.callback.call(trans.scope||window, result, trans.arg, true);
     },
 
-    toString : function(){
-        return "[Node"+(this.id?" "+this.id:"")+"]";
+    // 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:
@@ -22208,476 +22406,337 @@ Roo.extend(Roo.data.Node, Roo.util.Observable, {
  * Fork - LGPL
  * <script type="text/javascript">
  */
 
 /**
- * @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
- */
-Roo.ComponentMgr = function(){
-    var all = new Roo.util.MixedCollection();
-
-    return {
-        /**
-         * Registers a component.
-         * @param {Roo.Component} c The component
-         */
-        register : function(c){
-            all.add(c);
-        },
-
-        /**
-         * Unregisters a component.
-         * @param {Roo.Component} c The component
-         */
-        unregister : function(c){
-            all.remove(c);
-        },
-
-        /**
-         * Returns a component by id
-         * @param {String} id The component id
-         */
-        get : function(id){
-            return all.get(id);
-        },
-
-        /**
-         * Registers a function that will be called when a specified component is added to ComponentMgr
-         * @param {String} id The component id
-         * @param {Funtction} fn The callback function
-         * @param {Object} scope The scope of the callback
-         */
-        onAvailable : function(id, fn, scope){
-            all.on("add", function(index, o){
-                if(o.id == id){
-                    fn.call(scope || o, o);
-                    all.un("add", fn, scope);
-                }
-            });
-        }
-    };
-}();/*
- * 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.Component
- * @extends Roo.util.Observable
- * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
- * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
- * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
- * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
- * All visual components (widgets) that require rendering into a layout should subclass Component.
+ * @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.
  * @constructor
- * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
- * element and its id used as the component id.  If a string is passed, it is assumed to be the id of an existing element
- * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
+ * 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.Component = function(config){
-    config = config || {};
-    if(config.tagName || config.dom || typeof config == "string"){ // element object
-        config = {el: config, id: config.id || config};
-    }
-    this.initialConfig = config;
-
-    Roo.apply(this, config);
-    this.addEvents({
-        /**
-         * @event disable
-         * Fires after the component is disabled.
-            * @param {Roo.Component} this
-            */
-        disable : true,
-        /**
-         * @event enable
-         * Fires after the component is enabled.
-            * @param {Roo.Component} this
-            */
-        enable : true,
-        /**
-         * @event beforeshow
-         * Fires before the component is shown.  Return false to stop the show.
-            * @param {Roo.Component} this
-            */
-        beforeshow : true,
-        /**
-         * @event show
-         * Fires after the component is shown.
-            * @param {Roo.Component} this
-            */
-        show : true,
-        /**
-         * @event beforehide
-         * Fires before the component is hidden. Return false to stop the hide.
-            * @param {Roo.Component} this
-            */
-        beforehide : true,
-        /**
-         * @event hide
-         * Fires after the component is hidden.
-            * @param {Roo.Component} this
-            */
-        hide : true,
-        /**
-         * @event beforerender
-         * Fires before the component is rendered. Return false to stop the render.
-            * @param {Roo.Component} this
-            */
-        beforerender : true,
-        /**
-         * @event render
-         * Fires after the component is rendered.
-            * @param {Roo.Component} this
-            */
-        render : true,
-        /**
-         * @event beforedestroy
-         * Fires before the component is destroyed. Return false to stop the destroy.
-            * @param {Roo.Component} this
-            */
-        beforedestroy : true,
-        /**
-         * @event destroy
-         * Fires after the component is destroyed.
-            * @param {Roo.Component} this
-            */
-        destroy : true
+Roo.data.JsonReader = function(meta, recordType){
+    
+    meta = meta || {};
+    // set some defaults:
+    Roo.applyIf(meta, {
+        totalProperty: 'total',
+        successProperty : 'success',
+        root : 'data',
+        id : 'id'
     });
-    if(!this.id){
-        this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
-    }
-    Roo.ComponentMgr.register(this);
-    Roo.Component.superclass.constructor.call(this);
-    this.initComponent();
-    if(this.renderTo){ // not supported by all components yet. use at your own risk!
-        this.render(this.renderTo);
-        delete this.renderTo;
-    }
+    
+    Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
 };
-
-/** @private */
-Roo.Component.AUTO_ID = 1000;
-
-Roo.extend(Roo.Component, Roo.util.Observable, {
-    /**
-     * @scope Roo.Component.prototype
-     * @type {Boolean}
-     * true if this component is hidden. Read-only.
-     */
-    hidden : false,
-    /**
-     * @type {Boolean}
-     * true if this component is disabled. Read-only.
-     */
-    disabled : false,
-    /**
-     * @type {Boolean}
-     * true if this component has been rendered. Read-only.
-     */
-    rendered : false,
+Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
     
-    /** @cfg {String} disableClass
-     * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
-     */
-    disabledClass : "x-item-disabled",
-       /** @cfg {Boolean} allowDomMove
-        * Whether the component can move the Dom node when rendering (defaults to true).
-        */
-    allowDomMove : true,
-    /** @cfg {String} hideMode
-     * How this component should hidden. Supported values are
-     * "visibility" (css visibility), "offsets" (negative offset position) and
-     * "display" (css display) - defaults to "display".
-     */
-    hideMode: 'display',
-
-    /** @private */
-    ctype : "Roo.Component",
-
-    /**
-     * @cfg {String} actionMode 
-     * which property holds the element that used for  hide() / show() / disable() / enable()
-     * default is 'el' 
-     */
-    actionMode : "el",
-
-    /** @private */
-    getActionEl : function(){
-        return this[this.actionMode];
-    },
-
-    initComponent : Roo.emptyFn,
-    /**
-     * If this is a lazy rendering component, render it to its container element.
-     * @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();
-            }
-        }
-        return this;
-    },
-
-    /** @private */
-    // default function is not really useful
-    onRender : function(ct, position){
-        if(this.el){
-            this.el = Roo.get(this.el);
-            if(this.allowDomMove !== false){
-                ct.dom.insertBefore(this.el.dom, position);
-            }
-        }
-    },
-
-    /** @private */
-    getAutoCreate : function(){
-        var cfg = typeof this.autoCreate == "object" ?
-                      this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
-        if(this.id && !cfg.id){
-            cfg.id = this.id;
-        }
-        return cfg;
-    },
-
-    /** @private */
-    afterRender : Roo.emptyFn,
-
-    /**
-     * Destroys this component by purging any event listeners, removing the component's element from the DOM,
-     * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
-     */
-    destroy : function(){
-        if(this.fireEvent("beforedestroy", this) !== false){
-            this.purgeListeners();
-            this.beforeDestroy();
-            if(this.rendered){
-                this.el.removeAllListeners();
-                this.el.remove();
-                if(this.actionMode == "container"){
-                    this.container.remove();
-                }
-            }
-            this.onDestroy();
-            Roo.ComponentMgr.unregister(this);
-            this.fireEvent("destroy", this);
-        }
-    },
-
-       /** @private */
-    beforeDestroy : function(){
-
-    },
-
-       /** @private */
-       onDestroy : function(){
-
-    },
-
-    /**
-     * Returns the underlying {@link Roo.Element}.
-     * @return {Roo.Element} The element
-     */
-    getEl : function(){
-        return this.el;
-    },
-
     /**
-     * Returns the id of this component.
-     * @return {String}
+     * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
+     * Used by Store query builder to append _requestMeta to params.
+     * 
      */
-    getId : function(){
-        return this.id;
-    },
-
+    metaFromRemote : false,
     /**
-     * Try to focus this component.
-     * @param {Boolean} selectText True to also select the text in this component (if applicable)
-     * @return {Roo.Component} this
+     * 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.
      */
-    focus : function(selectText){
-        if(this.rendered){
-            this.el.focus();
-            if(selectText === true){
-                this.el.dom.select();
-            }
+    read : function(response){
+        var json = response.responseText;
+       
+        var o = /* eval:var:o */ eval("("+json+")");
+        if(!o) {
+            throw {message: "JsonReader.read: Json object not found"};
         }
-        return this;
-    },
-
-    /** @private */
-    blur : function(){
-        if(this.rendered){
-            this.el.blur();
+        
+        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;
+        return this.readRecords(o);
     },
 
-    /**
-     * Disable this component.
-     * @return {Roo.Component} this
-     */
-    disable : function(){
-        if(this.rendered){
-            this.onDisable();
-        }
-        this.disabled = true;
-        this.fireEvent("disable", this);
-        return this;
-    },
+    // private function a store will implement
+    onMetaChange : function(meta, recordType, o){
 
-       // private
-    onDisable : function(){
-        this.getActionEl().addClass(this.disabledClass);
-        this.el.dom.disabled = true;
     },
 
     /**
-     * Enable this component.
-     * @return {Roo.Component} this
-     */
-    enable : function(){
-        if(this.rendered){
-            this.onEnable();
-        }
-        this.disabled = false;
-        this.fireEvent("enable", this);
-        return this;
+        * @ignore
+        */
+    simpleAccess: function(obj, subsc) {
+       return obj[subsc];
     },
 
-       // private
-    onEnable : function(){
-        this.getActionEl().removeClass(this.disabledClass);
-        this.el.dom.disabled = false;
-    },
+       /**
+        * @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;
+        };
+    }(),
 
     /**
-     * Convenience function for setting disabled/enabled by boolean.
-     * @param {Boolean} disabled
+     * 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.
      */
-    setDisabled : function(disabled){
-        this[disabled ? "disable" : "enable"]();
-    },
+    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.prototype.fields, fi = f.items, fl = f.length;
 
-    /**
-     * Show this component.
-     * @return {Roo.Component} this
-     */
-    show: function(){
-        if(this.fireEvent("beforeshow", this) !== false){
-            this.hidden = false;
-            if(this.rendered){
-                this.onShow();
+//      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);
             }
-            this.fireEvent("show", this);
-        }
-        return this;
-    },
-
-    // private
-    onShow : function(){
-        var ae = this.getActionEl();
-        if(this.hideMode == 'visibility'){
-            ae.dom.style.visibility = "visible";
-        }else if(this.hideMode == 'offsets'){
-            ae.removeClass('x-hidden');
-        }else{
-            ae.dom.style.display = "";
         }
-    },
 
-    /**
-     * Hide this component.
-     * @return {Roo.Component} this
-     */
-    hide: function(){
-        if(this.fireEvent("beforehide", this) !== false){
-            this.hidden = true;
-            if(this.rendered){
-                this.onHide();
+       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;
             }
-            this.fireEvent("hide", this);
         }
-        return this;
-    },
-
-    // private
-    onHide : function(){
-        var ae = this.getActionEl();
-        if(this.hideMode == 'visibility'){
-            ae.dom.style.visibility = "hidden";
-        }else if(this.hideMode == 'offsets'){
-            ae.addClass('x-hidden');
-        }else{
-            ae.dom.style.display = "none";
+        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);
+               }
+               var record = new Record(values, id);
+               record.json = n;
+               records[i] = record;
+           }
+           return {
+            raw : o,
+               success : success,
+               records : records,
+               totalRecords : totalRecords
+           };
+    }
+});/*
+ * 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, {
     /**
-     * Convenience function to hide or show this component by boolean.
-     * @param {Boolean} visible True to show, false to hide
-     * @return {Roo.Component} this
+     * 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.
      */
-    setVisible: function(visible){
-        if(visible) {
-            this.show();
-        }else{
-            this.hide();
+    read : function(response){
+        var doc = response.responseXML;
+        if(!doc) {
+            throw {message: "XmlReader.read: XML Document not available"};
         }
-        return this;
+        return this.readRecords(doc);
     },
 
     /**
-     * Returns true if this component is visible.
+     * 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.
      */
-    isVisible : function(){
-        return this.getActionEl().isVisible();
-    },
+    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;
+           }
 
-    cloneConfig : function(overrides){
-        overrides = overrides || {};
-        var id = overrides.id || Roo.id();
-        var cfg = Roo.applyIf(overrides, this.initialConfig);
-        cfg.id = id; // prevent dup id
-        return new this.constructor(cfg);
+           return {
+               success : success,
+               records : records,
+               totalRecords : totalRecords || records.length
+           };
     }
 });/*
  * Based on:
@@ -22689,651 +22748,816 @@ Roo.extend(Roo.Component, 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>
+ * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
  * @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} 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}.
  */
+Roo.data.ArrayReader = function(meta, recordType){
+    Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
+};
 
-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} data A data block which is used by an 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
+           };
     }
-    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.extend(Roo.Layer, Roo.Element, {
+    Roo.data.Tree.superclass.constructor.call(this);
+};
 
-    getZIndex : function(){
-        return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
-    },
+Roo.extend(Roo.data.Tree, Roo.util.Observable, {
+    pathSeparator: "/",
 
-    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;
+    proxyNodeEvent : function(){
+        return this.fireEvent.apply(this, arguments);
     },
 
-    hideShim : function(){
-        if(this.shim){
-            this.shim.setDisplayed(false);
-            shims.push(this.shim);
-            delete this.shim;
-        }
+    /**
+     * Returns the root node for this tree.
+     * @return {Node}
+     */
+    getRootNode : function(){
+        return this.root;
     },
 
-    disableShadow : function(){
-        if(this.shadow){
-            this.shadowDisabled = true;
-            this.shadow.hide();
-            this.lastShadowOffset = this.shadowOffset;
-            this.shadowOffset = 0;
-        }
+    /**
+     * 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;
     },
 
-    enableShadow : function(show){
-        if(this.shadow){
-            this.shadowDisabled = false;
-            this.shadowOffset = this.lastShadowOffset;
-            delete this.lastShadowOffset;
-            if(show){
-                this.sync(true);
-            }
-        }
+    /**
+     * Gets a node in this tree by its id.
+     * @param {String} id
+     * @return {Node}
+     */
+    getNodeById : function(id){
+        return this.nodeHash[id];
     },
 
-    // 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);
+    registerNode : function(node){
+        this.nodeHash[node.id] = node;
+    },
 
-            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);
-            }
-            
-        }
+    unregisterNode : function(node){
+        delete this.nodeHash[node.id];
     },
 
-    // private
-    destroy : function(){
-        this.hideShim();
-        if(this.shadow){
-            this.shadow.hide();
+    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;
+    }
+     
+    
+    /**
+     * 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
+     */
+    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;
+
+    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(oldParent){
+                node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
             }
+            return node;
         }
     },
 
-    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]);
+    /**
+     * 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
-    hideAction : function(){
-        this.visible = false;
-        if(this.useDisplay === true){
-            this.setDisplayed(false);
-        }else{
-            this.setLeftTop(-10000,-10000);
+        // 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;
         }
-    },
 
-    // overridden Element method
-    setVisible : function(v, a, d, c, e){
-        if(v){
-            this.showAction();
+        // update child refs
+        if(this.firstChild == node){
+            this.setFirstChild(node.nextSibling);
         }
-        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();
-            }
+        if(this.lastChild == node){
+            this.setLastChild(node.previousSibling);
         }
-    },
 
-    storeXY : function(xy){
-        delete this.lastLT;
-        this.lastXY = xy;
+        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;
     },
 
-    storeLeftTop : function(left, top){
-        delete this.lastXY;
-        this.lastLT = [left, top];
-    },
+    /**
+     * 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
-    beforeFx : function(){
-        this.beforeAction();
-        return Roo.Layer.superclass.beforeFx.apply(this, arguments);
-    },
+        if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
+            return false;
+        }
+        var index = this.childNodes.indexOf(refNode);
+        var oldParent = node.parentNode;
+        var refIndex = index;
 
-    // private
-    afterFx : function(){
-        Roo.Layer.superclass.afterFx.apply(this, arguments);
-        this.sync(this.isVisible());
-    },
+        // when moving internally, indexes will change after remove
+        if(oldParent == this && this.childNodes.indexOf(node) < index){
+            refIndex--;
+        }
 
-    // private
-    beforeAction : function(){
-        if(!this.updating && this.shadow){
-            this.shadow.hide();
+        // 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;
     },
 
-    // overridden Element method
-    setLeft : function(left){
-        this.storeLeftTop(left, this.getTop(true));
-        supr.setLeft.apply(this, arguments);
-        this.sync();
+    /**
+     * Returns the child node at the specified index.
+     * @param {Number} index
+     * @return {Node}
+     */
+    item : function(index){
+        return this.childNodes[index];
     },
 
-    setTop : function(top){
-        this.storeLeftTop(this.getLeft(true), top);
-        supr.setTop.apply(this, arguments);
-        this.sync();
+    /**
+     * 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;
     },
 
-    setLeftTop : function(left, top){
-        this.storeLeftTop(left, top);
-        supr.setLeftTop.apply(this, arguments);
-        this.sync();
+    /**
+     * 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);
     },
 
-    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 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;
     },
 
-    // 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();
+    /**
+     * 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;
     },
 
-    // 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();
+    // 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);
+            }
         }
     },
 
-    // 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();
+    /**
+     * 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);
     },
 
-    // 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
+     * 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)
      */
-    setZIndex : function(zindex){
-        this.zindex = zindex;
-        this.setStyle("z-index", zindex + 2);
-        if(this.shadow){
-            this.shadow.setZIndex(zindex + 1);
-        }
-        if(this.shim){
-            this.shim.setStyle("z-index", zindex);
-        }
-    }
-});
-})();/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-
-
-/**
- * @class Roo.Shadow
- * Simple class that can provide a shadow effect for any element.  Note that the element MUST be absolutely positioned,
- * and the shadow does not provide any shimming.  This should be used only in simple cases -- for more advanced
- * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
- * @constructor
- * Create a new Shadow
- * @param {Object} config The config object
- */
-Roo.Shadow = function(config){
-    Roo.apply(this, config);
-    if(typeof this.mode != "string"){
-        this.mode = this.defaultMode;
-    }
-    var o = this.offset, a = {h: 0};
-    var rad = Math.floor(this.offset/2);
-    switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
-        case "drop":
-            a.w = 0;
-            a.l = a.t = o;
-            a.t -= 1;
-            if(Roo.isIE){
-                a.l -= this.offset + rad;
-                a.t -= this.offset + rad;
-                a.w -= rad;
-                a.h -= rad;
-                a.t += 1;
-            }
-        break;
-        case "sides":
-            a.w = (o*2);
-            a.l = -o;
-            a.t = o-1;
-            if(Roo.isIE){
-                a.l -= (this.offset - rad);
-                a.t -= this.offset + rad;
-                a.l += 1;
-                a.w -= (this.offset - rad)*2;
-                a.w -= rad + 1;
-                a.h -= 1;
-            }
-        break;
-        case "frame":
-            a.w = a.h = (o*2);
-            a.l = a.t = -o;
-            a.t += 1;
-            a.h -= 2;
-            if(Roo.isIE){
-                a.l -= (this.offset - rad);
-                a.t -= (this.offset - rad);
-                a.l += 1;
-                a.w -= (this.offset + rad + 1);
-                a.h -= (this.offset + rad);
-                a.h += 1;
+    bubble : function(fn, scope, args){
+        var p = this;
+        while(p){
+            if(fn.call(scope || p, args || p) === false){
+                break;
             }
-        break;
-    };
-
-    this.adjusts = a;
-};
+            p = p.parentNode;
+        }
+    },
 
-Roo.Shadow.prototype = {
     /**
-     * @cfg {String} mode
-     * The shadow display mode.  Supports the following options:<br />
-     * sides: Shadow displays on both sides and bottom only<br />
-     * frame: Shadow displays equally on all four sides<br />
-     * drop: Traditional bottom-right drop shadow (default)
+     * 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);
+            }
+        }
+    },
+
     /**
-     * @cfg {String} offset
-     * The number of pixels to offset the shadow from the element (defaults to 4)
+     * 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)
      */
-    offset: 4,
-
-    // private
-    defaultMode: "drop",
+    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;
+               }
+        }
+    },
 
     /**
-     * Displays the shadow under the target element
-     * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
+     * 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
      */
-    show : function(target){
-        target = Roo.get(target);
-        if(!this.el){
-            this.el = Roo.Shadow.Pool.pull();
-            if(this.el.dom.nextSibling != target.dom){
-                this.el.insertBefore(target);
-            }
-        }
-        this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
-        if(Roo.isIE){
-            this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
+    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];
+               }
         }
-        this.realign(
-            target.getLeft(true),
-            target.getTop(true),
-            target.getWidth(),
-            target.getHeight()
-        );
-        this.el.dom.style.display = "block";
+        return null;
     },
 
     /**
-     * Returns true if the shadow is visible, else false
+     * 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
      */
-    isVisible : function(){
-        return this.el ? true : false;  
+    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;
     },
 
     /**
-     * Direct alignment when values are already available. Show must be called at least once before
-     * calling this method to ensure it is initialized.
-     * @param {Number} left The target element left position
-     * @param {Number} top The target element top position
-     * @param {Number} width The target element width
-     * @param {Number} height The target element height
+     * Sorts this nodes children using the supplied sort function
+     * @param {Function} fn
+     * @param {Object} scope (optional)
      */
-    realign : function(l, t, w, h){
-        if(!this.el){
-            return;
-        }
-        var a = this.adjusts, d = this.el.dom, s = d.style;
-        var iea = 0;
-        s.left = (l+a.l)+"px";
-        s.top = (t+a.t)+"px";
-        var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
-        if(s.width != sws || s.height != shs){
-            s.width = sws;
-            s.height = shs;
-            if(!Roo.isIE){
-                var cn = d.childNodes;
-                var sww = Math.max(0, (sw-12))+"px";
-                cn[0].childNodes[1].style.width = sww;
-                cn[1].childNodes[1].style.width = sww;
-                cn[2].childNodes[1].style.width = sww;
-                cn[1].style.height = Math.max(0, (sh-12))+"px";
+    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);
+                }
             }
         }
     },
 
     /**
-     * Hides this shadow
+     * Returns true if this node is an ancestor (at any point) of the passed node.
+     * @param {Node} node
+     * @return {Boolean}
      */
-    hide : function(){
-        if(this.el){
-            this.el.dom.style.display = "none";
-            Roo.Shadow.Pool.push(this.el);
-            delete this.el;
-        }
+    contains : function(node){
+        return node.isAncestor(this);
     },
 
     /**
-     * Adjust the z-index of this shadow
-     * @param {Number} zindex The new z-index
+     * Returns true if the passed node is an ancestor (at any point) of this node.
+     * @param {Node} node
+     * @return {Boolean}
      */
-    setZIndex : function(z){
-        this.zIndex = z;
-        if(this.el){
-            this.el.setStyle("z-index", z);
-        }
-    }
-};
-
-// Private utility class that manages the internal Shadow cache
-Roo.Shadow.Pool = function(){
-    var p = [];
-    var markup = Roo.isIE ?
-                 '<div class="x-ie-shadow"></div>' :
-                 '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
-    return {
-        pull : function(){
-            var sh = p.shift();
-            if(!sh){
-                sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
-                sh.autoBoxAdjust = false;
+    isAncestor : function(node){
+        var p = this.parentNode;
+        while(p){
+            if(p == node){
+                return true;
             }
-            return sh;
-        },
-
-        push : function(sh){
-            p.push(sh);
+            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.
@@ -23343,279 +23567,454 @@ Roo.Shadow.Pool = function(){
  * Fork - LGPL
  * <script type="text/javascript">
  */
-
+ (function(){ 
 /**
- * @class Roo.BoxComponent
- * @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
- * layout containers.
+ * @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 {Roo.Element/String/Object} config The configuration options.
+ * @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.BoxComponent = function(config){
-    Roo.Component.call(this, config);
-    this.addEvents({
-        /**
-         * @event resize
-         * Fires after the component is resized.
-            * @param {Roo.Component} this
-            * @param {Number} adjWidth The box-adjusted width that was set
-            * @param {Number} adjHeight The box-adjusted height that was set
-            * @param {Number} rawWidth The width that was originally specified
-            * @param {Number} rawHeight The height that was originally specified
-            */
-        resize : true,
-        /**
-         * @event move
-         * Fires after the component is moved.
-            * @param {Roo.Component} this
-            * @param {Number} x The new x position
-            * @param {Number} y The new y position
-            */
-        move : true
-    });
+
+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();
 };
 
-Roo.extend(Roo.BoxComponent, Roo.Component, {
-    // private, set in afterRender to signify that the component has been rendered
-    boxReady : false,
-    // private, used to defer height settings to subclasses
-    deferHeight: false,
-    /** @cfg {Number} width
-     * width (optional) size of component
-     */
-     /** @cfg {Number} height
-     * height (optional) size of component
-     */
-     
-    /**
-     * Sets the width and height of the component.  This method fires the resize event.  This method can accept
-     * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
-     * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
-     * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
-     * @return {Roo.BoxComponent} this
-     */
-    setSize : function(w, h){
-        // support for standard size objects
-        if(typeof w == 'object'){
-            h = w.height;
-            w = w.width;
-        }
-        // not rendered
-        if(!this.boxReady){
-            this.width = w;
-            this.height = h;
-            return this;
-        }
+var supr = Roo.Element.prototype;
 
-        // prevent recalcs when not needed
-        if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
-            return this;
-        }
-        this.lastSize = {width: w, height: h};
+// shims are shared among layer to keep from having 100 iframes
+var shims = [];
 
-        var adj = this.adjustSize(w, h);
-        var aw = adj.width, ah = adj.height;
-        if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
-            var rz = this.getResizeEl();
-            if(!this.deferHeight && aw !== undefined && ah !== undefined){
-                rz.setSize(aw, ah);
-            }else if(!this.deferHeight && ah !== undefined){
-                rz.setHeight(ah);
-            }else if(aw !== undefined){
-                rz.setWidth(aw);
-            }
-            this.onResize(aw, ah, w, h);
-            this.fireEvent('resize', this, aw, ah, w, h);
-        }
-        return this;
-    },
+Roo.extend(Roo.Layer, Roo.Element, {
 
-    /**
-     * Gets the current size of the component's underlying element.
-     * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
-     */
-    getSize : function(){
-        return this.el.getSize();
+    getZIndex : function(){
+        return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
     },
 
-    /**
-     * Gets the current XY position of the component's underlying element.
-     * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
-     * @return {Array} The XY position of the element (e.g., [100, 200])
-     */
-    getPosition : function(local){
-        if(local === true){
-            return [this.el.getLeft(true), this.el.getTop(true)];
+    getShim : function(){
+        if(!this.useShim){
+            return null;
         }
-        return this.xy || this.el.getXY();
+        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;
     },
 
-    /**
-     * Gets the current box measurements of the component's underlying element.
-     * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
-     * @returns {Object} box An object in the format {x, y, width, height}
-     */
-    getBox : function(local){
-        var s = this.el.getSize();
-        if(local){
-            s.x = this.el.getLeft(true);
-            s.y = this.el.getTop(true);
-        }else{
-            var xy = this.xy || this.el.getXY();
-            s.x = xy[0];
-            s.y = xy[1];
+    hideShim : function(){
+        if(this.shim){
+            this.shim.setDisplayed(false);
+            shims.push(this.shim);
+            delete this.shim;
         }
-        return s;
     },
 
-    /**
-     * Sets the current box measurements of the component's underlying element.
-     * @param {Object} box An object in the format {x, y, width, height}
-     * @returns {Roo.BoxComponent} this
-     */
-    updateBox : function(box){
-        this.setSize(box.width, box.height);
-        this.setPagePosition(box.x, box.y);
-        return this;
+    disableShadow : function(){
+        if(this.shadow){
+            this.shadowDisabled = true;
+            this.shadow.hide();
+            this.lastShadowOffset = this.shadowOffset;
+            this.shadowOffset = 0;
+        }
     },
 
-    // protected
-    getResizeEl : function(){
-        return this.resizeEl || this.el;
+    enableShadow : function(show){
+        if(this.shadow){
+            this.shadowDisabled = false;
+            this.shadowOffset = this.lastShadowOffset;
+            delete this.lastShadowOffset;
+            if(show){
+                this.sync(true);
+            }
+        }
     },
 
-    // protected
-    getPositionEl : function(){
-        return this.positionEl || this.el;
-    },
+    // 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();
 
-    /**
-     * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
-     * This method fires the move event.
-     * @param {Number} left The new left
-     * @param {Number} top The new top
-     * @returns {Roo.BoxComponent} this
-     */
-    setPosition : function(x, y){
-        this.x = x;
-        this.y = y;
-        if(!this.boxReady){
-            return this;
-        }
-        var adj = this.adjustPosition(x, y);
-        var ax = adj.x, ay = adj.y;
+            var w = this.getWidth(),
+                h = this.getHeight();
 
-        var el = this.getPositionEl();
-        if(ax !== undefined || ay !== undefined){
-            if(ax !== undefined && ay !== undefined){
-                el.setLeftTop(ax, ay);
-            }else if(ax !== undefined){
-                el.setLeft(ax);
-            }else if(ay !== undefined){
-                el.setTop(ay);
+            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);
             }
-            this.onPosition(ax, ay);
-            this.fireEvent('move', this, ax, ay);
+            
         }
-        return this;
     },
 
-    /**
-     * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
-     * This method fires the move event.
-     * @param {Number} x The new x position
-     * @param {Number} y The new y position
-     * @returns {Roo.BoxComponent} this
-     */
-    setPagePosition : function(x, y){
-        this.pageX = x;
-        this.pageY = y;
-        if(!this.boxReady){
-            return;
+    // private
+    destroy : function(){
+        this.hideShim();
+        if(this.shadow){
+            this.shadow.hide();
         }
-        if(x === undefined || y === undefined){ // cannot translate undefined points
-            return;
+        this.removeAllListeners();
+        var pn = this.dom.parentNode;
+        if(pn){
+            pn.removeChild(this.dom);
         }
-        var p = this.el.translatePoints(x, y);
-        this.setPosition(p.left, p.top);
-        return this;
+        Roo.Element.uncache(this.id);
+    },
+
+    remove : function(){
+        this.destroy();
     },
 
     // private
-    onRender : function(ct, position){
-        Roo.BoxComponent.superclass.onRender.call(this, ct, position);
-        if(this.resizeEl){
-            this.resizeEl = Roo.get(this.resizeEl);
+    beginUpdate : function(){
+        this.updating = true;
+    },
+
+    // private
+    endUpdate : function(){
+        this.updating = false;
+        this.sync(true);
+    },
+
+    // private
+    hideUnders : function(negOffset){
+        if(this.shadow){
+            this.shadow.hide();
         }
-        if(this.positionEl){
-            this.positionEl = Roo.get(this.positionEl);
+        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
-    afterRender : function(){
-        Roo.BoxComponent.superclass.afterRender.call(this);
-        this.boxReady = true;
-        this.setSize(this.width, this.height);
-        if(this.x || this.y){
-            this.setPosition(this.x, this.y);
+    showAction : function(){
+        this.visible = true; // track visibility to prevent getStyle calls
+        if(this.useDisplay === true){
+            this.setDisplayed("");
+        }else if(this.lastXY){
+            supr.setXY.call(this, this.lastXY);
+        }else if(this.lastLT){
+            supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
         }
-        if(this.pageX || this.pageY){
-            this.setPagePosition(this.pageX, this.pageY);
+    },
+
+    // private
+    hideAction : function(){
+        this.visible = false;
+        if(this.useDisplay === true){
+            this.setDisplayed(false);
+        }else{
+            this.setLeftTop(-10000,-10000);
         }
     },
 
-    /**
-     * Force the component's size to recalculate based on the underlying element's current height and width.
-     * @returns {Roo.BoxComponent} this
-     */
-    syncSize : function(){
-        delete this.lastSize;
-        this.setSize(this.el.getWidth(), this.el.getHeight());
-        return this;
+    // 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();
+            }
+        }
     },
 
-    /**
-     * Called after the component is resized, this method is empty by default but can be implemented by any
-     * subclass that needs to perform custom logic after a resize occurs.
-     * @param {Number} adjWidth The box-adjusted width that was set
-     * @param {Number} adjHeight The box-adjusted height that was set
-     * @param {Number} rawWidth The width that was originally specified
-     * @param {Number} rawHeight The height that was originally specified
-     */
-    onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
+    storeXY : function(xy){
+        delete this.lastLT;
+        this.lastXY = xy;
+    },
 
+    storeLeftTop : function(left, top){
+        delete this.lastXY;
+        this.lastLT = [left, top];
     },
 
-    /**
-     * Called after the component is moved, this method is empty by default but can be implemented by any
-     * subclass that needs to perform custom logic after a move occurs.
-     * @param {Number} x The new x position
-     * @param {Number} y The new y position
-     */
-    onPosition : function(x, y){
+    // 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
-    adjustSize : function(w, h){
-        if(this.autoWidth){
-            w = 'auto';
+    beforeAction : function(){
+        if(!this.updating && this.shadow){
+            this.shadow.hide();
         }
-        if(this.autoHeight){
-            h = 'auto';
+    },
+
+    // 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();
         }
-        return {width : w, height: h};
     },
 
     // private
-    adjustPosition : function(x, y){
-        return {x : x, y: y};
+    createCB : function(c){
+        var el = this;
+        return function(){
+            el.constrainXY();
+            el.sync(true);
+            if(c){
+                c();
+            }
+        };
+    },
+
+    // overridden Element method
+    setX : function(x, a, d, c, e){
+        this.setXY([x, this.getY()], a, d, c, e);
+    },
+
+    // overridden Element method
+    setY : function(y, a, d, c, e){
+        this.setXY([this.getX(), y], a, d, c, e);
+    },
+
+    // overridden Element method
+    setSize : function(w, h, a, d, c, e){
+        this.beforeAction();
+        var cb = this.createCB(c);
+        supr.setSize.call(this, w, h, a, d, cb, e);
+        if(!a){
+            cb();
+        }
+    },
+
+    // overridden Element method
+    setWidth : function(w, a, d, c, e){
+        this.beforeAction();
+        var cb = this.createCB(c);
+        supr.setWidth.call(this, w, a, d, cb, e);
+        if(!a){
+            cb();
+        }
+    },
+
+    // overridden Element method
+    setHeight : function(h, a, d, c, e){
+        this.beforeAction();
+        var cb = this.createCB(c);
+        supr.setHeight.call(this, h, a, d, cb, e);
+        if(!a){
+            cb();
+        }
+    },
+
+    // overridden Element method
+    setBounds : function(x, y, w, h, a, d, c, e){
+        this.beforeAction();
+        var cb = this.createCB(c);
+        if(!a){
+            this.storeXY([x, y]);
+            supr.setXY.call(this, [x, y]);
+            supr.setSize.call(this, w, h, a, d, cb, e);
+            cb();
+        }else{
+            supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
+        }
+        return this;
+    },
+    
+    /**
+     * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
+     * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
+     * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
+     * @param {Number} zindex The new z-index to set
+     * @return {this} The Layer
+     */
+    setZIndex : function(zindex){
+        this.zindex = zindex;
+        this.setStyle("z-index", zindex + 2);
+        if(this.shadow){
+            this.shadow.setZIndex(zindex + 1);
+        }
+        if(this.shim){
+            this.shim.setStyle("z-index", zindex);
+        }
     }
-});/*
+});
+})();/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -23628,32 +24027,229 @@ Roo.extend(Roo.BoxComponent, Roo.Component, {
 
 
 /**
- * @class Roo.SplitBar
- * @extends Roo.util.Observable
- * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
- * <br><br>
- * Usage:
- * <pre><code>
-var split = new Roo.SplitBar("elementToDrag", "elementToSize",
-                   Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
-split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
-split.minSize = 100;
-split.maxSize = 600;
-split.animate = true;
-split.on('moved', splitterMoved);
-</code></pre>
+ * @class Roo.Shadow
+ * Simple class that can provide a shadow effect for any element.  Note that the element MUST be absolutely positioned,
+ * and the shadow does not provide any shimming.  This should be used only in simple cases -- for more advanced
+ * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
  * @constructor
- * Create a new SplitBar
- * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
- * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
- * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
- * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or  
-                        Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
-                        position of the SplitBar).
+ * Create a new Shadow
+ * @param {Object} config The config object
  */
-Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
-    
-    /** @private */
+Roo.Shadow = function(config){
+    Roo.apply(this, config);
+    if(typeof this.mode != "string"){
+        this.mode = this.defaultMode;
+    }
+    var o = this.offset, a = {h: 0};
+    var rad = Math.floor(this.offset/2);
+    switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
+        case "drop":
+            a.w = 0;
+            a.l = a.t = o;
+            a.t -= 1;
+            if(Roo.isIE){
+                a.l -= this.offset + rad;
+                a.t -= this.offset + rad;
+                a.w -= rad;
+                a.h -= rad;
+                a.t += 1;
+            }
+        break;
+        case "sides":
+            a.w = (o*2);
+            a.l = -o;
+            a.t = o-1;
+            if(Roo.isIE){
+                a.l -= (this.offset - rad);
+                a.t -= this.offset + rad;
+                a.l += 1;
+                a.w -= (this.offset - rad)*2;
+                a.w -= rad + 1;
+                a.h -= 1;
+            }
+        break;
+        case "frame":
+            a.w = a.h = (o*2);
+            a.l = a.t = -o;
+            a.t += 1;
+            a.h -= 2;
+            if(Roo.isIE){
+                a.l -= (this.offset - rad);
+                a.t -= (this.offset - rad);
+                a.l += 1;
+                a.w -= (this.offset + rad + 1);
+                a.h -= (this.offset + rad);
+                a.h += 1;
+            }
+        break;
+    };
+
+    this.adjusts = a;
+};
+
+Roo.Shadow.prototype = {
+    /**
+     * @cfg {String} mode
+     * The shadow display mode.  Supports the following options:<br />
+     * sides: Shadow displays on both sides and bottom only<br />
+     * frame: Shadow displays equally on all four sides<br />
+     * drop: Traditional bottom-right drop shadow (default)
+     */
+    /**
+     * @cfg {String} offset
+     * The number of pixels to offset the shadow from the element (defaults to 4)
+     */
+    offset: 4,
+
+    // private
+    defaultMode: "drop",
+
+    /**
+     * Displays the shadow under the target element
+     * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
+     */
+    show : function(target){
+        target = Roo.get(target);
+        if(!this.el){
+            this.el = Roo.Shadow.Pool.pull();
+            if(this.el.dom.nextSibling != target.dom){
+                this.el.insertBefore(target);
+            }
+        }
+        this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
+        if(Roo.isIE){
+            this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
+        }
+        this.realign(
+            target.getLeft(true),
+            target.getTop(true),
+            target.getWidth(),
+            target.getHeight()
+        );
+        this.el.dom.style.display = "block";
+    },
+
+    /**
+     * Returns true if the shadow is visible, else false
+     */
+    isVisible : function(){
+        return this.el ? true : false;  
+    },
+
+    /**
+     * Direct alignment when values are already available. Show must be called at least once before
+     * calling this method to ensure it is initialized.
+     * @param {Number} left The target element left position
+     * @param {Number} top The target element top position
+     * @param {Number} width The target element width
+     * @param {Number} height The target element height
+     */
+    realign : function(l, t, w, h){
+        if(!this.el){
+            return;
+        }
+        var a = this.adjusts, d = this.el.dom, s = d.style;
+        var iea = 0;
+        s.left = (l+a.l)+"px";
+        s.top = (t+a.t)+"px";
+        var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
+        if(s.width != sws || s.height != shs){
+            s.width = sws;
+            s.height = shs;
+            if(!Roo.isIE){
+                var cn = d.childNodes;
+                var sww = Math.max(0, (sw-12))+"px";
+                cn[0].childNodes[1].style.width = sww;
+                cn[1].childNodes[1].style.width = sww;
+                cn[2].childNodes[1].style.width = sww;
+                cn[1].style.height = Math.max(0, (sh-12))+"px";
+            }
+        }
+    },
+
+    /**
+     * Hides this shadow
+     */
+    hide : function(){
+        if(this.el){
+            this.el.dom.style.display = "none";
+            Roo.Shadow.Pool.push(this.el);
+            delete this.el;
+        }
+    },
+
+    /**
+     * Adjust the z-index of this shadow
+     * @param {Number} zindex The new z-index
+     */
+    setZIndex : function(z){
+        this.zIndex = z;
+        if(this.el){
+            this.el.setStyle("z-index", z);
+        }
+    }
+};
+
+// Private utility class that manages the internal Shadow cache
+Roo.Shadow.Pool = function(){
+    var p = [];
+    var markup = Roo.isIE ?
+                 '<div class="x-ie-shadow"></div>' :
+                 '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
+    return {
+        pull : function(){
+            var sh = p.shift();
+            if(!sh){
+                sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
+                sh.autoBoxAdjust = false;
+            }
+            return sh;
+        },
+
+        push : function(sh){
+            p.push(sh);
+        }
+    };
+}();/*
+ * 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.SplitBar
+ * @extends Roo.util.Observable
+ * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
+ * <br><br>
+ * Usage:
+ * <pre><code>
+var split = new Roo.SplitBar("elementToDrag", "elementToSize",
+                   Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
+split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
+split.minSize = 100;
+split.maxSize = 600;
+split.animate = true;
+split.on('moved', splitterMoved);
+</code></pre>
+ * @constructor
+ * Create a new SplitBar
+ * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
+ * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
+ * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
+ * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or  
+                        Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
+                        position of the SplitBar).
+ */
+Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
+    
+    /** @private */
     this.el = Roo.get(dragElement, true);
     this.el.dom.unselectable = "on";
     /** @private */
@@ -24117,7 +24713,9 @@ Roo.View = function(config, depreciated_tpl, depreciated_config){
         this.tpl = depreciated_tpl;
         Roo.apply(this, depreciated_config);
     }
-     
+    this.wrapEl  = this.el.wrap().wrap();
+    ///this.el = this.wrapEla.appendChild(document.createElement("div"));
+    
     
     if(typeof(this.tpl) == "string"){
         this.tpl = new Roo.Template(this.tpl);
@@ -24129,7 +24727,8 @@ Roo.View = function(config, depreciated_tpl, depreciated_config){
     
     this.tpl.compile();
    
-
+  
+    
      
     /** @private */
     this.addEvents({
@@ -24192,8 +24791,12 @@ Roo.View = function(config, depreciated_tpl, depreciated_config){
          * @param {Object} data to be rendered (change this)
          */
           "preparedata" : true
+          
+          
         });
 
+
+
     this.el.on({
         "click": this.onClick,
         "dblclick": this.onDblClick,
@@ -24208,7 +24811,25 @@ Roo.View = function(config, depreciated_tpl, depreciated_config){
         this.store = Roo.factory(this.store, Roo.data);
         this.setStore(this.store, true);
     }
+    
+    if ( this.footer && this.footer.xtype) {
+           
+         var fctr = this.wrapEl.appendChild(document.createElement("div"));
+        
+        this.footer.dataSource = this.store
+        this.footer.container = fctr;
+        this.footer = Roo.factory(this.footer, Roo);
+        fctr.insertFirst(this.el);
+        
+        // this is a bit insane - as the paging toolbar seems to detach the el..
+//        dom.parentNode.parentNode.parentNode
+         // they get detached?
+    }
+    
+    
     Roo.View.superclass.constructor.call(this);
+    
+    
 };
 
 Roo.extend(Roo.View, Roo.util.Observable, {
@@ -24264,8 +24885,10 @@ Roo.extend(Roo.View, Roo.util.Observable, {
      * @return {Roo.Element}
      */
     getEl : function(){
-        return this.el;
+        return this.wrapEl;
     },
+    
+    
 
     /**
      * Refreshes the view. - called by datachanged on the store. - do not call directly.
@@ -28448,6 +29071,17 @@ Roo.Resizable = function(el, config)
          * @param {Roo.EventObject} e The mousedown event
          */
         "beforeresize" : true,
+        /**
+         * @event resizing
+         * Fired a resizing.
+         * @param {Roo.Resizable} this
+         * @param {Number} x The new x position
+         * @param {Number} y The new y position
+         * @param {Number} w The new w width
+         * @param {Number} h The new h hight
+         * @param {Roo.EventObject} e The mouseup event
+         */
+        "resizing" : true,
         /**
          * @event resize
          * Fired after a resize.
@@ -28580,6 +29214,7 @@ Roo.extend(Roo.Resizable, Roo.util.Observable, {
 
     // private
     updateChildSize : function(){
+        
         if(this.resizeChild){
             var el = this.el;
             var child = this.resizeChild;
@@ -28645,6 +29280,7 @@ Roo.extend(Roo.Resizable, Roo.util.Observable, {
 
     // private
     onMouseMove : function(e){
+        
         if(this.enabled){
             try{// try catch so if something goes wrong the user doesn't get hung
 
@@ -28821,6 +29457,7 @@ Roo.extend(Roo.Resizable, Roo.util.Observable, {
             }
             }catch(e){}
         }
+        this.fireEvent("resizing", this, x, y, w, h, e);
     },
 
     // private
@@ -28852,7 +29489,10 @@ Roo.extend(Roo.Resizable, Roo.util.Observable, {
     getResizeChild : function(){
         return this.resizeChild;
     },
-
+    groupHandler : function()
+    {
+        
+    },
     /**
      * Destroys this resizable. If the element was wrapped and
      * removeEl is not true then the element remains.
@@ -36388,7 +37028,7 @@ side          Add an error icon to the right of the field with a popup on hover
      * Resets the current field value to the originally loaded value and clears any validation messages
      */
     reset : function(){
-        this.setValue(this.originalValue);
+        this.setValue(this.resetValue);
         this.clearInvalid();
     },
 
@@ -36402,6 +37042,7 @@ side          Add an error icon to the right of the field with a popup on hover
 
         // reference to original value for reset
         this.originalValue = this.getValue();
+        this.resetValue =  this.getValue();
     },
 
     // private
@@ -36481,12 +37122,15 @@ side          Add an error icon to the right of the field with a popup on hover
         if(!this.rendered || this.preventMark){ // not rendered
             return;
         }
-        this.el.addClass(this.invalidClass);
+        
+        var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
+        
+        obj.el.addClass(this.invalidClass);
         msg = msg || this.invalidText;
         switch(this.msgTarget){
             case 'qtip':
-                this.el.dom.qtip = msg;
-                this.el.dom.qclass = 'x-form-invalid-tip';
+                obj.el.dom.qtip = msg;
+                obj.el.dom.qclass = 'x-form-invalid-tip';
                 if(Roo.QuickTips){ // fix for floating editors interacting with DND
                     Roo.QuickTips.enable();
                 }
@@ -36535,10 +37179,12 @@ side          Add an error icon to the right of the field with a popup on hover
         if(!this.rendered || this.preventMark){ // not rendered
             return;
         }
-        this.el.removeClass(this.invalidClass);
+        var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
+        
+        obj.el.removeClass(this.invalidClass);
         switch(this.msgTarget){
             case 'qtip':
-                this.el.dom.qtip = '';
+                obj.el.dom.qtip = '';
                 break;
             case 'title':
                 this.el.dom.title = '';
@@ -36617,14 +37263,14 @@ side          Add an error icon to the right of the field with a popup on hover
                 if(tag == 'input'){
                     return w + 2;
                 }
-                if(tag = 'textarea'){
+                if(tag == 'textarea'){
                     return w-2;
                 }
             }else if(Roo.isOpera){
                 if(tag == 'input'){
                     return w + 2;
                 }
-                if(tag = 'textarea'){
+                if(tag == 'textarea'){
                     return w-2;
                 }
             }
@@ -39056,7 +39702,7 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
     // private
     reset : function(){
         // overridden so that last data is reset..
-        this.setValue(this.originalValue);
+        this.setValue(this.resetValue);
         this.clearInvalid();
         this.lastData = false;
         if (this.view) {
@@ -39749,6 +40395,17 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
         
     },
     
+    /**
+     * Validates the combox array value
+     * @return {Boolean} True if the value is valid, else false
+     */
+    validate : function(){
+        if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
+            this.clearInvalid();
+            return true;
+        }
+        return false;
+    },
     
     validateValue : function(value){
         return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
@@ -39830,8 +40487,32 @@ Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
         this.el.child('img').un('click', this.remove, this);
         this.el.remove();
         this.cb.updateHiddenEl();
-    }
+    },
     
+    /*@
+     * overide
+     * 
+     */
+    isDirty : function() {
+        if(this.disabled) {
+            return false;
+        }
+        
+        try {
+            var d = Roo.decode(String(this.originalValue));
+        } catch (e) {
+            return String(this.getValue()) !== String(this.originalValue);
+        }
+        
+        var originalValue = [];
+        
+        for (var i = 0; i < d.length; i++){
+            originalValue.push(d[i][this.valueField]);
+        }
+        
+        return String(this.getValue()) !== String(originalValue.join(','));
+        
+    }
     
 });/*
  * Based on:
@@ -40078,7 +40759,39 @@ Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
      */
     getGroupValue : function(){
         return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
-    }
+    },
+    
+    
+    onRender : function(ct, position){
+        Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
+        
+        if(this.inputValue !== undefined){
+            this.el.dom.value = this.inputValue;
+        }
+         
+        this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
+        //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
+        //var viewEl = this.wrap.createChild({ 
+        //    tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
+        //this.viewEl = viewEl;   
+        //this.wrap.on('click', this.onClick,  this); 
+        
+        //this.el.on('DOMAttrModified', this.setFromHidden,  this); //ff
+        //this.el.on('propertychange', this.setFromHidden,  this);  //ie
+        
+        
+        
+        if(this.boxLabel){
+            this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
+        //    viewEl.on('click', this.onClick,  this); 
+        }
+         if(this.checked){
+            this.el.dom.checked =   'checked' ;
+        }
+         
+    } 
+    
+    
 });//<script type="text/javascript">
 
 /*
@@ -40717,10 +41430,10 @@ Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
     insertTag : function(tg)
     {
         // could be a bit smarter... -> wrap the current selected tRoo..
-        if (tg.toLowerCase() == 'span') {
+        if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
             
             range = this.createRange(this.getSelection());
-            var wrappingNode = this.doc.createElement("span");
+            var wrappingNode = this.doc.createElement(tg.toLowerCase());
             wrappingNode.appendChild(range.extractContents());
             range.insertNode(wrappingNode);
 
@@ -41587,6 +42300,10 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
         ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
         ['div'],['span']
     ],
+    
+    cleanStyles : [
+        "font-size"
+    ],
      /**
      * @cfg {String} defaultFont default font to use.
      */
@@ -41813,6 +42530,35 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
             
             
         }
+        
+        var cmenu = { };
+        if (!this.disable.cleanStyles) {
+            cmenu = {
+                cls: 'x-btn-icon x-btn-clear',
+                
+                menu : {
+                    items : []
+                }
+            };
+            for (var i =0; i < this.cleanStyles.length; i++) {
+                cmenu.menu.items.push({
+                    actiontype : this.cleanStyles[i],
+                    html: 'Remove ' + this.cleanStyles[i],
+                    handler: function(a,b) {
+                        Roo.log(a);
+                        Roo.log(b);
+                        var c = Roo.get(editor.doc.body);
+                        c.select('[style]').each(function(s) {
+                            s.dom.style.removeProperty(a.actiontype);
+                        });
+                        
+                    },
+                    tabIndex:-1
+                });
+            }
+            
+            tb.add(cmenu);
+        }
          
         if (!this.disable.specialElements) {
             var semenu = {
@@ -42174,6 +42920,10 @@ Roo.form.HtmlEditor.ToolbarContext.types = {
             title: "Name",
             width: 50
         },
+        target:  {
+            title: "Target",
+            width: 120
+        },
         href:  {
             title: "Href",
             width: 220
@@ -43367,6 +44117,19 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
                 return;
             }
             var v = f.getValue();
+            if (f.inputType =='radio') {
+                if (typeof(ret[f.getName()]) == 'undefined') {
+                    ret[f.getName()] = ''; // empty..
+                }
+                
+                if (!f.el.dom.checked) {
+                    return;
+                    
+                }
+                v = f.el.dom.value;
+                
+            }
+            
             // not sure if this supported any more..
             if ((typeof(v) == 'object') && f.getRawValue) {
                 v = f.getRawValue() ; // dates..
@@ -43928,7 +44691,9 @@ Roo.Form = Roo.form.Form;
  * Fork - LGPL
  * <script type="text/javascript">
  */
+
+// as we use this in bootstrap.
+Roo.namespace('Roo.form');
  /**
  * @class Roo.form.Action
  * Internal Class used to handle form actions
@@ -43936,6 +44701,7 @@ Roo.Form = Roo.form.Form;
  * @param {Roo.form.BasicForm} el The form element or its id
  * @param {Object} config Configuration options
  */
+
  
  
 // define the action interface
@@ -43952,7 +44718,7 @@ Roo.form.Action.CLIENT_INVALID = 'client';
  * Server Validation Failed
  * @const 
  */
- Roo.form.Action.SERVER_INVALID = 'server';
+Roo.form.Action.SERVER_INVALID = 'server';
  /**
  * Connect to Server Failed
  * @const 
@@ -45657,7 +46423,7 @@ Roo.form.Signature = function(config){
          /**
          * @event confirm
          * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
-            * @param {Roo.form.ComboBox} combo This combo box
+            * @param {Roo.form.Signature} combo This combo box
             */
         'confirm' : true,
         /**
@@ -45728,22 +46494,25 @@ Roo.extend(Roo.form.Signature, Roo.form.Field,  {
             }, this.el
         );
             
+        this.svgID = Roo.id();
         this.svgEl = this.signPanel.createChild({
               xmlns : 'http://www.w3.org/2000/svg',
               tag : 'svg',
+              id : this.svgID + "-svg",
               width: this.width,
               height: this.height,
               viewBox: '0 0 '+this.width+' '+this.height,
               cn : [
                 {
                     tag: "rect",
-                    id: "svg-r",
+                    id: this.svgID + "-svg-r",
                     width: this.width,
                     height: this.height,
                     fill: "#ffa"
                 },
                 {
                     tag: "line",
+                    id: this.svgID + "-svg-l",
                     x1: "0", // start
                     y1: (this.height*0.8), // start set the line in 80% of height
                     x2: this.width, // end
@@ -45756,7 +46525,7 @@ Roo.extend(Roo.form.Signature, Roo.form.Field,  {
                 },
                 {
                     tag: "path",
-                    id: "svg-p",
+                    id: this.svgID + "-svg-p",
                     'stroke': "navy",
                     'stroke-width': "3",
                     'fill': "none",
@@ -45769,7 +46538,7 @@ Roo.extend(Roo.form.Signature, Roo.form.Field,  {
     },
     createSVG : function(){ 
         var svg = this.signPanel;
-        var r = svg.select('#svg-r', true).first().dom;
+        var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
         var t = this;
 
         r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
@@ -45800,7 +46569,7 @@ Roo.extend(Roo.form.Signature, Roo.form.Field,  {
     //mouse event headler 
     down : function (e) {
         this.signatureTmp += 'M' + this.getCoords(e) + ' ';
-        this.signPanel.select('#svg-p', true).first().attr('d', this.signatureTmp);
+        this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
         
         this.isMouseDown = true;
         
@@ -45809,7 +46578,7 @@ Roo.extend(Roo.form.Signature, Roo.form.Field,  {
     move : function (e) {
         if (this.isMouseDown) {
             this.signatureTmp += 'L' + this.getCoords(e) + ' ';
-            this.signPanel.select('#svg-p', true).first().attr('d', this.signatureTmp);
+            this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
         }
         
         e.preventDefault();
@@ -45827,7 +46596,7 @@ Roo.extend(Roo.form.Signature, Roo.form.Field,  {
             }
         }
         if(this.getValue() != this.signatureTmp){
-            this.signPanel.select('#svg-r', true).first().attr('fill', '#ffa');
+            this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
             this.isConfirmed = false;
         }
         e.preventDefault();
@@ -45873,7 +46642,7 @@ Roo.extend(Roo.form.Signature, Roo.form.Field,  {
             {
                 cls : '  x-signature-btn x-signature-'+id,
                 scope: editor, // was editor...
-                handler: this.setConfirmed,
+                handler: this.confirmHandler,
                 clickEvent:'mousedown',
                 text: this.labels.confirm
             }
@@ -45881,15 +46650,37 @@ Roo.extend(Roo.form.Signature, Roo.form.Field,  {
     
     },
     //public
+    /**
+     * when user is clicked confirm then show this image.....
+     * 
+     * @return {String} Image Data URI
+     */
     getImageDataURI : function(){
-        var svg = this.svgEl.dom.outerHTML;
-        Roo.log(this.svgEl);
+        var svg = this.svgEl.dom.parentNode.innerHTML;
         var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
-        return src;
+        return src; 
     },
+    /**
+     * 
+     * @return {Boolean} this.isConfirmed
+     */
     getConfirmed : function(){
         return this.isConfirmed;
     },
+    /**
+     * 
+     * @return {Number} this.width
+     */
+    getWidth : function(){
+        return this.width;
+    },
+    /**
+     * 
+     * @return {Number} this.height
+     */
+    getHeight : function(){
+        return this.height;
+    },
     // private
     getSignature : function(){
         return this.signatureTmp;
@@ -45897,23 +46688,40 @@ Roo.extend(Roo.form.Signature, Roo.form.Field,  {
     // private
     reset : function(){
         this.signatureTmp = '';
-        this.signPanel.select('#svg-r', true).first().attr('fill', '#ffa');
-        this.signPanel.select('#svg-p', true).first().attr('d', '');
+        this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
+        this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
         this.isConfirmed = false;
         Roo.form.Signature.superclass.reset.call(this);
     },
+    setSignature : function(s){
+        this.signatureTmp = s;
+        this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
+        this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
+        this.setValue(s);
+        this.isConfirmed = false;
+        Roo.form.Signature.superclass.reset.call(this);
+    }, 
     test : function(){
 //        Roo.log(this.signPanel.dom.contentWindow.up())
     },
     //private
     setConfirmed : function(){
+        
+        
+        
+//        Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
+    },
+    // private
+    confirmHandler : function(){
         if(!this.getSignature()){
             return;
         }
-        this.signPanel.select('#svg-r', true).first().attr('fill', '#cfc');
+        
+        this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
         this.setValue(this.getSignature());
         this.isConfirmed = true;
-//        Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
+        
+        this.fireEvent('confirm', this);
     },
     // private
     // Subclasses should provide the validation implementation by overriding this
@@ -45927,191 +46735,805 @@ Roo.extend(Roo.form.Signature, Roo.form.Field,  {
         }
         return false;
     }
-});//<script type="text/javasscript">
+});/*
+ * 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.DDView
- * A DnD enabled version of Roo.View.
- * @param {Element/String} container The Element in which to create the View.
- * @param {String} tpl The template string used to create the markup for each element of the View
- * @param {Object} config The configuration properties. These include all the config options of
- * {@link Roo.View} plus some specific to this class.<br>
- * <p>
- * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
- * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
- * <p>
- * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
-.x-view-drag-insert-above {
-       border-top:1px dotted #3366cc;
-}
-.x-view-drag-insert-below {
-       border-bottom:1px dotted #3366cc;
-}
-</code></pre>
- * 
+ * @class Roo.form.ComboBox
+ * @extends Roo.form.TriggerField
+ * A combobox control with support for autocomplete, remote-loading, paging and many other features.
+ * @constructor
+ * Create a new ComboBox.
+ * @param {Object} config Configuration options
  */
-Roo.DDView = function(container, tpl, config) {
-    Roo.DDView.superclass.constructor.apply(this, arguments);
-    this.getEl().setStyle("outline", "0px none");
-    this.getEl().unselectable();
-    if (this.dragGroup) {
-               this.setDraggable(this.dragGroup.split(","));
-    }
-    if (this.dropGroup) {
-               this.setDroppable(this.dropGroup.split(","));
-    }
-    if (this.deletable) {
-       this.setDeletable();
-    }
-    this.isDirtyFlag = false;
-       this.addEvents({
-               "drop" : true
-       });
+Roo.form.Select = function(config){
+    Roo.form.Select.superclass.constructor.call(this, config);
+     
 };
 
-Roo.extend(Roo.DDView, Roo.View, {
-/**    @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
-/**    @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
-/**    @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
-/**    @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
-
-       isFormField: true,
-
-       reset: Roo.emptyFn,
-       
-       clearInvalid: Roo.form.Field.prototype.clearInvalid,
-
-       validate: function() {
-               return true;
-       },
-       
-       destroy: function() {
-               this.purgeListeners();
-               this.getEl.removeAllListeners();
-               this.getEl().remove();
-               if (this.dragZone) {
-                       if (this.dragZone.destroy) {
-                               this.dragZone.destroy();
-                       }
-               }
-               if (this.dropZone) {
-                       if (this.dropZone.destroy) {
-                               this.dropZone.destroy();
-                       }
-               }
-       },
-
-/**    Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
-       getName: function() {
-               return this.name;
-       },
+Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
+    /**
+     * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
+     */
+    /**
+     * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
+     * rendering into an Roo.Editor, defaults to false)
+     */
+    /**
+     * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
+     * {tag: "input", type: "text", size: "24", autocomplete: "off"})
+     */
+    /**
+     * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
+     */
+    /**
+     * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
+     * the dropdown list (defaults to undefined, with no header element)
+     */
 
-/**    Loads the View from a JSON string representing the Records to put into the Store. */
-       setValue: function(v) {
-               if (!this.store) {
-                       throw "DDView.setValue(). DDView must be constructed with a valid Store";
-               }
-               var data = {};
-               data[this.store.reader.meta.root] = v ? [].concat(v) : [];
-               this.store.proxy = new Roo.data.MemoryProxy(data);
-               this.store.load();
-       },
+     /**
+     * @cfg {String/Roo.Template} tpl The template to use to render the output
+     */
+     
+    // private
+    defaultAutoCreate : {tag: "select"  },
+    /**
+     * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
+     */
+    listWidth: undefined,
+    /**
+     * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
+     * mode = 'remote' or 'text' if mode = 'local')
+     */
+    displayField: undefined,
+    /**
+     * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
+     * mode = 'remote' or 'value' if mode = 'local'). 
+     * Note: use of a valueField requires the user make a selection
+     * in order for a value to be mapped.
+     */
+    valueField: undefined,
+    
+    
+    /**
+     * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
+     * field's data value (defaults to the underlying DOM element's name)
+     */
+    hiddenName: undefined,
+    /**
+     * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
+     */
+    listClass: '',
+    /**
+     * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
+     */
+    selectedClass: 'x-combo-selected',
+    /**
+     * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
+     * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
+     * which displays a downward arrow icon).
+     */
+    triggerClass : 'x-form-arrow-trigger',
+    /**
+     * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
+     */
+    shadow:'sides',
+    /**
+     * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
+     * anchor positions (defaults to 'tl-bl')
+     */
+    listAlign: 'tl-bl?',
+    /**
+     * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
+     */
+    maxHeight: 300,
+    /**
+     * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
+     * query specified by the allQuery config option (defaults to 'query')
+     */
+    triggerAction: 'query',
+    /**
+     * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
+     * (defaults to 4, does not apply if editable = false)
+     */
+    minChars : 4,
+    /**
+     * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
+     * delay (typeAheadDelay) if it matches a known value (defaults to false)
+     */
+    typeAhead: false,
+    /**
+     * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
+     * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
+     */
+    queryDelay: 500,
+    /**
+     * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
+     * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
+     */
+    pageSize: 0,
+    /**
+     * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
+     * when editable = true (defaults to false)
+     */
+    selectOnFocus:false,
+    /**
+     * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
+     */
+    queryParam: 'query',
+    /**
+     * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
+     * when mode = 'remote' (defaults to 'Loading...')
+     */
+    loadingText: 'Loading...',
+    /**
+     * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
+     */
+    resizable: false,
+    /**
+     * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
+     */
+    handleHeight : 8,
+    /**
+     * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
+     * traditional select (defaults to true)
+     */
+    editable: true,
+    /**
+     * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
+     */
+    allQuery: '',
+    /**
+     * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
+     */
+    mode: 'remote',
+    /**
+     * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
+     * listWidth has a higher value)
+     */
+    minListWidth : 70,
+    /**
+     * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
+     * allow the user to set arbitrary text into the field (defaults to false)
+     */
+    forceSelection:false,
+    /**
+     * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
+     * if typeAhead = true (defaults to 250)
+     */
+    typeAheadDelay : 250,
+    /**
+     * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
+     * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
+     */
+    valueNotFoundText : undefined,
+    
+    /**
+     * @cfg {String} defaultValue The value displayed after loading the store.
+     */
+    defaultValue: '',
+    
+    /**
+     * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
+     */
+    blockFocus : false,
+    
+    /**
+     * @cfg {Boolean} disableClear Disable showing of clear button.
+     */
+    disableClear : false,
+    /**
+     * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
+     */
+    alwaysQuery : false,
+    
+    //private
+    addicon : false,
+    editicon: false,
+    
+    // element that contains real text value.. (when hidden is used..)
+     
+    // private
+    onRender : function(ct, position){
+        Roo.form.Field.prototype.onRender.call(this, ct, position);
+        
+        if(this.store){
+            this.store.on('beforeload', this.onBeforeLoad, this);
+            this.store.on('load', this.onLoad, this);
+            this.store.on('loadexception', this.onLoadException, this);
+            this.store.load({});
+        }
+        
+        
+        
+    },
 
-/**    @return {String} a parenthesised list of the ids of the Records in the View. */
-       getValue: function() {
-               var result = '(';
-               this.store.each(function(rec) {
-                       result += rec.id + ',';
-               });
-               return result.substr(0, result.length - 1) + ')';
-       },
-       
-       getIds: function() {
-               var i = 0, result = new Array(this.store.getCount());
-               this.store.each(function(rec) {
-                       result[i++] = rec.id;
-               });
-               return result;
-       },
-       
-       isDirty: function() {
-               return this.isDirtyFlag;
-       },
+    // private
+    initEvents : function(){
+        //Roo.form.ComboBox.superclass.initEvents.call(this);
+    },
 
-/**
- *     Part of the Roo.dd.DropZone interface. If no target node is found, the
- *     whole Element becomes the target, and this causes the drop gesture to append.
- */
-    getTargetFromEvent : function(e) {
-               var target = e.getTarget();
-               while ((target !== null) && (target.parentNode != this.el.dom)) {
-               target = target.parentNode;
-               }
-               if (!target) {
-                       target = this.el.dom.lastChild || this.el.dom;
-               }
-               return target;
+    onDestroy : function(){
+       
+        if(this.store){
+            this.store.un('beforeload', this.onBeforeLoad, this);
+            this.store.un('load', this.onLoad, this);
+            this.store.un('loadexception', this.onLoadException, this);
+        }
+        //Roo.form.ComboBox.superclass.onDestroy.call(this);
     },
 
-/**
- *     Create the drag data which consists of an object which has the property "ddel" as
- *     the drag proxy element. 
- */
-    getDragData : function(e) {
-        var target = this.findItemFromChild(e.getTarget());
-               if(target) {
-                       this.handleSelection(e);
-                       var selNodes = this.getSelectedNodes();
-            var dragData = {
-                source: this,
-                copy: this.copy || (this.allowCopy && e.ctrlKey),
-                nodes: selNodes,
-                records: []
-                       };
-                       var selectedIndices = this.getSelectedIndexes();
-                       for (var i = 0; i < selectedIndices.length; i++) {
-                               dragData.records.push(this.store.getAt(selectedIndices[i]));
-                       }
-                       if (selNodes.length == 1) {
-                               dragData.ddel = target.cloneNode(true); // the div element
-                       } else {
-                               var div = document.createElement('div'); // create the multi element drag "ghost"
-                               div.className = 'multi-proxy';
-                               for (var i = 0, len = selNodes.length; i < len; i++) {
-                                       div.appendChild(selNodes[i].cloneNode(true));
-                               }
-                               dragData.ddel = div;
-                       }
-            //console.log(dragData)
-            //console.log(dragData.ddel.innerHTML)
-                       return dragData;
-               }
-        //console.log('nodragData')
-               return false;
+    // private
+    fireKey : function(e){
+        if(e.isNavKeyPress() && !this.list.isVisible()){
+            this.fireEvent("specialkey", this, e);
+        }
     },
+
+    // private
+    onResize: function(w, h){
+        
+        return; 
     
-/**    Specify to which ddGroup items in this DDView may be dragged. */
-    setDraggable: function(ddGroup) {
-       if (ddGroup instanceof Array) {
-               Roo.each(ddGroup, this.setDraggable, this);
-               return;
-       }
-       if (this.dragZone) {
-               this.dragZone.addToGroup(ddGroup);
-       } else {
-                       this.dragZone = new Roo.dd.DragZone(this.getEl(), {
-                               containerScroll: true,
-                               ddGroup: ddGroup 
+        
+    },
 
-                       });
-//                     Draggability implies selection. DragZone's mousedown selects the element.
-                       if (!this.multiSelect) { this.singleSelect = true; }
+    /**
+     * Allow or prevent the user from directly editing the field text.  If false is passed,
+     * the user will only be able to select from the items defined in the dropdown list.  This method
+     * is the runtime equivalent of setting the 'editable' config option at config time.
+     * @param {Boolean} value True to allow the user to directly edit the field text
+     */
+    setEditable : function(value){
+         
+    },
 
-//                     Wire the DragZone's handlers up to methods in *this*
-                       this.dragZone.getDragData = this.getDragData.createDelegate(this);
-               }
+    // private
+    onBeforeLoad : function(){
+        
+        Roo.log("Select before load");
+        return;
+    
+        this.innerList.update(this.loadingText ?
+               '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
+        //this.restrictHeight();
+        this.selectedIndex = -1;
+    },
+
+    // private
+    onLoad : function(){
+
+    
+        var dom = this.el.dom;
+        dom.innerHTML = '';
+         var od = dom.ownerDocument;
+         
+        if (this.emptyText) {
+            var op = od.createElement('option');
+            op.setAttribute('value', '');
+            op.innerHTML = String.format('{0}', this.emptyText);
+            dom.appendChild(op);
+        }
+        if(this.store.getCount() > 0){
+           
+            var vf = this.valueField;
+            var df = this.displayField;
+            this.store.data.each(function(r) {
+                // which colmsn to use... testing - cdoe / title..
+                var op = od.createElement('option');
+                op.setAttribute('value', r.data[vf]);
+                op.innerHTML = String.format('{0}', r.data[df]);
+                dom.appendChild(op);
+            });
+            if (typeof(this.defaultValue != 'undefined')) {
+                this.setValue(this.defaultValue);
+            }
+            
+             
+        }else{
+            //this.onEmptyResults();
+        }
+        //this.el.focus();
+    },
+    // private
+    onLoadException : function()
+    {
+        dom.innerHTML = '';
+            
+        Roo.log("Select on load exception");
+        return;
+    
+        this.collapse();
+        Roo.log(this.store.reader.jsonData);
+        if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
+            Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
+        }
+        
+        
+    },
+    // private
+    onTypeAhead : function(){
+         
+    },
+
+    // private
+    onSelect : function(record, index){
+        Roo.log('on select?');
+        return;
+        if(this.fireEvent('beforeselect', this, record, index) !== false){
+            this.setFromData(index > -1 ? record.data : false);
+            this.collapse();
+            this.fireEvent('select', this, record, index);
+        }
+    },
+
+    /**
+     * Returns the currently selected field value or empty string if no value is set.
+     * @return {String} value The selected value
+     */
+    getValue : function(){
+        var dom = this.el.dom;
+        this.value = dom.options[dom.selectedIndex].value;
+        return this.value;
+        
+    },
+
+    /**
+     * Clears any text/value currently set in the field
+     */
+    clearValue : function(){
+        this.value = '';
+        this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
+        
+    },
+
+    /**
+     * Sets the specified value into the field.  If the value finds a match, the corresponding record text
+     * will be displayed in the field.  If the value does not match the data value of an existing item,
+     * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
+     * Otherwise the field will be blank (although the value will still be set).
+     * @param {String} value The value to match
+     */
+    setValue : function(v){
+        var d = this.el.dom;
+        for (var i =0; i < d.options.length;i++) {
+            if (v == d.options[i].value) {
+                d.selectedIndex = i;
+                this.value = v;
+                return;
+            }
+        }
+        this.clearValue();
+    },
+    /**
+     * @property {Object} the last set data for the element
+     */
+    
+    lastData : false,
+    /**
+     * Sets the value of the field based on a object which is related to the record format for the store.
+     * @param {Object} value the value to set as. or false on reset?
+     */
+    setFromData : function(o){
+        Roo.log('setfrom data?');
+         
+        
+        
+    },
+    // private
+    reset : function(){
+        this.clearValue();
+    },
+    // private
+    findRecord : function(prop, value){
+        
+        return false;
+    
+        var record;
+        if(this.store.getCount() > 0){
+            this.store.each(function(r){
+                if(r.data[prop] == value){
+                    record = r;
+                    return false;
+                }
+                return true;
+            });
+        }
+        return record;
+    },
+    
+    getName: function()
+    {
+        // returns hidden if it's set..
+        if (!this.rendered) {return ''};
+        return !this.hiddenName && this.el.dom.name  ? this.el.dom.name : (this.hiddenName || '');
+        
+    },
+     
+
+    
+
+    // private
+    onEmptyResults : function(){
+        Roo.log('empty results');
+        //this.collapse();
+    },
+
+    /**
+     * Returns true if the dropdown list is expanded, else false.
+     */
+    isExpanded : function(){
+        return false;
+    },
+
+    /**
+     * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
+     * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
+     * @param {String} value The data value of the item to select
+     * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
+     * selected item if it is not currently in view (defaults to true)
+     * @return {Boolean} True if the value matched an item in the list, else false
+     */
+    selectByValue : function(v, scrollIntoView){
+        Roo.log('select By Value');
+        return false;
+    
+        if(v !== undefined && v !== null){
+            var r = this.findRecord(this.valueField || this.displayField, v);
+            if(r){
+                this.select(this.store.indexOf(r), scrollIntoView);
+                return true;
+            }
+        }
+        return false;
+    },
+
+    /**
+     * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
+     * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
+     * @param {Number} index The zero-based index of the list item to select
+     * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
+     * selected item if it is not currently in view (defaults to true)
+     */
+    select : function(index, scrollIntoView){
+        Roo.log('select ');
+        return  ;
+        
+        this.selectedIndex = index;
+        this.view.select(index);
+        if(scrollIntoView !== false){
+            var el = this.view.getNode(index);
+            if(el){
+                this.innerList.scrollChildIntoView(el, false);
+            }
+        }
+    },
+
+      
+
+    // private
+    validateBlur : function(){
+        
+        return;
+        
+    },
+
+    // private
+    initQuery : function(){
+        this.doQuery(this.getRawValue());
+    },
+
+    // private
+    doForce : function(){
+        if(this.el.dom.value.length > 0){
+            this.el.dom.value =
+                this.lastSelectionText === undefined ? '' : this.lastSelectionText;
+             
+        }
+    },
+
+    /**
+     * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
+     * query allowing the query action to be canceled if needed.
+     * @param {String} query The SQL query to execute
+     * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
+     * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
+     * saved in the current store (defaults to false)
+     */
+    doQuery : function(q, forceAll){
+        
+        Roo.log('doQuery?');
+        if(q === undefined || q === null){
+            q = '';
+        }
+        var qe = {
+            query: q,
+            forceAll: forceAll,
+            combo: this,
+            cancel:false
+        };
+        if(this.fireEvent('beforequery', qe)===false || qe.cancel){
+            return false;
+        }
+        q = qe.query;
+        forceAll = qe.forceAll;
+        if(forceAll === true || (q.length >= this.minChars)){
+            if(this.lastQuery != q || this.alwaysQuery){
+                this.lastQuery = q;
+                if(this.mode == 'local'){
+                    this.selectedIndex = -1;
+                    if(forceAll){
+                        this.store.clearFilter();
+                    }else{
+                        this.store.filter(this.displayField, q);
+                    }
+                    this.onLoad();
+                }else{
+                    this.store.baseParams[this.queryParam] = q;
+                    this.store.load({
+                        params: this.getParams(q)
+                    });
+                    this.expand();
+                }
+            }else{
+                this.selectedIndex = -1;
+                this.onLoad();   
+            }
+        }
+    },
+
+    // private
+    getParams : function(q){
+        var p = {};
+        //p[this.queryParam] = q;
+        if(this.pageSize){
+            p.start = 0;
+            p.limit = this.pageSize;
+        }
+        return p;
+    },
+
+    /**
+     * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
+     */
+    collapse : function(){
+        
+    },
+
+    // private
+    collapseIf : function(e){
+        
+    },
+
+    /**
+     * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
+     */
+    expand : function(){
+        
+    } ,
+
+    // private
+     
+
+    /** 
+    * @cfg {Boolean} grow 
+    * @hide 
+    */
+    /** 
+    * @cfg {Number} growMin 
+    * @hide 
+    */
+    /** 
+    * @cfg {Number} growMax 
+    * @hide 
+    */
+    /**
+     * @hide
+     * @method autoSize
+     */
+    
+    setWidth : function()
+    {
+        
+    },
+    getResizeEl : function(){
+        return this.el;
+    }
+});//<script type="text/javasscript">
+
+/**
+ * @class Roo.DDView
+ * A DnD enabled version of Roo.View.
+ * @param {Element/String} container The Element in which to create the View.
+ * @param {String} tpl The template string used to create the markup for each element of the View
+ * @param {Object} config The configuration properties. These include all the config options of
+ * {@link Roo.View} plus some specific to this class.<br>
+ * <p>
+ * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
+ * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
+ * <p>
+ * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
+.x-view-drag-insert-above {
+       border-top:1px dotted #3366cc;
+}
+.x-view-drag-insert-below {
+       border-bottom:1px dotted #3366cc;
+}
+</code></pre>
+ * 
+ */
+Roo.DDView = function(container, tpl, config) {
+    Roo.DDView.superclass.constructor.apply(this, arguments);
+    this.getEl().setStyle("outline", "0px none");
+    this.getEl().unselectable();
+    if (this.dragGroup) {
+               this.setDraggable(this.dragGroup.split(","));
+    }
+    if (this.dropGroup) {
+               this.setDroppable(this.dropGroup.split(","));
+    }
+    if (this.deletable) {
+       this.setDeletable();
+    }
+    this.isDirtyFlag = false;
+       this.addEvents({
+               "drop" : true
+       });
+};
+
+Roo.extend(Roo.DDView, Roo.View, {
+/**    @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
+/**    @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
+/**    @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
+/**    @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
+
+       isFormField: true,
+
+       reset: Roo.emptyFn,
+       
+       clearInvalid: Roo.form.Field.prototype.clearInvalid,
+
+       validate: function() {
+               return true;
+       },
+       
+       destroy: function() {
+               this.purgeListeners();
+               this.getEl.removeAllListeners();
+               this.getEl().remove();
+               if (this.dragZone) {
+                       if (this.dragZone.destroy) {
+                               this.dragZone.destroy();
+                       }
+               }
+               if (this.dropZone) {
+                       if (this.dropZone.destroy) {
+                               this.dropZone.destroy();
+                       }
+               }
+       },
+
+/**    Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
+       getName: function() {
+               return this.name;
+       },
+
+/**    Loads the View from a JSON string representing the Records to put into the Store. */
+       setValue: function(v) {
+               if (!this.store) {
+                       throw "DDView.setValue(). DDView must be constructed with a valid Store";
+               }
+               var data = {};
+               data[this.store.reader.meta.root] = v ? [].concat(v) : [];
+               this.store.proxy = new Roo.data.MemoryProxy(data);
+               this.store.load();
+       },
+
+/**    @return {String} a parenthesised list of the ids of the Records in the View. */
+       getValue: function() {
+               var result = '(';
+               this.store.each(function(rec) {
+                       result += rec.id + ',';
+               });
+               return result.substr(0, result.length - 1) + ')';
+       },
+       
+       getIds: function() {
+               var i = 0, result = new Array(this.store.getCount());
+               this.store.each(function(rec) {
+                       result[i++] = rec.id;
+               });
+               return result;
+       },
+       
+       isDirty: function() {
+               return this.isDirtyFlag;
+       },
+
+/**
+ *     Part of the Roo.dd.DropZone interface. If no target node is found, the
+ *     whole Element becomes the target, and this causes the drop gesture to append.
+ */
+    getTargetFromEvent : function(e) {
+               var target = e.getTarget();
+               while ((target !== null) && (target.parentNode != this.el.dom)) {
+               target = target.parentNode;
+               }
+               if (!target) {
+                       target = this.el.dom.lastChild || this.el.dom;
+               }
+               return target;
+    },
+
+/**
+ *     Create the drag data which consists of an object which has the property "ddel" as
+ *     the drag proxy element. 
+ */
+    getDragData : function(e) {
+        var target = this.findItemFromChild(e.getTarget());
+               if(target) {
+                       this.handleSelection(e);
+                       var selNodes = this.getSelectedNodes();
+            var dragData = {
+                source: this,
+                copy: this.copy || (this.allowCopy && e.ctrlKey),
+                nodes: selNodes,
+                records: []
+                       };
+                       var selectedIndices = this.getSelectedIndexes();
+                       for (var i = 0; i < selectedIndices.length; i++) {
+                               dragData.records.push(this.store.getAt(selectedIndices[i]));
+                       }
+                       if (selNodes.length == 1) {
+                               dragData.ddel = target.cloneNode(true); // the div element
+                       } else {
+                               var div = document.createElement('div'); // create the multi element drag "ghost"
+                               div.className = 'multi-proxy';
+                               for (var i = 0, len = selNodes.length; i < len; i++) {
+                                       div.appendChild(selNodes[i].cloneNode(true));
+                               }
+                               dragData.ddel = div;
+                       }
+            //console.log(dragData)
+            //console.log(dragData.ddel.innerHTML)
+                       return dragData;
+               }
+        //console.log('nodragData')
+               return false;
+    },
+    
+/**    Specify to which ddGroup items in this DDView may be dragged. */
+    setDraggable: function(ddGroup) {
+       if (ddGroup instanceof Array) {
+               Roo.each(ddGroup, this.setDraggable, this);
+               return;
+       }
+       if (this.dragZone) {
+               this.dragZone.addToGroup(ddGroup);
+       } else {
+                       this.dragZone = new Roo.dd.DragZone(this.getEl(), {
+                               containerScroll: true,
+                               ddGroup: ddGroup 
+
+                       });
+//                     Draggability implies selection. DragZone's mousedown selects the element.
+                       if (!this.multiSelect) { this.singleSelect = true; }
+
+//                     Wire the DragZone's handlers up to methods in *this*
+                       this.dragZone.getDragData = this.getDragData.createDelegate(this);
+               }
     },
 
 /**    Specify from which ddGroup this DDView accepts drops. */
@@ -46890,6 +48312,7 @@ layout.addxtype({
         {
             case 'ContentPanel':  // ContentPanel (el, cfg)
             case 'ScrollPanel':  // ContentPanel (el, cfg)
+            case 'ViewPanel': 
                 if(cfg.autoCreate) {
                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
                 } else {
@@ -46955,7 +48378,9 @@ layout.addxtype({
                 }
                 break;
            
-               
+           
+           
+                
                 
                 
             default: 
@@ -48738,12 +50163,7 @@ Roo.ContentPanel = function(el, config, content){
     }
     // handle view.xtype
     
-    if (this.view && typeof(this.view.xtype) != 'undefined') {
-        this.view.el = this.el.appendChild(document.createElement("div"));
-        this.view = Roo.factory(this.view);
-        this.view.render && this.view.render(false, ''); // render blank..
-    }
-    
     
     
     this.addEvents({
@@ -48779,6 +50199,10 @@ Roo.ContentPanel = function(el, config, content){
         
         
     });
+    
+
+    
+    
     if(this.autoScroll){
         this.resizeEl.setStyle("overflow", "auto");
     } else {
@@ -48800,6 +50224,13 @@ Roo.ContentPanel = function(el, config, content){
     
     Roo.ContentPanel.superclass.constructor.call(this);
     
+    if (this.view && typeof(this.view.xtype) != 'undefined') {
+        this.view.el = this.el.appendChild(document.createElement("div"));
+        this.view = Roo.factory(this.view); 
+        this.view.render  &&  this.view.render(false, '');  
+    }
+    
+    
     this.fireEvent('render', this);
 };
 
@@ -49071,13 +50502,15 @@ layout.addxtype({
             return this.form;
         }
         // should only have one of theses..
-        if (['View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
-            // views..
+        if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
+            // views.. should not be just added - used named prop 'view''
+            
             cfg.el = this.el.appendChild(document.createElement("div"));
             // factory?
             
             var ret = new Roo.factory(cfg);
-            ret.render && ret.render(false, ''); // render blank..
+             
+             ret.render && ret.render(false, ''); // render blank..
             this.view = ret;
             return ret;
         }
@@ -49974,6 +51407,9 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
         c.on("dblclick", this.onDblClick, this);
         c.on("contextmenu", this.onContextMenu, this);
         c.on("keydown", this.onKeyDown, this);
+        if (Roo.isTouch) {
+            c.on("touchstart", this.onTouchStart, this);
+        }
 
         this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
 
@@ -50053,15 +51489,45 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
 
     // private
     processEvent : function(name, e){
-        this.fireEvent(name, e);
+        // does this fire select???
+        Roo.log('grid:processEvent '  + name);
+        
+        if (name != 'touchstart' ) {
+            this.fireEvent(name, e);    
+        }
+        
         var t = e.getTarget();
         var v = this.view;
         var header = v.findHeaderIndex(t);
         if(header !== false){
-            this.fireEvent("header" + name, this, header, e);
+            this.fireEvent("header" + (name == 'touchstart' ? 'click' : name), this, header, e);
         }else{
             var row = v.findRowIndex(t);
             var cell = v.findCellIndex(t);
+            if (name == 'touchstart') {
+                // first touch is always a click.
+                // hopefull this happens after selection is updated.?
+                name = false;
+                
+                if (typeof(this.selModel.getSelectedCell) != 'undefined') {
+                    var cs = this.selModel.getSelectedCell();
+                    if (row == cs[0] && cell == cs[1]){
+                        name = 'dblclick';
+                    }
+                }
+                if (typeof(this.selModel.getSelections) != 'undefined') {
+                    var cs = this.selModel.getSelections();
+                    var ds = this.dataSource;
+                    if (cs.length == 1 && ds.getAt(row) == cs[0]){
+                        name = 'dblclick';
+                    }
+                }
+                if (!name) {
+                    return;
+                }
+            }
+            
+            
             if(row !== false){
                 this.fireEvent("row" + name, this, row, e);
                 if(cell !== false){
@@ -50075,6 +51541,10 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
     onClick : function(e){
         this.processEvent("click", e);
     },
+   // private
+    onTouchStart : function(e){
+        this.processEvent("touchstart", e);
+    },
 
     // private
     onContextMenu : function(e, t){
@@ -54276,1589 +55746,416 @@ Roo.LoadMask = function(el, config){
         this.store.on('load', this.onLoad, this);
         this.store.on('loadexception', this.onLoadException, this);
         this.removeMask = false;
-    }else{
-        var um = this.el.getUpdateManager();
-        um.showLoadIndicator = false; // disable the default indicator
-        um.on('beforeupdate', this.onBeforeLoad, this);
-        um.on('update', this.onLoad, this);
-        um.on('failure', this.onLoad, this);
-        this.removeMask = true;
-    }
-};
-
-Roo.LoadMask.prototype = {
-    /**
-     * @cfg {Boolean} removeMask
-     * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
-     * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
-     */
-    /**
-     * @cfg {String} msg
-     * The text to display in a centered loading message box (defaults to 'Loading...')
-     */
-    msg : 'Loading...',
-    /**
-     * @cfg {String} msgCls
-     * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
-     */
-    msgCls : 'x-mask-loading',
-
-    /**
-     * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
-     * @type Boolean
-     */
-    disabled: false,
-
-    /**
-     * Disables the mask to prevent it from being displayed
-     */
-    disable : function(){
-       this.disabled = true;
-    },
-
-    /**
-     * Enables the mask so that it can be displayed
-     */
-    enable : function(){
-        this.disabled = false;
-    },
-    
-    onLoadException : function()
-    {
-        Roo.log(arguments);
-        
-        if (typeof(arguments[3]) != 'undefined') {
-            Roo.MessageBox.alert("Error loading",arguments[3]);
-        } 
-        /*
-        try {
-            if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
-                Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
-            }   
-        } catch(e) {
-            
-        }
-        */
-    
-        
-        
-        this.el.unmask(this.removeMask);
-    },
-    // private
-    onLoad : function()
-    {
-        this.el.unmask(this.removeMask);
-    },
-
-    // private
-    onBeforeLoad : function(){
-        if(!this.disabled){
-            this.el.mask(this.msg, this.msgCls);
-        }
-    },
-
-    // private
-    destroy : function(){
-        if(this.store){
-            this.store.un('beforeload', this.onBeforeLoad, this);
-            this.store.un('load', this.onLoad, this);
-            this.store.un('loadexception', this.onLoadException, this);
-        }else{
-            var um = this.el.getUpdateManager();
-            um.un('beforeupdate', this.onBeforeLoad, this);
-            um.un('update', this.onLoad, this);
-            um.un('failure', this.onLoad, this);
-        }
-    }
-};/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-
-
-/**
- * @class Roo.XTemplate
- * @extends Roo.Template
- * Provides a template that can have nested templates for loops or conditionals. The syntax is:
-<pre><code>
-var t = new Roo.XTemplate(
-       '&lt;select name="{name}"&gt;',
-               '&lt;tpl for="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
-       '&lt;/select&gt;'
-);
-// then append, applying the master template values
- </code></pre>
- *
- * Supported features:
- *
- *  Tags:
-
-<pre><code>
-      {a_variable} - output encoded.
-      {a_variable.format:("Y-m-d")} - call a method on the variable
-      {a_variable:raw} - unencoded output
-      {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
-      {a_variable:this.method_on_template(...)} - call a method on the template object.
-</code></pre>
- *  The tpl tag:
-<pre><code>
-        &lt;tpl for="a_variable or condition.."&gt;&lt;/tpl&gt;
-        &lt;tpl if="a_variable or condition"&gt;&lt;/tpl&gt;
-        &lt;tpl exec="some javascript"&gt;&lt;/tpl&gt;
-        &lt;tpl name="named_template"&gt;&lt;/tpl&gt; (experimental)
-  
-        &lt;tpl for="."&gt;&lt;/tpl&gt; - just iterate the property..
-        &lt;tpl for=".."&gt;&lt;/tpl&gt; - iterates with the parent (probably the template) 
-</code></pre>
- *      
- */
-Roo.XTemplate = function()
-{
-    Roo.XTemplate.superclass.constructor.apply(this, arguments);
-    if (this.html) {
-        this.compile();
-    }
-};
-
-
-Roo.extend(Roo.XTemplate, Roo.Template, {
-
-    /**
-     * The various sub templates
-     */
-    tpls : false,
-    /**
-     *
-     * basic tag replacing syntax
-     * WORD:WORD()
-     *
-     * // you can fake an object call by doing this
-     *  x.t:(test,tesT) 
-     * 
-     */
-    re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
-
-    /**
-     * compile the template
-     *
-     * This is not recursive, so I'm not sure how nested templates are really going to be handled..
-     *
-     */
-    compile: function()
-    {
-        var s = this.html;
-     
-        s = ['<tpl>', s, '</tpl>'].join('');
-    
-        var re     = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
-            nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
-            ifRe   = /^<tpl\b[^>]*?if="(.*?)"/,
-            execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
-            namedRe = /^<tpl\b[^>]*?name="(\w+)"/,  // named templates..
-            m,
-            id     = 0,
-            tpls   = [];
-    
-        while(true == !!(m = s.match(re))){
-            var forMatch   = m[0].match(nameRe),
-                ifMatch   = m[0].match(ifRe),
-                execMatch   = m[0].match(execRe),
-                namedMatch   = m[0].match(namedRe),
-                
-                exp  = null, 
-                fn   = null,
-                exec = null,
-                name = forMatch && forMatch[1] ? forMatch[1] : '';
-                
-            if (ifMatch) {
-                // if - puts fn into test..
-                exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
-                if(exp){
-                   fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
-                }
-            }
-            
-            if (execMatch) {
-                // exec - calls a function... returns empty if true is  returned.
-                exp = execMatch && execMatch[1] ? execMatch[1] : null;
-                if(exp){
-                   exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
-                }
-            }
-            
-            
-            if (name) {
-                // for = 
-                switch(name){
-                    case '.':  name = new Function('values', 'parent', 'with(values){ return values; }'); break;
-                    case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
-                    default:   name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
-                }
-            }
-            var uid = namedMatch ? namedMatch[1] : id;
-            
-            
-            tpls.push({
-                id:     namedMatch ? namedMatch[1] : id,
-                target: name,
-                exec:   exec,
-                test:   fn,
-                body:   m[1] || ''
-            });
-            if (namedMatch) {
-                s = s.replace(m[0], '');
-            } else { 
-                s = s.replace(m[0], '{xtpl'+ id + '}');
-            }
-            ++id;
-        }
-        this.tpls = [];
-        for(var i = tpls.length-1; i >= 0; --i){
-            this.compileTpl(tpls[i]);
-            this.tpls[tpls[i].id] = tpls[i];
-        }
-        this.master = tpls[tpls.length-1];
-        return this;
-    },
-    /**
-     * same as applyTemplate, except it's done to one of the subTemplates
-     * when using named templates, you can do:
-     *
-     * var str = pl.applySubTemplate('your-name', values);
-     *
-     * 
-     * @param {Number} id of the template
-     * @param {Object} values to apply to template
-     * @param {Object} parent (normaly the instance of this object)
-     */
-    applySubTemplate : function(id, values, parent)
-    {
-        
-        
-        var t = this.tpls[id];
-        
-        
-        try { 
-            if(t.test && !t.test.call(this, values, parent)){
-                return '';
-            }
-        } catch(e) {
-            Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
-            Roo.log(e.toString());
-            Roo.log(t.test);
-            return ''
-        }
-        try { 
-            
-            if(t.exec && t.exec.call(this, values, parent)){
-                return '';
-            }
-        } catch(e) {
-            Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
-            Roo.log(e.toString());
-            Roo.log(t.exec);
-            return ''
-        }
-        try {
-            var vs = t.target ? t.target.call(this, values, parent) : values;
-            parent = t.target ? values : parent;
-            if(t.target && vs instanceof Array){
-                var buf = [];
-                for(var i = 0, len = vs.length; i < len; i++){
-                    buf[buf.length] = t.compiled.call(this, vs[i], parent);
-                }
-                return buf.join('');
-            }
-            return t.compiled.call(this, vs, parent);
-        } catch (e) {
-            Roo.log("Xtemplate.applySubTemplate : Exception thrown");
-            Roo.log(e.toString());
-            Roo.log(t.compiled);
-            return '';
-        }
-    },
-
-    compileTpl : function(tpl)
-    {
-        var fm = Roo.util.Format;
-        var useF = this.disableFormats !== true;
-        var sep = Roo.isGecko ? "+" : ",";
-        var undef = function(str) {
-            Roo.log("Property not found :"  + str);
-            return '';
-        };
-        
-        var fn = function(m, name, format, args)
-        {
-            //Roo.log(arguments);
-            args = args ? args.replace(/\\'/g,"'") : args;
-            //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
-            if (typeof(format) == 'undefined') {
-                format= 'htmlEncode';
-            }
-            if (format == 'raw' ) {
-                format = false;
-            }
-            
-            if(name.substr(0, 4) == 'xtpl'){
-                return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
-            }
-            
-            // build an array of options to determine if value is undefined..
-            
-            // basically get 'xxxx.yyyy' then do
-            // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
-            //    (function () { Roo.log("Property not found"); return ''; })() :
-            //    ......
-            
-            var udef_ar = [];
-            var lookfor = '';
-            Roo.each(name.split('.'), function(st) {
-                lookfor += (lookfor.length ? '.': '') + st;
-                udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
-            });
-            
-            var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
-            
-            
-            if(format && useF){
-                
-                args = args ? ',' + args : "";
-                 
-                if(format.substr(0, 5) != "this."){
-                    format = "fm." + format + '(';
-                }else{
-                    format = 'this.call("'+ format.substr(5) + '", ';
-                    args = ", values";
-                }
-                
-                return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
-            }
-             
-            if (args.length) {
-                // called with xxyx.yuu:(test,test)
-                // change to ()
-                return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
-            }
-            // raw.. - :raw modifier..
-            return "'"+ sep + udef_st  + name + ")"+sep+"'";
-            
-        };
-        var body;
-        // branched to use + in gecko and [].join() in others
-        if(Roo.isGecko){
-            body = "tpl.compiled = function(values, parent){  with(values) { return '" +
-                   tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
-                    "';};};";
-        }else{
-            body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
-            body.push(tpl.body.replace(/(\r\n|\n)/g,
-                            '\\n').replace(/'/g, "\\'").replace(this.re, fn));
-            body.push("'].join('');};};");
-            body = body.join('');
-        }
-        
-        Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
-       
-        /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
-        eval(body);
-        
-        return this;
-    },
-
-    applyTemplate : function(values){
-        return this.master.compiled.call(this, values, {});
-        //var s = this.subs;
-    },
-
-    apply : function(){
-        return this.applyTemplate.apply(this, arguments);
-    }
-
- });
-
-Roo.XTemplate.from = function(el){
-    el = Roo.getDom(el);
-    return new Roo.XTemplate(el.value || el.innerHTML);
-};/*
- * 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.
- * 
- * 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 )
- * 
- * @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;
-        
-        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;
-            el = Roo.get(ename);
-            if (!el) {
-                Roo.log("Warning - element can not be found :#" + ename );
-                return;
-            }
-        }
-        
-        
-        if (!this.parent) {
-            
-            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' 
-            
-        var tree = this._tree ? this._tree() : this.tree();
-        tree.region = tree.region || this.region;
-        this.el = this.parent.el.addxtype(tree);
-        this.fireEvent('built', this);
-        
-        this.panel = this.el;
-        this.layout = this.panel.layout;
-               this.parentLayout = this.parent.layout  || false;  
-         
-    }
-    
-});
-
-Roo.apply(Roo.XComponent, {
-    /**
-     * @property  hideProgress
-     * true to disable the building progress bar.. usefull on single page renders.
-     * @type Boolean
-     */
-    hideProgress : false,
-    /**
-     * @property  buildCompleted
-     * True when the builder has completed building the interface.
-     * @type Boolean
-     */
-    buildCompleted : false,
-     
-    /**
-     * @property  topModule
-     * the upper most module - uses document.element as it's constructor.
-     * @type Object
-     */
-     
-    topModule  : false,
-      
-    /**
-     * @property  modules
-     * array of modules to be created by registration system.
-     * @type {Array} of Roo.XComponent
-     */
-    
-    modules : [],
-    /**
-     * @property  elmodules
-     * array of modules to be created by which use #ID 
-     * @type {Array} of Roo.XComponent
-     */
-     
-    elmodules : [],
-
-    
-    /**
-     * Register components to be built later.
-     *
-     * This solves the following issues
-     * - Building is not done on page load, but after an authentication process has occured.
-     * - Interface elements are registered on page load
-     * - Parent Interface elements may not be loaded before child, so this handles that..
-     * 
-     *
-     * example:
-     * 
-     * MyApp.register({
-          order : '000001',
-          module : 'Pman.Tab.projectMgr',
-          region : 'center',
-          parent : 'Pman.layout',
-          disabled : false,  // or use a function..
-        })
-     
-     * * @param {Object} details about module
-     */
-    register : function(obj) {
-               
-        Roo.XComponent.event.fireEvent('register', obj);
-        switch(typeof(obj.disabled) ) {
-                
-            case 'undefined':
-                break;
-            
-            case 'function':
-                if ( obj.disabled() ) {
-                        return;
-                }
-                break;
-            
-            default:
-                if (obj.disabled) {
-                        return;
-                }
-                break;
-        }
-               
-        this.modules.push(obj);
-         
-    },
-    /**
-     * convert a string to an object..
-     * eg. 'AAA.BBB' -> finds AAA.BBB
-
-     */
-    
-    toObject : function(str)
-    {
-        if (!str || typeof(str) == 'object') {
-            return str;
-        }
-        if (str.substring(0,1) == '#') {
-            return str;
-        }
-
-        var ar = str.split('.');
-        var rt, o;
-        rt = ar.shift();
-            /** eval:var:o */
-        try {
-            eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
-        } catch (e) {
-            throw "Module not found : " + str;
-        }
-        
-        if (o === false) {
-            throw "Module not found : " + str;
-        }
-        Roo.each(ar, function(e) {
-            if (typeof(o[e]) == 'undefined') {
-                throw "Module not found : " + str;
-            }
-            o = o[e];
-        });
-        
-        return o;
-        
-    },
-    
-    
-    /**
-     * move modules into their correct place in the tree..
-     * 
-     */
-    preBuild : function ()
-    {
-        var _t = this;
-        Roo.each(this.modules , function (obj)
-        {
-            Roo.XComponent.event.fireEvent('beforebuild', obj);
-            
-            var opar = obj.parent;
-            try { 
-                obj.parent = this.toObject(opar);
-            } catch(e) {
-                Roo.log("parent:toObject failed: " + e.toString());
-                return;
-            }
-            
-            if (!obj.parent) {
-                Roo.debug && Roo.log("GOT top level module");
-                Roo.debug && Roo.log(obj);
-                obj.modules = new Roo.util.MixedCollection(false, 
-                    function(o) { return o.order + '' }
-                );
-                this.topModule = obj;
-                return;
-            }
-                       // parent is a string (usually a dom element name..)
-            if (typeof(obj.parent) == 'string') {
-                this.elmodules.push(obj);
-                return;
-            }
-            if (obj.parent.constructor != Roo.XComponent) {
-                Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
-            }
-            if (!obj.parent.modules) {
-                obj.parent.modules = new Roo.util.MixedCollection(false, 
-                    function(o) { return o.order + '' }
-                );
-            }
-            if (obj.parent.disabled) {
-                obj.disabled = true;
-            }
-            obj.parent.modules.add(obj);
-        }, this);
-    },
-    
-     /**
-     * make a list of modules to build.
-     * @return {Array} list of modules. 
-     */ 
-    
-    buildOrder : function()
-    {
-        var _this = this;
-        var cmp = function(a,b) {   
-            return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
-        };
-        if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
-            throw "No top level modules to build";
-        }
-        
-        // make a flat list in order of modules to build.
-        var mods = this.topModule ? [ this.topModule ] : [];
-               
-        
-       // elmodules (is a list of DOM based modules )
-        Roo.each(this.elmodules, function(e) {
-            mods.push(e);
-            if (!this.topModule &&
-                typeof(e.parent) == 'string' &&
-                e.parent.substring(0,1) == '#' &&
-                Roo.get(e.parent.substr(1))
-               ) {
-                
-                _this.topModule = e;
-            }
-            
-        });
-
-        
-        // add modules to their parents..
-        var addMod = function(m) {
-            Roo.debug && Roo.log("build Order: add: " + m.name);
-                
-            mods.push(m);
-            if (m.modules && !m.disabled) {
-                Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
-                m.modules.keySort('ASC',  cmp );
-                Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
-    
-                m.modules.each(addMod);
-            } else {
-                Roo.debug && Roo.log("build Order: no child modules");
-            }
-            // not sure if this is used any more..
-            if (m.finalize) {
-                m.finalize.name = m.name + " (clean up) ";
-                mods.push(m.finalize);
-            }
-            
-        }
-        if (this.topModule) { 
-            this.topModule.modules.keySort('ASC',  cmp );
-            this.topModule.modules.each(addMod);
-        } 
-        return mods;
-    },
-    
-     /**
-     * Build the registered modules.
-     * @param {Object} parent element.
-     * @param {Function} optional method to call after module has been added.
-     * 
-     */ 
-   
-    build : function() 
-    {
-        
-        this.preBuild();
-        var mods = this.buildOrder();
-      
-        //this.allmods = mods;
-        //Roo.debug && Roo.log(mods);
-        //return;
-        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.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.hide();
-                }
-                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.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); 
- //<script type="text/javascript">
-
-
-/**
- * @class Roo.Login
- * @extends Roo.LayoutDialog
- * A generic Login Dialog..... - only one needed in theory!?!?
- *
- * Fires XComponent builder on success...
- * 
- * Sends 
- *    username,password, lang = for login actions.
- *    check = 1 for periodic checking that sesion is valid.
- *    passwordRequest = email request password
- *    logout = 1 = to logout
- * 
- * Affects: (this id="????" elements)
- *   loading  (removed) (used to indicate application is loading)
- *   loading-mask (hides) (used to hide application when it's building loading)
- *   
- * 
- * Usage: 
- *    
- * 
- * Myapp.login = Roo.Login({
-     url: xxxx,
-   
-     realm : 'Myapp', 
-     
-     
-     method : 'POST',
-     
-     
-     * 
- })
- * 
- * 
- * 
- **/
-Roo.Login = function(cfg)
-{
-    this.addEvents({
-        'refreshed' : true
-    });
-    
-    Roo.apply(this,cfg);
-    
-    Roo.onReady(function() {
-        this.onLoad();
-    }, this);
-    // call parent..
-    
-   
-    Roo.Login.superclass.constructor.call(this, this);
-    //this.addxtype(this.items[0]);
-    
-    
-}
-
+    }else{
+        var um = this.el.getUpdateManager();
+        um.showLoadIndicator = false; // disable the default indicator
+        um.on('beforeupdate', this.onBeforeLoad, this);
+        um.on('update', this.onLoad, this);
+        um.on('failure', this.onLoad, this);
+        this.removeMask = true;
+    }
+};
 
-Roo.extend(Roo.Login, Roo.LayoutDialog, {
-    
+Roo.LoadMask.prototype = {
     /**
-     * @cfg {String} method
-     * Method used to query for login details.
+     * @cfg {Boolean} removeMask
+     * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
+     * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
      */
-    
-    method : 'POST',
     /**
-     * @cfg {String} url
-     * URL to query login data. - eg. baseURL + '/Login.php'
+     * @cfg {String} msg
+     * The text to display in a centered loading message box (defaults to 'Loading...')
      */
-    url : '',
-    
+    msg : 'Loading...',
     /**
-     * @property user
-     * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
-     * @type {Object} 
+     * @cfg {String} msgCls
+     * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
      */
-    user : false,
+    msgCls : 'x-mask-loading',
+
     /**
-     * @property checkFails
-     * Number of times we have attempted to get authentication check, and failed.
-     * @type {Number} 
+     * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
+     * @type Boolean
      */
-    checkFails : 0,
-      /**
-     * @property intervalID
-     * The window interval that does the constant login checking.
-     * @type {Number} 
+    disabled: false,
+
+    /**
+     * Disables the mask to prevent it from being displayed
      */
-    intervalID : 0,
-    
+    disable : function(){
+       this.disabled = true;
+    },
+
+    /**
+     * Enables the mask so that it can be displayed
+     */
+    enable : function(){
+        this.disabled = false;
+    },
     
-    onLoad : function() // called on page load...
+    onLoadException : function()
     {
-        // load 
-         
-        if (Roo.get('loading')) { // clear any loading indicator..
-            Roo.get('loading').remove();
-        }
+        Roo.log(arguments);
         
-        //this.switchLang('en'); // set the language to english..
-       
-        this.check({
-            success:  function(response, opts)  {  // check successfull...
+        if (typeof(arguments[3]) != 'undefined') {
+            Roo.MessageBox.alert("Error loading",arguments[3]);
+        } 
+        /*
+        try {
+            if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
+                Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
+            }   
+        } catch(e) {
             
-                var res = this.processResponse(response);
-                this.checkFails =0;
-                if (!res.success) { // error!
-                    this.checkFails = 5;
-                    //console.log('call failure');
-                    return this.failure(response,opts);
-                }
-                
-                if (!res.data.id) { // id=0 == login failure.
-                    return this.show();
-                }
-                
-                              
-                        //console.log(success);
-                this.fillAuth(res.data);   
-                this.checkFails =0;
-                Roo.XComponent.build();
-            },
-            failure : this.show
-        });
-        
-    }, 
-    
+        }
+        */
     
-    check: function(cfg) // called every so often to refresh cookie etc..
+        
+        
+        this.el.unmask(this.removeMask);
+    },
+    // private
+    onLoad : function()
     {
-        if (cfg.again) { // could be undefined..
-            this.checkFails++;
-        } else {
-            this.checkFails = 0;
+        this.el.unmask(this.removeMask);
+    },
+
+    // private
+    onBeforeLoad : function(){
+        if(!this.disabled){
+            this.el.mask(this.msg, this.msgCls);
         }
-        var _this = this;
-        if (this.sending) {
-            if ( this.checkFails > 4) {
-                Roo.MessageBox.alert("Error",  
-                    "Error getting authentication status. - try reloading, or wait a while", function() {
-                        _this.sending = false;
-                    }); 
-                return;
-            }
-            cfg.again = true;
-            _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
-            return;
+    },
+
+    // private
+    destroy : function(){
+        if(this.store){
+            this.store.un('beforeload', this.onBeforeLoad, this);
+            this.store.un('load', this.onLoad, this);
+            this.store.un('loadexception', this.onLoadException, this);
+        }else{
+            var um = this.el.getUpdateManager();
+            um.un('beforeupdate', this.onBeforeLoad, this);
+            um.un('update', this.onLoad, this);
+            um.un('failure', this.onLoad, this);
         }
-        this.sending = true;
-        
-        Roo.Ajax.request({  
-            url: this.url,
-            params: {
-                getAuthUser: true
-            },  
-            method: this.method,
-            success:  cfg.success || this.success,
-            failure : cfg.failure || this.failure,
-            scope : this,
-            callCfg : cfg
-              
-        });  
-    }, 
+    }
+};/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+
+
+/**
+ * @class Roo.XTemplate
+ * @extends Roo.Template
+ * Provides a template that can have nested templates for loops or conditionals. The syntax is:
+<pre><code>
+var t = new Roo.XTemplate(
+       '&lt;select name="{name}"&gt;',
+               '&lt;tpl for="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
+       '&lt;/select&gt;'
+);
+// then append, applying the master template values
+ </code></pre>
+ *
+ * Supported features:
+ *
+ *  Tags:
+
+<pre><code>
+      {a_variable} - output encoded.
+      {a_variable.format:("Y-m-d")} - call a method on the variable
+      {a_variable:raw} - unencoded output
+      {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
+      {a_variable:this.method_on_template(...)} - call a method on the template object.
+</code></pre>
+ *  The tpl tag:
+<pre><code>
+        &lt;tpl for="a_variable or condition.."&gt;&lt;/tpl&gt;
+        &lt;tpl if="a_variable or condition"&gt;&lt;/tpl&gt;
+        &lt;tpl exec="some javascript"&gt;&lt;/tpl&gt;
+        &lt;tpl name="named_template"&gt;&lt;/tpl&gt; (experimental)
+  
+        &lt;tpl for="."&gt;&lt;/tpl&gt; - just iterate the property..
+        &lt;tpl for=".."&gt;&lt;/tpl&gt; - iterates with the parent (probably the template) 
+</code></pre>
+ *      
+ */
+Roo.XTemplate = function()
+{
+    Roo.XTemplate.superclass.constructor.apply(this, arguments);
+    if (this.html) {
+        this.compile();
+    }
+};
+
+
+Roo.extend(Roo.XTemplate, Roo.Template, {
+
+    /**
+     * The various sub templates
+     */
+    tpls : false,
+    /**
+     *
+     * basic tag replacing syntax
+     * WORD:WORD()
+     *
+     * // you can fake an object call by doing this
+     *  x.t:(test,tesT) 
+     * 
+     */
+    re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
+
+    /**
+     * compile the template
+     *
+     * This is not recursive, so I'm not sure how nested templates are really going to be handled..
+     *
+     */
+    compile: function()
+    {
+        var s = this.html;
+     
+        s = ['<tpl>', s, '</tpl>'].join('');
     
+        var re     = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
+            nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
+            ifRe   = /^<tpl\b[^>]*?if="(.*?)"/,
+            execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
+            namedRe = /^<tpl\b[^>]*?name="(\w+)"/,  // named templates..
+            m,
+            id     = 0,
+            tpls   = [];
     
-    logout: function()
-    {
-        window.onbeforeunload = function() { }; // false does not work for IE..
-        this.user = false;
-        var _this = this;
-        
-        Roo.Ajax.request({  
-            url: this.url,
-            params: {
-                logout: 1
-            },  
-            method: 'GET',
-            failure : function() {
-                Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
-                    document.location = document.location.toString() + '?ts=' + Math.random();
-                });
+        while(true == !!(m = s.match(re))){
+            var forMatch   = m[0].match(nameRe),
+                ifMatch   = m[0].match(ifRe),
+                execMatch   = m[0].match(execRe),
+                namedMatch   = m[0].match(namedRe),
                 
-            },
-            success : function() {
-                _this.user = false;
-                this.checkFails =0;
-                // fixme..
-                document.location = document.location.toString() + '?ts=' + Math.random();
+                exp  = null, 
+                fn   = null,
+                exec = null,
+                name = forMatch && forMatch[1] ? forMatch[1] : '';
+                
+            if (ifMatch) {
+                // if - puts fn into test..
+                exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
+                if(exp){
+                   fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
+                }
             }
-              
-              
-        }); 
-    },
-    
-    processResponse : function (response)
-    {
-        var res = '';
-        try {
-            res = Roo.decode(response.responseText);
-            // oops...
-            if (typeof(res) != 'object') {
-                res = { success : false, errorMsg : res, errors : true };
+            
+            if (execMatch) {
+                // exec - calls a function... returns empty if true is  returned.
+                exp = execMatch && execMatch[1] ? execMatch[1] : null;
+                if(exp){
+                   exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
+                }
             }
-            if (typeof(res.success) == 'undefined') {
-                res.success = false;
+            
+            
+            if (name) {
+                // for = 
+                switch(name){
+                    case '.':  name = new Function('values', 'parent', 'with(values){ return values; }'); break;
+                    case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
+                    default:   name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
+                }
             }
+            var uid = namedMatch ? namedMatch[1] : id;
             
-        } catch(e) {
-            res = { success : false,  errorMsg : response.responseText, errors : true };
-        }
-        return res;
-    },
-    
-    success : function(response, opts)  // check successfull...
-    {  
-        this.sending = false;
-        var res = this.processResponse(response);
-        if (!res.success) {
-            return this.failure(response, opts);
-        }
-        if (!res.data || !res.data.id) {
-            return this.failure(response,opts);
-        }
-        //console.log(res);
-        this.fillAuth(res.data);
-        
-        this.checkFails =0;
-        
-    },
-    
-    
-    failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
-    {
-        this.authUser = -1;
-        this.sending = false;
-        var res = this.processResponse(response);
-        //console.log(res);
-        if ( this.checkFails > 2) {
-        
-            Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg : 
-                "Error getting authentication status. - try reloading"); 
-            return;
+            
+            tpls.push({
+                id:     namedMatch ? namedMatch[1] : id,
+                target: name,
+                exec:   exec,
+                test:   fn,
+                body:   m[1] || ''
+            });
+            if (namedMatch) {
+                s = s.replace(m[0], '');
+            } else { 
+                s = s.replace(m[0], '{xtpl'+ id + '}');
+            }
+            ++id;
         }
-        opts.callCfg.again = true;
-        this.check.defer(1000, this, [ opts.callCfg ]);
-        return;  
-    },
-    
-    
-    
-    fillAuth: function(au) {
-        this.startAuthCheck();
-        this.authUserId = au.id;
-        this.authUser = au;
-        this.lastChecked = new Date();
-        this.fireEvent('refreshed', au);
-        //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
-        //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
-        au.lang = au.lang || 'en';
-        //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
-        Roo.state.Manager.set( this.realm + 'lang' , au.lang);
-        this.switchLang(au.lang );
-        
-     
-        // open system... - -on setyp..
-        if (this.authUserId  < 0) {
-            Roo.MessageBox.alert("Warning", 
-                "This is an open system - please set up a admin user with a password.");  
+        this.tpls = [];
+        for(var i = tpls.length-1; i >= 0; --i){
+            this.compileTpl(tpls[i]);
+            this.tpls[tpls[i].id] = tpls[i];
         }
-         
-        //Pman.onload(); // which should do nothing if it's a re-auth result...
-        
-             
+        this.master = tpls[tpls.length-1];
+        return this;
     },
-    
-    startAuthCheck : function() // starter for timeout checking..
+    /**
+     * same as applyTemplate, except it's done to one of the subTemplates
+     * when using named templates, you can do:
+     *
+     * var str = pl.applySubTemplate('your-name', values);
+     *
+     * 
+     * @param {Number} id of the template
+     * @param {Object} values to apply to template
+     * @param {Object} parent (normaly the instance of this object)
+     */
+    applySubTemplate : function(id, values, parent)
     {
-        if (this.intervalID) { // timer already in place...
-            return false;
-        }
-        var _this = this;
-        this.intervalID =  window.setInterval(function() {
-              _this.check(false);
-            }, 120000); // every 120 secs = 2mins..
-        
         
-    },
-         
-    
-    switchLang : function (lang) 
-    {
-        _T = typeof(_T) == 'undefined' ? false : _T;
-          if (!_T || !lang.length) {
-            return;
-        }
         
-        if (!_T && lang != 'en') {
-            Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
-            return;
-        }
+        var t = this.tpls[id];
         
-        if (typeof(_T.en) == 'undefined') {
-            _T.en = {};
-            Roo.apply(_T.en, _T);
-        }
         
-        if (typeof(_T[lang]) == 'undefined') {
-            Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
-            return;
+        try { 
+            if(t.test && !t.test.call(this, values, parent)){
+                return '';
+            }
+        } catch(e) {
+            Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
+            Roo.log(e.toString());
+            Roo.log(t.test);
+            return ''
         }
-        
-        
-        Roo.apply(_T, _T[lang]);
-        // just need to set the text values for everything...
-        var _this = this;
-        /* this will not work ...
-        if (this.form) { 
+        try { 
             
-               
-            function formLabel(name, val) {
-                _this.form.findField(name).fieldEl.child('label').dom.innerHTML  = val;
+            if(t.exec && t.exec.call(this, values, parent)){
+                return '';
             }
-            
-            formLabel('password', "Password"+':');
-            formLabel('username', "Email Address"+':');
-            formLabel('lang', "Language"+':');
-            this.dialog.setTitle("Login");
-            this.dialog.buttons[0].setText("Forgot Password");
-            this.dialog.buttons[1].setText("Login");
+        } catch(e) {
+            Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
+            Roo.log(e.toString());
+            Roo.log(t.exec);
+            return ''
+        }
+        try {
+            var vs = t.target ? t.target.call(this, values, parent) : values;
+            parent = t.target ? values : parent;
+            if(t.target && vs instanceof Array){
+                var buf = [];
+                for(var i = 0, len = vs.length; i < len; i++){
+                    buf[buf.length] = t.compiled.call(this, vs[i], parent);
+                }
+                return buf.join('');
+            }
+            return t.compiled.call(this, vs, parent);
+        } catch (e) {
+            Roo.log("Xtemplate.applySubTemplate : Exception thrown");
+            Roo.log(e.toString());
+            Roo.log(t.compiled);
+            return '';
         }
-        */
-        
-        
     },
-    
-    
-    title: "Login",
-    modal: true,
-    width:  350,
-    //height: 230,
-    height: 180,
-    shadow: true,
-    minWidth:200,
-    minHeight:180,
-    //proxyDrag: true,
-    closable: false,
-    draggable: false,
-    collapsible: false,
-    resizable: false,
-    center: {  // needed??
-        autoScroll:false,
-        titlebar: false,
-       // tabPosition: 'top',
-        hideTabs: true,
-        closeOnTab: true,
-        alwaysShowTabs: false
-    } ,
-    listeners : {
+
+    compileTpl : function(tpl)
+    {
+        var fm = Roo.util.Format;
+        var useF = this.disableFormats !== true;
+        var sep = Roo.isGecko ? "+" : ",";
+        var undef = function(str) {
+            Roo.log("Property not found :"  + str);
+            return '';
+        };
         
-        show  : function(dlg)
+        var fn = function(m, name, format, args)
         {
-            //console.log(this);
-            this.form = this.layout.getRegion('center').activePanel.form;
-            this.form.dialog = dlg;
-            this.buttons[0].form = this.form;
-            this.buttons[0].dialog = dlg;
-            this.buttons[1].form = this.form;
-            this.buttons[1].dialog = dlg;
-           
-           //this.resizeToLogo.defer(1000,this);
-            // this is all related to resizing for logos..
-            //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
-           //// if (!sz) {
-             //   this.resizeToLogo.defer(1000,this);
-             //   return;
-           // }
-            //var w = Ext.lib.Dom.getViewWidth() - 100;
-            //var h = Ext.lib.Dom.getViewHeight() - 100;
-            //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
-            //this.center();
-            if (this.disabled) {
-                this.hide();
-                return;
-            }
-            
-            if (this.user.id < 0) { // used for inital setup situations.
-                return;
+            //Roo.log(arguments);
+            args = args ? args.replace(/\\'/g,"'") : args;
+            //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
+            if (typeof(format) == 'undefined') {
+                format= 'htmlEncode';
             }
-            
-            if (this.intervalID) {
-                // remove the timer
-                window.clearInterval(this.intervalID);
-                this.intervalID = false;
+            if (format == 'raw' ) {
+                format = false;
             }
             
-            
-            if (Roo.get('loading')) {
-                Roo.get('loading').remove();
-            }
-            if (Roo.get('loading-mask')) {
-                Roo.get('loading-mask').hide();
+            if(name.substr(0, 4) == 'xtpl'){
+                return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
             }
             
-            //incomming._node = tnode;
-            this.form.reset();
-            //this.dialog.modal = !modal;
-            //this.dialog.show();
-            this.el.unmask(); 
+            // build an array of options to determine if value is undefined..
             
+            // basically get 'xxxx.yyyy' then do
+            // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
+            //    (function () { Roo.log("Property not found"); return ''; })() :
+            //    ......
             
-            this.form.setValues({
-                'username' : Roo.state.Manager.get(this.realm + '.username', ''),
-                'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
+            var udef_ar = [];
+            var lookfor = '';
+            Roo.each(name.split('.'), function(st) {
+                lookfor += (lookfor.length ? '.': '') + st;
+                udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
             });
             
-            this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
-            if (this.form.findField('username').getValue().length > 0 ){
-                this.form.findField('password').focus();
-            } else {
-               this.form.findField('username').focus();
-            }
-    
-        }
-    },
-    items : [
-         {
-       
-            xtype : 'ContentPanel',
-            xns : Roo,
-            region: 'center',
-            fitToFrame : true,
+            var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
             
-            items : [
-    
-                {
-               
-                    xtype : 'Form',
-                    xns : Roo.form,
-                    labelWidth: 100,
-                    style : 'margin: 10px;',
-                    
-                    listeners : {
-                        actionfailed : function(f, act) {
-                            // form can return { errors: .... }
-                                
-                            //act.result.errors // invalid form element list...
-                            //act.result.errorMsg// invalid form element list...
-                            
-                            this.dialog.el.unmask();
-                            Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg : 
-                                        "Login failed - communication error - try again.");
-                                      
-                        },
-                        actioncomplete: function(re, act) {
-                             
-                            Roo.state.Manager.set(
-                                this.dialog.realm + '.username',  
-                                    this.findField('username').getValue()
-                            );
-                            Roo.state.Manager.set(
-                                this.dialog.realm + '.lang',  
-                                this.findField('lang').getValue() 
-                            );
-                            
-                            this.dialog.fillAuth(act.result.data);
-                              
-                            this.dialog.hide();
-                            
-                            if (Roo.get('loading-mask')) {
-                                Roo.get('loading-mask').show();
-                            }
-                            Roo.XComponent.build();
-                            
-                             
-                            
-                        }
-                    },
-                    items : [
-                        {
-                            xtype : 'TextField',
-                            xns : Roo.form,
-                            fieldLabel: "Email Address",
-                            name: 'username',
-                            width:200,
-                            autoCreate : {tag: "input", type: "text", size: "20"}
-                        },
-                        {
-                            xtype : 'TextField',
-                            xns : Roo.form,
-                            fieldLabel: "Password",
-                            inputType: 'password',
-                            name: 'password',
-                            width:200,
-                            autoCreate : {tag: "input", type: "text", size: "20"},
-                            listeners : {
-                                specialkey : function(e,ev) {
-                                    if (ev.keyCode == 13) {
-                                        this.form.dialog.el.mask("Logging in");
-                                        this.form.doAction('submit', {
-                                            url: this.form.dialog.url,
-                                            method: this.form.dialog.method
-                                        });
-                                    }
-                                }
-                            }  
-                        },
-                        {
-                            xtype : 'ComboBox',
-                            xns : Roo.form,
-                            fieldLabel: "Language",
-                            name : 'langdisp',
-                            store: {
-                                xtype : 'SimpleStore',
-                                fields: ['lang', 'ldisp'],
-                                data : [
-                                    [ 'en', 'English' ],
-                                    [ 'zh_HK' , '\u7E41\u4E2D' ],
-                                    [ 'zh_CN', '\u7C21\u4E2D' ]
-                                ]
-                            },
-                            
-                            valueField : 'lang',
-                            hiddenName:  'lang',
-                            width: 200,
-                            displayField:'ldisp',
-                            typeAhead: false,
-                            editable: false,
-                            mode: 'local',
-                            triggerAction: 'all',
-                            emptyText:'Select a Language...',
-                            selectOnFocus:true,
-                            listeners : {
-                                select :  function(cb, rec, ix) {
-                                    this.form.switchLang(rec.data.lang);
-                                }
-                            }
-                        
-                        }
-                    ]
-                }
-                  
+            
+            if(format && useF){
                 
-            ]
-        }
-    ],
-    buttons : [
-        {
-            xtype : 'Button',
-            xns : 'Roo',
-            text : "Forgot Password",
-            listeners : {
-                click : function() {
-                    //console.log(this);
-                    var n = this.form.findField('username').getValue();
-                    if (!n.length) {
-                        Roo.MessageBox.alert("Error", "Fill in your email address");
-                        return;
-                    }
-                    Roo.Ajax.request({
-                        url: this.dialog.url,
-                        params: {
-                            passwordRequest: n
-                        },
-                        method: this.dialog.method,
-                        success:  function(response, opts)  {  // check successfull...
-                        
-                            var res = this.dialog.processResponse(response);
-                            if (!res.success) { // error!
-                               Roo.MessageBox.alert("Error" ,
-                                    res.errorMsg ? res.errorMsg  : "Problem Requesting Password Reset");
-                               return;
-                            }
-                            Roo.MessageBox.alert("Notice" ,
-                                "Please check you email for the Password Reset message");
-                        },
-                        failure : function() {
-                            Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
-                        }
-                        
-                    });
+                args = args ? ',' + args : "";
+                 
+                if(format.substr(0, 5) != "this."){
+                    format = "fm." + format + '(';
+                }else{
+                    format = 'this.call("'+ format.substr(5) + '", ';
+                    args = ", values";
                 }
-            }
-        },
-        {
-            xtype : 'Button',
-            xns : 'Roo',
-            text : "Login",
-            listeners : {
                 
-                click : function () {
-                        
-                    this.dialog.el.mask("Logging in");
-                    this.form.doAction('submit', {
-                            url: this.dialog.url,
-                            method: this.dialog.method
-                    });
-                }
+                return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
             }
+             
+            if (args.length) {
+                // called with xxyx.yuu:(test,test)
+                // change to ()
+                return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
+            }
+            // raw.. - :raw modifier..
+            return "'"+ sep + udef_st  + name + ")"+sep+"'";
+            
+        };
+        var body;
+        // branched to use + in gecko and [].join() in others
+        if(Roo.isGecko){
+            body = "tpl.compiled = function(values, parent){  with(values) { return '" +
+                   tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
+                    "';};};";
+        }else{
+            body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
+            body.push(tpl.body.replace(/(\r\n|\n)/g,
+                            '\\n').replace(/'/g, "\\'").replace(this.re, fn));
+            body.push("'].join('');};};");
+            body = body.join('');
         }
-    ]
-  
-  
-})
+        
+        Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
+       
+        /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
+        eval(body);
+        
+        return this;
+    },
+
+    applyTemplate : function(values){
+        return this.master.compiled.call(this, values, {});
+        //var s = this.subs;
+    },
 
+    apply : function(){
+        return this.applyTemplate.apply(this, arguments);
+    }
+
+ });
 
-   
\ No newline at end of file
+Roo.XTemplate.from = function(el){
+    el = Roo.getDom(el);
+    return new Roo.XTemplate(el.value || el.innerHTML);
+};
\ No newline at end of file