merge changes for seperator change
[roojs1] / roojs-ui-debug.js
index db1385d..5bfabbb 100644 (file)
  */
 
 
-
-/*
- * These classes are derivatives of the similarly named classes in the YUI Library.
- * The original license:
- * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
- * Code licensed under the BSD License:
- * http://developer.yahoo.net/yui/license.txt
- */
-
-(function() {
-
-var Event=Roo.EventManager;
-var Dom=Roo.lib.Dom;
-
 /**
- * @class Roo.dd.DragDrop
- * @extends Roo.util.Observable
- * Defines the interface and base operation of items that that can be
- * dragged or can be drop targets.  It was designed to be extended, overriding
- * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
- * Up to three html elements can be associated with a DragDrop instance:
- * <ul>
- * <li>linked element: the element that is passed into the constructor.
- * This is the element which defines the boundaries for interaction with
- * other DragDrop objects.</li>
- * <li>handle element(s): The drag operation only occurs if the element that
- * was clicked matches a handle element.  By default this is the linked
- * element, but there are times that you will want only a portion of the
- * linked element to initiate the drag operation, and the setHandleElId()
- * method provides a way to define this.</li>
- * <li>drag element: this represents the element that would be moved along
- * with the cursor during a drag operation.  By default, this is the linked
- * element itself as in {@link Roo.dd.DD}.  setDragElId() lets you define
- * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
- * </li>
- * </ul>
- * This class should not be instantiated until the onload event to ensure that
- * the associated elements are available.
- * The following would define a DragDrop obj that would interact with any
- * other DragDrop obj in the "group1" group:
- * <pre>
- *  dd = new Roo.dd.DragDrop("div1", "group1");
- * </pre>
- * Since none of the event handlers have been implemented, nothing would
- * actually happen if you were to run the code above.  Normally you would
- * override this class or one of the default implementations, but you can
- * also override the methods you want on an instance of the class...
- * <pre>
- *  dd.onDragDrop = function(e, id) {
- *  &nbsp;&nbsp;alert("dd was dropped on " + id);
- *  }
- * </pre>
- * @constructor
- * @param {String} id of the element that is linked to this instance
- * @param {String} sGroup the group of related DragDrop objects
- * @param {object} config an object containing configurable attributes
- *                Valid properties for DragDrop:
- *                    padding, isTarget, maintainOffset, primaryButtonOnly
+ * @class Roo.data.SortTypes
+ * @singleton
+ * Defines the default sorting (casting?) comparison functions used when sorting data.
  */
-Roo.dd.DragDrop = function(id, sGroup, config) {
-    if (id) {
-        this.init(id, sGroup, config);
-    }
-    
-};
-
-Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
-
-    /**
-     * The id of the element associated with this object.  This is what we
-     * refer to as the "linked element" because the size and position of
-     * this element is used to determine when the drag and drop objects have
-     * interacted.
-     * @property id
-     * @type String
-     */
-    id: null,
-
-    /**
-     * Configuration attributes passed into the constructor
-     * @property config
-     * @type object
-     */
-    config: null,
-
-    /**
-     * The id of the element that will be dragged.  By default this is same
-     * as the linked element , but could be changed to another element. Ex:
-     * Roo.dd.DDProxy
-     * @property dragElId
-     * @type String
-     * @private
-     */
-    dragElId: null,
-
-    /**
-     * the id of the element that initiates the drag operation.  By default
-     * this is the linked element, but could be changed to be a child of this
-     * element.  This lets us do things like only starting the drag when the
-     * header element within the linked html element is clicked.
-     * @property handleElId
-     * @type String
-     * @private
-     */
-    handleElId: null,
-
-    /**
-     * An associative array of HTML tags that will be ignored if clicked.
-     * @property invalidHandleTypes
-     * @type {string: string}
-     */
-    invalidHandleTypes: null,
-
-    /**
-     * An associative array of ids for elements that will be ignored if clicked
-     * @property invalidHandleIds
-     * @type {string: string}
-     */
-    invalidHandleIds: null,
-
-    /**
-     * An indexted array of css class names for elements that will be ignored
-     * if clicked.
-     * @property invalidHandleClasses
-     * @type string[]
-     */
-    invalidHandleClasses: null,
-
-    /**
-     * The linked element's absolute X position at the time the drag was
-     * started
-     * @property startPageX
-     * @type int
-     * @private
-     */
-    startPageX: 0,
-
-    /**
-     * The linked element's absolute X position at the time the drag was
-     * started
-     * @property startPageY
-     * @type int
-     * @private
-     */
-    startPageY: 0,
-
-    /**
-     * The group defines a logical collection of DragDrop objects that are
-     * related.  Instances only get events when interacting with other
-     * DragDrop object in the same group.  This lets us define multiple
-     * groups using a single DragDrop subclass if we want.
-     * @property groups
-     * @type {string: string}
-     */
-    groups: null,
-
-    /**
-     * Individual drag/drop instances can be locked.  This will prevent
-     * onmousedown start drag.
-     * @property locked
-     * @type boolean
-     * @private
-     */
-    locked: false,
-
-    /**
-     * Lock this instance
-     * @method lock
-     */
-    lock: function() { this.locked = true; },
-
-    /**
-     * Unlock this instace
-     * @method unlock
-     */
-    unlock: function() { this.locked = false; },
-
-    /**
-     * By default, all insances can be a drop target.  This can be disabled by
-     * setting isTarget to false.
-     * @method isTarget
-     * @type boolean
-     */
-    isTarget: true,
-
-    /**
-     * The padding configured for this drag and drop object for calculating
-     * the drop zone intersection with this object.
-     * @method padding
-     * @type int[]
-     */
-    padding: null,
-
-    /**
-     * Cached reference to the linked element
-     * @property _domRef
-     * @private
-     */
-    _domRef: null,
-
-    /**
-     * Internal typeof flag
-     * @property __ygDragDrop
-     * @private
-     */
-    __ygDragDrop: true,
-
-    /**
-     * Set to true when horizontal contraints are applied
-     * @property constrainX
-     * @type boolean
-     * @private
-     */
-    constrainX: false,
-
-    /**
-     * Set to true when vertical contraints are applied
-     * @property constrainY
-     * @type boolean
-     * @private
-     */
-    constrainY: false,
-
-    /**
-     * The left constraint
-     * @property minX
-     * @type int
-     * @private
-     */
-    minX: 0,
-
-    /**
-     * The right constraint
-     * @property maxX
-     * @type int
-     * @private
-     */
-    maxX: 0,
-
-    /**
-     * The up constraint
-     * @property minY
-     * @type int
-     * @type int
-     * @private
-     */
-    minY: 0,
-
-    /**
-     * The down constraint
-     * @property maxY
-     * @type int
-     * @private
-     */
-    maxY: 0,
-
-    /**
-     * Maintain offsets when we resetconstraints.  Set to true when you want
-     * the position of the element relative to its parent to stay the same
-     * when the page changes
-     *
-     * @property maintainOffset
-     * @type boolean
-     */
-    maintainOffset: false,
-
-    /**
-     * Array of pixel locations the element will snap to if we specified a
-     * horizontal graduation/interval.  This array is generated automatically
-     * when you define a tick interval.
-     * @property xTicks
-     * @type int[]
-     */
-    xTicks: null,
-
-    /**
-     * Array of pixel locations the element will snap to if we specified a
-     * vertical graduation/interval.  This array is generated automatically
-     * when you define a tick interval.
-     * @property yTicks
-     * @type int[]
-     */
-    yTicks: null,
-
-    /**
-     * By default the drag and drop instance will only respond to the primary
-     * button click (left button for a right-handed mouse).  Set to true to
-     * allow drag and drop to start with any mouse click that is propogated
-     * by the browser
-     * @property primaryButtonOnly
-     * @type boolean
-     */
-    primaryButtonOnly: true,
-
-    /**
-     * The availabe property is false until the linked dom element is accessible.
-     * @property available
-     * @type boolean
-     */
-    available: false,
-
-    /**
-     * By default, drags can only be initiated if the mousedown occurs in the
-     * region the linked element is.  This is done in part to work around a
-     * bug in some browsers that mis-report the mousedown if the previous
-     * mouseup happened outside of the window.  This property is set to true
-     * if outer handles are defined.
-     *
-     * @property hasOuterHandles
-     * @type boolean
-     * @default false
-     */
-    hasOuterHandles: false,
-
-    /**
-     * Code that executes immediately before the startDrag event
-     * @method b4StartDrag
-     * @private
-     */
-    b4StartDrag: function(x, y) { },
-
-    /**
-     * Abstract method called after a drag/drop object is clicked
-     * and the drag or mousedown time thresholds have beeen met.
-     * @method startDrag
-     * @param {int} X click location
-     * @param {int} Y click location
-     */
-    startDrag: function(x, y) { /* override this */ },
-
-    /**
-     * Code that executes immediately before the onDrag event
-     * @method b4Drag
-     * @private
-     */
-    b4Drag: function(e) { },
-
-    /**
-     * Abstract method called during the onMouseMove event while dragging an
-     * object.
-     * @method onDrag
-     * @param {Event} e the mousemove event
-     */
-    onDrag: function(e) { /* override this */ },
-
-    /**
-     * 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 */ },
-
-    /**
-     * Code that executes immediately before the onDragOver event
-     * @method b4DragOver
-     * @private
-     */
-    b4DragOver: function(e) { },
-
-    /**
-     * Abstract method called when this element is hovering over another
-     * DragDrop obj
-     * @method onDragOver
-     * @param {Event} e the mousemove event
-     * @param {String|DragDrop[]} id In POINT mode, the element
-     * id this is hovering over.  In INTERSECT mode, an array of dd items
-     * being hovered over.
-     */
-    onDragOver: function(e, id) { /* override this */ },
-
-    /**
-     * Code that executes immediately before the onDragOut event
-     * @method b4DragOut
-     * @private
-     */
-    b4DragOut: function(e) { },
-
-    /**
-     * 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) { },
-
-    /**
-     * 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 */ },
-
-    /**
-     * 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 */ },
-
-    /**
-     * Code that executes immediately before the endDrag event
-     * @method b4EndDrag
-     * @private
-     */
-    b4EndDrag: function(e) { },
-
-    /**
-     * Fired when we are done dragging the object
-     * @method endDrag
-     * @param {Event} e the mouseup event
-     */
-    endDrag: function(e) { /* override this */ },
-
-    /**
-     * Code executed immediately before the onMouseDown event
-     * @method b4MouseDown
-     * @param {Event} e the mousedown event
-     * @private
-     */
-    b4MouseDown: function(e) {  },
-
+Roo.data.SortTypes = {
     /**
-     * Event handler that fires when a drag/drop obj gets a mousedown
-     * @method onMouseDown
-     * @param {Event} e the mousedown event
+     * Default sort that does nothing
+     * @param {Mixed} s The value being converted
+     * @return {Mixed} The comparison value
      */
-    onMouseDown: function(e) { /* override this */ },
-
+    none : function(s){
+        return s;
+    },
+    
     /**
-     * Event handler that fires when a drag/drop obj gets a mouseup
-     * @method onMouseUp
-     * @param {Event} e the mouseup event
+     * The regular expression used to strip tags
+     * @type {RegExp}
+     * @property
      */
-    onMouseUp: function(e) { /* override this */ },
-
+    stripTagsRE : /<\/?[^>]+>/gi,
+    
     /**
-     * Override the onAvailable method to do what is needed after the initial
-     * position was determined.
-     * @method onAvailable
+     * Strips all HTML tags to sort on text only
+     * @param {Mixed} s The value being converted
+     * @return {String} The comparison value
      */
-    onAvailable: function () {
+    asText : function(s){
+        return String(s).replace(this.stripTagsRE, "");
     },
-
-    /*
-     * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
-     * @type Object
+    
+    /**
+     * Strips all HTML tags to sort on text only - Case insensitive
+     * @param {Mixed} s The value being converted
+     * @return {String} The comparison value
      */
-    defaultPadding : {left:0, right:0, top:0, bottom:0},
-
-    /*
-     * Initializes the drag drop object's constraints to restrict movement to a certain element.
- *
- * Usage:
- <pre><code>
- var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
-                { dragElId: "existingProxyDiv" });
- dd.startDrag = function(){
-     this.constrainTo("parent-id");
- };
- </code></pre>
- * Or you can initalize it using the {@link Roo.Element} object:
- <pre><code>
- Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
-     startDrag : function(){
-         this.constrainTo("parent-id");
-     }
- });
- </code></pre>
-     * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
-     * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
-     * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
-     * an object containing the sides to pad. For example: {right:10, bottom:10}
-     * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
-     */
-    constrainTo : function(constrainTo, pad, inContent){
-        if(typeof pad == "number"){
-            pad = {left: pad, right:pad, top:pad, bottom:pad};
-        }
-        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};
-        }
-
-
-        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
-        );
+    asUCText : function(s){
+        return String(s).toUpperCase().replace(this.stripTagsRE, "");
     },
-
+    
     /**
-     * Returns a reference to the linked element
-     * @method getEl
-     * @return {HTMLElement} the html element
+     * Case insensitive string
+     * @param {Mixed} s The value being converted
+     * @return {String} The comparison value
      */
-    getEl: function() {
-        if (!this._domRef) {
-            this._domRef = Roo.getDom(this.id);
-        }
-
-        return this._domRef;
+    asUCString : function(s) {
+       return String(s).toUpperCase();
     },
-
+    
     /**
-     * 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
+     * Date sorting
+     * @param {Mixed} s The value being converted
+     * @return {Number} The comparison value
      */
-    getDragEl: function() {
-        return Roo.getDom(this.dragElId);
+    asDate : function(s) {
+        if(!s){
+            return 0;
+        }
+        if(s instanceof Date){
+            return s.getTime();
+        }
+       return Date.parse(String(s));
     },
-
+    
     /**
-     * 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
+     * Float sorting
+     * @param {Mixed} s The value being converted
+     * @return {Float} The comparison value
      */
-    init: function(id, sGroup, config) {
-        this.initTarget(id, sGroup, config);
-        if (!Roo.isTouch) {
-            Event.on(this.id, "mousedown", this.handleMouseDown, this);
+    asFloat : function(s) {
+       var val = parseFloat(String(s).replace(/,/g, ""));
+        if(isNaN(val)) {
+            val = 0;
         }
-        Event.on(this.id, "touchstart", this.handleMouseDown, this);
-        // Event.on(this.id, "selectstart", Event.preventDefault);
+       return val;
     },
-
+    
     /**
-     * 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
+     * Integer sorting
+     * @param {Mixed} s The value being converted
+     * @return {Number} The comparison value
      */
-    initTarget: function(id, sGroup, config) {
-
-        // configuration attributes
-        this.config = config || {};
-
-        // create a local reference to the drag and drop manager
-        this.DDM = Roo.dd.DDM;
-        // initialize the groups array
-        this.groups = {};
-
-        // assume that we have an element reference instead of an id if the
-        // parameter is not a string
-        if (typeof id !== "string") {
-            id = Roo.id(id);
+    asInt : function(s) {
+        var val = parseInt(String(s).replace(/,/g, ""));
+        if(isNaN(val)) {
+            val = 0;
         }
+       return val;
+    }
+};/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
 
-        // 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();
-    },
+/**
+* @class Roo.data.Record
+ * Instances of this class encapsulate both record <em>definition</em> information, and record
+ * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
+ * to access Records cached in an {@link Roo.data.Store} object.<br>
+ * <p>
+ * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
+ * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
+ * objects.<br>
+ * <p>
+ * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
+ * @constructor
+ * This constructor should not be used to create Record objects. Instead, use the constructor generated by
+ * {@link #create}. The parameters are the same.
+ * @param {Array} data An associative Array of data values keyed by the field name.
+ * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
+ * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
+ * not specified an integer id is generated.
+ */
+Roo.data.Record = function(data, id){
+    this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
+    this.data = data;
+};
 
-    /**
-     * 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() {
+/**
+ * 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'}
+);
 
-        // configurable properties:
-        //    padding, isTarget, maintainOffset, primaryButtonOnly
-        this.padding           = this.config.padding || [0, 0, 0, 0];
-        this.isTarget          = (this.config.isTarget !== false);
-        this.maintainOffset    = (this.config.maintainOffset);
-        this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
+var myNewRecord = new TopicRecord({
+    title: 'Do my job please',
+    author: 'noobie',
+    totalPosts: 1,
+    lastPost: new Date(),
+    lastPoster: 'Animal',
+    excerpt: 'No way dude!'
+});
+myStore.add(myNewRecord);
+</code></pre>
+ * @method create
+ * @static
+ */
+Roo.data.Record.create = function(o){
+    var f = function(){
+        f.superclass.constructor.apply(this, arguments);
+    };
+    Roo.extend(f, Roo.data.Record);
+    var p = f.prototype;
+    p.fields = new Roo.util.MixedCollection(false, function(field){
+        return field.name;
+    });
+    for(var i = 0, len = o.length; i < len; i++){
+        p.fields.add(new Roo.data.Field(o[i]));
+    }
+    f.getField = function(name){
+        return p.fields.get(name);  
+    };
+    return f;
+};
 
-    },
+Roo.data.Record.AUTO_ID = 1000;
+Roo.data.Record.EDIT = 'edit';
+Roo.data.Record.REJECT = 'reject';
+Roo.data.Record.COMMIT = 'commit';
 
+Roo.data.Record.prototype = {
     /**
-     * Executed when the linked element is available
-     * @method handleOnAvailable
-     * @private
+     * Readonly flag - true if this record has been modified.
+     * @type Boolean
      */
-    handleOnAvailable: function() {
-        this.available = true;
-        this.resetConstraints();
-        this.onAvailable();
-    },
+    dirty : false,
+    editing : false,
+    error: null,
+    modified: null,
 
-     /**
-     * Configures the padding for the target zone in px.  Effectively expands
-     * (or reduces) the virtual object size for targeting calculations.
-     * Supports css-style shorthand; if only one parameter is passed, all sides
-     * will have that padding, and if only two are passed, the top and bottom
-     * will have the first param, the left and right the second.
-     * @method setPadding
-     * @param {int} iTop    Top pad
-     * @param {int} iRight  Right pad
-     * @param {int} iBot    Bot pad
-     * @param {int} iLeft   Left pad
-     */
-    setPadding: function(iTop, iRight, iBot, iLeft) {
-        // this.padding = [iLeft, iRight, iTop, iBot];
-        if (!iRight && 0 !== iRight) {
-            this.padding = [iTop, iTop, iTop, iTop];
-        } else if (!iBot && 0 !== iBot) {
-            this.padding = [iTop, iRight, iTop, iRight];
-        } else {
-            this.padding = [iTop, iRight, iBot, iLeft];
-        }
+    // private
+    join : function(store){
+        this.store = store;
     },
 
     /**
-     * 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
+     * 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.
      */
-    setInitPosition: function(diffX, diffY) {
-        var el = this.getEl();
-
-        if (!this.DDM.verifyEl(el)) {
+    set : function(name, value){
+        if(this.data[name] == value){
             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);
+        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);
+        }       
     },
 
     /**
-     * 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
+     * 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.
      */
-    setStartPosition: function(pos) {
-        var p = pos || Dom.getXY( this.getEl() );
-        this.deltaSetXY = null;
-
-        this.startPageX = p[0];
-        this.startPageY = p[1];
+    get : function(name){
+        return this.data[name]; 
     },
 
-    /**
-     * 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);
+    // private
+    beginEdit : function(){
+        this.editing = true;
+        this.modified = {}; 
     },
 
-    /**
-     * Remove's this instance from the supplied interaction group
-     * @method removeFromGroup
-     * @param {string}  sGroup  The group to drop
-     */
-    removeFromGroup: function(sGroup) {
-        if (this.groups[sGroup]) {
-            delete this.groups[sGroup];
-        }
-
-        this.DDM.removeDDFromGroup(this, sGroup);
+    // private
+    cancelEdit : function(){
+        this.editing = false;
+        delete this.modified;
     },
 
-    /**
-     * 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;
+    // private
+    endEdit : function(){
+        this.editing = false;
+        if(this.dirty && this.store){
+            this.store.afterEdit(this);
+        }
     },
 
     /**
-     * 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.
+     * 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.
      */
-    setHandleElId: function(id) {
-        if (typeof id !== "string") {
-            id = Roo.id(id);
+    reject : function(){
+        var m = this.modified;
+        for(var n in m){
+            if(typeof m[n] != "function"){
+                this.data[n] = m[n];
+            }
+        }
+        this.dirty = false;
+        delete this.modified;
+        this.editing = false;
+        if(this.store){
+            this.store.afterReject(this);
         }
-        this.handleElId = id;
-        this.DDM.regHandle(this.id, id);
     },
 
     /**
-     * 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
+     * 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.
      */
-    setOuterHandleElId: function(id) {
-        if (typeof id !== "string") {
-            id = Roo.id(id);
+    commit : function(){
+        this.dirty = false;
+        delete this.modified;
+        this.editing = false;
+        if(this.store){
+            this.store.afterCommit(this);
         }
-        Event.on(id, "mousedown",
-                this.handleMouseDown, this);
-        this.setHandleElId(id);
-
-        this.hasOuterHandles = true;
     },
 
-    /**
-     * 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);
+    // private
+    hasError : function(){
+        return this.error != null;
     },
 
-    destroy : function(){
-        this.unreg();
+    // private
+    clearError : function(){
+        this.error = null;
     },
 
     /**
-     * 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
+     * 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}
      */
-    isLocked: function() {
-        return (this.DDM.isLocked() || this.locked);
-    },
+    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">
+ */
 
-    /**
-     * 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..
-        }
-        
 
-        if (this.isLocked()) {
-            //Roo.log('locked');
-            return;
+
+/**
+ * @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"
+    };
+
+    if(config && config.data){
+        this.inlineData = config.data;
+        delete config.data;
+    }
+
+    Roo.apply(this, config);
+    
+    if(this.reader){ // reader passed
+        this.reader = Roo.factory(this.reader, Roo.data);
+        this.reader.xmodule = this.xmodule || false;
+        if(!this.recordType){
+            this.recordType = this.reader.recordType;
+        }
+        if(this.reader.onMetaChange){
+            this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
         }
+    }
 
-        this.DDM.refreshCache(this.groups);
-//        Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
-        var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
-        if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) )  {
-            //Roo.log('no outer handes or not over target');
-                // do nothing.
-        } else {
-//            Roo.log('check validator');
-            if (this.clickValidator(e)) {
-//                Roo.log('validate success');
-                // set the initial element position
-                this.setStartPosition();
+    if(this.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
+    });
+    
+    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);
 
-                this.b4MouseDown(e);
-                this.onMouseDown(e);
+    if(this.inlineData){
+        this.loadData(this.inlineData);
+        delete this.inlineData;
+    }
+};
 
-                this.DDM.handleMouseDown(e, this);
+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.
+    */
+    /**
+    * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
+    * on any HTTP request
+    */
+    /**
+    * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
+    */
+    /**
+    * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
+    */
+    multiSort: false,
+    /**
+    * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
+    * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
+    */
+    remoteSort : false,
 
-                this.DDM.stopEvent(e);
-            } else {
+    /**
+    * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
+     * loaded or when a record is removed. (defaults to false).
+    */
+    pruneModifiedRecords : false,
 
+    // private
+    lastOptions : null,
 
-            }
+    /**
+     * Add Records to the Store and fires the add event.
+     * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
+     */
+    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);
     },
 
-    clickValidator: function(e) {
-        var target = e.getTarget();
-        return ( this.isValidHandleChild(target) &&
-                    (this.id == this.handleElId ||
-                        this.DDM.handleWasClicked(target, this.id)) );
+    /**
+     * Remove a Record from the Store and fires the remove event.
+     * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
+     */
+    remove : function(record){
+        var index = this.data.indexOf(record);
+        this.data.removeAt(index);
+        if(this.pruneModifiedRecords){
+            this.modified.remove(record);
+        }
+        this.fireEvent("remove", this, record, index);
     },
 
     /**
-     * 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
+     * Remove all Records from the Store and fires the clear event.
      */
-    addInvalidHandleType: function(tagName) {
-        var type = tagName.toUpperCase();
-        this.invalidHandleTypes[type] = type;
+    removeAll : function(){
+        this.data.clear();
+        if(this.pruneModifiedRecords){
+            this.modified = [];
+        }
+        this.fireEvent("clear", this);
     },
 
     /**
-     * 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
+     * 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.
      */
-    addInvalidHandleId: function(id) {
-        if (typeof id !== "string") {
-            id = Roo.id(id);
+    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.invalidHandleIds[id] = id;
+        this.fireEvent("add", this, records, index);
     },
 
     /**
-     * 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
+     * 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.
      */
-    addInvalidHandleClass: function(cssClass) {
-        this.invalidHandleClasses.push(cssClass);
+    indexOf : function(record){
+        return this.data.indexOf(record);
     },
 
     /**
-     * Unsets an excluded tag name set by addInvalidHandleType
-     * @method removeInvalidHandleType
-     * @param {string} tagName the type of element to unexclude
+     * 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.
      */
-    removeInvalidHandleType: function(tagName) {
-        var type = tagName.toUpperCase();
-        // this.invalidHandleTypes[type] = null;
-        delete this.invalidHandleTypes[type];
+    indexOfId : function(id){
+        return this.data.indexOfKey(id);
     },
 
     /**
-     * Unsets an invalid handle id
-     * @method removeInvalidHandleId
-     * @param {string} id the id of the element to re-enable
+     * 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.
      */
-    removeInvalidHandleId: function(id) {
-        if (typeof id !== "string") {
-            id = Roo.id(id);
-        }
-        delete this.invalidHandleIds[id];
+    getById : function(id){
+        return this.data.key(id);
     },
 
     /**
-     * Unsets an invalid css class
-     * @method removeInvalidHandleClass
-     * @param {string} cssClass the class of the element(s) you wish to
-     * re-enable
+     * 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.
      */
-    removeInvalidHandleClass: function(cssClass) {
-        for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
-            if (this.invalidHandleClasses[i] == cssClass) {
-                delete this.invalidHandleClasses[i];
-            }
-        }
+    getAt : function(index){
+        return this.data.itemAt(index);
     },
 
     /**
-     * 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
+     * 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
      */
-    isValidHandleChild: function(node) {
-
-        var valid = true;
-        // var n = (node.nodeName == "#text") ? node.parentNode : node;
-        var nodeName;
-        try {
-            nodeName = node.nodeName.toUpperCase();
-        } catch(e) {
-            nodeName = node.nodeName;
-        }
-        valid = valid && !this.invalidHandleTypes[nodeName];
-        valid = valid && !this.invalidHandleIds[node.id];
-
-        for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
-            valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
-        }
-
-
-        return valid;
+    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;
     },
 
     /**
-     * Create the array of horizontal tick marks if an interval was specified
-     * in setXConstraint().
-     * @method setXTicks
-     * @private
+     * 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>
      */
-    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;
+    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;
             }
-        }
-
-        for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
-            if (!tickMap[i]) {
-                this.xTicks[this.xTicks.length] = i;
-                tickMap[i] = true;
+            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);
         }
-
-        this.xTicks.sort(this.DDM.numericSort) ;
     },
 
     /**
-     * Create the array of vertical tick marks if an interval was specified in
-     * setYConstraint().
-     * @method setYTicks
-     * @private
+     * 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).
      */
-    setYTicks: function(iStartY, iTickSize) {
-        this.yTicks = [];
-        this.yTickSize = iTickSize;
-
-        var tickMap = {};
+    reload : function(options){
+        this.load(Roo.applyIf(options||{}, this.lastOptions));
+    },
 
-        for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
-            if (!tickMap[i]) {
-                this.yTicks[this.yTicks.length] = i;
-                tickMap[i] = true;
+    // 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;
         }
-
-        for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
-            if (!tickMap[i]) {
-                this.yTicks[this.yTicks.length] = i;
-                tickMap[i] = true;
+        // 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);
         }
+        
+        if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
+                
+            var e = new Roo.data.Record({});
 
-        this.yTicks.sort(this.DDM.numericSort) ;
+            e.set(this.parent.displayField, this.parent.emptyTitle);
+            e.set(this.parent.valueField, '');
+
+            this.insert(0, e);
+        }
+            
+        this.fireEvent("load", this, r, options, o);
+        if(options.callback){
+            options.callback.call(options.scope || this, r, options, true);
+        }
     },
 
+
     /**
-     * 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.
+     * 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.
      */
-    setXConstraint: function(iLeft, iRight, iTickSize) {
-        this.leftConstraint = iLeft;
-        this.rightConstraint = iRight;
-
-        this.minX = this.initPageX - iLeft;
-        this.maxX = this.initPageX + iRight;
-        if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
-
-        this.constrainX = true;
+    loadData : function(o, append){
+        var r = this.reader.readRecords(o);
+        this.loadRecords(r, {add: append}, true);
     },
+    
+     /**
+     * using 'cn' the nested child reader read the child array into it's child stores.
+     * @param {Object} rec The record with a 'children array
+     */
+    loadDataFromChildren : function(rec)
+    {
+        this.loadData(this.reader.toLoadData(rec));
+    },
+    
 
     /**
-     * Clears any constraints applied to this instance.  Also clears ticks
-     * since they can't exist independent of a constraint at this time.
-     * @method clearConstraints
+     * 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>
      */
-    clearConstraints: function() {
-        this.constrainX = false;
-        this.constrainY = false;
-        this.clearTicks();
+    getCount : function(){
+        return this.data.length || 0;
     },
 
     /**
-     * Clears any tick interval defined for this instance
-     * @method clearTicks
+     * 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>
      */
-    clearTicks: function() {
-        this.xTicks = null;
-        this.yTicks = null;
-        this.xTickSize = 0;
-        this.yTickSize = 0;
+    getTotalCount : function(){
+        return this.totalLength || 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.
+     * 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>
      */
-    setYConstraint: function(iUp, iDown, iTickSize) {
-        this.topConstraint = iUp;
-        this.bottomConstraint = iDown;
-
-        this.minY = this.initPageY - iUp;
-        this.maxY = this.initPageY + iDown;
-        if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
-
-        this.constrainY = true;
+    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);
+            }
+        }
     },
 
     /**
-     * resetConstraints must be called if you manually reposition a dd element.
-     * @method resetConstraints
-     * @param {boolean} maintainOffset
+     * 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")
      */
-    resetConstraints: function() {
-
-
-        // Maintain offsets if necessary
-        if (this.initPageX || this.initPageX === 0) {
-            // figure out how much this thing has moved
-            var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
-            var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
-
-            this.setInitPosition(dx, dy);
+    setDefaultSort : function(field, dir){
+        this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
+    },
 
-        // This is the first time we have detected the element's position
-        } else {
-            this.setInitPosition();
+    /**
+     * 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;
+            }
         }
-
-        if (this.constrainX) {
-            this.setXConstraint( this.leftConstraint,
-                                 this.rightConstraint,
-                                 this.xTickSize        );
+        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.constrainY) {
-            this.setYConstraint( this.topConstraint,
-                                 this.bottomConstraint,
-                                 this.yTickSize         );
-        }
+    /**
+     * 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);
     },
 
     /**
-     * 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
+     * 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.
      */
-    getTick: function(val, tickArray) {
+    getModifiedRecords : function(){
+        return this.modified;
+    },
 
-        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];
-                }
+    // private
+    createFilterFn : function(property, value, anyMatch){
+        if(!value.exec){ // not a regex
+            value = String(value);
+            if(value.length == 0){
+                return false;
             }
-
-            // The value is larger than the last tick, so we return the last
-            // tick.
-            return tickArray[tickArray.length - 1];
+            value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
         }
+        return function(r){
+            return value.test(r.data[property]);
+        };
     },
 
     /**
-     * toString method
-     * @method toString
-     * @return {string} string representation of the dd obj
-     */
-    toString: function() {
-        return ("DragDrop " + this.id);
-    }
-
-});
+     * Sums the value of <i>property</i> for each record between start and end and returns the result.
+     * @param {String} property A field on your records
+     * @param {Number} start The record index to start at (defaults to 0)
+     * @param {Number} end The last record index to include (defaults to length - 1)
+     * @return {Number} The sum
+     */
+    sum : function(property, start, end){
+        var rs = this.data.items, v = 0;
+        start = start || 0;
+        end = (end || end === 0) ? end : rs.length-1;
 
-})();
-/*
+        for(var i = start; i <= end; i++){
+            v += (rs[i].data[property] || 0);
+        }
+        return v;
+    },
+
+    /**
+     * 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
+    afterEdit : function(record){
+        if(this.modified.indexOf(record) == -1){
+            this.modified.push(record);
+        }
+        this.fireEvent("update", this, record, Roo.data.Record.EDIT);
+    },
+    
+    // private
+    afterReject : function(record){
+        this.modified.remove(record);
+        this.fireEvent("update", this, record, Roo.data.Record.REJECT);
+    },
+
+    // private
+    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);
+    },
+    
+    moveIndex : function(data, type)
+    {
+        var index = this.indexOf(data);
+        
+        var newIndex = index + type;
+        
+        this.remove(data);
+        
+        this.insert(newIndex, data);
+        
+    }
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -1188,1303 +1092,343 @@ Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
  * <script type="text/javascript">
  */
 
-
 /**
- * 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.
+ * @class Roo.data.SimpleStore
+ * @extends Roo.data.Store
+ * Small helper class to make creating Stores from Array data easier.
+ * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
+ * @cfg {Array} fields An array of field definition objects, or field name strings.
+ * @cfg {Object} an existing reader (eg. copied from another store)
+ * @cfg {Array} data The multi-dimensional array of data
+ * @constructor
+ * @param {Object} config
+ */
+Roo.data.SimpleStore = function(config)
+{
+    Roo.data.SimpleStore.superclass.constructor.call(this, {
+        isLocal : true,
+        reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
+                id: config.id
+            },
+            Roo.data.Record.create(config.fields)
+        ),
+        proxy : new Roo.data.MemoryProxy(config.data)
+    });
+    this.load();
+};
+Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
  */
-
-// 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
+/**
+ * @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>
+ * <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
+ */
+Roo.data.JsonStore = function(c){
+    Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
+        proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
+        reader: new Roo.data.JsonReader(c, c.fields)
+    }));
+};
+Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
  */
-Roo.dd.DragDropMgr = function() {
-
-    var Event = Roo.EventManager;
-
-    return {
-
-        /**
-         * 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: {},
-
-        /**
-         * 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 DragDrop object that is currently being dragged
-         * @property dragCurrent
-         * @type DragDrop
-         * @private
-         * @static
-         **/
-        dragCurrent: null,
-
-        /**
-         * the DragDrop object(s) that are being hovered over
-         * @property dragOvers
-         * @type Array
-         * @private
-         * @static
-         */
-        dragOvers: {},
-
-        /**
-         * the X distance between the cursor and the object being dragged
-         * @property deltaX
-         * @type int
-         * @private
-         * @static
-         */
-        deltaX: 0,
-
-        /**
-         * the Y distance between the cursor and the object being dragged
-         * @property deltaY
-         * @type int
-         * @private
-         * @static
-         */
-        deltaY: 0,
-
-        /**
-         * 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
-         * @static
-         */
-        initalized: false,
-
-        /**
-         * All drag and drop can be disabled.
-         * @property locked
-         * @private
-         * @static
-         */
-        locked: false,
-
-        /**
-         * Called the first time an element is registered.
-         * @method init
-         * @private
-         * @static
-         */
-        init: function() {
-            this.initialized = true;
-        },
-
-        /**
-         * 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,
 
-        /**
-         * 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,
+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;
+        }
+    }
 
-        /**
-         * The current drag and drop mode.  Default: POINT
-         * @property mode
-         * @type int
-         * @static
-         */
-        mode: 0,
+    // define once
+    var stripRe = /[\$,%]/g;
 
-        /**
-         * 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;
+    // 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 '';
                     }
-                    oDD[sMethod].apply(oDD, args);
-                }
-            }
-        },
-
-        /**
-         * Drag and drop initialization.  Sets up the global event handlers
-         * @method _onLoad
-         * @private
-         * @static
-         */
-        _onLoad: function() {
-
-            this.init();
-
-            if (!Roo.isTouch) {
-                Event.on(document, "mouseup",   this.handleMouseUp, this, true);
-                Event.on(document, "mousemove", this.handleMouseMove, this, true);
-            }
-            Event.on(document, "touchend",   this.handleMouseUp, this, true);
-            Event.on(document, "touchmove", this.handleMouseMove, this, true);
+                    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;
             
-            Event.on(window,   "unload",    this._onUnload, this, true);
-            Event.on(window,   "resize",    this._onResize, this, true);
-            // Event.on(window,   "mouseout",    this._test);
-
-        },
+        }
+        this.convert = cv;
+    }
+};
 
-        /**
-         * Reset constraints on all drag and drop objs
-         * @method _onResize
-         * @private
-         * @static
-         */
-        _onResize: function(e) {
-            this._execOnAll("resetConstraints", []);
-        },
+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.
 
-        /**
-         * Lock all drag and drop functionality
-         * @method lock
-         * @static
-         */
-        lock: function() { this.locked = true; },
+/**
+ * @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.
+ */
 
-        /**
-         * Unlock all drag and drop functionality
-         * @method unlock
-         * @static
-         */
-        unlock: function() { this.locked = false; },
+Roo.data.DataReader = function(meta, recordType){
+    
+    this.meta = meta;
+    
+    this.recordType = recordType instanceof Array ? 
+        Roo.data.Record.create(recordType) : recordType;
+};
 
-        /**
-         * Is drag and drop locked?
-         * @method isLocked
-         * @return {boolean} True if drag and drop is locked, false otherwise.
-         * @static
-         */
-        isLocked: function() { return this.locked; },
+Roo.data.DataReader.prototype = {
+    
+    
+    readerType : 'Data',
+     /**
+     * Create an empty record
+     * @param {Object} data (optional) - overlay some values
+     * @return {Roo.data.Record} record created.
+     */
+    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;
+            }
+            
+        });
+        return new this.recordType(Roo.apply(da, d));
+    }
+    
+    
+};/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
 
+/**
+ * @class Roo.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.DataProxy = function(){
+    this.addEvents({
         /**
-         * 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
+         * @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.
          */
-        locationCache: {},
-
+        beforeload : true,
         /**
-         * 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
+         * @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.
          */
-        useCache: true,
-
+        load : 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
+         * @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.
          */
-        clickPixelThresh: 3,
+        loadexception : true
+    });
+    Roo.data.DataProxy.superclass.constructor.call(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,
+Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
 
-        /**
-         * 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,
+    /**
+     * @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.MemoryProxy.superclass.constructor.call(this);
+    this.data = data;
+};
 
-        /**
-         * Timeout used for the click time threshold
-         * @property clickTimeout
-         * @type Object
-         * @private
-         * @static
-         */
-        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;
-        },
-
-        /**
-         * 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] = {};
-            }
-
-            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];
-        },
-
-        /**
-         * 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;
-                    }
-                }
-            }
-
-            return oDDs;
-        },
-
-        /**
-         * Returns true if the specified dd target is a legal target for
-         * the specifice drag obj
-         * @method isLegalTarget
-         * @param {DragDrop} the drag obj
-         * @param {DragDrop} the target
-         * @return {boolean} true if the target is a legal target for the
-         * dd obj
-         * @static
-         */
-        isLegalTarget: function (oDD, oTargetDD) {
-            var targets = this.getRelated(oDD, true);
-            for (var i=0, len=targets.length;i<len;++i) {
-                if (targets[i].id == oTargetDD.id) {
-                    return true;
-                }
-            }
-
-            return false;
-        },
-
-        /**
-         * My goal is to be able to transparently determine if an object is
-         * typeof DragDrop, and the exact subclass of DragDrop.  typeof
-         * returns "object", oDD.constructor.toString() always returns
-         * "DragDrop" and not the name of the subclass.  So for now it just
-         * evaluates a well-known variable in DragDrop.
-         * @method isTypeOfDD
-         * @param {Object} the object to evaluate
-         * @return {boolean} true if typeof oDD = DragDrop
-         * @static
-         */
-        isTypeOfDD: function (oDD) {
-            return (oDD && oDD.__ygDragDrop);
-        },
-
-        /**
-         * Utility function to determine if a given element has been
-         * registered as a drag drop handle for the given Drag Drop object.
-         * @method isHandle
-         * @param {String} id the element id to check
-         * @return {boolean} true if this element is a DragDrop handle, false
-         * otherwise
-         * @static
-         */
-        isHandle: function(sDDId, sHandleId) {
-            return ( this.handleIds[sDDId] &&
-                            this.handleIds[sDDId][sHandleId] );
-        },
-
-        /**
-         * 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;
-        },
-
-        /**
-         * 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.dragCurrent = oDD;
-
-            var el = oDD.getEl();
-
-            // track start position
-            this.startX = e.getPageX();
-            this.startY = e.getPageY();
-
-            this.deltaX = this.startX - el.offsetLeft;
-            this.deltaY = this.startY - el.offsetTop;
-
-            this.dragThreshMet = false;
-
-            this.clickTimeout = setTimeout(
-                    function() {
-                        var DDM = Roo.dd.DDM;
-                        DDM.startDrag(DDM.startX, DDM.startY);
-                    },
-                    this.clickTimeThresh );
-        },
-
-        /**
-         * Fired when either the drag pixel threshol or the mousedown hold
-         * time threshold has been met.
-         * @method startDrag
-         * @param x {int} the X position of the original mousedown
-         * @param y {int} the Y position of the original mousedown
-         * @static
-         */
-        startDrag: function(x, y) {
-            clearTimeout(this.clickTimeout);
-            if (this.dragCurrent) {
-                this.dragCurrent.b4StartDrag(x, y);
-                this.dragCurrent.startDrag(x, y);
-            }
-            this.dragThreshMet = true;
-        },
-
-        /**
-         * 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(Roo.QuickTips){
-                Roo.QuickTips.enable();
-            }
-            if (! this.dragCurrent) {
-                return;
-            }
-
-            clearTimeout(this.clickTimeout);
-
-            if (this.dragThreshMet) {
-                this.fireEvents(e, true);
-            } else {
-            }
-
-            this.stopDrag(e);
-
-            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();
-            }
-
-            if (this.preventDefault) {
-                e.preventDefault();
-            }
-        },
-
-        /**
-         * Internal function to clean up event handlers after the drag
-         * operation is complete
-         * @method stopDrag
-         * @param {Event} e the event
-         * @private
-         * @static
-         */
-        stopDrag: function(e) {
-            // Fire the drag end event for the item that was dragged
-            if (this.dragCurrent) {
-                if (this.dragThreshMet) {
-                    this.dragCurrent.b4EndDrag(e);
-                    this.dragCurrent.endDrag(e);
-                }
-
-                this.dragCurrent.onMouseUp(e);
-            }
-
-            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;
-            }
-
-            // 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);
-            }
-
-            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);
-                }
-            }
-
-            if (this.dragThreshMet) {
-                this.dragCurrent.b4Drag(e);
-                this.dragCurrent.onDrag(e);
-                if(!this.dragCurrent.moveOnly){
-                    this.fireEvents(e, false);
-                }
-            }
-
-            this.stopEvent(e);
-
-            return true;
-        },
-
-        /**
-         * 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 the user did the mouse up outside of the window, we could
-            // get here even though we have ended the drag.
-            if (!dc || dc.isLocked()) {
-                return;
-            }
-
-            var pt = e.getPoint();
-
-            // cache the previous dragOver array
-            var oldOvers = [];
-
-            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) {
-
-                var ddo = this.dragOvers[i];
-
-                if (! this.isTypeOfDD(ddo)) {
-                    continue;
-                }
-
-                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;
-                }
-
-                for (i in this.ids[sGroup]) {
-                    var oDD = this.ids[sGroup][i];
-                    if (! this.isTypeOfDD(oDD)) {
-                        continue;
-                    }
-
-                    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 {
-
-                                // initial drag over: dragEnter fires
-                                if (!oldOvers[oDD.id]) {
-                                    enterEvts.push( oDD );
-                                // subsequent drag overs: dragOver fires
-                                } else {
-                                    overEvts.push( oDD );
-                                }
-
-                                this.dragOvers[oDD.id] = oDD;
-                            }
-                        }
-                    }
-                }
-            }
-
-            if (this.mode) {
-                if (outEvts.length) {
-                    dc.b4DragOut(e, outEvts);
-                    dc.onDragOut(e, outEvts);
-                }
-
-                if (enterEvts.length) {
-                    dc.onDragEnter(e, enterEvts);
-                }
-
-                if (overEvts.length) {
-                    dc.b4DragOver(e, overEvts);
-                    dc.onDragOver(e, overEvts);
-                }
-
-                if (dropEvts.length) {
-                    dc.b4DragDrop(e, dropEvts);
-                    dc.onDragDrop(e, dropEvts);
-                }
-
-            } else {
-                // fire dragout events
-                var len = 0;
-                for (i=0, len=outEvts.length; i<len; ++i) {
-                    dc.b4DragOut(e, outEvts[i].id);
-                    dc.onDragOut(e, outEvts[i].id);
-                }
-
-                // fire enter events
-                for (i=0,len=enterEvts.length; i<len; ++i) {
-                    // dc.b4DragEnter(e, oDD.id);
-                    dc.onDragEnter(e, enterEvts[i].id);
-                }
-
-                // fire over events
-                for (i=0,len=overEvts.length; i<len; ++i) {
-                    dc.b4DragOver(e, overEvts[i].id);
-                    dc.onDragOver(e, overEvts[i].id);
-                }
-
-                // fire drop events
-                for (i=0, len=dropEvts.length; i<len; ++i) {
-                    dc.b4DragDrop(e, dropEvts[i].id);
-                    dc.onDragDrop(e, dropEvts[i].id);
-                }
-
-            }
-
-            // notify about a drop that did not find a target
-            if (isDrop && !dropEvts.length) {
-                dc.onInvalidDrop(e);
-            }
-
-        },
-
-        /**
-         * 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) {
-
-            var len = dds.length;
-
-            if (len == 1) {
-                winner = dds[0];
-            } else {
-                // Loop through the targeted items
-                for (var i=0; i<len; ++i) {
-                    var dd = dds[i];
-                    // If the cursor is over the object, it wins.  If the
-                    // cursor is over multiple matches, the first one we come
-                    // to wins.
-                    if (dd.cursorIsOver) {
-                        winner = dd;
-                        break;
-                    // Otherwise the object with the most overlap wins
-                    } else {
-                        if (!winner ||
-                            winner.overlap.getArea() < dd.overlap.getArea()) {
-                            winner = dd;
-                        }
-                    }
-                }
-            }
-
-            return winner;
-        },
-
-        /**
-         * Refreshes the cache of the top-left and bottom-right points of the
-         * drag and drop objects in the specified group(s).  This is in the
-         * format that is stored in the drag and drop instance, so typical
-         * usage is:
-         * <code>
-         * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
-         * </code>
-         * Alternatively:
-         * <code>
-         * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
-         * </code>
-         * @TODO this really should be an indexed array.  Alternatively this
-         * method could accept both.
-         * @method refreshCache
-         * @param {Object} groups an associative array of groups to refresh
-         * @static
-         */
-        refreshCache: function(groups) {
-            for (var sGroup in groups) {
-                if ("string" != typeof sGroup) {
-                    continue;
-                }
-                for (var i in this.ids[sGroup]) {
-                    var oDD = this.ids[sGroup][i];
-
-                    if (this.isTypeOfDD(oDD)) {
-                    // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
-                        var loc = this.getLocation(oDD);
-                        if (loc) {
-                            this.locationCache[oDD.id] = loc;
-                        } else {
-                            delete this.locationCache[oDD.id];
-                            // this will unregister the drag and drop object if
-                            // the element is not in a usable state
-                            // oDD.unreg();
-                        }
-                    }
-                }
-            }
-        },
-
-        /**
-         * This checks to make sure an element exists and is in the DOM.  The
-         * main purpose is to handle cases where innerHTML is used to remove
-         * drag and drop objects from the DOM.  IE provides an 'unspecified
-         * error' when trying to access the offsetParent of such an element
-         * @method verifyEl
-         * @param {HTMLElement} el the element to check
-         * @return {boolean} true if the element looks usable
-         * @static
-         */
-        verifyEl: function(el) {
-            if (el) {
-                var parent;
-                if(Roo.isIE){
-                    try{
-                        parent = el.offsetParent;
-                    }catch(e){}
-                }else{
-                    parent = el.offsetParent;
-                }
-                if (parent) {
-                    return true;
-                }
-            }
-
-            return false;
-        },
-
-        /**
-         * Returns a Region object containing the drag and drop element's position
-         * and size, including the padding configured for it
-         * @method getLocation
-         * @param {DragDrop} oDD the drag and drop object to get the
-         *                       location for
-         * @return {Roo.lib.Region} a Region object representing the total area
-         *                             the element occupies, including any padding
-         *                             the instance is configured for.
-         * @static
-         */
-        getLocation: function(oDD) {
-            if (! this.isTypeOfDD(oDD)) {
-                return null;
-            }
-
-            var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
-
-            try {
-                pos= Roo.lib.Dom.getXY(el);
-            } catch (e) { }
-
-            if (!pos) {
-                return null;
-            }
-
-            x1 = pos[0];
-            x2 = x1 + el.offsetWidth;
-            y1 = pos[1];
-            y2 = y1 + el.offsetHeight;
-
-            t = y1 - oDD.padding[0];
-            r = x2 + oDD.padding[1];
-            b = y2 + oDD.padding[2];
-            l = x1 - oDD.padding[3];
-
-            return new Roo.lib.Region( t, r, b, l );
-        },
-
-        /**
-         * Checks the cursor location to see if it over the target
-         * @method isOverTarget
-         * @param {Roo.lib.Point} pt The point to evaluate
-         * @param {DragDrop} oTarget the DragDrop object we are inspecting
-         * @return {boolean} true if the mouse is over the target
-         * @private
-         * @static
-         */
-        isOverTarget: function(pt, oTarget, intersect) {
-            // use cache if available
-            var loc = this.locationCache[oTarget.id];
-            if (!loc || !this.useCache) {
-                loc = this.getLocation(oTarget);
-                this.locationCache[oTarget.id] = loc;
-
-            }
-
-            if (!loc) {
-                return false;
-            }
-
-            oTarget.cursorIsOver = loc.contains( pt );
-
-            // DragDrop is using this as a sanity check for the initial mousedown
-            // in this case we are done.  In POINT mode, if the drag obj has no
-            // contraints, we are also done. Otherwise we need to evaluate the
-            // location of the target as related to the actual location of the
-            // dragged element.
-            var dc = this.dragCurrent;
-            if (!dc || !dc.getTargetCoord ||
-                    (!intersect && !dc.constrainX && !dc.constrainY)) {
-                return oTarget.cursorIsOver;
-            }
-
-            oTarget.overlap = null;
-
-            // Get the current location of the drag element, this is the
-            // location of the mouse event less the delta that represents
-            // where the original mousedown happened on the element.  We
-            // need to consider constraints and ticks as well.
-            var pos = dc.getTargetCoord(pt.x, pt.y);
-
-            var el = dc.getDragEl();
-            var curRegion = new Roo.lib.Region( pos.y,
-                                                   pos.x + el.offsetWidth,
-                                                   pos.y + el.offsetHeight,
-                                                   pos.x );
-
-            var overlap = curRegion.intersect(loc);
-
-            if (overlap) {
-                oTarget.overlap = overlap;
-                return (intersect) ? true : oTarget.cursorIsOver;
-            } else {
-                return false;
-            }
-        },
-
-        /**
-         * unload event handler
-         * @method _onUnload
-         * @private
-         * @static
-         */
-        _onUnload: function(e, me) {
-            Roo.dd.DragDropMgr.unregAll();
-        },
-
-        /**
-         * Cleans up the drag and drop events and objects.
-         * @method unregAll
-         * @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 = {};
-        },
-
-        /**
-         * A cache of DOM elements
-         * @property elementCache
-         * @private
-         * @static
-         */
-        elementCache: {},
-
-        /**
-         * 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
-         */
-        getElWrapper: function(id) {
-            var oWrapper = this.elementCache[id];
-            if (!oWrapper || !oWrapper.el) {
-                oWrapper = this.elementCache[id] =
-                    new this.ElementWrapper(Roo.getDom(id));
-            }
-            return oWrapper;
-        },
-
-        /**
-         * 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
-         */
-        getElement: function(id) {
-            return Roo.getDom(id);
-        },
-
-        /**
-         * 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
-         */
-        getCss: function(id) {
-            var el = Roo.getDom(id);
-            return (el) ? el.style : null;
-        },
-
-        /**
-         * Inner class for cached elements
-         * @class DragDropMgr.ElementWrapper
-         * @for DragDropMgr
-         * @private
-         * @deprecated
-         */
-        ElementWrapper: function(el) {
-                /**
-                 * The element
-                 * @property el
-                 */
-                this.el = el || null;
-                /**
-                 * The element id
-                 * @property id
-                 */
-                this.id = this.el && el.id;
-                /**
-                 * A reference to the style property
-                 * @property css
-                 */
-                this.css = this.el && el.style;
-            },
-
-        /**
-         * Returns the X position of an html element
-         * @method getPosX
-         * @param el the element for which to get the position
-         * @return {int} the X coordinate
-         * @for DragDropMgr
-         * @deprecated use Roo.lib.Dom.getX instead
-         * @static
-         */
-        getPosX: function(el) {
-            return Roo.lib.Dom.getX(el);
-        },
-
-        /**
-         * Returns the Y position of an html element
-         * @method getPosY
-         * @param el the element for which to get the position
-         * @return {int} the Y coordinate
-         * @deprecated use Roo.lib.Dom.getY instead
-         * @static
-         */
-        getPosY: function(el) {
-            return Roo.lib.Dom.getY(el);
-        },
-
-        /**
-         * Swap two nodes.  In IE, we use the native method, for others we
-         * emulate the IE behavior
-         * @method swapNode
-         * @param n1 the first node to swap
-         * @param n2 the other node to swap
-         * @static
-         */
-        swapNode: function(n1, n2) {
-            if (n1.swapNode) {
-                n1.swapNode(n2);
-            } else {
-                var p = n2.parentNode;
-                var s = n2.nextSibling;
-
-                if (s == n1) {
-                    p.insertBefore(n1, n2);
-                } else if (n2 == n1.nextSibling) {
-                    p.insertBefore(n2, n1);
-                } else {
-                    n1.parentNode.replaceChild(n2, n1);
-                    p.insertBefore(n1, s);
-                }
-            }
-        },
-
-        /**
-         * Returns the 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 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);
-        },
-
-        /**
-         * Gets the scrollTop
-         * @method getScrollTop
-         * @return {int} the document's scrollTop
-         * @static
-         */
-        getScrollTop: function () { return this.getScroll().top; },
-
-        /**
-         * Gets the scrollLeft
-         * @method getScrollLeft
-         * @return {int} the document's scrollTop
-         * @static
-         */
-        getScrollLeft: function () { return this.getScroll().left; },
-
-        /**
-         * Sets the x/y position of an element to the location of the
-         * target element.
-         * @method moveToEl
-         * @param {HTMLElement} moveEl      The element to move
-         * @param {HTMLElement} targetEl    The position reference element
-         * @static
-         */
-        moveToEl: function (moveEl, targetEl) {
-            var aCoord = Roo.lib.Dom.getXY(targetEl);
-            Roo.lib.Dom.setXY(moveEl, aCoord);
-        },
-
-        /**
-         * Numeric array sort function
-         * @method numericSort
-         * @static
-         */
-        numericSort: function(a, b) { return (a - b); },
-
-        /**
-         * Internal counter
-         * @property _timeoutCount
-         * @private
-         * @static
-         */
-        _timeoutCount: 0,
-
-        /**
-         * Trying to make the load order less important.  Without this we get
-         * an error if this file is loaded before the Event Utility.
-         * @method _addListeners
-         * @private
-         * @static
-         */
-        _addListeners: function() {
-            var DDM = Roo.dd.DDM;
-            if ( Roo.lib.Event && document ) {
-                DDM._onLoad();
-            } else {
-                if (DDM._timeoutCount > 2000) {
-                } else {
-                    setTimeout(DDM._addListeners, 10);
-                    if (document && document.body) {
-                        DDM._timeoutCount += 1;
-                    }
-                }
-            }
-        },
-
-        /**
-         * Recursively searches the immediate parent and all child nodes for
-         * the handle element in order to determine wheter or not it was
-         * clicked.
-         * @method handleWasClicked
-         * @param node the html element to inspect
-         * @static
-         */
-        handleWasClicked: function(node, id) {
-            if (this.isHandle(id, node.id)) {
-                return true;
-            } else {
-                // check to see if this is a text node child of the one we want
-                var p = node.parentNode;
-
-                while (p) {
-                    if (this.isHandle(id, p.id)) {
-                        return true;
-                    } else {
-                        p = p.parentNode;
-                    }
-                }
-            }
-
-            return false;
+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(params.data ? params.data :this.data);
+        }catch(e){
+            this.fireEvent("loadexception", this, arg, null, e);
+            callback.call(scope, null, arg, false);
+            return;
         }
-
-    };
-
-}();
-
-// shorter alias, save a few bytes
-Roo.dd.DDM = Roo.dd.DragDropMgr;
-Roo.dd.DDM._addListeners();
-
-}/*
+        callback.call(scope, result, arg, true);
+    },
+    
+    // private
+    update : function(params, records){
+        
+    }
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -2494,295 +1438,145 @@ Roo.dd.DDM._addListeners();
  * Fork - LGPL
  * <script type="text/javascript">
  */
-
 /**
- * @class Roo.dd.DD
- * A DragDrop implementation where the linked element follows the
- * mouse cursor during a drag.
- * @extends Roo.dd.DragDrop
+ * @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 {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
+ * @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.dd.DD = function(id, sGroup, config) {
-    if (id) {
-        this.init(id, sGroup, config);
-    }
+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.dd.DD, Roo.dd.DragDrop, {
-
+Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
+    // thse are take from connection...
+    
     /**
-     * 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
+     * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
      */
-    scroll: true,
-
     /**
-     * Sets the pointer offset to the distance between the linked element's top
-     * left corner and the location the element was clicked
-     * @method autoOffset
-     * @param {int} iPageX the X coordinate of the click
-     * @param {int} iPageY the Y coordinate of the click
+     * @cfg {Object} extraParams (Optional) An object containing properties which are used as
+     * extra parameters to each request made by this object. (defaults to undefined)
      */
-    autoOffset: function(iPageX, iPageY) {
-        var x = iPageX - this.startPageX;
-        var y = iPageY - this.startPageY;
-        this.setDelta(x, y);
-    },
-
     /**
-     * Sets the pointer offset.  You can call this directly to force the
-     * offset to be in a particular location (e.g., pass in 0,0 to set it
-     * to the center of the object)
-     * @method setDelta
-     * @param {int} iDeltaX the distance from the left
-     * @param {int} iDeltaY the distance from the top
+     * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
+     *  to each request made by this object. (defaults to undefined)
      */
-    setDelta: function(iDeltaX, iDeltaY) {
-        this.deltaX = iDeltaX;
-        this.deltaY = iDeltaY;
-    },
-
     /**
-     * Sets the drag element to the location of the mousedown or click event,
-     * maintaining the cursor location relative to the location on the element
-     * that was clicked.  Override this if you want to place the element in a
-     * location other than where the cursor is.
-     * @method setDragElPos
-     * @param {int} iPageX the X coordinate of the mousedown or drag event
-     * @param {int} iPageY the Y coordinate of the mousedown or drag event
+     * @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)
      */
-    setDragElPos: function(iPageX, iPageY) {
-        // the first time we do this, we are going to check to make sure
-        // the element has css positioning
-
-        var el = this.getDragEl();
-        this.alignElWithMouse(el, iPageX, iPageY);
-    },
-
     /**
-     * Sets the element to the location of the mousedown or click event,
-     * maintaining the cursor location relative to the location on the element
-     * that was clicked.  Override this if you want to place the element in a
-     * location other than where the cursor is.
-     * @method alignElWithMouse
-     * @param {HTMLElement} el the element to move
-     * @param {int} iPageX the X coordinate of the mousedown or drag event
-     * @param {int} iPageY the Y coordinate of the mousedown or drag event
+     * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
      */
-    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;
-    },
-
-    /**
-     * 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)
+     /**
+     * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
+     * @type Boolean
      */
-    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];
-        }
-    },
+  
 
     /**
-     * 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
+     * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
+     * @type Boolean
      */
-    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);
-            }
-        }
-    },
-
     /**
-     * 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
+     * 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.
      */
-    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};
+    getConnection : function(){
+        return this.useAjax ? Roo.Ajax : this.conn;
     },
 
-    /*
-     * Sets up config options specific to this class. Overrides
-     * Roo.dd.DragDrop, but all versions of this method through the
-     * inheritance chain are called
+    /**
+     * 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.
      */
-    applyConfig: function() {
-        Roo.dd.DD.superclass.applyConfig.call(this);
-        this.scroll = (this.config.scroll !== false);
-    },
-
-    /*
-     * Event that fires prior to the onMouseDown event.  Overrides
-     * Roo.dd.DragDrop.
-     */
-    b4MouseDown: function(e) {
-        // this.resetConstraints();
-        this.autoOffset(e.getPageX(),
-                            e.getPageY());
-    },
-
-    /*
-     * 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) {
+    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);
+        }
     },
 
-    onDragEnter: function(e, id) {
+    // private
+    loadResponse : function(o, success, response){
+        delete this.activeRequest;
+        if(!success){
+            this.fireEvent("loadexception", this, o, response);
+            o.request.callback.call(o.request.scope, null, o.request.arg, false);
+            return;
+        }
+        var result;
+        try {
+            result = o.reader.read(response);
+        }catch(e){
+            this.fireEvent("loadexception", this, o, response, e);
+            o.request.callback.call(o.request.scope, null, o.request.arg, false);
+            return;
+        }
+        
+        this.fireEvent("load", this, o, o.request.arg);
+        o.request.callback.call(o.request.scope, result, o.request.arg, true);
     },
 
-    onDragOver: function(e, id) {
-    },
+    // private
+    update : function(dataSet){
 
-    onDragOut: function(e, id) {
     },
 
-    onDragDrop: function(e, id) {
-    },
+    // private
+    updateResponse : function(dataSet){
 
-    endDrag: function(e) {
     }
-
-    */
-
 });/*
  * Based on:
  * Ext JS Library 1.1.1
@@ -2795,247 +1589,195 @@ Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
  */
 
 /**
- * @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.
+ * @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>
  *
- * @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
+ * @param {Object} config A configuration object.
  */
-Roo.dd.DDProxy = function(id, sGroup, config) {
-    if (id) {
-        this.init(id, sGroup, config);
-        this.initFrame();
-    }
+Roo.data.ScriptTagProxy = function(config){
+    Roo.data.ScriptTagProxy.superclass.constructor.call(this);
+    Roo.apply(this, config);
+    this.head = document.getElementsByTagName("head")[0];
 };
 
-/**
- * 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, {
+Roo.data.ScriptTagProxy.TRANS_ID = 1000;
 
+Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
     /**
-     * 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
+     * @cfg {String} url The URL from which to request the data object.
      */
-    resizeFrame: true,
-
     /**
-     * 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
+     * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
      */
-    centerFrame: false,
-
+    timeout : 30000,
     /**
-     * Creates the proxy element if it does not yet exist
-     * @method createFrame
+     * @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.
      */
-    createFrame: function() {
-        var self = this;
-        var body = document.body;
-
-        if (!body || !body.firstChild) {
-            setTimeout( function() { self.createFrame(); }, 50 );
-            return;
-        }
-
-        var div = this.getDragEl();
-
-        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;
-
-            // 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);
-        }
-    },
-
+    callbackParam : "callback",
     /**
-     * Initialization for the drag frame element.  Must be called in the
-     * constructor of all subclasses
-     * @method initFrame
+     *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
+     * name to the request.
      */
-    initFrame: function() {
-        this.createFrame();
-    },
-
-    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);
-    },
+    nocache : true,
 
     /**
-     * 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
+     * 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.
      */
-    showFrame: function(iPageX, iPageY) {
-        var el = this.getEl();
-        var dragEl = this.getDragEl();
-        var s = dragEl.style;
+    load : function(params, reader, callback, scope, arg){
+        if(this.fireEvent("beforeload", this, params) !== false){
 
-        this._resizeProxy();
+            var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
 
-        if (this.centerFrame) {
-            this.setDelta( Math.round(parseInt(s.width,  10)/2),
-                           Math.round(parseInt(s.height, 10)/2) );
-        }
+            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;
 
-        this.setDragElPos(iPageX, iPageY);
+            window[trans.cb] = function(o){
+                conn.handleResponse(o, trans);
+            };
 
-        Roo.fly(dragEl).show();
-    },
+            url += String.format("&{0}={1}", this.callbackParam, trans.cb);
 
-    /**
-     * The proxy is automatically resized to the dimensions of the linked
-     * element when a drag is initiated, unless resizeFrame is set to false
-     * @method _resizeProxy
-     * @private
-     */
-    _resizeProxy: function() {
-        if (this.resizeFrame) {
-            var el = this.getEl();
-            Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
-        }
-    },
+            if(this.autoAbort !== false){
+                this.abort();
+            }
 
-    // overrides Roo.dd.DragDrop
-    b4MouseDown: function(e) {
-        var x = e.getPageX();
-        var y = e.getPageY();
-        this.autoOffset(x, y);
-        this.setDragElPos(x, y);
-    },
+            trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
 
-    // overrides Roo.dd.DragDrop
-    b4StartDrag: function(x, y) {
-        // show the drag frame
-        this.showFrame(x, y);
-    },
+            var script = document.createElement("script");
+            script.setAttribute("src", url);
+            script.setAttribute("type", "text/javascript");
+            script.setAttribute("id", trans.scriptId);
+            this.head.appendChild(script);
 
-    // overrides Roo.dd.DragDrop
-    b4EndDrag: function(e) {
-        Roo.fly(this.getDragEl()).hide();
+            this.trans = trans;
+        }else{
+            callback.call(scope||this, null, arg, false);
+        }
     },
 
-    // overrides Roo.dd.DragDrop
-    // By default we try to move the element to the last location of the frame.
-    // This is so that the default behavior mirrors that of Roo.dd.DD.
-    endDrag: function(e) {
-
-        var lel = this.getEl();
-        var del = this.getDragEl();
-
-        // Show the drag frame briefly so we can get its position
-        del.style.visibility = "";
-
-        this.beforeMove();
-        // Hide the linked element before the move to get around a Safari
-        // rendering bug.
-        lel.style.visibility = "hidden";
-        Roo.dd.DDM.moveToEl(lel, del);
-        del.style.visibility = "hidden";
-        lel.style.visibility = "";
-
-        this.afterDrag();
+    // private
+    isLoading : function(){
+        return this.trans ? true : false;
     },
 
-    beforeMove : function(){
-
+    /**
+     * Abort the current server request.
+     */
+    abort : function(){
+        if(this.isLoading()){
+            this.destroyTrans(this.trans);
+        }
     },
 
-    afterDrag : function(){
-
+    // 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){}
+            };
+        }
     },
 
-    toString: function() {
-        return ("DDProxy " + this.id);
-    }
-
-});
-/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-
- /**
- * @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 || {} 
-        });    
-    }
-};
+    // private
+    handleResponse : function(o, trans){
+        this.trans = false;
+        this.destroyTrans(trans, true);
+        var result;
+        try {
+            result = trans.reader.readRecords(o);
+        }catch(e){
+            this.fireEvent("loadexception", this, o, trans.arg, e);
+            trans.callback.call(trans.scope||window, null, trans.arg, false);
+            return;
+        }
+        this.fireEvent("load", this, o, trans.arg);
+        trans.callback.call(trans.scope||window, result, trans.arg, true);
+    },
 
-// Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
-Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
-    toString: function() {
-        return ("DDTarget " + 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:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -3045,315 +1787,218 @@ Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
  * Fork - LGPL
  * <script type="text/javascript">
  */
 
 /**
- * @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
+ * @class Roo.data.JsonReader
+ * @extends Roo.data.DataReader
+ * Data reader class to create an Array of Roo.data.Record objects from a JSON response
+ * based on mappings in a provided Roo.data.Record constructor.
+ * 
+ * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
+ * in the reply previously. 
+ * 
+ * <p>
+ * Example code:
+ * <pre><code>
+var RecordDef = Roo.data.Record.create([
+    {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
+    {name: 'occupation'}                 // This field will use "occupation" as the mapping.
+]);
+var myReader = new Roo.data.JsonReader({
+    totalProperty: "results",    // The property which contains the total dataset size (optional)
+    root: "rows",                // The property which contains an Array of row objects
+    id: "id"                     // The property within each row object that provides an ID for the record (optional)
+}, RecordDef);
+</code></pre>
+ * <p>
+ * This would consume a JSON file like this:
+ * <pre><code>
+{ 'results': 2, 'rows': [
+    { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
+    { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
+}
+</code></pre>
+ * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
+ * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
+ * paged from the remote server.
+ * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
+ * @cfg {String} root name of the property which contains the Array of row objects.
+ * @cfg {String} id Name of the property within a row object that contains a record identifier value.
+ * @cfg {Array} fields Array of field definition objects
+ * @constructor
+ * Create a new JsonReader
+ * @param {Object} meta Metadata configuration options
+ * @param {Object} recordType Either an Array of field definition objects,
+ * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
  */
-Roo.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);
-        }
-    };
+Roo.data.JsonReader = function(meta, recordType){
     
-    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);
-            }
-        }
-    };
+    meta = meta || {};
+    // set some defaults:
+    Roo.applyIf(meta, {
+        totalProperty: 'total',
+        successProperty : 'success',
+        root : 'data',
+        id : 'id'
+    });
     
-    var clearProc = function(){
-        if(proc.id){
-            clearInterval(proc.id);
-        }
-        proc.id = 0;
-        proc.el = null;
-        proc.dir = "";
-    };
+    Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
+};
+Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
     
-    var startProc = function(el, dir){
-         Roo.log('scroll startproc');
-        clearProc();
-        proc.el = el;
-        proc.dir = dir;
-        proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
-    };
+    readerType : 'Json',
     
-    var onFire = function(e, isDrop){
+    /**
+     * @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;
        
-        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;
-                }
-            }
+        var o = /* eval:var:o */ eval("("+json+")");
+        if(!o) {
+            throw {message: "JsonReader.read: Json object not found"};
         }
-        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();
-                }
-            }
+        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);
         }
-    };
-}();/*
- * 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;
+        return this.readRecords(o);
+    },
 
-    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;
-                }
-            }
-        },
+    // private function a store will implement
+    onMetaChange : function(meta, recordType, o){
 
-    /**
-     * 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 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];
-        },
+        * @ignore
+        */
+    simpleAccess: function(obj, subsc) {
+       return obj[subsc];
+    },
 
-    /**
-     * 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;
-        },
+       /**
+        * @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;
+        };
+    }(),
 
     /**
-     * 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
+     * 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.
      */
-        getTarget : function(id){
-            if(typeof id != "string"){ // must be element?
-                id = id.id;
-            }
-            return elements[id];
-        },
+    readRecords : function(o){
+        /**
+         * After any data loads, the raw JSON data is available for further custom processing.
+         * @type Object
+         */
+        this.o = o;
+        var s = this.meta, Record = this.recordType,
+            f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
 
-    /**
-     * 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;
-        }
-    };
-}();/*
+//      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
+        };
+    },
+    // used when loading children.. @see loadDataFromChildren
+    toLoadData: function(rec)
+    {
+       // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
+       var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
+       return { data : data, total : data.length };
+       
+    }
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -3363,173 +2008,132 @@ 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.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
- * @param {Object} config
+ * 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.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.data.XmlReader = function(meta, recordType){
+    meta = meta || {};
+    Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
 };
-
-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",
-    /**
-     * @cfg {String} dropNotAllowed
-     * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
-     */
-    dropNotAllowed : "x-dd-drop-nodrop",
-
-    /**
-     * 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
-     */
-    setStatus : function(cssClass){
-        cssClass = cssClass || this.dropNotAllowed;
-        if(this.dropStatus != cssClass){
-            this.el.replaceClass(this.dropStatus, cssClass);
-            this.dropStatus = cssClass;
-        }
-    },
-
-    /**
-     * 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
-     */
-    reset : function(clearGhost){
-        this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
-        this.dropStatus = this.dropNotAllowed;
-        if(clearGhost){
-            this.ghost.update("");
-        }
-    },
-
-    /**
-     * Updates the contents of the ghost element
-     * @param {String} html The html that will replace the current innerHTML of the ghost element
-     */
-    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');
-               }
-    },
+Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
+    
+    readerType : 'Xml',
     
     /**
-     * Returns the underlying proxy {@link Roo.Layer}
-     * @return {Roo.Layer} el
-    */
-    getEl : function(){
-        return this.el;
-    },
-
-    /**
-     * Returns the ghost element
-     * @return {Roo.Element} el
-     */
-    getGhost : function(){
-        return this.ghost;
-    },
-
-    /**
-     * Hides the proxy
-     * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
-     */
-    hide : function(clear){
-        this.el.hide();
-        if(clear){
-            this.reset(true);
-        }
-    },
-
-    /**
-     * Stops the repair animation if it's currently running
+     * 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.
      */
-    stop : function(){
-        if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
-            this.anim.stop();
+    read : function(response){
+        var doc = response.responseXML;
+        if(!doc) {
+            throw {message: "XmlReader.read: XML Document not available"};
         }
+        return this.readRecords(doc);
     },
 
     /**
-     * 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
+     * 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.
      */
-    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();
-        }
-    },
+    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;
+           }
 
-    // private
-    afterRepair : function(){
-        this.hide(true);
-        if(typeof this.callback == "function"){
-            this.callback.call(this.scope || this);
-        }
-        this.callback = null;
-        this.scope = null;
+           return {
+               success : success,
+               records : records,
+               totalRecords : totalRecords || records.length
+           };
     }
-};/*
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -3541,938 +2145,836 @@ 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.data.ArrayReader
+ * @extends Roo.data.DataReader
+ * Data reader class to create an Array of Roo.data.Record objects from an Array.
+ * Each element of that Array represents a row of data fields. The
+ * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
+ * of the field definition if it exists, or the field's ordinal position in the definition.<br>
+ * <p>
+ * Example code:.
+ * <pre><code>
+var RecordDef = Roo.data.Record.create([
+    {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
+    {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
+]);
+var myReader = new Roo.data.ArrayReader({
+    id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
+}, RecordDef);
+</code></pre>
+ * <p>
+ * This would consume an Array like this:
+ * <pre><code>
+[ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
+  </code></pre>
  * @constructor
- * @param {String/HTMLElement/Element} el The container element
- * @param {Object} config
+ * Create a new JsonReader
+ * @param {Object} meta Metadata configuration options.
+ * @param {Object|Array} recordType Either an Array of field definition objects
+ * 
+ * @cfg {Array} fields Array of field definition objects
+ * @cfg {String} id Name of the property within a row object that contains a record identifier value.
+ * as specified to {@link Roo.data.Record#create},
+ * or an {@link Roo.data.Record} object
+ *
+ * 
+ * created using {@link Roo.data.Record#create}.
  */
-Roo.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.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.ArrayReader = function(meta, recordType)
+{    
+    Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
 };
 
-Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
-    /**
-     * @cfg {String} dropAllowed
-     * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
-     */
-    dropAllowed : "x-dd-drop-ok",
-    /**
-     * @cfg {String} dropNotAllowed
-     * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
-     */
-    dropNotAllowed : "x-dd-drop-nodrop",
-
-    /**
-     * Returns the data object associated with this drag source
-     * @return {Object} data An object containing arbitrary data
+Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
+    
+      /**
+     * Create a data block containing Roo.data.Records from an XML document.
+     * @param {Object} o An Array of row objects which represents the dataset.
+     * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
+     * a cache of Roo.data.Records.
      */
-    getDragData : function(e){
-        return this.dragData;
+    readRecords : function(o)
+    {
+        var sid = this.meta ? this.meta.id : null;
+       var recordType = this.recordType, fields = recordType.prototype.fields;
+       var records = [];
+       var root = o;
+       for(var i = 0; i < root.length; i++){
+               var n = root[i];
+           var values = {};
+           var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
+           for(var j = 0, jlen = fields.length; j < jlen; j++){
+               var f = fields.items[j];
+               var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
+               var v = n[k] !== undefined ? n[k] : f.defaultValue;
+               v = f.convert(v);
+               values[f.name] = v;
+           }
+           var record = new recordType(values, id);
+           record.json = n;
+           records[records.length] = record;
+       }
+       return {
+           records : records,
+           totalRecords : records.length
+       };
     },
+    // used when loading children.. @see loadDataFromChildren
+    toLoadData: function(rec)
+    {
+       // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
+       return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
+       
+    }
+    
+    
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
 
-    // private
-    onDragEnter : function(e, id){
-        var target = Roo.dd.DragDropMgr.getDDById(id);
-        this.cachedTarget = target;
-        if(this.beforeDragEnter(target, e, id) !== false){
-            if(target.isNotifyTarget){
-                var status = target.notifyEnter(this, e, this.dragData);
-                this.proxy.setStatus(status);
-            }else{
-                this.proxy.setStatus(this.dropAllowed);
-            }
-            
-            if(this.afterDragEnter){
-                /**
-                 * An empty function by default, but provided so that you can perform a custom action
-                 * when the dragged item enters the drop target by providing an implementation.
-                 * @param {Roo.dd.DragDrop} target The drop target
-                 * @param {Event} e The event object
-                 * @param {String} id The id of the dragged element
-                 * @method afterDragEnter
-                 */
-                this.afterDragEnter(target, e, id);
-            }
-        }
-    },
 
-    /**
-     * An empty function by default, but provided so that you can perform a custom action
-     * before the dragged item enters the drop target and optionally cancel the onDragEnter.
-     * @param {Roo.dd.DragDrop} target The drop target
-     * @param {Event} e The event object
-     * @param {String} id The id of the dragged element
-     * @return {Boolean} isValid True if the drag event is valid, else false to cancel
-     */
-    beforeDragEnter : function(target, e, id){
-        return true;
-    },
+/**
+ * @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
+   });
 
-    // private
-    alignElWithMouse: function() {
-        Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
-        this.proxy.sync();
-    },
+    Roo.data.Tree.superclass.constructor.call(this);
+};
 
-    // private
-    onDragOver : function(e, id){
-        var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
-        if(this.beforeDragOver(target, e, id) !== false){
-            if(target.isNotifyTarget){
-                var status = target.notifyOver(this, e, this.dragData);
-                this.proxy.setStatus(status);
-            }
+Roo.extend(Roo.data.Tree, Roo.util.Observable, {
+    pathSeparator: "/",
 
-            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);
-            }
-        }
+    proxyNodeEvent : function(){
+        return this.fireEvent.apply(this, arguments);
     },
 
     /**
-     * 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
+     * Returns the root node for this tree.
+     * @return {Node}
      */
-    beforeDragOver : function(target, e, id){
-        return true;
-    },
-
-    // private
-    onDragOut : function(e, id){
-        var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
-        if(this.beforeDragOut(target, e, id) !== false){
-            if(target.isNotifyTarget){
-                target.notifyOut(this, e, this.dragData);
-            }
-            this.proxy.reset();
-            if(this.afterDragOut){
-                /**
-                 * An empty function by default, but provided so that you can perform a custom action
-                 * after the dragged item is dragged out of the target without dropping.
-                 * @param {Roo.dd.DragDrop} target The drop target
-                 * @param {Event} e The event object
-                 * @param {String} id The id of the dragged element
-                 * @method afterDragOut
-                 */
-                this.afterDragOut(target, e, id);
-            }
-        }
-        this.cachedTarget = null;
+    getRootNode : function(){
+        return this.root;
     },
 
     /**
-     * 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
+     * Sets the root node for this tree.
+     * @param {Node} node
+     * @return {Node}
      */
-    beforeDragOut : function(target, e, id){
-        return true;
-    },
-    
-    // private
-    onDragDrop : function(e, id){
-        var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
-        if(this.beforeDragDrop(target, e, id) !== false){
-            if(target.isNotifyTarget){
-                if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
-                    this.onValidDrop(target, e, id);
-                }else{
-                    this.onInvalidDrop(target, e, id);
-                }
-            }else{
-                this.onValidDrop(target, e, id);
-            }
-            
-            if(this.afterDragDrop){
-                /**
-                 * An empty function by default, but provided so that you can perform a custom action
-                 * after a valid drag drop has occurred by providing an implementation.
-                 * @param {Roo.dd.DragDrop} target The drop target
-                 * @param {Event} e The event object
-                 * @param {String} id The id of the dropped element
-                 * @method afterDragDrop
-                 */
-                this.afterDragDrop(target, e, id);
-            }
-        }
-        delete this.cachedTarget;
+    setRootNode : function(node){
+        this.root = node;
+        node.ownerTree = this;
+        node.isRoot = true;
+        this.registerNode(node);
+        return node;
     },
 
     /**
-     * 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
+     * Gets a node in this tree by its id.
+     * @param {String} id
+     * @return {Node}
      */
-    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
-    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);
-        }
+    getNodeById : function(id){
+        return this.nodeHash[id];
     },
 
-    // private
-    afterRepair : function(){
-        if(Roo.enableFx){
-            this.el.highlight(this.hlColor || "c3daf9");
-        }
-        this.dragging = false;
+    registerNode : function(node){
+        this.nodeHash[node.id] = node;
     },
 
-    /**
-     * 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;
+    unregisterNode : function(node){
+        delete this.nodeHash[node.id];
     },
 
-    // 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);
-        } 
-    },
+    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){
     /**
-     * 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
+     * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
+     * @type {Object}
      */
-    onBeforeDrag : function(data, e){
-        return true;
-    },
-
+    this.attributes = attributes || {};
+    this.leaf = this.attributes.leaf;
     /**
-     * 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
+     * The node id. @type String
      */
-    onStartDrag : Roo.emptyFn,
-
-    // private - YUI override
-    startDrag : function(x, y){
-        this.proxy.reset();
-        this.dragging = true;
-        this.proxy.update("");
-        this.onInitDrag(x, y);
-        this.proxy.show();
-    },
-
-    // private
-    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;
-    },
-
-    /**
-     * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
-     * @return {Roo.dd.StatusProxy} proxy The StatusProxy
-     */
-    getProxy : function(){
-        return this.proxy;  
-    },
-
-    /**
-     * 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){
-    },
-    
-    // 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">
- */
-
-
-/**
- * @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.id = this.attributes.id;
+    if(!this.id){
+        this.id = Roo.id(null, "ynode-");
+        this.attributes.id = this.id;
     }
-    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
+     * 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;
+        };
+    }
     /**
-     * @cfg {String} dropAllowed
-     * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
+     * The parent node for this node. @type Node
      */
-    dropAllowed : "x-dd-drop-ok",
+    this.parentNode = null;
     /**
-     * @cfg {String} dropNotAllowed
-     * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
+     * The first direct child node of this node, or null if this node has no child nodes. @type Node
      */
-    dropNotAllowed : "x-dd-drop-nodrop",
+    this.firstChild = null;
     /**
-     * @cfg {boolean} success
-     * set this after drop listener.. 
+     * The last direct child node of this node, or null if this node has no child nodes. @type Node
      */
-    success : false,
+    this.lastChild = null;
     /**
-     * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
-     * if the drop point is valid for over/enter..
+     * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
      */
-    valid : false,
-    // private
-    isTarget : true,
-
-    // private
-    isNotifyTarget : true,
-    
+    this.previousSibling = null;
     /**
-     * @hide
+     * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
      */
-    notifyEnter : function(dd, e, data)
-    {
-        this.valid = true;
-        this.fireEvent('enter', dd, e, data);
-        if(this.overClass){
-            this.el.addClass(this.overClass);
+    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;
         }
-        return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
-            this.valid ? this.dropAllowed : this.dropNotAllowed
-        );
+        // 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;
     },
 
     /**
-     * @hide
+     * Returns true if this node is a leaf
+     * @return {Boolean}
      */
-    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
-        );
+    isLeaf : function(){
+        return this.leaf === true;
     },
 
-    /**
-     * @hide
-     */
-    notifyOut : function(dd, e, data)
-    {
-        this.fireEvent('out', dd, e, data);
-        if(this.overClass){
-            this.el.removeClass(this.overClass);
-        }
+    // private
+    setFirstChild : function(node){
+        this.firstChild = node;
     },
 
-    /**
-     * @hide
-     */
-    notifyDrop : function(dd, e, data)
-    {
-        this.success = false;
-        this.fireEvent('drop', dd, e, data);
-        return this.success;
-    }
-});/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-
+    //private
+    setLastChild : function(node){
+        this.lastChild = node;
+    },
 
-/**
- * @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, {
-    /**
-     * @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)
+     * Returns true if this node is the last child of its parent
+     * @return {Boolean}
      */
+    isLast : function(){
+       return (!this.parentNode ? true : this.parentNode.lastChild == this);
+    },
 
     /**
-     * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
-     * for a valid target to drag based on the mouse down. Override this method
-     * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
-     * object has a "ddel" attribute (with an HTML Element) for other functions to work.
-     * @param {EventObject} e The mouse down event
-     * @return {Object} The dragData
+     * Returns true if this node is the first child of its parent
+     * @return {Boolean}
      */
-    getDragData : function(e){
-        return Roo.dd.Registry.getHandleFromEvent(e);
+    isFirst : function(){
+       return (!this.parentNode ? true : this.parentNode.firstChild == this);
     },
-    
-    /**
-     * 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;
+
+    hasChildNodes : function(){
+        return !this.isLeaf() && this.childNodes.length > 0;
     },
-    
+
     /**
-     * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel 
+     * 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
      */
-    afterRepair : function(){
-        if(Roo.enableFx){
-            Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
+    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(this.ownerTree) {
+                this.ownerTree.fireEvent("appendnode", this, node, index);
+            }
+            if(oldParent){
+                node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
+            }
+            return node;
         }
-        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])
+     * Removes a child node from this node.
+     * @param {Node} node The node to remove
+     * @return {Node} The removed node
      */
-    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);
-};
+    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;
+        }
 
-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);
-    },
+        // remove it from childNodes collection
+        this.childNodes.splice(index, 1);
 
-    /**
-     * 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){
-        
-    },
+        // update siblings
+        if(node.previousSibling){
+            node.previousSibling.nextSibling = node.nextSibling;
+        }
+        if(node.nextSibling){
+            node.nextSibling.previousSibling = node.previousSibling;
+        }
 
-    /**
-     * 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;
-    },
+        // update child refs
+        if(this.firstChild == node){
+            this.setFirstChild(node.nextSibling);
+        }
+        if(this.lastChild == node){
+            this.setLastChild(node.previousSibling);
+        }
 
-    /**
-     * 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){
-        
+        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;
     },
 
     /**
-     * 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
+     * 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
      */
-    onNodeDrop : function(n, dd, e, data){
-        return false;
+    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;
     },
 
     /**
-     * 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
+     * Returns the child node at the specified index.
+     * @param {Number} index
+     * @return {Node}
      */
-    onContainerOver : function(dd, e, data){
-        return this.dropNotAllowed;
+    item : function(index){
+        return this.childNodes[index];
     },
 
     /**
-     * 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
+     * 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
      */
-    onContainerDrop : function(dd, e, data){
-        return false;
+    replaceChild : function(newChild, oldChild){
+        this.insertBefore(newChild, oldChild);
+        this.removeChild(oldChild);
+        return oldChild;
     },
 
     /**
-     * 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 index of a child node
+     * @param {Node} node
+     * @return {Number} The index of the node or -1 if it was not found
      */
-    notifyEnter : function(dd, e, data){
-        return this.dropNotAllowed;
+    indexOf : function(child){
+        return this.childNodes.indexOf(child);
     },
 
     /**
-     * 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
+     * Returns the tree this node is in.
+     * @return {Tree}
      */
-    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);
+    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;
             }
-            this.onNodeEnter(n, dd, e, data);
-            this.lastOverNode = n;
         }
-        return this.onNodeOver(n, dd, e, data);
+        return this.ownerTree;
     },
 
     /**
-     * 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 depth of this node (the root node has a depth of 0)
+     * @return {Number}
      */
-    notifyOut : function(dd, e, data){
-        if(this.lastOverNode){
-            this.onNodeOut(this.lastOverNode, dd, e, data);
-            this.lastOverNode = null;
+    getDepth : function(){
+        var depth = 0;
+        var p = this;
+        while(p.parentNode){
+            ++depth;
+            p = p.parentNode;
         }
+        return depth;
     },
 
-    /**
-     * 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
-     */
-    notifyDrop : function(dd, e, data){
-        if(this.lastOverNode){
-            this.onNodeOut(this.lastOverNode, dd, e, data);
-            this.lastOverNode = null;
+    // 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 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.
- *
- * 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 = {
     /**
-     * Default sort that does nothing
-     * @param {Mixed} s The value being converted
-     * @return {Mixed} The comparison value
+     * 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
      */
-    none : function(s){
-        return s;
+    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);
     },
-    
+
     /**
-     * The regular expression used to strip tags
-     * @type {RegExp}
-     * @property
+     * 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)
      */
-    stripTagsRE : /<\/?[^>]+>/gi,
-    
+    bubble : function(fn, scope, args){
+        var p = this;
+        while(p){
+            if(fn.call(scope || p, args || p) === false){
+                break;
+            }
+            p = p.parentNode;
+        }
+    },
+
     /**
-     * Strips all HTML tags to sort on text only
-     * @param {Mixed} s The value being converted
-     * @return {String} The comparison value
+     * 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)
      */
-    asText : function(s){
-        return String(s).replace(this.stripTagsRE, "");
+    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);
+            }
+        }
     },
-    
+
     /**
-     * Strips all HTML tags to sort on text only - Case insensitive
-     * @param {Mixed} s The value being converted
-     * @return {String} The comparison value
+     * 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)
      */
-    asUCText : function(s){
-        return String(s).toUpperCase().replace(this.stripTagsRE, "");
+    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;
+               }
+        }
     },
-    
+
     /**
-     * Case insensitive string
-     * @param {Mixed} s The value being converted
-     * @return {String} The comparison value
+     * 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
      */
-    asUCString : function(s) {
-       return String(s).toUpperCase();
+    findChild : function(attribute, value){
+        var cs = this.childNodes;
+        for(var i = 0, len = cs.length; i < len; i++) {
+               if(cs[i].attributes[attribute] == value){
+                   return cs[i];
+               }
+        }
+        return null;
     },
-    
+
     /**
-     * Date sorting
-     * @param {Mixed} s The value being converted
-     * @return {Number} The comparison value
+     * 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
      */
-    asDate : function(s) {
-        if(!s){
-            return 0;
+    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];
+               }
         }
-        if(s instanceof Date){
-            return s.getTime();
+        return null;
+    },
+
+    /**
+     * Sorts this nodes children using the supplied sort function
+     * @param {Function} fn
+     * @param {Object} scope (optional)
+     */
+    sort : function(fn, scope){
+        var cs = this.childNodes;
+        var len = cs.length;
+        if(len > 0){
+            var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
+            cs.sort(sortFn);
+            for(var i = 0; i < len; i++){
+                var n = cs[i];
+                n.previousSibling = cs[i-1];
+                n.nextSibling = cs[i+1];
+                if(i == 0){
+                    this.setFirstChild(n);
+                }
+                if(i == len-1){
+                    this.setLastChild(n);
+                }
+            }
         }
-       return Date.parse(String(s));
     },
-    
+
     /**
-     * Float sorting
-     * @param {Mixed} s The value being converted
-     * @return {Float} The comparison value
+     * Returns true if this node is an ancestor (at any point) of the passed node.
+     * @param {Node} node
+     * @return {Boolean}
      */
-    asFloat : function(s) {
-       var val = parseFloat(String(s).replace(/,/g, ""));
-        if(isNaN(val)) val = 0;
-       return val;
+    contains : function(node){
+        return node.isAncestor(this);
     },
-    
+
     /**
-     * Integer sorting
-     * @param {Mixed} s The value being converted
-     * @return {Number} The comparison value
+     * Returns true if the passed node is an ancestor (at any point) of this node.
+     * @param {Node} node
+     * @return {Boolean}
      */
-    asInt : function(s) {
-        var val = parseInt(String(s).replace(/,/g, ""));
-        if(isNaN(val)) val = 0;
-       return val;
+    isAncestor : function(node){
+        var p = this.parentNode;
+        while(p){
+            if(p == node){
+                return true;
+            }
+            p = p.parentNode;
+        }
+        return false;
+    },
+
+    toString : function(){
+        return "[Node"+(this.id?" "+this.id:"")+"]";
     }
-};/*
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -4482,1166 +2984,1092 @@ Roo.data.SortTypes = {
  * Fork - LGPL
  * <script type="text/javascript">
  */
-
+ (function(){ 
 /**
-* @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.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
- * 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.
+ * @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.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
- */
-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.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);
     }
-    f.getField = function(name){
-        return p.fields.get(name);  
-    };
-    return f;
+    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.data.Record.AUTO_ID = 1000;
-Roo.data.Record.EDIT = 'edit';
-Roo.data.Record.REJECT = 'reject';
-Roo.data.Record.COMMIT = 'commit';
+var supr = Roo.Element.prototype;
 
-Roo.data.Record.prototype = {
-    /**
-     * Readonly flag - true if this record has been modified.
-     * @type Boolean
-     */
-    dirty : false,
-    editing : false,
-    error: null,
-    modified: null,
+// shims are shared among layer to keep from having 100 iframes
+var shims = [];
 
-    // private
-    join : function(store){
-        this.store = store;
+Roo.extend(Roo.Layer, Roo.Element, {
+
+    getZIndex : function(){
+        return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
     },
 
-    /**
-     * 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;
+    getShim : function(){
+        if(!this.useShim){
+            return null;
         }
-        this.dirty = true;
-        if(!this.modified){
-            this.modified = {};
+        if(this.shim){
+            return this.shim;
         }
-        if(typeof this.modified[name] == 'undefined'){
-            this.modified[name] = this.data[name];
+        var shim = shims.shift();
+        if(!shim){
+            shim = this.createShim();
+            shim.enableDisplayMode('block');
+            shim.dom.style.display = 'none';
+            shim.dom.style.visibility = 'visible';
         }
-        this.data[name] = value;
-        if(!this.editing && this.store){
-            this.store.afterEdit(this);
-        }       
+        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;
     },
 
-    /**
-     * 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]; 
+    hideShim : function(){
+        if(this.shim){
+            this.shim.setDisplayed(false);
+            shims.push(this.shim);
+            delete this.shim;
+        }
     },
 
-    // private
-    beginEdit : function(){
-        this.editing = true;
-        this.modified = {}; 
+    disableShadow : function(){
+        if(this.shadow){
+            this.shadowDisabled = true;
+            this.shadow.hide();
+            this.lastShadowOffset = this.shadowOffset;
+            this.shadowOffset = 0;
+        }
     },
 
-    // private
-    cancelEdit : function(){
-        this.editing = false;
-        delete this.modified;
+    enableShadow : function(show){
+        if(this.shadow){
+            this.shadowDisabled = false;
+            this.shadowOffset = this.lastShadowOffset;
+            delete this.lastShadowOffset;
+            if(show){
+                this.sync(true);
+            }
+        }
     },
 
     // private
-    endEdit : function(){
-        this.editing = false;
-        if(this.dirty && this.store){
-            this.store.afterEdit(this);
+    // this code can execute repeatedly in milliseconds (i.e. during a drag) so
+    // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
+    sync : function(doShow){
+        var sw = this.shadow;
+        if(!this.updating && this.isVisible() && (sw || this.useShim)){
+            var sh = this.getShim();
+
+            var w = this.getWidth(),
+                h = this.getHeight();
+
+            var l = this.getLeft(true),
+                t = this.getTop(true);
+
+            if(sw && !this.shadowDisabled){
+                if(doShow && !sw.isVisible()){
+                    sw.show(this);
+                }else{
+                    sw.realign(l, t, w, h);
+                }
+                if(sh){
+                    if(doShow){
+                       sh.show();
+                    }
+                    // fit the shim behind the shadow, so it is shimmed too
+                    var a = sw.adjusts, s = sh.dom.style;
+                    s.left = (Math.min(l, l+a.l))+"px";
+                    s.top = (Math.min(t, t+a.t))+"px";
+                    s.width = (w+a.w)+"px";
+                    s.height = (h+a.h)+"px";
+                }
+            }else if(sh){
+                if(doShow){
+                   sh.show();
+                }
+                sh.setSize(w, h);
+                sh.setLeftTop(l, t);
+            }
+            
         }
     },
 
-    /**
-     * 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.
-     */
-    reject : function(){
-        var m = this.modified;
-        for(var n in m){
-            if(typeof m[n] != "function"){
-                this.data[n] = m[n];
-            }
+    // private
+    destroy : function(){
+        this.hideShim();
+        if(this.shadow){
+            this.shadow.hide();
         }
-        this.dirty = false;
-        delete this.modified;
-        this.editing = false;
-        if(this.store){
-            this.store.afterReject(this);
+        this.removeAllListeners();
+        var pn = this.dom.parentNode;
+        if(pn){
+            pn.removeChild(this.dom);
         }
+        Roo.Element.uncache(this.id);
     },
 
-    /**
-     * 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);
-        }
+    remove : function(){
+        this.destroy();
     },
 
     // private
-    hasError : function(){
-        return this.error != null;
+    beginUpdate : function(){
+        this.updating = true;
     },
 
     // private
-    clearError : function(){
-        this.error = null;
+    endUpdate : function(){
+        this.updating = false;
+        this.sync(true);
     },
 
-    /**
-     * 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
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
+    // private
+    hideUnders : function(negOffset){
+        if(this.shadow){
+            this.shadow.hide();
+        }
+        this.hideShim();
+    },
+
+    // private
+    constrainXY : function(){
+        if(this.constrain){
+            var vw = Roo.lib.Dom.getViewWidth(),
+                vh = Roo.lib.Dom.getViewHeight();
+            var s = Roo.get(document).getScroll();
 
+            var xy = this.getXY();
+            var x = xy[0], y = xy[1];   
+            var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
+            // only move it if it needs it
+            var moved = false;
+            // first validate right/bottom
+            if((x + w) > vw+s.left){
+                x = vw - w - this.shadowOffset;
+                moved = true;
+            }
+            if((y + h) > vh+s.top){
+                y = vh - h - this.shadowOffset;
+                moved = true;
+            }
+            // then make sure top/left isn't negative
+            if(x < s.left){
+                x = s.left;
+                moved = true;
+            }
+            if(y < s.top){
+                y = s.top;
+                moved = true;
+            }
+            if(moved){
+                if(this.avoidY){
+                    var ay = this.avoidY;
+                    if(y <= ay && (y+h) >= ay){
+                        y = ay-h-5;   
+                    }
+                }
+                xy = [x, y];
+                this.storeXY(xy);
+                supr.setXY.call(this, xy);
+                this.sync();
+            }
+        }
+    },
 
+    isVisible : function(){
+        return this.visible;    
+    },
 
-/**
- * @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"
-    };
+    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(config && config.data){
-        this.inlineData = config.data;
-        delete config.data;
-    }
+    // private
+    hideAction : function(){
+        this.visible = false;
+        if(this.useDisplay === true){
+            this.setDisplayed(false);
+        }else{
+            this.setLeftTop(-10000,-10000);
+        }
+    },
 
-    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;
+    // overridden Element method
+    setVisible : function(v, a, d, c, e){
+        if(v){
+            this.showAction();
         }
-        if(this.reader.onMetaChange){
-            this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
+        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.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
-    });
-    
-    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;
-    }
-};
+    storeXY : function(xy){
+        delete this.lastLT;
+        this.lastXY = xy;
+    },
 
-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.
-    */
-    /**
-    * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
-    * on any HTTP request
-    */
-    /**
-    * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
-    */
-    /**
-    * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
-    */
-    multiSort: false,
-    /**
-    * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
-    * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
-    */
-    remoteSort : false,
+    storeLeftTop : function(left, top){
+        delete this.lastXY;
+        this.lastLT = [left, top];
+    },
 
-    /**
-    * @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
+    beforeFx : function(){
+        this.beforeAction();
+        return Roo.Layer.superclass.beforeFx.apply(this, arguments);
+    },
 
     // private
-    lastOptions : null,
+    afterFx : function(){
+        Roo.Layer.superclass.afterFx.apply(this, arguments);
+        this.sync(this.isVisible());
+    },
 
-    /**
-     * 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.
-     */
-    add : function(records){
-        records = [].concat(records);
-        for(var i = 0, len = records.length; i < len; i++){
-            records[i].join(this);
+    // private
+    beforeAction : function(){
+        if(!this.updating && this.shadow){
+            this.shadow.hide();
         }
-        var index = this.data.length;
-        this.data.addAll(records);
-        this.fireEvent("add", this, records, index);
     },
 
-    /**
-     * Remove a Record from the Store and fires the remove event.
-     * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
-     */
-    remove : function(record){
-        var index = this.data.indexOf(record);
-        this.data.removeAt(index);
-        if(this.pruneModifiedRecords){
-            this.modified.remove(record);
-        }
-        this.fireEvent("remove", this, record, index);
+    // overridden Element method
+    setLeft : function(left){
+        this.storeLeftTop(left, this.getTop(true));
+        supr.setLeft.apply(this, arguments);
+        this.sync();
     },
 
-    /**
-     * Remove all Records from the Store and fires the clear event.
-     */
-    removeAll : function(){
-        this.data.clear();
-        if(this.pruneModifiedRecords){
-            this.modified = [];
-        }
-        this.fireEvent("clear", this);
+    setTop : function(top){
+        this.storeLeftTop(this.getLeft(true), top);
+        supr.setTop.apply(this, arguments);
+        this.sync();
     },
 
-    /**
-     * 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);
+    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();
         }
-        this.fireEvent("add", this, records, index);
     },
 
-    /**
-     * Get the index within the cache of the passed Record.
-     * @param {Roo.data.Record} record The Roo.data.Record object to to find.
-     * @return {Number} The index of the passed Record. Returns -1 if not found.
-     */
-    indexOf : function(record){
-        return this.data.indexOf(record);
+    // private
+    createCB : function(c){
+        var el = this;
+        return function(){
+            el.constrainXY();
+            el.sync(true);
+            if(c){
+                c();
+            }
+        };
     },
 
-    /**
-     * Get the index within the cache of the Record with the passed id.
-     * @param {String} id The id of the Record to find.
-     * @return {Number} The index of the Record. Returns -1 if not found.
-     */
-    indexOfId : function(id){
-        return this.data.indexOfKey(id);
+    // overridden Element method
+    setX : function(x, a, d, c, e){
+        this.setXY([x, this.getY()], a, d, c, e);
     },
 
-    /**
-     * Get the Record with the specified id.
-     * @param {String} id The id of the Record to find.
-     * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
-     */
-    getById : function(id){
-        return this.data.key(id);
+    // overridden Element method
+    setY : function(y, a, d, c, e){
+        this.setXY([this.getX(), y], a, d, c, 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.
-     */
-    getAt : function(index){
-        return this.data.itemAt(index);
+    // 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 a range of Records between specified indices.
-     * @param {Number} startIndex (optional) The starting index (defaults to 0)
-     * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
-     * @return {Roo.data.Record[]} An array of Records
-     */
-    getRange : function(start, end){
-        return this.data.getRange(start, end);
+    // 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
-    storeOptions : function(o){
-        o = Roo.apply({}, o);
-        delete o.callback;
-        delete o.scope;
-        this.lastOptions = o;
+    // 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();
+        }
     },
 
-    /**
-     * 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);
+    // 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;
     },
-
+    
     /**
-     * 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).
+     * 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
      */
-    reload : function(options){
-        this.load(Roo.applyIf(options||{}, this.lastOptions));
-    },
-
-    // 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;
+    setZIndex : function(zindex){
+        this.zindex = zindex;
+        this.setStyle("z-index", zindex + 2);
+        if(this.shadow){
+            this.shadow.setZIndex(zindex + 1);
         }
-        // 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;
+        if(this.shim){
+            this.shim.setStyle("z-index", zindex);
         }
-        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 = [];
+    }
+});
+})();/*
+ * 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;
             }
-            for(var i = 0, len = r.length; i < len; i++){
-                r[i].join(this);
+        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;
             }
-            if(this.snapshot){
-                this.data = this.snapshot;
-                delete this.snapshot;
+        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;
             }
-            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);
-        }
-    },
+        break;
+    };
 
+    this.adjusts = a;
+};
 
+Roo.Shadow.prototype = {
     /**
-     * Loads data from a passed data block. A Reader which understands the format of the data
-     * must have been configured in the constructor.
-     * @param {Object} data The data block from which to read the Records.  The format of the data expected
-     * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
-     * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
+     * @cfg {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)
      */
-    loadData : function(o, append){
-        var r = this.reader.readRecords(o);
-        this.loadRecords(r, {add: append}, true);
-    },
-
     /**
-     * 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>
+     * @cfg {String} offset
+     * The number of pixels to offset the shadow from the element (defaults to 4)
      */
-    getCount : function(){
-        return this.data.length || 0;
-    },
+    offset: 4,
 
-    /**
-     * 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;
-    },
+    // private
+    defaultMode: "drop",
 
     /**
-     * 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>
+     * Displays the shadow under the target element
+     * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
      */
-    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);
+    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";
     },
 
     /**
-     * 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")
+     * Returns true if the shadow is visible, else false
      */
-    setDefaultSort : function(field, dir){
-        this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
+    isVisible : function(){
+        return this.el ? true : false;  
     },
 
     /**
-     * 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")
+     * 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
      */
-    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;
-            }
+    realign : function(l, t, w, h){
+        if(!this.el){
+            return;
         }
-        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);
+        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";
+            }
         }
     },
 
     /**
-     * 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).
+     * Hides this shadow
      */
-    each : function(fn, scope){
-        this.data.each(fn, scope);
+    hide : function(){
+        if(this.el){
+            this.el.dom.style.display = "none";
+            Roo.Shadow.Pool.push(this.el);
+            delete this.el;
+        }
     },
 
     /**
-     * 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.
+     * Adjust the z-index of this shadow
+     * @param {Number} zindex The new z-index
      */
-    getModifiedRecords : function(){
-        return this.modified;
-    },
+    setZIndex : function(z){
+        this.zIndex = z;
+        if(this.el){
+            this.el.setStyle("z-index", z);
+        }
+    }
+};
 
-    // private
-    createFilterFn : function(property, value, anyMatch){
-        if(!value.exec){ // not a regex
-            value = String(value);
-            if(value.length == 0){
-                return false;
+// 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;
             }
-            value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
+            return sh;
+        },
+
+        push : function(sh){
+            p.push(sh);
         }
-        return function(r){
-            return value.test(r.data[property]);
-        };
-    },
+    };
+}();/*
+ * 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">
+ */
 
-    /**
-     * Sums the value of <i>property</i> for each record between start and end and returns the result.
-     * @param {String} property A field on your records
-     * @param {Number} start The record index to start at (defaults to 0)
-     * @param {Number} end The last record index to include (defaults to length - 1)
-     * @return {Number} The sum
-     */
-    sum : function(property, start, end){
-        var rs = this.data.items, v = 0;
-        start = start || 0;
-        end = (end || end === 0) ? end : rs.length-1;
 
-        for(var i = start; i <= end; i++){
-            v += (rs[i].data[property] || 0);
-        }
-        return v;
-    },
+/**
+ * @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 */
+    this.resizingEl = Roo.get(resizingElement, true);
 
     /**
-     * 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
+     * @private
+     * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
+     * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
+     * @type Number
      */
-    filter : function(property, value, anyMatch){
-        var fn = this.createFilterFn(property, value, anyMatch);
-        return fn ? this.filterBy(fn) : this.clearFilter();
-    },
-
+    this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
+    
     /**
-     * Filter by a function. The specified function will be called with each
-     * record in this data source. If the function returns true the record is included,
-     * otherwise it is filtered.
-     * @param {Function} fn The function to be called, it will receive 2 args (record, id)
-     * @param {Object} scope (optional) The scope of the function (defaults to this)
+     * The minimum size of the resizing element. (Defaults to 0)
+     * @type Number
      */
-    filterBy : function(fn, scope){
-        this.snapshot = this.snapshot || this.data;
-        this.data = this.queryBy(fn, scope||this);
-        this.fireEvent("datachanged", this);
-    },
-
+    this.minSize = 0;
+    
     /**
-     * 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
+     * The maximum size of the resizing element. (Defaults to 2000)
+     * @type Number
      */
-    query : function(property, value, anyMatch){
-        var fn = this.createFilterFn(property, value, anyMatch);
-        return fn ? this.queryBy(fn) : this.data.clone();
-    },
-
+    this.maxSize = 2000;
+    
     /**
-     * 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);
-    },
-
+     * Whether to animate the transition to the new size
+     * @type Boolean
+     */
+    this.animate = false;
+    
     /**
-     * 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;
-    },
-
+     * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
+     * @type Boolean
+     */
+    this.useShim = false;
+    
+    /** @private */
+    this.shim = null;
+    
+    if(!existingProxy){
+        /** @private */
+        this.proxy = Roo.SplitBar.createProxy(this.orientation);
+    }else{
+        this.proxy = Roo.get(existingProxy).dom;
+    }
+    /** @private */
+    this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
+    
+    /** @private */
+    this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
+    
+    /** @private */
+    this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
+    
+    /** @private */
+    this.dragSpecs = {};
+    
     /**
-     * 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
+     * @private The adapter to use to positon and resize elements
      */
-    clearFilter : function(suppressEvent){
-        if(this.snapshot && this.snapshot != this.data){
-            this.data = this.snapshot;
-            delete this.snapshot;
-            if(suppressEvent !== true){
-                this.fireEvent("datachanged", this);
-            }
+    this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
+    this.adapter.init(this);
+    
+    if(this.orientation == Roo.SplitBar.HORIZONTAL){
+        /** @private */
+        this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
+        this.el.addClass("x-splitbar-h");
+    }else{
+        /** @private */
+        this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
+        this.el.addClass("x-splitbar-v");
+    }
+    
+    this.addEvents({
+        /**
+         * @event resize
+         * Fires when the splitter is moved (alias for {@link #event-moved})
+         * @param {Roo.SplitBar} this
+         * @param {Number} newSize the new width or height
+         */
+        "resize" : true,
+        /**
+         * @event moved
+         * Fires when the splitter is moved
+         * @param {Roo.SplitBar} this
+         * @param {Number} newSize the new width or height
+         */
+        "moved" : true,
+        /**
+         * @event beforeresize
+         * Fires before the splitter is dragged
+         * @param {Roo.SplitBar} this
+         */
+        "beforeresize" : true,
+
+        "beforeapply" : true
+    });
+
+    Roo.util.Observable.call(this);
+};
+
+Roo.extend(Roo.SplitBar, Roo.util.Observable, {
+    onStartProxyDrag : function(x, y){
+        this.fireEvent("beforeresize", this);
+        if(!this.overlay){
+            var o = Roo.DomHelper.insertFirst(document.body,  {cls: "x-drag-overlay", html: "&#160;"}, true);
+            o.unselectable();
+            o.enableDisplayMode("block");
+            // all splitbars share the same overlay
+            Roo.SplitBar.prototype.overlay = o;
         }
+        this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
+        this.overlay.show();
+        Roo.get(this.proxy).setDisplayed("block");
+        var size = this.adapter.getElementSize(this);
+        this.activeMinSize = this.getMinimumSize();;
+        this.activeMaxSize = this.getMaximumSize();;
+        var c1 = size - this.activeMinSize;
+        var c2 = Math.max(this.activeMaxSize - size, 0);
+        if(this.orientation == Roo.SplitBar.HORIZONTAL){
+            this.dd.resetConstraints();
+            this.dd.setXConstraint(
+                this.placement == Roo.SplitBar.LEFT ? c1 : c2, 
+                this.placement == Roo.SplitBar.LEFT ? c2 : c1
+            );
+            this.dd.setYConstraint(0, 0);
+        }else{
+            this.dd.resetConstraints();
+            this.dd.setXConstraint(0, 0);
+            this.dd.setYConstraint(
+                this.placement == Roo.SplitBar.TOP ? c1 : c2, 
+                this.placement == Roo.SplitBar.TOP ? c2 : c1
+            );
+         }
+        this.dragSpecs.startSize = size;
+        this.dragSpecs.startPoint = [x, y];
+        Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
     },
-
-    // private
-    afterEdit : function(record){
-        if(this.modified.indexOf(record) == -1){
-            this.modified.push(record);
+    
+    /** 
+     * @private Called after the drag operation by the DDProxy
+     */
+    onEndProxyDrag : function(e){
+        Roo.get(this.proxy).setDisplayed(false);
+        var endPoint = Roo.lib.Event.getXY(e);
+        if(this.overlay){
+            this.overlay.hide();
+        }
+        var newSize;
+        if(this.orientation == Roo.SplitBar.HORIZONTAL){
+            newSize = this.dragSpecs.startSize + 
+                (this.placement == Roo.SplitBar.LEFT ?
+                    endPoint[0] - this.dragSpecs.startPoint[0] :
+                    this.dragSpecs.startPoint[0] - endPoint[0]
+                );
+        }else{
+            newSize = this.dragSpecs.startSize + 
+                (this.placement == Roo.SplitBar.TOP ?
+                    endPoint[1] - this.dragSpecs.startPoint[1] :
+                    this.dragSpecs.startPoint[1] - endPoint[1]
+                );
+        }
+        newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
+        if(newSize != this.dragSpecs.startSize){
+            if(this.fireEvent('beforeapply', this, newSize) !== false){
+                this.adapter.setElementSize(this, newSize);
+                this.fireEvent("moved", this, newSize);
+                this.fireEvent("resize", this, newSize);
+            }
         }
-        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);
+    /**
+     * Get the adapter this SplitBar uses
+     * @return The adapter object
+     */
+    getAdapter : function(){
+        return this.adapter;
     },
-
-    // private
-    afterCommit : function(record){
-        this.modified.remove(record);
-        this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
+    
+    /**
+     * Set the adapter this SplitBar uses
+     * @param {Object} adapter A SplitBar adapter object
+     */
+    setAdapter : function(adapter){
+        this.adapter = adapter;
+        this.adapter.init(this);
     },
-
+    
     /**
-     * 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.
+     * Gets the minimum size for the resizing element
+     * @return {Number} The minimum size
      */
-    commitChanges : function(){
-        var m = this.modified.slice(0);
-        this.modified = [];
-        for(var i = 0, len = m.length; i < len; i++){
-            m[i].commit();
-        }
+    getMinimumSize : function(){
+        return this.minSize;
     },
-
+    
     /**
-     * Cancel outstanding changes on all changed records.
+     * Sets the minimum size for the resizing element
+     * @param {Number} minSize The minimum size
      */
-    rejectChanges : function(){
-        var m = this.modified.slice(0);
-        this.modified = [];
-        for(var i = 0, len = m.length; i < len; i++){
-            m[i].reject();
-        }
+    setMinimumSize : function(minSize){
+        this.minSize = minSize;
     },
-
-    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);
+    
+    /**
+     * Gets the maximum size for the resizing element
+     * @return {Number} The maximum size
+     */
+    getMaximumSize : function(){
+        return this.maxSize;
+    },
+    
+    /**
+     * Sets the maximum size for the resizing element
+     * @param {Number} maxSize The maximum size
+     */
+    setMaximumSize : function(maxSize){
+        this.maxSize = maxSize;
+    },
+    
+    /**
+     * Sets the initialize size for the resizing element
+     * @param {Number} size The initial size
+     */
+    setCurrentSize : function(size){
+        var oldAnimate = this.animate;
+        this.animate = false;
+        this.adapter.setElementSize(this, size);
+        this.animate = oldAnimate;
+    },
+    
+    /**
+     * Destroy this splitbar. 
+     * @param {Boolean} removeEl True to remove the element
+     */
+    destroy : function(removeEl){
+        if(this.shim){
+            this.shim.remove();
+        }
+        this.dd.unreg();
+        this.proxy.parentNode.removeChild(this.proxy);
+        if(removeEl){
+            this.el.remove();
+        }
     }
-});/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
+});
 
 /**
- * @class Roo.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
- * @param {Object} config
+ * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
  */
-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.SplitBar.createProxy = function(dir){
+    var proxy = new Roo.Element(document.createElement("div"));
+    proxy.unselectable();
+    var cls = 'x-splitbar-proxy';
+    proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
+    document.body.appendChild(proxy.dom);
+    return proxy.dom;
 };
-Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
 
-/**
-/**
- * @extends Roo.data.Store
- * @class Roo.data.JsonStore
- * Small helper class to make creating Stores for JSON data easier. <br/>
-<pre><code>
-var store = new Roo.data.JsonStore({
-    url: 'get-images.php',
-    root: 'images',
-    fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
-});
-</code></pre>
- * <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
+/** 
+ * @class Roo.SplitBar.BasicLayoutAdapter
+ * Default Adapter. It assumes the splitter and resizing element are not positioned
+ * elements and only gets/sets the width of the element. Generally used for table based layouts.
  */
-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.SplitBar.BasicLayoutAdapter = function(){
 };
-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";
-    }
+Roo.SplitBar.BasicLayoutAdapter.prototype = {
+    // do nothing for now
+    init : function(s){
     
-    var st = Roo.data.SortTypes;
-    // named sortTypes are supported, here we look them up
-    if(typeof this.sortType == "string"){
-        this.sortType = st[this.sortType];
-    }
+    },
+    /**
+     * Called before drag operations to get the current size of the resizing element. 
+     * @param {Roo.SplitBar} s The SplitBar using this adapter
+     */
+     getElementSize : function(s){
+        if(s.orientation == Roo.SplitBar.HORIZONTAL){
+            return s.resizingEl.getWidth();
+        }else{
+            return s.resizingEl.getHeight();
+        }
+    },
     
-    // 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;
+    /**
+     * Called after drag operations to set the size of the resizing element.
+     * @param {Roo.SplitBar} s The SplitBar using this adapter
+     * @param {Number} newSize The new size to set
+     * @param {Function} onComplete A function to be invoked when resizing is complete
+     */
+    setElementSize : function(s, newSize, onComplete){
+        if(s.orientation == Roo.SplitBar.HORIZONTAL){
+            if(!s.animate){
+                s.resizingEl.setWidth(newSize);
+                if(onComplete){
+                    onComplete(s, newSize);
+                }
+            }else{
+                s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
+            }
+        }else{
+            
+            if(!s.animate){
+                s.resizingEl.setHeight(newSize);
+                if(onComplete){
+                    onComplete(s, newSize);
+                }
+            }else{
+                s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
+            }
         }
     }
+};
 
-    // define once
-    var stripRe = /[\$,%]/g;
+/** 
+ *@class Roo.SplitBar.AbsoluteLayoutAdapter
+ * @extends Roo.SplitBar.BasicLayoutAdapter
+ * Adapter that  moves the splitter element to align with the resized sizing element. 
+ * Used with an absolute positioned SplitBar.
+ * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
+ * document.body, make sure you assign an id to the body element.
+ */
+Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
+    this.basic = new Roo.SplitBar.BasicLayoutAdapter();
+    this.container = Roo.get(container);
+};
 
-    // 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); };
+Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
+    init : function(s){
+        this.basic.init(s);
+    },
+    
+    getElementSize : function(s){
+        return this.basic.getElementSize(s);
+    },
+    
+    setElementSize : function(s, newSize, onComplete){
+        this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
+    },
+    
+    moveSplitter : function(s){
+        var yes = Roo.SplitBar;
+        switch(s.placement){
+            case yes.LEFT:
+                s.el.setX(s.resizingEl.getRight());
                 break;
-            case "int":
-                cv = function(v){
-                    return v !== undefined && v !== null && v !== '' ?
-                           parseInt(String(v).replace(stripRe, ""), 10) : '';
-                    };
+            case yes.RIGHT:
+                s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
                 break;
-            case "float":
-                cv = function(v){
-                    return v !== undefined && v !== null && v !== '' ?
-                           parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
-                    };
+            case yes.TOP:
+                s.el.setY(s.resizingEl.getBottom());
                 break;
-            case "bool":
-            case "boolean":
-                cv = function(v){ return v === true || v === "true" || v == 1; };
+            case yes.BOTTOM:
+                s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
                 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.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
+/**
+ * Orientation constant - Create a vertical SplitBar
+ * @static
+ * @type Number
  */
-// 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.
+Roo.SplitBar.VERTICAL = 1;
 
 /**
- * @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.
+ * Orientation constant - Create a horizontal SplitBar
+ * @static
+ * @type Number
  */
+Roo.SplitBar.HORIZONTAL = 2;
 
-Roo.data.DataReader = function(meta, recordType){
-    
-    this.meta = meta;
-    
-    this.recordType = recordType instanceof Array ? 
-        Roo.data.Record.create(recordType) : recordType;
-};
+/**
+ * Placement constant - The resizing element is to the left of the splitter element
+ * @static
+ * @type Number
+ */
+Roo.SplitBar.LEFT = 1;
 
-Roo.data.DataReader.prototype = {
-     /**
-     * Create an empty record
-     * @param {Object} data (optional) - overlay some values
-     * @return {Roo.data.Record} record created.
-     */
-    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;
-            }
-            
-        });
-        return new this.recordType(Roo.apply(da, d));
-    }
-    
-};/*
+/**
+ * Placement constant - The resizing element is to the right of the splitter element
+ * @static
+ * @type Number
+ */
+Roo.SplitBar.RIGHT = 2;
+
+/**
+ * Placement constant - The resizing element is positioned above the splitter element
+ * @static
+ * @type Number
+ */
+Roo.SplitBar.TOP = 3;
+
+/**
+ * Placement constant - The resizing element is positioned under splitter element
+ * @static
+ * @type Number
+ */
+Roo.SplitBar.BOTTOM = 4;
+/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -5653,463 +4081,691 @@ Roo.data.DataReader.prototype = {
  */
 
 /**
- * @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}.
+ * @class Roo.View
+ * @extends Roo.util.Observable
+ * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
+ * This class also supports single and multi selection modes. <br>
+ * Create a data model bound view:
+ <pre><code>
+ var store = new Roo.data.Store(...);
+
+ var view = new Roo.View({
+    el : "my-element",
+    tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
+    singleSelect: true,
+    selectedClass: "ydataview-selected",
+    store: store
+ });
+
+ // listen for node click?
+ view.on("click", function(vw, index, node, e){
+ alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
+ });
+
+ // load XML data
+ dataModel.load("foobar.xml");
+ </code></pre>
+ For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
+ * <br><br>
+ * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
+ * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
+ * 
+ * Note: old style constructor is still suported (container, template, config)
+ * 
+ * @constructor
+ * Create a new View
+ * @param {Object} config The config object
+ * 
  */
-Roo.data.DataProxy = function(){
+Roo.View = function(config, depreciated_tpl, depreciated_config){
+    
+    this.parent = false;
+    
+    if (typeof(depreciated_tpl) == 'undefined') {
+        // new way.. - universal constructor.
+        Roo.apply(this, config);
+        this.el  = Roo.get(this.el);
+    } else {
+        // old format..
+        this.el  = Roo.get(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);
+    } else {
+        // support xtype ctors..
+        this.tpl = new Roo.factory(this.tpl, Roo);
+    }
+    
+    
+    this.tpl.compile();
+    
+    /** @private */
     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.
+         * @event beforeclick
+         * Fires before a click is processed. Returns false to cancel the default action.
+         * @param {Roo.View} this
+         * @param {Number} index The index of the target node
+         * @param {HTMLElement} node The target node
+         * @param {Roo.EventObject} e The raw event object
          */
-        beforeload : true,
+            "beforeclick" : 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.
+         * @event click
+         * Fires when a template node is clicked.
+         * @param {Roo.View} this
+         * @param {Number} index The index of the target node
+         * @param {HTMLElement} node The target node
+         * @param {Roo.EventObject} e The raw event object
          */
-        load : true,
+            "click" : 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.
+         * @event dblclick
+         * Fires when a template node is double clicked.
+         * @param {Roo.View} this
+         * @param {Number} index The index of the target node
+         * @param {HTMLElement} node The target node
+         * @param {Roo.EventObject} e The raw event object
          */
-        loadexception : true
-    });
-    Roo.data.DataProxy.superclass.constructor.call(this);
-};
+            "dblclick" : true,
+        /**
+         * @event contextmenu
+         * Fires when a template node is right clicked.
+         * @param {Roo.View} this
+         * @param {Number} index The index of the target node
+         * @param {HTMLElement} node The target node
+         * @param {Roo.EventObject} e The raw event object
+         */
+            "contextmenu" : true,
+        /**
+         * @event selectionchange
+         * Fires when the selected nodes change.
+         * @param {Roo.View} this
+         * @param {Array} selections Array of the selected nodes
+         */
+            "selectionchange" : true,
+    
+        /**
+         * @event beforeselect
+         * Fires before a selection is made. If any handlers return false, the selection is cancelled.
+         * @param {Roo.View} this
+         * @param {HTMLElement} node The node to be selected
+         * @param {Array} selections Array of currently selected nodes
+         */
+            "beforeselect" : true,
+        /**
+         * @event preparedata
+         * Fires on every row to render, to allow you to change the data.
+         * @param {Roo.View} this
+         * @param {Object} data to be rendered (change this)
+         */
+          "preparedata" : true
+          
+          
+        });
 
-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.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;
-        }
-        callback.call(scope, result, arg, true);
-    },
+    this.el.on({
+        "click": this.onClick,
+        "dblclick": this.onDblClick,
+        "contextmenu": this.onContextMenu,
+        scope:this
+    });
+
+    this.selections = [];
+    this.nodes = [];
+    this.cmp = new Roo.CompositeElementLite([]);
+    if(this.store){
+        this.store = Roo.factory(this.store, Roo.data);
+        this.setStore(this.store, true);
+    }
     
-    // private
-    update : function(params, records){
+    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?
     }
-});/*
- * 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.View.superclass.constructor.call(this);
+    
+    
 };
 
-Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
-    // thse are take from connection...
+Roo.extend(Roo.View, Roo.util.Observable, {
     
-    /**
-     * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
+     /**
+     * @cfg {Roo.data.Store} store Data store to load data from.
      */
+    store : false,
+    
     /**
-     * @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 {String|Roo.Element} el The container element.
      */
+    el : '',
+    
     /**
-     * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
-     *  to each request made by this object. (defaults to undefined)
+     * @cfg {String|Roo.Template} tpl The template used by this View 
      */
+    tpl : false,
     /**
-     * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
+     * @cfg {String} dataName the named area of the template to use as the data area
+     *                          Works with domtemplates roo-name="name"
      */
+    dataName: false,
     /**
-     * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
+     * @cfg {String} selectedClass The css class to add to selected nodes
      */
+    selectedClass : "x-view-selected",
      /**
-     * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
-     * @type Boolean
+     * @cfg {String} emptyText The empty text to show when nothing is loaded.
      */
-  
-
+    emptyText : "",
+    
     /**
-     * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
-     * @type Boolean
+     * @cfg {String} text to display on mask (default Loading)
      */
+    mask : false,
     /**
-     * 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.
+     * @cfg {Boolean} multiSelect Allow multiple selection
      */
-    getConnection : function(){
-        return this.useAjax ? Roo.Ajax : this.conn;
-    },
-
+    multiSelect : false,
     /**
-     * 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.
+     * @cfg {Boolean} singleSelect Allow single selection
      */
-    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);
-        }
+    singleSelect:  false,
+    
+    /**
+     * @cfg {Boolean} toggleSelect - selecting 
+     */
+    toggleSelect : false,
+    
+    /**
+     * @cfg {Boolean} tickable - selecting 
+     */
+    tickable : false,
+    
+    /**
+     * Returns the element this view is bound to.
+     * @return {Roo.Element}
+     */
+    getEl : function(){
+        return this.wrapEl;
     },
+    
+    
 
-    // 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);
+    /**
+     * Refreshes the view. - called by datachanged on the store. - do not call directly.
+     */
+    refresh : function(){
+        //Roo.log('refresh');
+        var t = this.tpl;
+        
+        // if we are using something like 'domtemplate', then
+        // the what gets used is:
+        // t.applySubtemplate(NAME, data, wrapping data..)
+        // the outer template then get' applied with
+        //     the store 'extra data'
+        // and the body get's added to the
+        //      roo-name="data" node?
+        //      <span class='roo-tpl-{name}'></span> ?????
+        
+        
+        
+        this.clearSelections();
+        this.el.update("");
+        var html = [];
+        var records = this.store.getRange();
+        if(records.length < 1) {
+            
+            // is this valid??  = should it render a template??
+            
+            this.el.update(this.emptyText);
             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;
+        var el = this.el;
+        if (this.dataName) {
+            this.el.update(t.apply(this.store.meta)); //????
+            el = this.el.child('.roo-tpl-' + this.dataName);
         }
         
-        this.fireEvent("load", this, o, o.request.arg);
-        o.request.callback.call(o.request.scope, result, o.request.arg, true);
-    },
-
-    // private
-    update : function(dataSet){
-
+        for(var i = 0, len = records.length; i < len; i++){
+            var data = this.prepareData(records[i].data, i, records[i]);
+            this.fireEvent("preparedata", this, data, i, records[i]);
+            
+            var d = Roo.apply({}, data);
+            
+            if(this.tickable){
+                Roo.apply(d, {'roo-id' : Roo.id()});
+                
+                var _this = this;
+            
+                Roo.each(this.parent.item, function(item){
+                    if(item[_this.parent.valueField] != data[_this.parent.valueField]){
+                        return;
+                    }
+                    Roo.apply(d, {'roo-data-checked' : 'checked'});
+                });
+            }
+            
+            html[html.length] = Roo.util.Format.trim(
+                this.dataName ?
+                    t.applySubtemplate(this.dataName, d, this.store.meta) :
+                    t.apply(d)
+            );
+        }
+        
+        
+        
+        el.update(html.join(""));
+        this.nodes = el.dom.childNodes;
+        this.updateIndexes(0);
     },
+    
 
-    // 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">
- */
+    /**
+     * Function to override to reformat the data that is sent to
+     * the template for each node.
+     * DEPRICATED - use the preparedata event handler.
+     * @param {Array/Object} data The raw data (array of colData for a data model bound view or
+     * a JSON object for an UpdateManager bound view).
+     */
+    prepareData : function(data, index, record)
+    {
+        this.fireEvent("preparedata", this, data, index, record);
+        return data;
+    },
 
-/**
- * @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];
-};
+    onUpdate : function(ds, record){
+        // Roo.log('on update');   
+        this.clearSelections();
+        var index = this.store.indexOf(record);
+        var n = this.nodes[index];
+        this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
+        n.parentNode.removeChild(n);
+        this.updateIndexes(index, index);
+    },
 
-Roo.data.ScriptTagProxy.TRANS_ID = 1000;
+    
+    
+// --------- FIXME     
+    onAdd : function(ds, records, index)
+    {
+        //Roo.log(['on Add', ds, records, index] );        
+        this.clearSelections();
+        if(this.nodes.length == 0){
+            this.refresh();
+            return;
+        }
+        var n = this.nodes[index];
+        for(var i = 0, len = records.length; i < len; i++){
+            var d = this.prepareData(records[i].data, i, records[i]);
+            if(n){
+                this.tpl.insertBefore(n, d);
+            }else{
+                
+                this.tpl.append(this.el, d);
+            }
+        }
+        this.updateIndexes(index);
+    },
+
+    onRemove : function(ds, record, index){
+       // Roo.log('onRemove');
+        this.clearSelections();
+        var el = this.dataName  ?
+            this.el.child('.roo-tpl-' + this.dataName) :
+            this.el; 
+        
+        el.dom.removeChild(this.nodes[index]);
+        this.updateIndexes(index);
+    },
 
-Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
-    /**
-     * @cfg {String} url The URL from which to request the data object.
-     */
     /**
-     * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
+     * Refresh an individual node.
+     * @param {Number} index
      */
-    timeout : 30000,
+    refreshNode : function(index){
+        this.onUpdate(this.store, this.store.getAt(index));
+    },
+
+    updateIndexes : function(startIndex, endIndex){
+        var ns = this.nodes;
+        startIndex = startIndex || 0;
+        endIndex = endIndex || ns.length - 1;
+        for(var i = startIndex; i <= endIndex; i++){
+            ns[i].nodeIndex = i;
+        }
+    },
+
     /**
-     * @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.
+     * Changes the data store this view uses and refresh the view.
+     * @param {Store} store
      */
-    callbackParam : "callback",
+    setStore : function(store, initial){
+        if(!initial && this.store){
+            this.store.un("datachanged", this.refresh);
+            this.store.un("add", this.onAdd);
+            this.store.un("remove", this.onRemove);
+            this.store.un("update", this.onUpdate);
+            this.store.un("clear", this.refresh);
+            this.store.un("beforeload", this.onBeforeLoad);
+            this.store.un("load", this.onLoad);
+            this.store.un("loadexception", this.onLoad);
+        }
+        if(store){
+          
+            store.on("datachanged", this.refresh, this);
+            store.on("add", this.onAdd, this);
+            store.on("remove", this.onRemove, this);
+            store.on("update", this.onUpdate, this);
+            store.on("clear", this.refresh, this);
+            store.on("beforeload", this.onBeforeLoad, this);
+            store.on("load", this.onLoad, this);
+            store.on("loadexception", this.onLoad, this);
+        }
+        
+        if(store){
+            this.refresh();
+        }
+    },
     /**
-     *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
-     * name to the request.
+     * onbeforeLoad - masks the loading area.
+     *
      */
-    nocache : true,
+    onBeforeLoad : function(store,opts)
+    {
+         //Roo.log('onBeforeLoad');   
+        if (!opts.add) {
+            this.el.update("");
+        }
+        this.el.mask(this.mask ? this.mask : "Loading" ); 
+    },
+    onLoad : function ()
+    {
+        this.el.unmask();
+    },
+    
 
     /**
-     * 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 the template node the passed child belongs to or null if it doesn't belong to one.
+     * @param {HTMLElement} node
+     * @return {HTMLElement} The template node
      */
-    load : function(params, reader, callback, scope, arg){
-        if(this.fireEvent("beforeload", this, params) !== false){
-
-            var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
+    findItemFromChild : function(node){
+        var el = this.dataName  ?
+            this.el.child('.roo-tpl-' + this.dataName,true) :
+            this.el.dom; 
+        
+        if(!node || node.parentNode == el){
+                   return node;
+           }
+           var p = node.parentNode;
+           while(p && p != el){
+            if(p.parentNode == el){
+               return p;
+            }
+            p = p.parentNode;
+        }
+           return null;
+    },
 
-            var url = this.url;
-            url += (url.indexOf("?") != -1 ? "&" : "?") + p;
-            if(this.nocache){
-                url += "&_dc=" + (new Date().getTime());
+    /** @ignore */
+    onClick : function(e){
+        var item = this.findItemFromChild(e.getTarget());
+        if(item){
+            var index = this.indexOf(item);
+            if(this.onItemClick(item, index, e) !== false){
+                this.fireEvent("click", this, index, item, e);
             }
-            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;
+        }else{
+            this.clearSelections();
+        }
+    },
 
-            window[trans.cb] = function(o){
-                conn.handleResponse(o, trans);
-            };
+    /** @ignore */
+    onContextMenu : function(e){
+        var item = this.findItemFromChild(e.getTarget());
+        if(item){
+            this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
+        }
+    },
 
-            url += String.format("&{0}={1}", this.callbackParam, trans.cb);
+    /** @ignore */
+    onDblClick : function(e){
+        var item = this.findItemFromChild(e.getTarget());
+        if(item){
+            this.fireEvent("dblclick", this, this.indexOf(item), item, e);
+        }
+    },
 
-            if(this.autoAbort !== false){
-                this.abort();
+    onItemClick : function(item, index, e)
+    {
+        if(this.fireEvent("beforeclick", this, index, item, e) === false){
+            return false;
+        }
+        if (this.toggleSelect) {
+            var m = this.isSelected(item) ? 'unselect' : 'select';
+            //Roo.log(m);
+            var _t = this;
+            _t[m](item, true, false);
+            return true;
+        }
+        if(this.multiSelect || this.singleSelect){
+            if(this.multiSelect && e.shiftKey && this.lastSelection){
+                this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
+            }else{
+                this.select(item, this.multiSelect && e.ctrlKey);
+                this.lastSelection = item;
             }
+            
+            if(!this.tickable){
+                e.preventDefault();
+            }
+            
+        }
+        return true;
+    },
 
-            trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
+    /**
+     * Get the number of selected nodes.
+     * @return {Number}
+     */
+    getSelectionCount : function(){
+        return this.selections.length;
+    },
 
-            var script = document.createElement("script");
-            script.setAttribute("src", url);
-            script.setAttribute("type", "text/javascript");
-            script.setAttribute("id", trans.scriptId);
-            this.head.appendChild(script);
+    /**
+     * Get the currently selected nodes.
+     * @return {Array} An array of HTMLElements
+     */
+    getSelectedNodes : function(){
+        return this.selections;
+    },
 
-            this.trans = trans;
-        }else{
-            callback.call(scope||this, null, arg, false);
+    /**
+     * Get the indexes of the selected nodes.
+     * @return {Array}
+     */
+    getSelectedIndexes : function(){
+        var indexes = [], s = this.selections;
+        for(var i = 0, len = s.length; i < len; i++){
+            indexes.push(s[i].nodeIndex);
         }
+        return indexes;
     },
 
-    // private
-    isLoading : function(){
-        return this.trans ? true : false;
+    /**
+     * Clear all selections
+     * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
+     */
+    clearSelections : function(suppressEvent){
+        if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
+            this.cmp.elements = this.selections;
+            this.cmp.removeClass(this.selectedClass);
+            this.selections = [];
+            if(!suppressEvent){
+                this.fireEvent("selectionchange", this, this.selections);
+            }
+        }
     },
 
     /**
-     * Abort the current server request.
+     * Returns true if the passed node is selected
+     * @param {HTMLElement/Number} node The node or node index
+     * @return {Boolean}
      */
-    abort : function(){
-        if(this.isLoading()){
-            this.destroyTrans(this.trans);
+    isSelected : function(node){
+        var s = this.selections;
+        if(s.length < 1){
+            return false;
         }
+        node = this.getNode(node);
+        return s.indexOf(node) !== -1;
     },
 
-    // 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){}
-            };
+    /**
+     * Selects nodes.
+     * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
+     * @param {Boolean} keepExisting (optional) true to keep existing selections
+     * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
+     */
+    select : function(nodeInfo, keepExisting, suppressEvent){
+        if(nodeInfo instanceof Array){
+            if(!keepExisting){
+                this.clearSelections(true);
+            }
+            for(var i = 0, len = nodeInfo.length; i < len; i++){
+                this.select(nodeInfo[i], true, true);
+            }
+            return;
+        } 
+        var node = this.getNode(nodeInfo);
+        if(!node || this.isSelected(node)){
+            return; // already selected.
         }
+        if(!keepExisting){
+            this.clearSelections(true);
+        }
+        
+        if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
+            Roo.fly(node).addClass(this.selectedClass);
+            this.selections.push(node);
+            if(!suppressEvent){
+                this.fireEvent("selectionchange", this, this.selections);
+            }
+        }
+        
+        
     },
-
-    // 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);
+      /**
+     * Unselects nodes.
+     * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
+     * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
+     * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
+     */
+    unselect : function(nodeInfo, keepExisting, suppressEvent)
+    {
+        if(nodeInfo instanceof Array){
+            Roo.each(this.selections, function(s) {
+                this.unselect(s, nodeInfo);
+            }, this);
             return;
         }
-        this.fireEvent("load", this, o, trans.arg);
-        trans.callback.call(trans.scope||window, result, trans.arg, true);
+        var node = this.getNode(nodeInfo);
+        if(!node || !this.isSelected(node)){
+            //Roo.log("not selected");
+            return; // not selected.
+        }
+        // fireevent???
+        var ns = [];
+        Roo.each(this.selections, function(s) {
+            if (s == node ) {
+                Roo.fly(node).removeClass(this.selectedClass);
+
+                return;
+            }
+            ns.push(s);
+        },this);
+        
+        this.selections= ns;
+        this.fireEvent("selectionchange", this, this.selections);
     },
 
-    // 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);
+    /**
+     * Gets a template node.
+     * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
+     * @return {HTMLElement} The node or null if it wasn't found
+     */
+    getNode : function(nodeInfo){
+        if(typeof nodeInfo == "string"){
+            return document.getElementById(nodeInfo);
+        }else if(typeof nodeInfo == "number"){
+            return this.nodes[nodeInfo];
+        }
+        return nodeInfo;
+    },
+
+    /**
+     * Gets a range template nodes.
+     * @param {Number} startIndex
+     * @param {Number} endIndex
+     * @return {Array} An array of nodes
+     */
+    getNodes : function(start, end){
+        var ns = this.nodes;
+        start = start || 0;
+        end = typeof end == "undefined" ? ns.length - 1 : end;
+        var nodes = [];
+        if(start <= end){
+            for(var i = start; i <= end; i++){
+                nodes.push(ns[i]);
+            }
+        } else{
+            for(var i = start; i >= end; i--){
+                nodes.push(ns[i]);
+            }
+        }
+        return nodes;
+    },
+
+    /**
+     * Finds the index of the passed node
+     * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
+     * @return {Number} The index of the node or -1
+     */
+    indexOf : function(node){
+        node = this.getNode(node);
+        if(typeof node.nodeIndex == "number"){
+            return node.nodeIndex;
+        }
+        var ns = this.nodes;
+        for(var i = 0, len = ns.length; i < len; i++){
+            if(ns[i] == node){
+                return i;
+            }
+        }
+        return -1;
     }
-});/*
+});
+/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -6121,203 +4777,310 @@ Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
  */
 
 /**
- * @class Roo.data.JsonReader
- * @extends Roo.data.DataReader
- * Data reader class to create an Array of Roo.data.Record objects from a JSON response
- * based on mappings in a provided Roo.data.Record constructor.
- * 
- * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
- * in the reply previously. 
- * 
- * <p>
- * Example code:
- * <pre><code>
-var RecordDef = Roo.data.Record.create([
-    {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
-    {name: 'occupation'}                 // This field will use "occupation" as the mapping.
-]);
-var myReader = new Roo.data.JsonReader({
-    totalProperty: "results",    // The property which contains the total dataset size (optional)
-    root: "rows",                // The property which contains an Array of row objects
-    id: "id"                     // The property within each row object that provides an ID for the record (optional)
-}, RecordDef);
-</code></pre>
- * <p>
- * This would consume a JSON file like this:
- * <pre><code>
-{ 'results': 2, 'rows': [
-    { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
-    { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
-}
+ * @class Roo.JsonView
+ * @extends Roo.View
+ * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
+<pre><code>
+var view = new Roo.JsonView({
+    container: "my-element",
+    tpl: '&lt;div id="{id}"&gt;{foo} - {bar}&lt;/div&gt;', // auto create template
+    multiSelect: true, 
+    jsonRoot: "data" 
+});
+
+// listen for node click?
+view.on("click", function(vw, index, node, e){
+    alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
+});
+
+// direct load of JSON data
+view.load("foobar.php");
+
+// Example from my blog list
+var tpl = new Roo.Template(
+    '&lt;div class="entry"&gt;' +
+    '&lt;a class="entry-title" href="{link}"&gt;{title}&lt;/a&gt;' +
+    "&lt;h4&gt;{date} by {author} | {comments} Comments&lt;/h4&gt;{description}" +
+    "&lt;/div&gt;&lt;hr /&gt;"
+);
+
+var moreView = new Roo.JsonView({
+    container :  "entry-list", 
+    template : tpl,
+    jsonRoot: "posts"
+});
+moreView.on("beforerender", this.sortEntries, this);
+moreView.load({
+    url: "/blog/get-posts.php",
+    params: "allposts=true",
+    text: "Loading Blog Entries..."
+});
 </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.
+* 
+* Note: old code is supported with arguments : (container, template, config)
+* 
+* 
  * @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}.
+ * Create a new JsonView
+ * 
+ * @param {Object} config The config object
+ * 
  */
-Roo.data.JsonReader = function(meta, recordType){
+Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
     
-    meta = meta || {};
-    // set some defaults:
-    Roo.applyIf(meta, {
-        totalProperty: 'total',
-        successProperty : 'success',
-        root : 'data',
-        id : 'id'
-    });
     
-    Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
+    Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
+
+    var um = this.el.getUpdateManager();
+    um.setRenderer(this);
+    um.on("update", this.onLoad, this);
+    um.on("failure", this.onLoadException, this);
+
+    /**
+     * @event beforerender
+     * Fires before rendering of the downloaded JSON data.
+     * @param {Roo.JsonView} this
+     * @param {Object} data The JSON data loaded
+     */
+    /**
+     * @event load
+     * Fires when data is loaded.
+     * @param {Roo.JsonView} this
+     * @param {Object} data The JSON data loaded
+     * @param {Object} response The raw Connect response object
+     */
+    /**
+     * @event loadexception
+     * Fires when loading fails.
+     * @param {Roo.JsonView} this
+     * @param {Object} response The raw Connect response object
+     */
+    this.addEvents({
+        'beforerender' : true,
+        'load' : true,
+        'loadexception' : true
+    });
 };
-Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
-    
+Roo.extend(Roo.JsonView, Roo.View, {
     /**
-     * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
-     * Used by Store query builder to append _requestMeta to params.
-     * 
+     * @type {String} The root property in the loaded JSON object that contains the data
      */
-    metaFromRemote : false,
+    jsonRoot : "",
+
     /**
-     * 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.
+     * Refreshes the view.
      */
-    read : function(response){
-        var json = response.responseText;
-       
-        var o = /* eval:var:o */ eval("("+json+")");
-        if(!o) {
-            throw {message: "JsonReader.read: Json object not found"};
+    refresh : function(){
+        this.clearSelections();
+        this.el.update("");
+        var html = [];
+        var o = this.jsonData;
+        if(o && o.length > 0){
+            for(var i = 0, len = o.length; i < len; i++){
+                var data = this.prepareData(o[i], i, o);
+                html[html.length] = this.tpl.apply(data);
+            }
+        }else{
+            html.push(this.emptyText);
         }
+        this.el.update(html.join(""));
+        this.nodes = this.el.dom.childNodes;
+        this.updateIndexes(0);
+    },
+
+    /**
+     * Performs an async HTTP request, and loads the JSON from the response. If <i>params</i> are specified it uses POST, otherwise it uses GET.
+     * @param {Object/String/Function} url The URL for this request, or a function to call to get the URL, or a config object containing any of the following options:
+     <pre><code>
+     view.load({
+         url: "your-url.php",
+         params: {param1: "foo", param2: "bar"}, // or a URL encoded string
+         callback: yourFunction,
+         scope: yourObject, //(optional scope)
+         discardUrl: false,
+         nocache: false,
+         text: "Loading...",
+         timeout: 30,
+         scripts: false
+     });
+     </code></pre>
+     * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
+     * are respectively shorthand for <i>disableCaching</i>, <i>indicatorText</i>, and <i>loadScripts</i> and are used to set their associated property on this UpdateManager instance.
+     * @param {String/Object} params (optional) The parameters to pass, as either a URL encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
+     * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
+     * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used URL. If true, it will not store the URL.
+     */
+    load : function(){
+        var um = this.el.getUpdateManager();
+        um.update.apply(um, arguments);
+    },
+
+    // note - render is a standard framework call...
+    // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
+    render : function(el, response){
         
-        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);
+        this.clearSelections();
+        this.el.update("");
+        var o;
+        try{
+            if (response != '') {
+                o = Roo.util.JSON.decode(response.responseText);
+                if(this.jsonRoot){
+                    
+                    o = o[this.jsonRoot];
+                }
+            }
+        } catch(e){
         }
-        return this.readRecords(o);
+        /**
+         * The current JSON data or null
+         */
+        this.jsonData = o;
+        this.beforeRender();
+        this.refresh();
     },
 
-    // private function a store will implement
-    onMetaChange : function(meta, recordType, o){
+/**
+ * Get the number of records in the current JSON dataset
+ * @return {Number}
+ */
+    getCount : function(){
+        return this.jsonData ? this.jsonData.length : 0;
+    },
 
+/**
+ * Returns the JSON object for the specified node(s)
+ * @param {HTMLElement/Array} node The node or an array of nodes
+ * @return {Object/Array} If you pass in an array, you get an array back, otherwise
+ * you get the JSON object for the node
+ */
+    getNodeData : function(node){
+        if(node instanceof Array){
+            var data = [];
+            for(var i = 0, len = node.length; i < len; i++){
+                data.push(this.getNodeData(node[i]));
+            }
+            return data;
+        }
+        return this.jsonData[this.indexOf(node)] || null;
     },
 
-    /**
-        * @ignore
-        */
-    simpleAccess: function(obj, subsc) {
-       return obj[subsc];
+    beforeRender : function(){
+        this.snapshot = this.jsonData;
+        if(this.sortInfo){
+            this.sort.apply(this, this.sortInfo);
+        }
+        this.fireEvent("beforerender", this, this.jsonData);
     },
 
-       /**
-        * @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;
-        };
-    }(),
+    onLoad : function(el, o){
+        this.fireEvent("load", this, this.jsonData, o);
+    },
 
-    /**
-     * 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;
+    onLoadException : function(el, o){
+        this.fireEvent("loadexception", this, o);
+    },
 
-//      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);
+/**
+ * Filter the data by a specific property.
+ * @param {String} property A property on your JSON objects
+ * @param {String/RegExp} value Either string that the property values
+ * should start with, or a RegExp to test against the property
+ */
+    filter : function(property, value){
+        if(this.jsonData){
+            var data = [];
+            var ss = this.snapshot;
+            if(typeof value == "string"){
+                var vlen = value.length;
+                if(vlen == 0){
+                    this.clearFilter();
+                    return;
+                }
+                value = value.toLowerCase();
+                for(var i = 0, len = ss.length; i < len; i++){
+                    var o = ss[i];
+                    if(o[property].substr(0, vlen).toLowerCase() == value){
+                        data.push(o);
+                    }
+                }
+            } else if(value.exec){ // regex?
+                for(var i = 0, len = ss.length; i < len; i++){
+                    var o = ss[i];
+                    if(value.test(o[property])){
+                        data.push(o);
+                    }
+                }
+            } else{
+                return;
             }
+            this.jsonData = data;
+            this.refresh();
         }
+    },
 
-       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;
+/**
+ * Filter by a function. The passed function will be called with each
+ * object in the current dataset. If the function returns true the value is kept,
+ * otherwise it is filtered.
+ * @param {Function} fn
+ * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
+ */
+    filterBy : function(fn, scope){
+        if(this.jsonData){
+            var data = [];
+            var ss = this.snapshot;
+            for(var i = 0, len = ss.length; i < len; i++){
+                var o = ss[i];
+                if(fn.call(scope || this, o)){
+                    data.push(o);
+                }
             }
+            this.jsonData = data;
+            this.refresh();
         }
-        if(s.successProperty){
-            var vs = this.getSuccess(o);
-            if(vs === false || vs === 'false'){
-                success = false;
-            }
+    },
+
+/**
+ * Clears the current filter.
+ */
+    clearFilter : function(){
+        if(this.snapshot && this.jsonData != this.snapshot){
+            this.jsonData = this.snapshot;
+            this.refresh();
         }
-        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;
+    },
+
+
+/**
+ * Sorts the data for this view and refreshes it.
+ * @param {String} property A property on your JSON objects to sort on
+ * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
+ * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
+ */
+    sort : function(property, dir, sortType){
+        this.sortInfo = Array.prototype.slice.call(arguments, 0);
+        if(this.jsonData){
+            var p = property;
+            var dsc = dir && dir.toLowerCase() == "desc";
+            var f = function(o1, o2){
+                var v1 = sortType ? sortType(o1[p]) : o1[p];
+                var v2 = sortType ? sortType(o2[p]) : o2[p];
+                ;
+                if(v1 < v2){
+                    return dsc ? +1 : -1;
+                } else if(v1 > v2){
+                    return dsc ? -1 : +1;
+                } else{
+                    return 0;
                 }
-                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
-           };
+            };
+            this.jsonData.sort(f);
+            this.refresh();
+            if(this.jsonData != this.snapshot){
+                this.snapshot.sort(f);
+            }
+        }
     }
 });/*
  * Based on:
@@ -6329,206 +5092,142 @@ Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
  * 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:
+ * @class Roo.ColorPalette
+ * @extends Roo.Component
+ * Simple color palette class for choosing colors.  The palette can be rendered to any container.<br />
+ * Here's an example of typical usage:
  * <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>
+var cp = new Roo.ColorPalette({value:'993300'});  // initial selected color
+cp.render('my-div');
+
+cp.on('select', function(palette, selColor){
+    // do something with selColor
+});
 </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.
+ * Create a new ColorPalette
+ * @param {Object} config The config object
  */
-Roo.data.XmlReader = function(meta, recordType){
-    meta = meta || {};
-    Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
+Roo.ColorPalette = function(config){
+    Roo.ColorPalette.superclass.constructor.call(this, config);
+    this.addEvents({
+        /**
+            * @event select
+            * Fires when a color is selected
+            * @param {ColorPalette} this
+            * @param {String} color The 6-digit color hex code (without the # symbol)
+            */
+        select: true
+    });
+
+    if(this.handler){
+        this.on("select", this.handler, this.scope, true);
+    }
 };
-Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
+Roo.extend(Roo.ColorPalette, Roo.Component, {
     /**
-     * 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.
+     * @cfg {String} itemCls
+     * The CSS class to apply to the containing element (defaults to "x-color-palette")
      */
-    read : function(response){
-        var doc = response.responseXML;
-        if(!doc) {
-            throw {message: "XmlReader.read: XML Document not available"};
-        }
-        return this.readRecords(doc);
-    },
-
+    itemCls : "x-color-palette",
     /**
-     * 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.
+     * @cfg {String} value
+     * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol).  Note that
+     * the hex codes are case-sensitive.
      */
-    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;
-           }
+    value : null,
+    clickEvent:'click',
+    // private
+    ctype: "Roo.ColorPalette",
 
-           return {
-               success : success,
-               records : records,
-               totalRecords : totalRecords || records.length
-           };
-    }
-});/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
+    /**
+     * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
+     */
+    allowReselect : false,
 
-/**
- * @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);
+    /**
+     * <p>An array of 6-digit color hex code strings (without the # symbol).  This array can contain any number
+     * of colors, and each hex code should be unique.  The width of the palette is controlled via CSS by adjusting
+     * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
+     * of colors with the width setting until the box is symmetrical.</p>
+     * <p>You can override individual colors if needed:</p>
+     * <pre><code>
+var cp = new Roo.ColorPalette();
+cp.colors[0] = "FF0000";  // change the first box to red
 </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}.
- */
-Roo.data.ArrayReader = function(meta, recordType){
-    Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
-};
 
-Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
+Or you can provide a custom array of your own for complete control:
+<pre><code>
+var cp = new Roo.ColorPalette();
+cp.colors = ["000000", "993300", "333300"];
+</code></pre>
+     * @type Array
+     */
+    colors : [
+        "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
+        "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
+        "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
+        "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
+        "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
+    ],
+
+    // private
+    onRender : function(container, position){
+        var t = new Roo.MasterTemplate(
+            '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on">&#160;</span></em></a></tpl>'
+        );
+        var c = this.colors;
+        for(var i = 0, len = c.length; i < len; i++){
+            t.add([c[i]]);
+        }
+        var el = document.createElement("div");
+        el.className = this.itemCls;
+        t.overwrite(el);
+        container.dom.insertBefore(el, position);
+        this.el = Roo.get(el);
+        this.el.on(this.clickEvent, this.handleClick,  this, {delegate: "a"});
+        if(this.clickEvent != 'click'){
+            this.el.on('click', Roo.emptyFn,  this, {delegate: "a", preventDefault:true});
+        }
+    },
+
+    // private
+    afterRender : function(){
+        Roo.ColorPalette.superclass.afterRender.call(this);
+        if(this.value){
+            var s = this.value;
+            this.value = null;
+            this.select(s);
+        }
+    },
+
+    // private
+    handleClick : function(e, t){
+        e.preventDefault();
+        if(!this.disabled){
+            var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
+            this.select(c.toUpperCase());
+        }
+    },
+
     /**
-     * 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.
+     * Selects the specified color in the palette (fires the select event)
+     * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
      */
-    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;
+    select : function(color){
+        color = color.replace("#", "");
+        if(color != this.value || this.allowReselect){
+            var el = this.el;
+            if(this.value){
+                el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
             }
-               var record = new recordType(values, id);
-               record.json = n;
-               records[records.length] = record;
-           }
-           return {
-               records : records,
-               totalRecords : records.length
-           };
+            el.child("a.color-"+color).addClass("x-color-palette-sel");
+            this.value = color;
+            this.fireEvent("select", this, color);
+        }
     }
 });/*
  * Based on:
@@ -6540,737 +5239,661 @@ Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
  * Fork - LGPL
  * <script type="text/javascript">
  */
-
-
 /**
- * @class Roo.data.Tree
- * @extends Roo.util.Observable
- * Represents a tree data structure and bubbles all the events for its nodes. The nodes
- * in the tree have most standard DOM functionality.
+ * @class Roo.DatePicker
+ * @extends Roo.Component
+ * Simple date picker class.
  * @constructor
- * @param {Node} root (optional) The root node
+ * Create a new DatePicker
+ * @param {Object} config The config object
  */
-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.DatePicker = function(config){
+    Roo.DatePicker.superclass.constructor.call(this, config);
 
-    Roo.data.Tree.superclass.constructor.call(this);
-};
+    this.value = config && config.value ?
+                 config.value.clearTime() : new Date().clearTime();
 
-Roo.extend(Roo.data.Tree, Roo.util.Observable, {
-    pathSeparator: "/",
+    this.addEvents({
+        /**
+            * @event select
+            * Fires when a date is selected
+            * @param {DatePicker} this
+            * @param {Date} date The selected date
+            */
+        'select': true,
+        /**
+            * @event monthchange
+            * Fires when the displayed month changes 
+            * @param {DatePicker} this
+            * @param {Date} date The selected month
+            */
+        'monthchange': true
+    });
 
-    proxyNodeEvent : function(){
-        return this.fireEvent.apply(this, arguments);
-    },
+    if(this.handler){
+        this.on("select", this.handler,  this.scope || this);
+    }
+    // build the disabledDatesRE
+    if(!this.disabledDatesRE && this.disabledDates){
+        var dd = this.disabledDates;
+        var re = "(?:";
+        for(var i = 0; i < dd.length; i++){
+            re += dd[i];
+            if(i != dd.length-1) {
+                re += "|";
+            }
+        }
+        this.disabledDatesRE = new RegExp(re + ")");
+    }
+};
 
+Roo.extend(Roo.DatePicker, Roo.Component, {
     /**
-     * Returns the root node for this tree.
-     * @return {Node}
+     * @cfg {String} todayText
+     * The text to display on the button that selects the current date (defaults to "Today")
      */
-    getRootNode : function(){
-        return this.root;
-    },
-
+    todayText : "Today",
     /**
-     * Sets the root node for this tree.
-     * @param {Node} node
-     * @return {Node}
+     * @cfg {String} okText
+     * The text to display on the ok button
      */
-    setRootNode : function(node){
-        this.root = node;
-        node.ownerTree = this;
-        node.isRoot = true;
-        this.registerNode(node);
-        return node;
-    },
-
+    okText : "&#160;OK&#160;", // &#160; to give the user extra clicking room
     /**
-     * Gets a node in this tree by its id.
-     * @param {String} id
-     * @return {Node}
+     * @cfg {String} cancelText
+     * The text to display on the cancel button
      */
-    getNodeById : function(id){
-        return this.nodeHash[id];
-    },
-
-    registerNode : function(node){
-        this.nodeHash[node.id] = node;
-    },
-
-    unregisterNode : function(node){
-        delete this.nodeHash[node.id];
-    },
-
-    toString : function(){
-        return "[Tree"+(this.id?" "+this.id:"")+"]";
-    }
-});
-
-/**
- * @class Roo.data.Node
- * @extends Roo.util.Observable
- * @cfg {Boolean} leaf true if this node is a leaf and does not have children
- * @cfg {String} id The id for this node. If one is not specified, one is generated.
- * @constructor
- * @param {Object} attributes The attributes/config for the node
- */
-Roo.data.Node = function(attributes){
+    cancelText : "Cancel",
     /**
-     * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
-     * @type {Object}
+     * @cfg {String} todayTip
+     * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
      */
-    this.attributes = attributes || {};
-    this.leaf = this.attributes.leaf;
+    todayTip : "{0} (Spacebar)",
     /**
-     * The node id. @type String
+     * @cfg {Date} minDate
+     * Minimum allowable date (JavaScript date object, defaults to null)
      */
-    this.id = this.attributes.id;
-    if(!this.id){
-        this.id = Roo.id(null, "ynode-");
-        this.attributes.id = this.id;
-    }
-     
-    
+    minDate : null,
     /**
-     * All child nodes of this node. @type Array
+     * @cfg {Date} maxDate
+     * Maximum allowable date (JavaScript date object, defaults to null)
      */
-    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;
-        };
-    }
+    maxDate : null,
     /**
-     * The parent node for this node. @type Node
+     * @cfg {String} minText
+     * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
      */
-    this.parentNode = null;
+    minText : "This date is before the minimum date",
     /**
-     * The first direct child node of this node, or null if this node has no child nodes. @type Node
+     * @cfg {String} maxText
+     * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
      */
-    this.firstChild = null;
+    maxText : "This date is after the maximum date",
     /**
-     * The last direct child node of this node, or null if this node has no child nodes. @type Node
+     * @cfg {String} format
+     * The default date format string which can be overriden for localization support.  The format must be
+     * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
      */
-    this.lastChild = null;
+    format : "m/d/y",
     /**
-     * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
+     * @cfg {Array} disabledDays
+     * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
      */
-    this.previousSibling = null;
+    disabledDays : null,
     /**
-     * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
+     * @cfg {String} disabledDaysText
+     * The tooltip to display when the date falls on a disabled day (defaults to "")
      */
-    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;
-    },
+    disabledDaysText : "",
+    /**
+     * @cfg {RegExp} disabledDatesRE
+     * JavaScript regular expression used to disable a pattern of dates (defaults to null)
+     */
+    disabledDatesRE : null,
+    /**
+     * @cfg {String} disabledDatesText
+     * The tooltip text to display when the date falls on a disabled date (defaults to "")
+     */
+    disabledDatesText : "",
+    /**
+     * @cfg {Boolean} constrainToViewport
+     * True to constrain the date picker to the viewport (defaults to true)
+     */
+    constrainToViewport : true,
+    /**
+     * @cfg {Array} monthNames
+     * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
+     */
+    monthNames : Date.monthNames,
+    /**
+     * @cfg {Array} dayNames
+     * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
+     */
+    dayNames : Date.dayNames,
+    /**
+     * @cfg {String} nextText
+     * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
+     */
+    nextText: 'Next Month (Control+Right)',
+    /**
+     * @cfg {String} prevText
+     * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
+     */
+    prevText: 'Previous Month (Control+Left)',
+    /**
+     * @cfg {String} monthYearText
+     * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
+     */
+    monthYearText: 'Choose a month (Control+Up/Down to move years)',
+    /**
+     * @cfg {Number} startDay
+     * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
+     */
+    startDay : 0,
+    /**
+     * @cfg {Bool} showClear
+     * Show a clear button (usefull for date form elements that can be blank.)
+     */
+    
+    showClear: false,
+    
+    /**
+     * Sets the value of the date field
+     * @param {Date} value The date to set
+     */
+    setValue : function(value){
+        var old = this.value;
+        
+        if (typeof(value) == 'string') {
+         
+            value = Date.parseDate(value, this.format);
+        }
+        if (!value) {
+            value = new Date();
+        }
+        
+        this.value = value.clearTime(true);
+        if(this.el){
+            this.update(this.value);
+        }
+    },
 
     /**
-     * Returns true if this node is a leaf
-     * @return {Boolean}
+     * Gets the current selected value of the date field
+     * @return {Date} The selected date
      */
-    isLeaf : function(){
-        return this.leaf === true;
+    getValue : function(){
+        return this.value;
     },
 
     // private
-    setFirstChild : function(node){
-        this.firstChild = node;
+    focus : function(){
+        if(this.el){
+            this.update(this.activeDate);
+        }
     },
 
-    //private
-    setLastChild : function(node){
-        this.lastChild = node;
-    },
+    // privateval
+    onRender : function(container, position){
+        
+        var m = [
+             '<table cellspacing="0">',
+                '<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'">&#160;</a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'">&#160;</a></td></tr>',
+                '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
+        var dn = this.dayNames;
+        for(var i = 0; i < 7; i++){
+            var d = this.startDay+i;
+            if(d > 6){
+                d = d-7;
+            }
+            m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
+        }
+        m[m.length] = "</tr></thead><tbody><tr>";
+        for(var i = 0; i < 42; i++) {
+            if(i % 7 == 0 && i != 0){
+                m[m.length] = "</tr><tr>";
+            }
+            m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
+        }
+        m[m.length] = '</tr></tbody></table></td></tr><tr>'+
+            '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
 
+        var el = document.createElement("div");
+        el.className = "x-date-picker";
+        el.innerHTML = m.join("");
 
-    /**
-     * Returns true if this node is the last child of its parent
-     * @return {Boolean}
-     */
-    isLast : function(){
-       return (!this.parentNode ? true : this.parentNode.lastChild == this);
-    },
+        container.dom.insertBefore(el, position);
 
-    /**
-     * Returns true if this node is the first child of its parent
-     * @return {Boolean}
-     */
-    isFirst : function(){
-       return (!this.parentNode ? true : this.parentNode.firstChild == this);
-    },
+        this.el = Roo.get(el);
+        this.eventEl = Roo.get(el.firstChild);
 
-    hasChildNodes : function(){
-        return !this.isLeaf() && this.childNodes.length > 0;
-    },
+        new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
+            handler: this.showPrevMonth,
+            scope: this,
+            preventDefault:true,
+            stopDefault:true
+        });
 
-    /**
-     * 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;
-        }
-    },
+        new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
+            handler: this.showNextMonth,
+            scope: this,
+            preventDefault:true,
+            stopDefault:true
+        });
 
-    /**
-     * 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;
-        }
+        this.eventEl.on("mousewheel", this.handleMouseWheel,  this);
 
-        // remove it from childNodes collection
-        this.childNodes.splice(index, 1);
+        this.monthPicker = this.el.down('div.x-date-mp');
+        this.monthPicker.enableDisplayMode('block');
+        
+        var kn = new Roo.KeyNav(this.eventEl, {
+            "left" : function(e){
+                e.ctrlKey ?
+                    this.showPrevMonth() :
+                    this.update(this.activeDate.add("d", -1));
+            },
 
-        // update siblings
-        if(node.previousSibling){
-            node.previousSibling.nextSibling = node.nextSibling;
-        }
-        if(node.nextSibling){
-            node.nextSibling.previousSibling = node.previousSibling;
-        }
+            "right" : function(e){
+                e.ctrlKey ?
+                    this.showNextMonth() :
+                    this.update(this.activeDate.add("d", 1));
+            },
 
-        // update child refs
-        if(this.firstChild == node){
-            this.setFirstChild(node.nextSibling);
-        }
-        if(this.lastChild == node){
-            this.setLastChild(node.previousSibling);
-        }
+            "up" : function(e){
+                e.ctrlKey ?
+                    this.showNextYear() :
+                    this.update(this.activeDate.add("d", -7));
+            },
 
-        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;
-    },
+            "down" : function(e){
+                e.ctrlKey ?
+                    this.showPrevYear() :
+                    this.update(this.activeDate.add("d", 7));
+            },
 
-    /**
-     * 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;
-        }
+            "pageUp" : function(e){
+                this.showNextMonth();
+            },
 
-        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;
+            "pageDown" : function(e){
+                this.showPrevMonth();
+            },
 
-        // when moving internally, indexes will change after remove
-        if(oldParent == this && this.childNodes.indexOf(node) < index){
-            refIndex--;
-        }
+            "enter" : function(e){
+                e.stopPropagation();
+                return true;
+            },
 
-        // 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);
+            scope : this
+        });
+
+        this.eventEl.on("click", this.handleDateClick,  this, {delegate: "a.x-date-date"});
+
+        this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday,  this);
+
+        this.el.unselectable();
+        
+        this.cells = this.el.select("table.x-date-inner tbody td");
+        this.textNodes = this.el.query("table.x-date-inner tbody span");
+
+        this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
+            text: "&#160;",
+            tooltip: this.monthYearText
+        });
+
+        this.mbtn.on('click', this.showMonthPicker, this);
+        this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
+
+
+        var today = (new Date()).dateFormat(this.format);
+        
+        var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
+        if (this.showClear) {
+            baseTb.add( new Roo.Toolbar.Fill());
         }
-        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;
+        baseTb.add({
+            text: String.format(this.todayText, today),
+            tooltip: String.format(this.todayTip, today),
+            handler: this.selectToday,
+            scope: this
+        });
+        
+        //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
+            
+        //});
+        if (this.showClear) {
+            
+            baseTb.add( new Roo.Toolbar.Fill());
+            baseTb.add({
+                text: '&#160;',
+                cls: 'x-btn-icon x-btn-clear',
+                handler: function() {
+                    //this.value = '';
+                    this.fireEvent("select", this, '');
+                },
+                scope: this
+            });
         }
-        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);
+        
+        
+        if(Roo.isIE){
+            this.el.repaint();
         }
-        return node;
+        this.update(this.value);
     },
 
-    /**
-     * Returns the child node at the specified index.
-     * @param {Number} index
-     * @return {Node}
-     */
-    item : function(index){
-        return this.childNodes[index];
-    },
+    createMonthPicker : function(){
+        if(!this.monthPicker.dom.firstChild){
+            var buf = ['<table border="0" cellspacing="0">'];
+            for(var i = 0; i < 6; i++){
+                buf.push(
+                    '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
+                    '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
+                    i == 0 ?
+                    '<td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-prev"></a></td><td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-next"></a></td></tr>' :
+                    '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
+                );
+            }
+            buf.push(
+                '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
+                    this.okText,
+                    '</button><button type="button" class="x-date-mp-cancel">',
+                    this.cancelText,
+                    '</button></td></tr>',
+                '</table>'
+            );
+            this.monthPicker.update(buf.join(''));
+            this.monthPicker.on('click', this.onMonthClick, this);
+            this.monthPicker.on('dblclick', this.onMonthDblClick, this);
 
-    /**
-     * 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;
+            this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
+            this.mpYears = this.monthPicker.select('td.x-date-mp-year');
+
+            this.mpMonths.each(function(m, a, i){
+                i += 1;
+                if((i%2) == 0){
+                    m.dom.xmonth = 5 + Math.round(i * .5);
+                }else{
+                    m.dom.xmonth = Math.round((i-1) * .5);
+                }
+            });
+        }
     },
 
-    /**
-     * 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);
+    showMonthPicker : function(){
+        this.createMonthPicker();
+        var size = this.el.getSize();
+        this.monthPicker.setSize(size);
+        this.monthPicker.child('table').setSize(size);
+
+        this.mpSelMonth = (this.activeDate || this.value).getMonth();
+        this.updateMPMonth(this.mpSelMonth);
+        this.mpSelYear = (this.activeDate || this.value).getFullYear();
+        this.updateMPYear(this.mpSelYear);
+
+        this.monthPicker.slideIn('t', {duration:.2});
     },
 
-    /**
-     * 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;
+    updateMPYear : function(y){
+        this.mpyear = y;
+        var ys = this.mpYears.elements;
+        for(var i = 1; i <= 10; i++){
+            var td = ys[i-1], y2;
+            if((i%2) == 0){
+                y2 = y + Math.round(i * .5);
+                td.firstChild.innerHTML = y2;
+                td.xyear = y2;
+            }else{
+                y2 = y - (5-Math.round(i * .5));
+                td.firstChild.innerHTML = y2;
+                td.xyear = y2;
             }
+            this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
         }
-        return this.ownerTree;
     },
 
-    /**
-     * 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;
+    updateMPMonth : function(sm){
+        this.mpMonths.each(function(m, a, i){
+            m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
+        });
     },
 
-    // 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);
-            }
-        }
+    selectMPMonth: function(m){
+        
     },
 
-    /**
-     * 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;
+    onMonthClick : function(e, t){
+        e.stopEvent();
+        var el = new Roo.Element(t), pn;
+        if(el.is('button.x-date-mp-cancel')){
+            this.hideMonthPicker();
+        }
+        else if(el.is('button.x-date-mp-ok')){
+            this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
+            this.hideMonthPicker();
+        }
+        else if(pn = el.up('td.x-date-mp-month', 2)){
+            this.mpMonths.removeClass('x-date-mp-sel');
+            pn.addClass('x-date-mp-sel');
+            this.mpSelMonth = pn.dom.xmonth;
+        }
+        else if(pn = el.up('td.x-date-mp-year', 2)){
+            this.mpYears.removeClass('x-date-mp-sel');
+            pn.addClass('x-date-mp-sel');
+            this.mpSelYear = pn.dom.xyear;
+        }
+        else if(el.is('a.x-date-mp-prev')){
+            this.updateMPYear(this.mpyear-10);
+        }
+        else if(el.is('a.x-date-mp-next')){
+            this.updateMPYear(this.mpyear+10);
         }
-        var sep = this.getOwnerTree().pathSeparator;
-        return sep + b.join(sep);
     },
 
-    /**
-     * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
-     * function call will be the scope provided or the current node. The arguments to the function
-     * will be the args provided or the current node. If the function returns false at any point,
-     * the bubble is stopped.
-     * @param {Function} fn The function to call
-     * @param {Object} scope (optional) The scope of the function (defaults to current node)
-     * @param {Array} args (optional) The args to call the function with (default to passing the current node)
-     */
-    bubble : function(fn, scope, args){
-        var p = this;
-        while(p){
-            if(fn.call(scope || p, args || p) === false){
-                break;
-            }
-            p = p.parentNode;
+    onMonthDblClick : function(e, t){
+        e.stopEvent();
+        var el = new Roo.Element(t), pn;
+        if(pn = el.up('td.x-date-mp-month', 2)){
+            this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
+            this.hideMonthPicker();
+        }
+        else if(pn = el.up('td.x-date-mp-year', 2)){
+            this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
+            this.hideMonthPicker();
         }
     },
 
-    /**
-     * 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);
+    hideMonthPicker : function(disableAnim){
+        if(this.monthPicker){
+            if(disableAnim === true){
+                this.monthPicker.hide();
+            }else{
+                this.monthPicker.slideOut('t', {duration:.2});
             }
         }
     },
 
-    /**
-     * 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;
-               }
-        }
+    // private
+    showPrevMonth : function(e){
+        this.update(this.activeDate.add("mo", -1));
     },
 
-    /**
-     * Finds the first child that has the attribute with the specified value.
-     * @param {String} attribute The attribute name
-     * @param {Mixed} value The value to search for
-     * @return {Node} The found child or null if none was found
-     */
-    findChild : function(attribute, value){
-        var cs = this.childNodes;
-        for(var i = 0, len = cs.length; i < len; i++) {
-               if(cs[i].attributes[attribute] == value){
-                   return cs[i];
-               }
-        }
-        return null;
+    // private
+    showNextMonth : function(e){
+        this.update(this.activeDate.add("mo", 1));
     },
 
-    /**
-     * 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];
-               }
+    // private
+    showPrevYear : function(){
+        this.update(this.activeDate.add("y", -1));
+    },
+
+    // private
+    showNextYear : function(){
+        this.update(this.activeDate.add("y", 1));
+    },
+
+    // private
+    handleMouseWheel : function(e){
+        var delta = e.getWheelDelta();
+        if(delta > 0){
+            this.showPrevMonth();
+            e.stopEvent();
+        } else if(delta < 0){
+            this.showNextMonth();
+            e.stopEvent();
         }
-        return null;
     },
 
-    /**
-     * Sorts this nodes children using the supplied sort function
-     * @param {Function} fn
-     * @param {Object} scope (optional)
-     */
-    sort : function(fn, scope){
-        var cs = this.childNodes;
-        var len = cs.length;
-        if(len > 0){
-            var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
-            cs.sort(sortFn);
-            for(var i = 0; i < len; i++){
-                var n = cs[i];
-                n.previousSibling = cs[i-1];
-                n.nextSibling = cs[i+1];
-                if(i == 0){
-                    this.setFirstChild(n);
-                }
-                if(i == len-1){
-                    this.setLastChild(n);
-                }
-            }
+    // private
+    handleDateClick : function(e, t){
+        e.stopEvent();
+        if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
+            this.setValue(new Date(t.dateValue));
+            this.fireEvent("select", this, this.value);
         }
     },
 
-    /**
-     * 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
+    selectToday : function(){
+        this.setValue(new Date().clearTime());
+        this.fireEvent("select", this, this.value);
     },
 
-    /**
-     * 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;
+    // private
+    update : function(date)
+    {
+        var vd = this.activeDate;
+        this.activeDate = date;
+        if(vd && this.el){
+            var t = date.getTime();
+            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
+                this.cells.removeClass("x-date-selected");
+                this.cells.each(function(c){
+                   if(c.dom.firstChild.dateValue == t){
+                       c.addClass("x-date-selected");
+                       setTimeout(function(){
+                            try{c.dom.firstChild.focus();}catch(e){}
+                       }, 50);
+                       return false;
+                   }
+                });
+                return;
             }
-            p = p.parentNode;
         }
-        return false;
-    },
+        
+        var days = date.getDaysInMonth();
+        var firstOfMonth = date.getFirstDateOfMonth();
+        var startingPos = firstOfMonth.getDay()-this.startDay;
 
-    toString : function(){
-        return "[Node"+(this.id?" "+this.id:"")+"]";
+        if(startingPos <= this.startDay){
+            startingPos += 7;
+        }
+
+        var pm = date.add("mo", -1);
+        var prevStart = pm.getDaysInMonth()-startingPos;
+
+        var cells = this.cells.elements;
+        var textEls = this.textNodes;
+        days += startingPos;
+
+        // convert everything to numbers so it's fast
+        var day = 86400000;
+        var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
+        var today = new Date().clearTime().getTime();
+        var sel = date.clearTime().getTime();
+        var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
+        var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
+        var ddMatch = this.disabledDatesRE;
+        var ddText = this.disabledDatesText;
+        var ddays = this.disabledDays ? this.disabledDays.join("") : false;
+        var ddaysText = this.disabledDaysText;
+        var format = this.format;
+
+        var setCellClass = function(cal, cell){
+            cell.title = "";
+            var t = d.getTime();
+            cell.firstChild.dateValue = t;
+            if(t == today){
+                cell.className += " x-date-today";
+                cell.title = cal.todayText;
+            }
+            if(t == sel){
+                cell.className += " x-date-selected";
+                setTimeout(function(){
+                    try{cell.firstChild.focus();}catch(e){}
+                }, 50);
+            }
+            // disabling
+            if(t < min) {
+                cell.className = " x-date-disabled";
+                cell.title = cal.minText;
+                return;
+            }
+            if(t > max) {
+                cell.className = " x-date-disabled";
+                cell.title = cal.maxText;
+                return;
+            }
+            if(ddays){
+                if(ddays.indexOf(d.getDay()) != -1){
+                    cell.title = ddaysText;
+                    cell.className = " x-date-disabled";
+                }
+            }
+            if(ddMatch && format){
+                var fvalue = d.dateFormat(format);
+                if(ddMatch.test(fvalue)){
+                    cell.title = ddText.replace("%0", fvalue);
+                    cell.className = " x-date-disabled";
+                }
+            }
+        };
+
+        var i = 0;
+        for(; i < startingPos; i++) {
+            textEls[i].innerHTML = (++prevStart);
+            d.setDate(d.getDate()+1);
+            cells[i].className = "x-date-prevday";
+            setCellClass(this, cells[i]);
+        }
+        for(; i < days; i++){
+            intDay = i - startingPos + 1;
+            textEls[i].innerHTML = (intDay);
+            d.setDate(d.getDate()+1);
+            cells[i].className = "x-date-active";
+            setCellClass(this, cells[i]);
+        }
+        var extraDays = 0;
+        for(; i < 42; i++) {
+             textEls[i].innerHTML = (++extraDays);
+             d.setDate(d.getDate()+1);
+             cells[i].className = "x-date-nextday";
+             setCellClass(this, cells[i]);
+        }
+
+        this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
+        this.fireEvent('monthchange', this, date);
+        
+        if(!this.internalRender){
+            var main = this.el.dom.firstChild;
+            var w = main.offsetWidth;
+            this.el.setWidth(w + this.el.getBorderWidth("lr"));
+            Roo.fly(main).setWidth(w);
+            this.internalRender = true;
+            // opera does not respect the auto grow header center column
+            // then, after it gets a width opera refuses to recalculate
+            // without a second pass
+            if(Roo.isOpera && !this.secondPass){
+                main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
+                this.secondPass = true;
+                this.update.defer(10, this, [date]);
+            }
+        }
+        
+        
     }
-});/*
+});        /*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -7280,2213 +5903,2192 @@ Roo.extend(Roo.data.Node, Roo.util.Observable, {
  * Fork - LGPL
  * <script type="text/javascript">
  */
- (function(){ 
 /**
- * @class Roo.Layer
- * @extends Roo.Element
- * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
- * automatic maintaining of shadow/shim positions.
- * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
- * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
- * you can pass a string with a CSS class name. False turns off the shadow.
- * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
- * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
- * @cfg {String} cls CSS class to add to the element
- * @cfg {Number} zindex Starting z-index (defaults to 11000)
- * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
+ * @class Roo.TabPanel
+ * @extends Roo.util.Observable
+ * A lightweight tab container.
+ * <br><br>
+ * Usage:
+ * <pre><code>
+// basic tabs 1, built from existing content
+var tabs = new Roo.TabPanel("tabs1");
+tabs.addTab("script", "View Script");
+tabs.addTab("markup", "View Markup");
+tabs.activate("script");
+
+// more advanced tabs, built from javascript
+var jtabs = new Roo.TabPanel("jtabs");
+jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
+
+// set up the UpdateManager
+var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
+var updater = tab2.getUpdateManager();
+updater.setDefaultUrl("ajax1.htm");
+tab2.on('activate', updater.refresh, updater, true);
+
+// Use setUrl for Ajax loading
+var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
+tab3.setUrl("ajax2.htm", null, true);
+
+// Disabled tab
+var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
+tab4.disable();
+
+jtabs.activate("jtabs-1");
+ * </code></pre>
  * @constructor
- * @param {Object} config An object with config options.
- * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
+ * Create a new TabPanel.
+ * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
+ * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
  */
-
-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);
+Roo.TabPanel = function(container, config){
+    /**
+    * The container element for this TabPanel.
+    * @type Roo.Element
+    */
+    this.el = Roo.get(container, true);
+    if(config){
+        if(typeof config == "boolean"){
+            this.tabPosition = config ? "bottom" : "top";
+        }else{
+            Roo.apply(this, config);
+        }
     }
-    if(config.cls){
-        this.addClass(config.cls);
+    if(this.tabPosition == "bottom"){
+        this.bodyEl = Roo.get(this.createBody(this.el.dom));
+        this.el.addClass("x-tabs-bottom");
     }
-    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.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
+    this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
+    this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
+    if(Roo.isIE){
+        Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
     }
-    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;
+    if(this.tabPosition != "bottom"){
+        /** The body element that contains {@link Roo.TabPanelItem} bodies. +
+         * @type Roo.Element
+         */
+        this.bodyEl = Roo.get(this.createBody(this.el.dom));
+        this.el.addClass("x-tabs-top");
     }
-    this.useShim = config.shim !== false && Roo.useShims;
-    this.useDisplay = config.useDisplay;
-    this.hide();
-};
+    this.items = [];
 
-var supr = Roo.Element.prototype;
+    this.bodyEl.setStyle("position", "relative");
 
-// shims are shared among layer to keep from having 100 iframes
-var shims = [];
+    this.active = null;
+    this.activateDelegate = this.activate.createDelegate(this);
 
-Roo.extend(Roo.Layer, Roo.Element, {
+    this.addEvents({
+        /**
+         * @event tabchange
+         * Fires when the active tab changes
+         * @param {Roo.TabPanel} this
+         * @param {Roo.TabPanelItem} activePanel The new active tab
+         */
+        "tabchange": true,
+        /**
+         * @event beforetabchange
+         * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
+         * @param {Roo.TabPanel} this
+         * @param {Object} e Set cancel to true on this object to cancel the tab change
+         * @param {Roo.TabPanelItem} tab The tab being changed to
+         */
+        "beforetabchange" : true
+    });
 
-    getZIndex : function(){
-        return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
-    },
+    Roo.EventManager.onWindowResize(this.onResize, this);
+    this.cpad = this.el.getPadding("lr");
+    this.hiddenCount = 0;
 
-    getShim : function(){
-        if(!this.useShim){
-            return null;
-        }
-        if(this.shim){
-            return this.shim;
+
+    // toolbar on the tabbar support...
+    if (this.toolbar) {
+        var tcfg = this.toolbar;
+        tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');  
+        this.toolbar = new Roo.Toolbar(tcfg);
+        if (Roo.isSafari) {
+            var tbl = tcfg.container.child('table', true);
+            tbl.setAttribute('width', '100%');
         }
-        var shim = shims.shift();
-        if(!shim){
-            shim = this.createShim();
-            shim.enableDisplayMode('block');
-            shim.dom.style.display = 'none';
-            shim.dom.style.visibility = 'visible';
-        }
-        var pn = this.dom.parentNode;
-        if(shim.dom.parentNode != pn){
-            pn.insertBefore(shim.dom, this.dom);
-        }
-        shim.setStyle('z-index', this.getZIndex()-2);
-        this.shim = shim;
-        return shim;
-    },
-
-    hideShim : function(){
-        if(this.shim){
-            this.shim.setDisplayed(false);
-            shims.push(this.shim);
-            delete this.shim;
-        }
-    },
-
-    disableShadow : function(){
-        if(this.shadow){
-            this.shadowDisabled = true;
-            this.shadow.hide();
-            this.lastShadowOffset = this.shadowOffset;
-            this.shadowOffset = 0;
-        }
-    },
-
-    enableShadow : function(show){
-        if(this.shadow){
-            this.shadowDisabled = false;
-            this.shadowOffset = this.lastShadowOffset;
-            delete this.lastShadowOffset;
-            if(show){
-                this.sync(true);
-            }
-        }
-    },
+        
+    }
+   
 
-    // private
-    // this code can execute repeatedly in milliseconds (i.e. during a drag) so
-    // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
-    sync : function(doShow){
-        var sw = this.shadow;
-        if(!this.updating && this.isVisible() && (sw || this.useShim)){
-            var sh = this.getShim();
 
-            var w = this.getWidth(),
-                h = this.getHeight();
+    Roo.TabPanel.superclass.constructor.call(this);
+};
 
-            var l = this.getLeft(true),
-                t = this.getTop(true);
+Roo.extend(Roo.TabPanel, Roo.util.Observable, {
+    /*
+     *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
+     */
+    tabPosition : "top",
+    /*
+     *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
+     */
+    currentTabWidth : 0,
+    /*
+     *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
+     */
+    minTabWidth : 40,
+    /*
+     *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
+     */
+    maxTabWidth : 250,
+    /*
+     *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
+     */
+    preferredTabWidth : 175,
+    /*
+     *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
+     */
+    resizeTabs : false,
+    /*
+     *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
+     */
+    monitorResize : true,
+    /*
+     *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar. 
+     */
+    toolbar : false,
 
-            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);
-            }
-            
+    /**
+     * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
+     * @param {String} id The id of the div to use <b>or create</b>
+     * @param {String} text The text for the tab
+     * @param {String} content (optional) Content to put in the TabPanelItem body
+     * @param {Boolean} closable (optional) True to create a close icon on the tab
+     * @return {Roo.TabPanelItem} The created TabPanelItem
+     */
+    addTab : function(id, text, content, closable){
+        var item = new Roo.TabPanelItem(this, id, text, closable);
+        this.addTabItem(item);
+        if(content){
+            item.setContent(content);
         }
+        return item;
     },
 
-    // private
-    destroy : function(){
-        this.hideShim();
-        if(this.shadow){
-            this.shadow.hide();
-        }
-        this.removeAllListeners();
-        var pn = this.dom.parentNode;
-        if(pn){
-            pn.removeChild(this.dom);
-        }
-        Roo.Element.uncache(this.id);
+    /**
+     * Returns the {@link Roo.TabPanelItem} with the specified id/index
+     * @param {String/Number} id The id or index of the TabPanelItem to fetch.
+     * @return {Roo.TabPanelItem}
+     */
+    getTab : function(id){
+        return this.items[id];
     },
 
-    remove : function(){
-        this.destroy();
+    /**
+     * Hides the {@link Roo.TabPanelItem} with the specified id/index
+     * @param {String/Number} id The id or index of the TabPanelItem to hide.
+     */
+    hideTab : function(id){
+        var t = this.items[id];
+        if(!t.isHidden()){
+           t.setHidden(true);
+           this.hiddenCount++;
+           this.autoSizeTabs();
+        }
     },
 
-    // private
-    beginUpdate : function(){
-        this.updating = true;
+    /**
+     * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
+     * @param {String/Number} id The id or index of the TabPanelItem to unhide.
+     */
+    unhideTab : function(id){
+        var t = this.items[id];
+        if(t.isHidden()){
+           t.setHidden(false);
+           this.hiddenCount--;
+           this.autoSizeTabs();
+        }
     },
 
-    // private
-    endUpdate : function(){
-        this.updating = false;
-        this.sync(true);
+    /**
+     * Adds an existing {@link Roo.TabPanelItem}.
+     * @param {Roo.TabPanelItem} item The TabPanelItem to add
+     */
+    addTabItem : function(item){
+        this.items[item.id] = item;
+        this.items.push(item);
+        if(this.resizeTabs){
+           item.setWidth(this.currentTabWidth || this.preferredTabWidth);
+           this.autoSizeTabs();
+        }else{
+            item.autoSize();
+        }
     },
 
-    // private
-    hideUnders : function(negOffset){
-        if(this.shadow){
-            this.shadow.hide();
+    /**
+     * Removes a {@link Roo.TabPanelItem}.
+     * @param {String/Number} id The id or index of the TabPanelItem to remove.
+     */
+    removeTab : function(id){
+        var items = this.items;
+        var tab = items[id];
+        if(!tab) { return; }
+        var index = items.indexOf(tab);
+        if(this.active == tab && items.length > 1){
+            var newTab = this.getNextAvailable(index);
+            if(newTab) {
+                newTab.activate();
+            }
         }
-        this.hideShim();
+        this.stripEl.dom.removeChild(tab.pnode.dom);
+        if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
+            this.bodyEl.dom.removeChild(tab.bodyEl.dom);
+        }
+        items.splice(index, 1);
+        delete this.items[tab.id];
+        tab.fireEvent("close", tab);
+        tab.purgeListeners();
+        this.autoSizeTabs();
     },
 
-    // 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;
+    getNextAvailable : function(start){
+        var items = this.items;
+        var index = start;
+        // look for a next tab that will slide over to
+        // replace the one being removed
+        while(index < items.length){
+            var item = items[++index];
+            if(item && !item.isHidden()){
+                return item;
             }
-            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();
+        }
+        // if one isn't found select the previous tab (on the left)
+        index = start;
+        while(index >= 0){
+            var item = items[--index];
+            if(item && !item.isHidden()){
+                return item;
             }
         }
+        return null;
     },
 
-    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]);
+    /**
+     * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
+     * @param {String/Number} id The id or index of the TabPanelItem to disable.
+     */
+    disableTab : function(id){
+        var tab = this.items[id];
+        if(tab && this.active != tab){
+            tab.disable();
         }
     },
 
-    // private
-    hideAction : function(){
-        this.visible = false;
-        if(this.useDisplay === true){
-            this.setDisplayed(false);
-        }else{
-            this.setLeftTop(-10000,-10000);
-        }
+    /**
+     * Enables a {@link Roo.TabPanelItem} that is disabled.
+     * @param {String/Number} id The id or index of the TabPanelItem to enable.
+     */
+    enableTab : function(id){
+        var tab = this.items[id];
+        tab.enable();
     },
 
-    // overridden Element method
-    setVisible : function(v, a, d, c, e){
-        if(v){
-            this.showAction();
+    /**
+     * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
+     * @param {String/Number} id The id or index of the TabPanelItem to activate.
+     * @return {Roo.TabPanelItem} The TabPanelItem.
+     */
+    activate : function(id){
+        var tab = this.items[id];
+        if(!tab){
+            return null;
         }
-        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(tab == this.active || tab.disabled){
+            return tab;
+        }
+        var e = {};
+        this.fireEvent("beforetabchange", this, e, tab);
+        if(e.cancel !== true && !tab.disabled){
+            if(this.active){
+                this.active.hide();
             }
+            this.active = this.items[id];
+            this.active.show();
+            this.fireEvent("tabchange", this, this.active);
         }
+        return tab;
     },
 
-    storeXY : function(xy){
-        delete this.lastLT;
-        this.lastXY = xy;
-    },
-
-    storeLeftTop : function(left, top){
-        delete this.lastXY;
-        this.lastLT = [left, top];
-    },
-
-    // private
-    beforeFx : function(){
-        this.beforeAction();
-        return Roo.Layer.superclass.beforeFx.apply(this, arguments);
+    /**
+     * Gets the active {@link Roo.TabPanelItem}.
+     * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
+     */
+    getActiveTab : function(){
+        return this.active;
     },
 
-    // private
-    afterFx : function(){
-        Roo.Layer.superclass.afterFx.apply(this, arguments);
-        this.sync(this.isVisible());
+    /**
+     * Updates the tab body element to fit the height of the container element
+     * for overflow scrolling
+     * @param {Number} targetHeight (optional) Override the starting height from the elements height
+     */
+    syncHeight : function(targetHeight){
+        var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
+        var bm = this.bodyEl.getMargins();
+        var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
+        this.bodyEl.setHeight(newHeight);
+        return newHeight;
     },
 
-    // private
-    beforeAction : function(){
-        if(!this.updating && this.shadow){
-            this.shadow.hide();
+    onResize : function(){
+        if(this.monitorResize){
+            this.autoSizeTabs();
         }
     },
 
-    // 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();
+    /**
+     * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
+     */
+    beginUpdate : function(){
+        this.updating = true;
     },
 
-    setLeftTop : function(left, top){
-        this.storeLeftTop(left, top);
-        supr.setLeftTop.apply(this, arguments);
-        this.sync();
+    /**
+     * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
+     */
+    endUpdate : function(){
+        this.updating = false;
+        this.autoSizeTabs();
     },
 
-    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();
+    /**
+     * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
+     */
+    autoSizeTabs : function(){
+        var count = this.items.length;
+        var vcount = count - this.hiddenCount;
+        if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
+            return;
         }
-    },
-
-    // private
-    createCB : function(c){
-        var el = this;
-        return function(){
-            el.constrainXY();
-            el.sync(true);
-            if(c){
-                c();
+        var w = Math.max(this.el.getWidth() - this.cpad, 10);
+        var availWidth = Math.floor(w / vcount);
+        var b = this.stripBody;
+        if(b.getWidth() > w){
+            var tabs = this.items;
+            this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
+            if(availWidth < this.minTabWidth){
+                /*if(!this.sleft){    // incomplete scrolling code
+                    this.createScrollButtons();
+                }
+                this.showScroll();
+                this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
             }
-        };
-    },
-
-    // overridden Element method
-    setX : function(x, a, d, c, e){
-        this.setXY([x, this.getY()], a, d, c, e);
+        }else{
+            if(this.currentTabWidth < this.preferredTabWidth){
+                this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
+            }
+        }
     },
 
-    // overridden Element method
-    setY : function(y, a, d, c, e){
-        this.setXY([this.getX(), y], a, d, c, e);
-    },
+    /**
+     * Returns the number of tabs in this TabPanel.
+     * @return {Number}
+     */
+     getCount : function(){
+         return this.items.length;
+     },
 
-    // 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();
+    /**
+     * Resizes all the tabs to the passed width
+     * @param {Number} The new width
+     */
+    setTabWidth : function(width){
+        this.currentTabWidth = width;
+        for(var i = 0, len = this.items.length; i < len; i++) {
+               if(!this.items[i].isHidden()) {
+                this.items[i].setWidth(width);
+            }
         }
     },
 
-    // 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
+     * Destroys this TabPanel
+     * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
      */
-    setZIndex : function(zindex){
-        this.zindex = zindex;
-        this.setStyle("z-index", zindex + 2);
-        if(this.shadow){
-            this.shadow.setZIndex(zindex + 1);
+    destroy : function(removeEl){
+        Roo.EventManager.removeResizeListener(this.onResize, this);
+        for(var i = 0, len = this.items.length; i < len; i++){
+            this.items[i].purgeListeners();
         }
-        if(this.shim){
-            this.shim.setStyle("z-index", zindex);
+        if(removeEl === true){
+            this.el.update("");
+            this.el.remove();
         }
     }
 });
-})();/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-
 
 /**
- * @class Roo.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
+ * @class Roo.TabPanelItem
+ * @extends Roo.util.Observable
+ * Represents an individual item (tab plus body) in a TabPanel.
+ * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
+ * @param {String} id The id of this TabPanelItem
+ * @param {String} text The text for the tab of this TabPanelItem
+ * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
  */
-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 = {
+Roo.TabPanelItem = function(tabPanel, id, text, closable){
     /**
-     * @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)
+     * The {@link Roo.TabPanel} this TabPanelItem belongs to
+     * @type Roo.TabPanel
      */
+    this.tabPanel = tabPanel;
     /**
-     * @cfg {String} offset
-     * The number of pixels to offset the shadow from the element (defaults to 4)
+     * The id for this TabPanelItem
+     * @type String
      */
-    offset: 4,
+    this.id = id;
+    /** @private */
+    this.disabled = false;
+    /** @private */
+    this.text = text;
+    /** @private */
+    this.loaded = false;
+    this.closable = closable;
 
-    // private
-    defaultMode: "drop",
+    /**
+     * The body element for this TabPanelItem.
+     * @type Roo.Element
+     */
+    this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
+    this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
+    this.bodyEl.setStyle("display", "block");
+    this.bodyEl.setStyle("zoom", "1");
+    this.hideAction();
+
+    var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
+    /** @private */
+    this.el = Roo.get(els.el, true);
+    this.inner = Roo.get(els.inner, true);
+    this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
+    this.pnode = Roo.get(els.el.parentNode, true);
+    this.el.on("mousedown", this.onTabMouseDown, this);
+    this.el.on("click", this.onTabClick, this);
+    /** @private */
+    if(closable){
+        var c = Roo.get(els.close, true);
+        c.dom.title = this.closeText;
+        c.addClassOnOver("close-over");
+        c.on("click", this.closeClick, this);
+     }
+
+    this.addEvents({
+         /**
+         * @event activate
+         * Fires when this tab becomes the active tab.
+         * @param {Roo.TabPanel} tabPanel The parent TabPanel
+         * @param {Roo.TabPanelItem} this
+         */
+        "activate": true,
+        /**
+         * @event beforeclose
+         * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
+         * @param {Roo.TabPanelItem} this
+         * @param {Object} e Set cancel to true on this object to cancel the close.
+         */
+        "beforeclose": true,
+        /**
+         * @event close
+         * Fires when this tab is closed.
+         * @param {Roo.TabPanelItem} this
+         */
+         "close": true,
+        /**
+         * @event deactivate
+         * Fires when this tab is no longer the active tab.
+         * @param {Roo.TabPanel} tabPanel The parent TabPanel
+         * @param {Roo.TabPanelItem} this
+         */
+         "deactivate" : true
+    });
+    this.hidden = false;
 
+    Roo.TabPanelItem.superclass.constructor.call(this);
+};
+
+Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
+    purgeListeners : function(){
+       Roo.util.Observable.prototype.purgeListeners.call(this);
+       this.el.removeAllListeners();
+    },
     /**
-     * Displays the shadow under the target element
-     * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
+     * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
      */
-    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)+")";
+    show : function(){
+        this.pnode.addClass("on");
+        this.showAction();
+        if(Roo.isOpera){
+            this.tabPanel.stripWrap.repaint();
         }
-        this.realign(
-            target.getLeft(true),
-            target.getTop(true),
-            target.getWidth(),
-            target.getHeight()
-        );
-        this.el.dom.style.display = "block";
+        this.fireEvent("activate", this.tabPanel, this);
     },
 
     /**
-     * Returns true if the shadow is visible, else false
+     * Returns true if this tab is the active tab.
+     * @return {Boolean}
      */
-    isVisible : function(){
-        return this.el ? true : false;  
+    isActive : function(){
+        return this.tabPanel.getActiveTab() == this;
     },
 
     /**
-     * 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
+     * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
      */
-    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";
-            }
-        }
+    hide : function(){
+        this.pnode.removeClass("on");
+        this.hideAction();
+        this.fireEvent("deactivate", this.tabPanel, this);
+    },
+
+    hideAction : function(){
+        this.bodyEl.hide();
+        this.bodyEl.setStyle("position", "absolute");
+        this.bodyEl.setLeft("-20000px");
+        this.bodyEl.setTop("-20000px");
+    },
+
+    showAction : function(){
+        this.bodyEl.setStyle("position", "relative");
+        this.bodyEl.setTop("");
+        this.bodyEl.setLeft("");
+        this.bodyEl.show();
     },
 
     /**
-     * Hides this shadow
+     * Set the tooltip for the tab.
+     * @param {String} tooltip The tab's tooltip
      */
-    hide : function(){
-        if(this.el){
-            this.el.dom.style.display = "none";
-            Roo.Shadow.Pool.push(this.el);
-            delete this.el;
+    setTooltip : function(text){
+        if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
+            this.textEl.dom.qtip = text;
+            this.textEl.dom.removeAttribute('title');
+        }else{
+            this.textEl.dom.title = text;
         }
     },
 
+    onTabClick : function(e){
+        e.preventDefault();
+        this.tabPanel.activate(this.id);
+    },
+
+    onTabMouseDown : function(e){
+        e.preventDefault();
+        this.tabPanel.activate(this.id);
+    },
+
+    getWidth : function(){
+        return this.inner.getWidth();
+    },
+
+    setWidth : function(width){
+        var iwidth = width - this.pnode.getPadding("lr");
+        this.inner.setWidth(iwidth);
+        this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
+        this.pnode.setWidth(width);
+    },
+
     /**
-     * Adjust the z-index of this shadow
-     * @param {Number} zindex The new z-index
+     * Show or hide the tab
+     * @param {Boolean} hidden True to hide or false to show.
      */
-    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;
-        },
+    setHidden : function(hidden){
+        this.hidden = hidden;
+        this.pnode.setStyle("display", hidden ? "none" : "");
+    },
 
-        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">
- */
+    /**
+     * Returns true if this tab is "hidden"
+     * @return {Boolean}
+     */
+    isHidden : function(){
+        return this.hidden;
+    },
 
+    /**
+     * Returns the text for this tab
+     * @return {String}
+     */
+    getText : function(){
+        return this.text;
+    },
 
-/**
- * @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 */
-    this.resizingEl = Roo.get(resizingElement, true);
+    autoSize : function(){
+        //this.el.beginMeasure();
+        this.textEl.setWidth(1);
+        /*
+         *  #2804 [new] Tabs in Roojs
+         *  increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
+         */
+        this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
+        //this.el.endMeasure();
+    },
 
     /**
-     * @private
-     * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
-     * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
-     * @type Number
+     * Sets the text for the tab (Note: this also sets the tooltip text)
+     * @param {String} text The tab's text and tooltip
      */
-    this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
-    
+    setText : function(text){
+        this.text = text;
+        this.textEl.update(text);
+        this.setTooltip(text);
+        if(!this.tabPanel.resizeTabs){
+            this.autoSize();
+        }
+    },
     /**
-     * The minimum size of the resizing element. (Defaults to 0)
-     * @type Number
+     * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
      */
-    this.minSize = 0;
-    
+    activate : function(){
+        this.tabPanel.activate(this.id);
+    },
+
     /**
-     * The maximum size of the resizing element. (Defaults to 2000)
-     * @type Number
+     * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
      */
-    this.maxSize = 2000;
-    
+    disable : function(){
+        if(this.tabPanel.active != this){
+            this.disabled = true;
+            this.pnode.addClass("disabled");
+        }
+    },
+
     /**
-     * Whether to animate the transition to the new size
-     * @type Boolean
+     * Enables this TabPanelItem if it was previously disabled.
      */
-    this.animate = false;
-    
+    enable : function(){
+        this.disabled = false;
+        this.pnode.removeClass("disabled");
+    },
+
     /**
-     * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
-     * @type Boolean
+     * Sets the content for this TabPanelItem.
+     * @param {String} content The content
+     * @param {Boolean} loadScripts true to look for and load scripts
      */
-    this.useShim = false;
-    
-    /** @private */
-    this.shim = null;
-    
-    if(!existingProxy){
-        /** @private */
-        this.proxy = Roo.SplitBar.createProxy(this.orientation);
-    }else{
-        this.proxy = Roo.get(existingProxy).dom;
-    }
-    /** @private */
-    this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
-    
-    /** @private */
-    this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
-    
-    /** @private */
-    this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
-    
-    /** @private */
-    this.dragSpecs = {};
-    
+    setContent : function(content, loadScripts){
+        this.bodyEl.update(content, loadScripts);
+    },
+
     /**
-     * @private The adapter to use to positon and resize elements
+     * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
+     * @return {Roo.UpdateManager} The UpdateManager
      */
-    this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
-    this.adapter.init(this);
-    
-    if(this.orientation == Roo.SplitBar.HORIZONTAL){
-        /** @private */
-        this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
-        this.el.addClass("x-splitbar-h");
-    }else{
-        /** @private */
-        this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
-        this.el.addClass("x-splitbar-v");
+    getUpdateManager : function(){
+        return this.bodyEl.getUpdateManager();
+    },
+
+    /**
+     * Set a URL to be used to load the content for this TabPanelItem.
+     * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
+     * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
+     * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
+     * @return {Roo.UpdateManager} The UpdateManager
+     */
+    setUrl : function(url, params, loadOnce){
+        if(this.refreshDelegate){
+            this.un('activate', this.refreshDelegate);
+        }
+        this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
+        this.on("activate", this.refreshDelegate);
+        return this.bodyEl.getUpdateManager();
+    },
+
+    /** @private */
+    _handleRefresh : function(url, params, loadOnce){
+        if(!loadOnce || !this.loaded){
+            var updater = this.bodyEl.getUpdateManager();
+            updater.update(url, params, this._setLoaded.createDelegate(this));
+        }
+    },
+
+    /**
+     *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
+     *   Will fail silently if the setUrl method has not been called.
+     *   This does not activate the panel, just updates its content.
+     */
+    refresh : function(){
+        if(this.refreshDelegate){
+           this.loaded = false;
+           this.refreshDelegate();
+        }
+    },
+
+    /** @private */
+    _setLoaded : function(){
+        this.loaded = true;
+    },
+
+    /** @private */
+    closeClick : function(e){
+        var o = {};
+        e.stopEvent();
+        this.fireEvent("beforeclose", this, o);
+        if(o.cancel !== true){
+            this.tabPanel.removeTab(this.id);
+        }
+    },
+    /**
+     * The text displayed in the tooltip for the close icon.
+     * @type String
+     */
+    closeText : "Close this tab"
+});
+
+/** @private */
+Roo.TabPanel.prototype.createStrip = function(container){
+    var strip = document.createElement("div");
+    strip.className = "x-tabs-wrap";
+    container.appendChild(strip);
+    return strip;
+};
+/** @private */
+Roo.TabPanel.prototype.createStripList = function(strip){
+    // div wrapper for retard IE
+    // returns the "tr" element.
+    strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
+        '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
+        '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
+    return strip.firstChild.firstChild.firstChild.firstChild;
+};
+/** @private */
+Roo.TabPanel.prototype.createBody = function(container){
+    var body = document.createElement("div");
+    Roo.id(body, "tab-body");
+    Roo.fly(body).addClass("x-tabs-body");
+    container.appendChild(body);
+    return body;
+};
+/** @private */
+Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
+    var body = Roo.getDom(id);
+    if(!body){
+        body = document.createElement("div");
+        body.id = id;
+    }
+    Roo.fly(body).addClass("x-tabs-item-body");
+    bodyEl.insertBefore(body, bodyEl.firstChild);
+    return body;
+};
+/** @private */
+Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
+    var td = document.createElement("td");
+    stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
+    //stripEl.appendChild(td);
+    if(closable){
+        td.className = "x-tabs-closable";
+        if(!this.closeTpl){
+            this.closeTpl = new Roo.Template(
+               '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
+               '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
+               '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
+            );
+        }
+        var el = this.closeTpl.overwrite(td, {"text": text});
+        var close = el.getElementsByTagName("div")[0];
+        var inner = el.getElementsByTagName("em")[0];
+        return {"el": el, "close": close, "inner": inner};
+    } else {
+        if(!this.tabTpl){
+            this.tabTpl = new Roo.Template(
+               '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
+               '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
+            );
+        }
+        var el = this.tabTpl.overwrite(td, {"text": text});
+        var inner = el.getElementsByTagName("em")[0];
+        return {"el": el, "inner": inner};
+    }
+};/*
+ * 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.Button
+ * @extends Roo.util.Observable
+ * Simple Button class
+ * @cfg {String} text The button text
+ * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
+ * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
+ * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
+ * @cfg {Object} scope The scope of the handler
+ * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
+ * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
+ * @cfg {Boolean} hidden True to start hidden (defaults to false)
+ * @cfg {Boolean} disabled True to start disabled (defaults to false)
+ * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
+ * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
+   applies if enableToggle = true)
+ * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
+ * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
+  an {@link Roo.util.ClickRepeater} config object (defaults to false).
+ * @constructor
+ * Create a new button
+ * @param {Object} config The config object
+ */
+Roo.Button = function(renderTo, config)
+{
+    if (!config) {
+        config = renderTo;
+        renderTo = config.renderTo || false;
     }
     
+    Roo.apply(this, config);
     this.addEvents({
         /**
-         * @event resize
-         * Fires when the splitter is moved (alias for {@link #event-moved})
-         * @param {Roo.SplitBar} this
-         * @param {Number} newSize the new width or height
-         */
-        "resize" : true,
+            * @event click
+            * Fires when this button is clicked
+            * @param {Button} this
+            * @param {EventObject} e The click event
+            */
+           "click" : true,
         /**
-         * @event moved
-         * Fires when the splitter is moved
-         * @param {Roo.SplitBar} this
-         * @param {Number} newSize the new width or height
-         */
-        "moved" : true,
+            * @event toggle
+            * Fires when the "pressed" state of this button changes (only if enableToggle = true)
+            * @param {Button} this
+            * @param {Boolean} pressed
+            */
+           "toggle" : true,
         /**
-         * @event beforeresize
-         * Fires before the splitter is dragged
-         * @param {Roo.SplitBar} this
-         */
-        "beforeresize" : true,
-
-        "beforeapply" : true
+            * @event mouseover
+            * Fires when the mouse hovers over the button
+            * @param {Button} this
+            * @param {Event} e The event object
+            */
+        'mouseover' : true,
+        /**
+            * @event mouseout
+            * Fires when the mouse exits the button
+            * @param {Button} this
+            * @param {Event} e The event object
+            */
+        'mouseout': true,
+         /**
+            * @event render
+            * Fires when the button is rendered
+            * @param {Button} this
+            */
+        'render': true
     });
-
+    if(this.menu){
+        this.menu = Roo.menu.MenuMgr.get(this.menu);
+    }
+    // register listeners first!!  - so render can be captured..
     Roo.util.Observable.call(this);
+    if(renderTo){
+        this.render(renderTo);
+    }
+    
+  
 };
 
-Roo.extend(Roo.SplitBar, Roo.util.Observable, {
-    onStartProxyDrag : function(x, y){
-        this.fireEvent("beforeresize", this);
-        if(!this.overlay){
-            var o = Roo.DomHelper.insertFirst(document.body,  {cls: "x-drag-overlay", html: "&#160;"}, true);
-            o.unselectable();
-            o.enableDisplayMode("block");
-            // all splitbars share the same overlay
-            Roo.SplitBar.prototype.overlay = o;
-        }
-        this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
-        this.overlay.show();
-        Roo.get(this.proxy).setDisplayed("block");
-        var size = this.adapter.getElementSize(this);
-        this.activeMinSize = this.getMinimumSize();;
-        this.activeMaxSize = this.getMaximumSize();;
-        var c1 = size - this.activeMinSize;
-        var c2 = Math.max(this.activeMaxSize - size, 0);
-        if(this.orientation == Roo.SplitBar.HORIZONTAL){
-            this.dd.resetConstraints();
-            this.dd.setXConstraint(
-                this.placement == Roo.SplitBar.LEFT ? c1 : c2, 
-                this.placement == Roo.SplitBar.LEFT ? c2 : c1
-            );
-            this.dd.setYConstraint(0, 0);
-        }else{
-            this.dd.resetConstraints();
-            this.dd.setXConstraint(0, 0);
-            this.dd.setYConstraint(
-                this.placement == Roo.SplitBar.TOP ? c1 : c2, 
-                this.placement == Roo.SplitBar.TOP ? c2 : c1
-            );
-         }
-        this.dragSpecs.startSize = size;
-        this.dragSpecs.startPoint = [x, y];
-        Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
-    },
-    
-    /** 
-     * @private Called after the drag operation by the DDProxy
+Roo.extend(Roo.Button, Roo.util.Observable, {
+    /**
+     * 
      */
-    onEndProxyDrag : function(e){
-        Roo.get(this.proxy).setDisplayed(false);
-        var endPoint = Roo.lib.Event.getXY(e);
-        if(this.overlay){
-            this.overlay.hide();
-        }
-        var newSize;
-        if(this.orientation == Roo.SplitBar.HORIZONTAL){
-            newSize = this.dragSpecs.startSize + 
-                (this.placement == Roo.SplitBar.LEFT ?
-                    endPoint[0] - this.dragSpecs.startPoint[0] :
-                    this.dragSpecs.startPoint[0] - endPoint[0]
-                );
-        }else{
-            newSize = this.dragSpecs.startSize + 
-                (this.placement == Roo.SplitBar.TOP ?
-                    endPoint[1] - this.dragSpecs.startPoint[1] :
-                    this.dragSpecs.startPoint[1] - endPoint[1]
-                );
-        }
-        newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
-        if(newSize != this.dragSpecs.startSize){
-            if(this.fireEvent('beforeapply', this, newSize) !== false){
-                this.adapter.setElementSize(this, newSize);
-                this.fireEvent("moved", this, newSize);
-                this.fireEvent("resize", this, newSize);
-            }
-        }
-    },
     
     /**
-     * Get the adapter this SplitBar uses
-     * @return The adapter object
+     * Read-only. True if this button is hidden
+     * @type Boolean
      */
-    getAdapter : function(){
-        return this.adapter;
-    },
-    
+    hidden : false,
     /**
-     * Set the adapter this SplitBar uses
-     * @param {Object} adapter A SplitBar adapter object
+     * Read-only. True if this button is disabled
+     * @type Boolean
      */
-    setAdapter : function(adapter){
-        this.adapter = adapter;
-        this.adapter.init(this);
-    },
-    
+    disabled : false,
     /**
-     * Gets the minimum size for the resizing element
-     * @return {Number} The minimum size
+     * Read-only. True if this button is pressed (only if enableToggle = true)
+     * @type Boolean
      */
-    getMinimumSize : function(){
-        return this.minSize;
-    },
-    
+    pressed : false,
+
     /**
-     * Sets the minimum size for the resizing element
-     * @param {Number} minSize The minimum size
+     * @cfg {Number} tabIndex 
+     * The DOM tabIndex for this button (defaults to undefined)
      */
-    setMinimumSize : function(minSize){
-        this.minSize = minSize;
-    },
-    
+    tabIndex : undefined,
+
     /**
-     * Gets the maximum size for the resizing element
-     * @return {Number} The maximum size
+     * @cfg {Boolean} enableToggle
+     * True to enable pressed/not pressed toggling (defaults to false)
      */
-    getMaximumSize : function(){
-        return this.maxSize;
-    },
-    
+    enableToggle: false,
     /**
-     * Sets the maximum size for the resizing element
-     * @param {Number} maxSize The maximum size
+     * @cfg {Mixed} menu
+     * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
      */
-    setMaximumSize : function(maxSize){
-        this.maxSize = maxSize;
-    },
-    
+    menu : undefined,
     /**
-     * Sets the initialize size for the resizing element
-     * @param {Number} size The initial size
+     * @cfg {String} menuAlign
+     * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
      */
-    setCurrentSize : function(size){
-        var oldAnimate = this.animate;
-        this.animate = false;
-        this.adapter.setElementSize(this, size);
-        this.animate = oldAnimate;
-    },
-    
+    menuAlign : "tl-bl?",
+
     /**
-     * Destroy this splitbar. 
-     * @param {Boolean} removeEl True to remove the element
+     * @cfg {String} iconCls
+     * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
      */
-    destroy : function(removeEl){
-        if(this.shim){
-            this.shim.remove();
-        }
-        this.dd.unreg();
-        this.proxy.parentNode.removeChild(this.proxy);
-        if(removeEl){
-            this.el.remove();
-        }
-    }
-});
+    iconCls : undefined,
+    /**
+     * @cfg {String} type
+     * The button's type, corresponding to the DOM input element type attribute.  Either "submit," "reset" or "button" (default).
+     */
+    type : 'button',
 
-/**
- * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
- */
-Roo.SplitBar.createProxy = function(dir){
-    var proxy = new Roo.Element(document.createElement("div"));
-    proxy.unselectable();
-    var cls = 'x-splitbar-proxy';
-    proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
-    document.body.appendChild(proxy.dom);
-    return proxy.dom;
-};
+    // private
+    menuClassTarget: 'tr',
 
-/** 
- * @class Roo.SplitBar.BasicLayoutAdapter
- * Default Adapter. It assumes the splitter and resizing element are not positioned
- * elements and only gets/sets the width of the element. Generally used for table based layouts.
- */
-Roo.SplitBar.BasicLayoutAdapter = function(){
-};
+    /**
+     * @cfg {String} clickEvent
+     * The type of event to map to the button's event handler (defaults to 'click')
+     */
+    clickEvent : 'click',
 
-Roo.SplitBar.BasicLayoutAdapter.prototype = {
-    // do nothing for now
-    init : function(s){
-    
-    },
     /**
-     * Called before drag operations to get the current size of the resizing element. 
-     * @param {Roo.SplitBar} s The SplitBar using this adapter
+     * @cfg {Boolean} handleMouseEvents
+     * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
+     */
+    handleMouseEvents : true,
+
+    /**
+     * @cfg {String} tooltipType
+     * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
+     */
+    tooltipType : 'qtip',
+
+    /**
+     * @cfg {String} cls
+     * A CSS class to apply to the button's main element.
      */
-     getElementSize : function(s){
-        if(s.orientation == Roo.SplitBar.HORIZONTAL){
-            return s.resizingEl.getWidth();
-        }else{
-            return s.resizingEl.getHeight();
-        }
-    },
     
     /**
-     * Called after drag operations to set the size of the resizing element.
-     * @param {Roo.SplitBar} s The SplitBar using this adapter
-     * @param {Number} newSize The new size to set
-     * @param {Function} onComplete A function to be invoked when resizing is complete
+     * @cfg {Roo.Template} template (Optional)
+     * An {@link Roo.Template} with which to create the Button's main element. This Template must
+     * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
+     * require code modifications if required elements (e.g. a button) aren't present.
      */
-    setElementSize : function(s, newSize, onComplete){
-        if(s.orientation == Roo.SplitBar.HORIZONTAL){
-            if(!s.animate){
-                s.resizingEl.setWidth(newSize);
-                if(onComplete){
-                    onComplete(s, newSize);
+
+    // private
+    render : function(renderTo){
+        var btn;
+        if(this.hideParent){
+            this.parentEl = Roo.get(renderTo);
+        }
+        if(!this.dhconfig){
+            if(!this.template){
+                if(!Roo.Button.buttonTemplate){
+                    // hideous table template
+                    Roo.Button.buttonTemplate = new Roo.Template(
+                        '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
+                        '<td class="x-btn-left"><i>&#160;</i></td><td class="x-btn-center"><em unselectable="on"><button class="x-btn-text" type="{1}">{0}</button></em></td><td class="x-btn-right"><i>&#160;</i></td>',
+                        "</tr></tbody></table>");
                 }
-            }else{
-                s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
+                this.template = Roo.Button.buttonTemplate;
             }
-        }else{
-            
-            if(!s.animate){
-                s.resizingEl.setHeight(newSize);
-                if(onComplete){
-                    onComplete(s, newSize);
+            btn = this.template.append(renderTo, [this.text || '&#160;', this.type], true);
+            var btnEl = btn.child("button:first");
+            btnEl.on('focus', this.onFocus, this);
+            btnEl.on('blur', this.onBlur, this);
+            if(this.cls){
+                btn.addClass(this.cls);
+            }
+            if(this.icon){
+                btnEl.setStyle('background-image', 'url(' +this.icon +')');
+            }
+            if(this.iconCls){
+                btnEl.addClass(this.iconCls);
+                if(!this.cls){
+                    btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
                 }
-            }else{
-                s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
             }
-        }
-    }
-};
-
-/** 
- *@class Roo.SplitBar.AbsoluteLayoutAdapter
- * @extends Roo.SplitBar.BasicLayoutAdapter
- * Adapter that  moves the splitter element to align with the resized sizing element. 
- * Used with an absolute positioned SplitBar.
- * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
- * document.body, make sure you assign an id to the body element.
- */
-Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
-    this.basic = new Roo.SplitBar.BasicLayoutAdapter();
-    this.container = Roo.get(container);
-};
-
-Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
-    init : function(s){
-        this.basic.init(s);
+            if(this.tabIndex !== undefined){
+                btnEl.dom.tabIndex = this.tabIndex;
+            }
+            if(this.tooltip){
+                if(typeof this.tooltip == 'object'){
+                    Roo.QuickTips.tips(Roo.apply({
+                          target: btnEl.id
+                    }, this.tooltip));
+                } else {
+                    btnEl.dom[this.tooltipType] = this.tooltip;
+                }
+            }
+        }else{
+            btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
+        }
+        this.el = btn;
+        if(this.id){
+            this.el.dom.id = this.el.id = this.id;
+        }
+        if(this.menu){
+            this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
+            this.menu.on("show", this.onMenuShow, this);
+            this.menu.on("hide", this.onMenuHide, this);
+        }
+        btn.addClass("x-btn");
+        if(Roo.isIE && !Roo.isIE7){
+            this.autoWidth.defer(1, this);
+        }else{
+            this.autoWidth();
+        }
+        if(this.handleMouseEvents){
+            btn.on("mouseover", this.onMouseOver, this);
+            btn.on("mouseout", this.onMouseOut, this);
+            btn.on("mousedown", this.onMouseDown, this);
+        }
+        btn.on(this.clickEvent, this.onClick, this);
+        //btn.on("mouseup", this.onMouseUp, this);
+        if(this.hidden){
+            this.hide();
+        }
+        if(this.disabled){
+            this.disable();
+        }
+        Roo.ButtonToggleMgr.register(this);
+        if(this.pressed){
+            this.el.addClass("x-btn-pressed");
+        }
+        if(this.repeat){
+            var repeater = new Roo.util.ClickRepeater(btn,
+                typeof this.repeat == "object" ? this.repeat : {}
+            );
+            repeater.on("click", this.onClick,  this);
+        }
+        
+        this.fireEvent('render', this);
+        
     },
-    
-    getElementSize : function(s){
-        return this.basic.getElementSize(s);
+    /**
+     * Returns the button's underlying element
+     * @return {Roo.Element} The element
+     */
+    getEl : function(){
+        return this.el;  
     },
     
-    setElementSize : function(s, newSize, onComplete){
-        this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
+    /**
+     * Destroys this Button and removes any listeners.
+     */
+    destroy : function(){
+        Roo.ButtonToggleMgr.unregister(this);
+        this.el.removeAllListeners();
+        this.purgeListeners();
+        this.el.remove();
     },
-    
-    moveSplitter : function(s){
-        var yes = Roo.SplitBar;
-        switch(s.placement){
-            case yes.LEFT:
-                s.el.setX(s.resizingEl.getRight());
-                break;
-            case yes.RIGHT:
-                s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
-                break;
-            case yes.TOP:
-                s.el.setY(s.resizingEl.getBottom());
-                break;
-            case yes.BOTTOM:
-                s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
-                break;
-        }
-    }
-};
-
-/**
- * Orientation constant - Create a vertical SplitBar
- * @static
- * @type Number
- */
-Roo.SplitBar.VERTICAL = 1;
-
-/**
- * Orientation constant - Create a horizontal SplitBar
- * @static
- * @type Number
- */
-Roo.SplitBar.HORIZONTAL = 2;
-
-/**
- * Placement constant - The resizing element is to the left of the splitter element
- * @static
- * @type Number
- */
-Roo.SplitBar.LEFT = 1;
-
-/**
- * Placement constant - The resizing element is to the right of the splitter element
- * @static
- * @type Number
- */
-Roo.SplitBar.RIGHT = 2;
-
-/**
- * Placement constant - The resizing element is positioned above the splitter element
- * @static
- * @type Number
- */
-Roo.SplitBar.TOP = 3;
-
-/**
- * Placement constant - The resizing element is positioned under splitter element
- * @static
- * @type Number
- */
-Roo.SplitBar.BOTTOM = 4;
-/*
- * 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.View
- * @extends Roo.util.Observable
- * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
- * This class also supports single and multi selection modes. <br>
- * Create a data model bound view:
- <pre><code>
- var store = new Roo.data.Store(...);
-
- var view = new Roo.View({
-    el : "my-element",
-    tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
-    singleSelect: true,
-    selectedClass: "ydataview-selected",
-    store: store
- });
-
- // listen for node click?
- view.on("click", function(vw, index, node, e){
- alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
- });
-
- // load XML data
- dataModel.load("foobar.xml");
- </code></pre>
- For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
- * <br><br>
- * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
- * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
- * 
- * Note: old style constructor is still suported (container, template, config)
- * 
- * @constructor
- * Create a new View
- * @param {Object} config The config object
- * 
- */
-Roo.View = function(config, depreciated_tpl, depreciated_config){
-    
-    if (typeof(depreciated_tpl) == 'undefined') {
-        // new way.. - universal constructor.
-        Roo.apply(this, config);
-        this.el  = Roo.get(this.el);
-    } else {
-        // old format..
-        this.el  = Roo.get(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);
-    } else {
-        // support xtype ctors..
-        this.tpl = new Roo.factory(this.tpl, Roo);
-    }
-    
-    
-    this.tpl.compile();
-   
-  
-    
-     
-    /** @private */
-    this.addEvents({
-        /**
-         * @event beforeclick
-         * Fires before a click is processed. Returns false to cancel the default action.
-         * @param {Roo.View} this
-         * @param {Number} index The index of the target node
-         * @param {HTMLElement} node The target node
-         * @param {Roo.EventObject} e The raw event object
-         */
-            "beforeclick" : true,
-        /**
-         * @event click
-         * Fires when a template node is clicked.
-         * @param {Roo.View} this
-         * @param {Number} index The index of the target node
-         * @param {HTMLElement} node The target node
-         * @param {Roo.EventObject} e The raw event object
-         */
-            "click" : true,
-        /**
-         * @event dblclick
-         * Fires when a template node is double clicked.
-         * @param {Roo.View} this
-         * @param {Number} index The index of the target node
-         * @param {HTMLElement} node The target node
-         * @param {Roo.EventObject} e The raw event object
-         */
-            "dblclick" : true,
-        /**
-         * @event contextmenu
-         * Fires when a template node is right clicked.
-         * @param {Roo.View} this
-         * @param {Number} index The index of the target node
-         * @param {HTMLElement} node The target node
-         * @param {Roo.EventObject} e The raw event object
-         */
-            "contextmenu" : true,
-        /**
-         * @event selectionchange
-         * Fires when the selected nodes change.
-         * @param {Roo.View} this
-         * @param {Array} selections Array of the selected nodes
-         */
-            "selectionchange" : true,
-    
-        /**
-         * @event beforeselect
-         * Fires before a selection is made. If any handlers return false, the selection is cancelled.
-         * @param {Roo.View} this
-         * @param {HTMLElement} node The node to be selected
-         * @param {Array} selections Array of currently selected nodes
-         */
-            "beforeselect" : true,
-        /**
-         * @event preparedata
-         * Fires on every row to render, to allow you to change the data.
-         * @param {Roo.View} this
-         * @param {Object} data to be rendered (change this)
-         */
-          "preparedata" : true
-          
-          
-        });
-
-
-
-    this.el.on({
-        "click": this.onClick,
-        "dblclick": this.onDblClick,
-        "contextmenu": this.onContextMenu,
-        scope:this
-    });
 
-    this.selections = [];
-    this.nodes = [];
-    this.cmp = new Roo.CompositeElementLite([]);
-    if(this.store){
-        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);
-    
-    
-};
+    // private
+    autoWidth : function(){
+        if(this.el){
+            this.el.setWidth("auto");
+            if(Roo.isIE7 && Roo.isStrict){
+                var ib = this.el.child('button');
+                if(ib && ib.getWidth() > 20){
+                    ib.clip();
+                    ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
+                }
+            }
+            if(this.minWidth){
+                if(this.hidden){
+                    this.el.beginMeasure();
+                }
+                if(this.el.getWidth() < this.minWidth){
+                    this.el.setWidth(this.minWidth);
+                }
+                if(this.hidden){
+                    this.el.endMeasure();
+                }
+            }
+        }
+    },
 
-Roo.extend(Roo.View, Roo.util.Observable, {
-    
-     /**
-     * @cfg {Roo.data.Store} store Data store to load data from.
-     */
-    store : false,
-    
     /**
-     * @cfg {String|Roo.Element} el The container element.
+     * Assigns this button's click handler
+     * @param {Function} handler The function to call when the button is clicked
+     * @param {Object} scope (optional) Scope for the function passed in
      */
-    el : '',
+    setHandler : function(handler, scope){
+        this.handler = handler;
+        this.scope = scope;  
+    },
     
     /**
-     * @cfg {String|Roo.Template} tpl The template used by this View 
+     * Sets this button's text
+     * @param {String} text The button text
      */
-    tpl : false,
+    setText : function(text){
+        this.text = text;
+        if(this.el){
+            this.el.child("td.x-btn-center button.x-btn-text").update(text);
+        }
+        this.autoWidth();
+    },
+    
     /**
-     * @cfg {String} dataName the named area of the template to use as the data area
-     *                          Works with domtemplates roo-name="name"
+     * Gets the text for this button
+     * @return {String} The button text
      */
-    dataName: false,
+    getText : function(){
+        return this.text;  
+    },
+    
     /**
-     * @cfg {String} selectedClass The css class to add to selected nodes
-     */
-    selectedClass : "x-view-selected",
-     /**
-     * @cfg {String} emptyText The empty text to show when nothing is loaded.
+     * Show this button
      */
-    emptyText : "",
+    show: function(){
+        this.hidden = false;
+        if(this.el){
+            this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
+        }
+    },
     
     /**
-     * @cfg {String} text to display on mask (default Loading)
+     * Hide this button
      */
-    mask : false,
+    hide: function(){
+        this.hidden = true;
+        if(this.el){
+            this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
+        }
+    },
+    
     /**
-     * @cfg {Boolean} multiSelect Allow multiple selection
+     * Convenience function for boolean show/hide
+     * @param {Boolean} visible True to show, false to hide
      */
-    multiSelect : false,
+    setVisible: function(visible){
+        if(visible) {
+            this.show();
+        }else{
+            this.hide();
+        }
+    },
+    
     /**
-     * @cfg {Boolean} singleSelect Allow single selection
+     * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
+     * @param {Boolean} state (optional) Force a particular state
      */
-    singleSelect:  false,
+    toggle : function(state){
+        state = state === undefined ? !this.pressed : state;
+        if(state != this.pressed){
+            if(state){
+                this.el.addClass("x-btn-pressed");
+                this.pressed = true;
+                this.fireEvent("toggle", this, true);
+            }else{
+                this.el.removeClass("x-btn-pressed");
+                this.pressed = false;
+                this.fireEvent("toggle", this, false);
+            }
+            if(this.toggleHandler){
+                this.toggleHandler.call(this.scope || this, this, state);
+            }
+        }
+    },
     
     /**
-     * @cfg {Boolean} toggleSelect - selecting 
+     * Focus the button
      */
-    toggleSelect : false,
+    focus : function(){
+        this.el.child('button:first').focus();
+    },
     
     /**
-     * Returns the element this view is bound to.
-     * @return {Roo.Element}
+     * Disable this button
      */
-    getEl : function(){
-        return this.wrapEl;
+    disable : function(){
+        if(this.el){
+            this.el.addClass("x-btn-disabled");
+        }
+        this.disabled = true;
     },
     
-    
-
     /**
-     * Refreshes the view. - called by datachanged on the store. - do not call directly.
+     * Enable this button
      */
-    refresh : function(){
-        var t = this.tpl;
-        
-        // if we are using something like 'domtemplate', then
-        // the what gets used is:
-        // t.applySubtemplate(NAME, data, wrapping data..)
-        // the outer template then get' applied with
-        //     the store 'extra data'
-        // and the body get's added to the
-        //      roo-name="data" node?
-        //      <span class='roo-tpl-{name}'></span> ?????
-        
-        
-        
-        this.clearSelections();
-        this.el.update("");
-        var html = [];
-        var records = this.store.getRange();
-        if(records.length < 1) {
-            
-            // is this valid??  = should it render a template??
-            
-            this.el.update(this.emptyText);
-            return;
-        }
-        var el = this.el;
-        if (this.dataName) {
-            this.el.update(t.apply(this.store.meta)); //????
-            el = this.el.child('.roo-tpl-' + this.dataName);
-        }
-        
-        for(var i = 0, len = records.length; i < len; i++){
-            var data = this.prepareData(records[i].data, i, records[i]);
-            this.fireEvent("preparedata", this, data, i, records[i]);
-            html[html.length] = Roo.util.Format.trim(
-                this.dataName ?
-                    t.applySubtemplate(this.dataName, data, this.store.meta) :
-                    t.apply(data)
-            );
+    enable : function(){
+        if(this.el){
+            this.el.removeClass("x-btn-disabled");
         }
-        
-        
-        
-        el.update(html.join(""));
-        this.nodes = el.dom.childNodes;
-        this.updateIndexes(0);
+        this.disabled = false;
     },
 
     /**
-     * Function to override to reformat the data that is sent to
-     * the template for each node.
-     * DEPRICATED - use the preparedata event handler.
-     * @param {Array/Object} data The raw data (array of colData for a data model bound view or
-     * a JSON object for an UpdateManager bound view).
+     * Convenience function for boolean enable/disable
+     * @param {Boolean} enabled True to enable, false to disable
      */
-    prepareData : function(data, index, record)
-    {
-        this.fireEvent("preparedata", this, data, index, record);
-        return data;
-    },
-
-    onUpdate : function(ds, record){
-        this.clearSelections();
-        var index = this.store.indexOf(record);
-        var n = this.nodes[index];
-        this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
-        n.parentNode.removeChild(n);
-        this.updateIndexes(index, index);
+    setDisabled : function(v){
+        this[v !== true ? "enable" : "disable"]();
     },
 
-    
-    
-// --------- FIXME     
-    onAdd : function(ds, records, index)
+    // private
+    onClick : function(e)
     {
-        this.clearSelections();
-        if(this.nodes.length == 0){
-            this.refresh();
+        if(e){
+            e.preventDefault();
+        }
+        if(e.button != 0){
             return;
         }
-        var n = this.nodes[index];
-        for(var i = 0, len = records.length; i < len; i++){
-            var d = this.prepareData(records[i].data, i, records[i]);
-            if(n){
-                this.tpl.insertBefore(n, d);
-            }else{
-                
-                this.tpl.append(this.el, d);
+        if(!this.disabled){
+            if(this.enableToggle){
+                this.toggle();
+            }
+            if(this.menu && !this.menu.isVisible()){
+                this.menu.show(this.el, this.menuAlign);
+            }
+            this.fireEvent("click", this, e);
+            if(this.handler){
+                this.el.removeClass("x-btn-over");
+                this.handler.call(this.scope || this, this, e);
             }
         }
-        this.updateIndexes(index);
-    },
-
-    onRemove : function(ds, record, index){
-        this.clearSelections();
-        var el = this.dataName  ?
-            this.el.child('.roo-tpl-' + this.dataName) :
-            this.el; 
-        el.dom.removeChild(this.nodes[index]);
-        this.updateIndexes(index);
-    },
-
-    /**
-     * Refresh an individual node.
-     * @param {Number} index
-     */
-    refreshNode : function(index){
-        this.onUpdate(this.store, this.store.getAt(index));
     },
-
-    updateIndexes : function(startIndex, endIndex){
-        var ns = this.nodes;
-        startIndex = startIndex || 0;
-        endIndex = endIndex || ns.length - 1;
-        for(var i = startIndex; i <= endIndex; i++){
-            ns[i].nodeIndex = i;
+    // private
+    onMouseOver : function(e){
+        if(!this.disabled){
+            this.el.addClass("x-btn-over");
+            this.fireEvent('mouseover', this, e);
         }
     },
-
-    /**
-     * Changes the data store this view uses and refresh the view.
-     * @param {Store} store
-     */
-    setStore : function(store, initial){
-        if(!initial && this.store){
-            this.store.un("datachanged", this.refresh);
-            this.store.un("add", this.onAdd);
-            this.store.un("remove", this.onRemove);
-            this.store.un("update", this.onUpdate);
-            this.store.un("clear", this.refresh);
-            this.store.un("beforeload", this.onBeforeLoad);
-            this.store.un("load", this.onLoad);
-            this.store.un("loadexception", this.onLoad);
+    // private
+    onMouseOut : function(e){
+        if(!e.within(this.el,  true)){
+            this.el.removeClass("x-btn-over");
+            this.fireEvent('mouseout', this, e);
         }
-        if(store){
-          
-            store.on("datachanged", this.refresh, this);
-            store.on("add", this.onAdd, this);
-            store.on("remove", this.onRemove, this);
-            store.on("update", this.onUpdate, this);
-            store.on("clear", this.refresh, this);
-            store.on("beforeload", this.onBeforeLoad, this);
-            store.on("load", this.onLoad, this);
-            store.on("loadexception", this.onLoad, this);
+    },
+    // private
+    onFocus : function(e){
+        if(!this.disabled){
+            this.el.addClass("x-btn-focus");
         }
-        
-        if(store){
-            this.refresh();
+    },
+    // private
+    onBlur : function(e){
+        this.el.removeClass("x-btn-focus");
+    },
+    // private
+    onMouseDown : function(e){
+        if(!this.disabled && e.button == 0){
+            this.el.addClass("x-btn-click");
+            Roo.get(document).on('mouseup', this.onMouseUp, this);
         }
     },
-    /**
-     * onbeforeLoad - masks the loading area.
-     *
-     */
-    onBeforeLoad : function()
-    {
-        this.el.update("");
-        this.el.mask(this.mask ? this.mask : "Loading" ); 
+    // private
+    onMouseUp : function(e){
+        if(e.button == 0){
+            this.el.removeClass("x-btn-click");
+            Roo.get(document).un('mouseup', this.onMouseUp, this);
+        }
     },
-    onLoad : function ()
-    {
-        this.el.unmask();
+    // private
+    onMenuShow : function(e){
+        this.el.addClass("x-btn-menu-active");
     },
-    
+    // private
+    onMenuHide : function(e){
+        this.el.removeClass("x-btn-menu-active");
+    }   
+});
 
+// Private utility class used by Button
+Roo.ButtonToggleMgr = function(){
+   var groups = {};
+   
+   function toggleGroup(btn, state){
+       if(state){
+           var g = groups[btn.toggleGroup];
+           for(var i = 0, l = g.length; i < l; i++){
+               if(g[i] != btn){
+                   g[i].toggle(false);
+               }
+           }
+       }
+   }
+   
+   return {
+       register : function(btn){
+           if(!btn.toggleGroup){
+               return;
+           }
+           var g = groups[btn.toggleGroup];
+           if(!g){
+               g = groups[btn.toggleGroup] = [];
+           }
+           g.push(btn);
+           btn.on("toggle", toggleGroup);
+       },
+       
+       unregister : function(btn){
+           if(!btn.toggleGroup){
+               return;
+           }
+           var g = groups[btn.toggleGroup];
+           if(g){
+               g.remove(btn);
+               btn.un("toggle", toggleGroup);
+           }
+       }
+   };
+}();/*
+ * 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.SplitButton
+ * @extends Roo.Button
+ * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
+ * click event of the button.  Typically this would be used to display a dropdown menu that provides additional
+ * options to the primary button action, but any custom handler can provide the arrowclick implementation.
+ * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
+ * @cfg {String} arrowTooltip The title attribute of the arrow
+ * @constructor
+ * Create a new menu button
+ * @param {String/HTMLElement/Element} renderTo The element to append the button to
+ * @param {Object} config The config object
+ */
+Roo.SplitButton = function(renderTo, config){
+    Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
     /**
-     * Returns the template node the passed child belongs to or null if it doesn't belong to one.
-     * @param {HTMLElement} node
-     * @return {HTMLElement} The template node
+     * @event arrowclick
+     * Fires when this button's arrow is clicked
+     * @param {SplitButton} this
+     * @param {EventObject} e The click event
      */
-    findItemFromChild : function(node){
-        var el = this.dataName  ?
-            this.el.child('.roo-tpl-' + this.dataName,true) :
-            this.el.dom; 
-        
-        if(!node || node.parentNode == el){
-                   return node;
-           }
-           var p = node.parentNode;
-           while(p && p != el){
-            if(p.parentNode == el){
-               return p;
+    this.addEvents({"arrowclick":true});
+};
+
+Roo.extend(Roo.SplitButton, Roo.Button, {
+    render : function(renderTo){
+        // this is one sweet looking template!
+        var tpl = new Roo.Template(
+            '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
+            '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
+            '<tr><td class="x-btn-left"><i>&#160;</i></td><td class="x-btn-center"><button class="x-btn-text" type="{1}">{0}</button></td></tr>',
+            "</tbody></table></td><td>",
+            '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
+            '<tr><td class="x-btn-center"><button class="x-btn-menu-arrow-el" type="button">&#160;</button></td><td class="x-btn-right"><i>&#160;</i></td></tr>',
+            "</tbody></table></td></tr></table>"
+        );
+        var btn = tpl.append(renderTo, [this.text, this.type], true);
+        var btnEl = btn.child("button");
+        if(this.cls){
+            btn.addClass(this.cls);
+        }
+        if(this.icon){
+            btnEl.setStyle('background-image', 'url(' +this.icon +')');
+        }
+        if(this.iconCls){
+            btnEl.addClass(this.iconCls);
+            if(!this.cls){
+                btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
             }
-            p = p.parentNode;
         }
-           return null;
-    },
-
-    /** @ignore */
-    onClick : function(e){
-        var item = this.findItemFromChild(e.getTarget());
-        if(item){
-            var index = this.indexOf(item);
-            if(this.onItemClick(item, index, e) !== false){
-                this.fireEvent("click", this, index, item, e);
+        this.el = btn;
+        if(this.handleMouseEvents){
+            btn.on("mouseover", this.onMouseOver, this);
+            btn.on("mouseout", this.onMouseOut, this);
+            btn.on("mousedown", this.onMouseDown, this);
+            btn.on("mouseup", this.onMouseUp, this);
+        }
+        btn.on(this.clickEvent, this.onClick, this);
+        if(this.tooltip){
+            if(typeof this.tooltip == 'object'){
+                Roo.QuickTips.tips(Roo.apply({
+                      target: btnEl.id
+                }, this.tooltip));
+            } else {
+                btnEl.dom[this.tooltipType] = this.tooltip;
             }
-        }else{
-            this.clearSelections();
         }
-    },
-
-    /** @ignore */
-    onContextMenu : function(e){
-        var item = this.findItemFromChild(e.getTarget());
-        if(item){
-            this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
+        if(this.arrowTooltip){
+            btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
         }
-    },
-
-    /** @ignore */
-    onDblClick : function(e){
-        var item = this.findItemFromChild(e.getTarget());
-        if(item){
-            this.fireEvent("dblclick", this, this.indexOf(item), item, e);
+        if(this.hidden){
+            this.hide();
         }
-    },
-
-    onItemClick : function(item, index, e)
-    {
-        if(this.fireEvent("beforeclick", this, index, item, e) === false){
-            return false;
+        if(this.disabled){
+            this.disable();
         }
-        if (this.toggleSelect) {
-            var m = this.isSelected(item) ? 'unselect' : 'select';
-            Roo.log(m);
-            var _t = this;
-            _t[m](item, true, false);
-            return true;
+        if(this.pressed){
+            this.el.addClass("x-btn-pressed");
         }
-        if(this.multiSelect || this.singleSelect){
-            if(this.multiSelect && e.shiftKey && this.lastSelection){
-                this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
-            }else{
-                this.select(item, this.multiSelect && e.ctrlKey);
-                this.lastSelection = item;
-            }
-            e.preventDefault();
+        if(Roo.isIE && !Roo.isIE7){
+            this.autoWidth.defer(1, this);
+        }else{
+            this.autoWidth();
         }
-        return true;
+        if(this.menu){
+            this.menu.on("show", this.onMenuShow, this);
+            this.menu.on("hide", this.onMenuHide, this);
+        }
+        this.fireEvent('render', this);
     },
 
+    // private
+    autoWidth : function(){
+        if(this.el){
+            var tbl = this.el.child("table:first");
+            var tbl2 = this.el.child("table:last");
+            this.el.setWidth("auto");
+            tbl.setWidth("auto");
+            if(Roo.isIE7 && Roo.isStrict){
+                var ib = this.el.child('button:first');
+                if(ib && ib.getWidth() > 20){
+                    ib.clip();
+                    ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
+                }
+            }
+            if(this.minWidth){
+                if(this.hidden){
+                    this.el.beginMeasure();
+                }
+                if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
+                    tbl.setWidth(this.minWidth-tbl2.getWidth());
+                }
+                if(this.hidden){
+                    this.el.endMeasure();
+                }
+            }
+            this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
+        } 
+    },
     /**
-     * Get the number of selected nodes.
-     * @return {Number}
+     * Sets this button's click handler
+     * @param {Function} handler The function to call when the button is clicked
+     * @param {Object} scope (optional) Scope for the function passed above
      */
-    getSelectionCount : function(){
-        return this.selections.length;
+    setHandler : function(handler, scope){
+        this.handler = handler;
+        this.scope = scope;  
     },
-
+    
     /**
-     * Get the currently selected nodes.
-     * @return {Array} An array of HTMLElements
+     * Sets this button's arrow click handler
+     * @param {Function} handler The function to call when the arrow is clicked
+     * @param {Object} scope (optional) Scope for the function passed above
      */
-    getSelectedNodes : function(){
-        return this.selections;
+    setArrowHandler : function(handler, scope){
+        this.arrowHandler = handler;
+        this.scope = scope;  
     },
-
+    
     /**
-     * Get the indexes of the selected nodes.
-     * @return {Array}
+     * Focus the button
      */
-    getSelectedIndexes : function(){
-        var indexes = [], s = this.selections;
-        for(var i = 0, len = s.length; i < len; i++){
-            indexes.push(s[i].nodeIndex);
+    focus : function(){
+        if(this.el){
+            this.el.child("button:first").focus();
         }
-        return indexes;
     },
 
-    /**
-     * Clear all selections
-     * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
-     */
-    clearSelections : function(suppressEvent){
-        if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
-            this.cmp.elements = this.selections;
-            this.cmp.removeClass(this.selectedClass);
-            this.selections = [];
-            if(!suppressEvent){
-                this.fireEvent("selectionchange", this, this.selections);
+    // private
+    onClick : function(e){
+        e.preventDefault();
+        if(!this.disabled){
+            if(e.getTarget(".x-btn-menu-arrow-wrap")){
+                if(this.menu && !this.menu.isVisible()){
+                    this.menu.show(this.el, this.menuAlign);
+                }
+                this.fireEvent("arrowclick", this, e);
+                if(this.arrowHandler){
+                    this.arrowHandler.call(this.scope || this, this, e);
+                }
+            }else{
+                this.fireEvent("click", this, e);
+                if(this.handler){
+                    this.handler.call(this.scope || this, this, e);
+                }
             }
         }
     },
-
-    /**
-     * Returns true if the passed node is selected
-     * @param {HTMLElement/Number} node The node or node index
-     * @return {Boolean}
-     */
-    isSelected : function(node){
-        var s = this.selections;
-        if(s.length < 1){
-            return false;
+    // private
+    onMouseDown : function(e){
+        if(!this.disabled){
+            Roo.fly(e.getTarget("table")).addClass("x-btn-click");
         }
-        node = this.getNode(node);
-        return s.indexOf(node) !== -1;
     },
+    // private
+    onMouseUp : function(e){
+        Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
+    }   
+});
+
+
+// backwards compat
+Roo.MenuButton = Roo.SplitButton;/*
+ * 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.Toolbar
+ * Basic Toolbar class.
+ * @constructor
+ * Creates a new Toolbar
+ * @param {Object} container The config object
+ */ 
+Roo.Toolbar = function(container, buttons, config)
+{
+    /// old consturctor format still supported..
+    if(container instanceof Array){ // omit the container for later rendering
+        buttons = container;
+        config = buttons;
+        container = null;
+    }
+    if (typeof(container) == 'object' && container.xtype) {
+        config = container;
+        container = config.container;
+        buttons = config.buttons || []; // not really - use items!!
+    }
+    var xitems = [];
+    if (config && config.items) {
+        xitems = config.items;
+        delete config.items;
+    }
+    Roo.apply(this, config);
+    this.buttons = buttons;
+    
+    if(container){
+        this.render(container);
+    }
+    this.xitems = xitems;
+    Roo.each(xitems, function(b) {
+        this.add(b);
+    }, this);
+    
+};
 
+Roo.Toolbar.prototype = {
     /**
-     * Selects nodes.
-     * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
-     * @param {Boolean} keepExisting (optional) true to keep existing selections
-     * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
+     * @cfg {Array} items
+     * array of button configs or elements to add (will be converted to a MixedCollection)
      */
-    select : function(nodeInfo, keepExisting, suppressEvent){
-        if(nodeInfo instanceof Array){
-            if(!keepExisting){
-                this.clearSelections(true);
-            }
-            for(var i = 0, len = nodeInfo.length; i < len; i++){
-                this.select(nodeInfo[i], true, true);
-            }
-            return;
-        } 
-        var node = this.getNode(nodeInfo);
-        if(!node || this.isSelected(node)){
-            return; // already selected.
-        }
-        if(!keepExisting){
-            this.clearSelections(true);
-        }
-        if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
-            Roo.fly(node).addClass(this.selectedClass);
-            this.selections.push(node);
-            if(!suppressEvent){
-                this.fireEvent("selectionchange", this, this.selections);
-            }
-        }
-        
-        
-    },
-      /**
-     * Unselects nodes.
-     * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
-     * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
-     * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
+    
+    /**
+     * @cfg {String/HTMLElement/Element} container
+     * The id or element that will contain the toolbar
      */
-    unselect : function(nodeInfo, keepExisting, suppressEvent)
-    {
-        if(nodeInfo instanceof Array){
-            Roo.each(this.selections, function(s) {
-                this.unselect(s, nodeInfo);
-            }, this);
-            return;
+    // private
+    render : function(ct){
+        this.el = Roo.get(ct);
+        if(this.cls){
+            this.el.addClass(this.cls);
         }
-        var node = this.getNode(nodeInfo);
-        if(!node || !this.isSelected(node)){
-            Roo.log("not selected");
-            return; // not selected.
+        // using a table allows for vertical alignment
+        // 100% width is needed by Safari...
+        this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
+        this.tr = this.el.child("tr", true);
+        var autoId = 0;
+        this.items = new Roo.util.MixedCollection(false, function(o){
+            return o.id || ("item" + (++autoId));
+        });
+        if(this.buttons){
+            this.add.apply(this, this.buttons);
+            delete this.buttons;
         }
-        // fireevent???
-        var ns = [];
-        Roo.each(this.selections, function(s) {
-            if (s == node ) {
-                Roo.fly(node).removeClass(this.selectedClass);
-
-                return;
-            }
-            ns.push(s);
-        },this);
-        
-        this.selections= ns;
-        this.fireEvent("selectionchange", this, this.selections);
     },
 
     /**
-     * Gets a template node.
-     * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
-     * @return {HTMLElement} The node or null if it wasn't found
+     * Adds element(s) to the toolbar -- this function takes a variable number of 
+     * arguments of mixed type and adds them to the toolbar.
+     * @param {Mixed} arg1 The following types of arguments are all valid:<br />
+     * <ul>
+     * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
+     * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
+     * <li>Field: Any form field (equivalent to {@link #addField})</li>
+     * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
+     * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
+     * Note that there are a few special strings that are treated differently as explained nRoo.</li>
+     * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
+     * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
+     * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
+     * </ul>
+     * @param {Mixed} arg2
+     * @param {Mixed} etc.
      */
-    getNode : function(nodeInfo){
-        if(typeof nodeInfo == "string"){
-            return document.getElementById(nodeInfo);
-        }else if(typeof nodeInfo == "number"){
-            return this.nodes[nodeInfo];
+    add : function(){
+        var a = arguments, l = a.length;
+        for(var i = 0; i < l; i++){
+            this._add(a[i]);
         }
-        return nodeInfo;
     },
-
-    /**
-     * Gets a range template nodes.
-     * @param {Number} startIndex
-     * @param {Number} endIndex
-     * @return {Array} An array of nodes
-     */
-    getNodes : function(start, end){
-        var ns = this.nodes;
-        start = start || 0;
-        end = typeof end == "undefined" ? ns.length - 1 : end;
-        var nodes = [];
-        if(start <= end){
-            for(var i = start; i <= end; i++){
-                nodes.push(ns[i]);
+    // private..
+    _add : function(el) {
+        
+        if (el.xtype) {
+            el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
+        }
+        
+        if (el.applyTo){ // some kind of form field
+            return this.addField(el);
+        } 
+        if (el.render){ // some kind of Toolbar.Item
+            return this.addItem(el);
+        }
+        if (typeof el == "string"){ // string
+            if(el == "separator" || el == "-"){
+                return this.addSeparator();
             }
-        } else{
-            for(var i = start; i >= end; i--){
-                nodes.push(ns[i]);
+            if (el == " "){
+                return this.addSpacer();
+            }
+            if(el == "->"){
+                return this.addFill();
             }
+            return this.addText(el);
+            
         }
-        return nodes;
+        if(el.tagName){ // element
+            return this.addElement(el);
+        }
+        if(typeof el == "object"){ // must be button config?
+            return this.addButton(el);
+        }
+        // and now what?!?!
+        return false;
+        
     },
-
+    
     /**
-     * Finds the index of the passed node
-     * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
-     * @return {Number} The index of the node or -1
+     * Add an Xtype element
+     * @param {Object} xtype Xtype Object
+     * @return {Object} created Object
      */
-    indexOf : function(node){
-        node = this.getNode(node);
-        if(typeof node.nodeIndex == "number"){
-            return node.nodeIndex;
-        }
-        var ns = this.nodes;
-        for(var i = 0, len = ns.length; i < len; i++){
-            if(ns[i] == node){
-                return i;
-            }
-        }
-        return -1;
-    }
-});
-/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-
-/**
- * @class Roo.JsonView
- * @extends Roo.View
- * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
-<pre><code>
-var view = new Roo.JsonView({
-    container: "my-element",
-    tpl: '&lt;div id="{id}"&gt;{foo} - {bar}&lt;/div&gt;', // auto create template
-    multiSelect: true, 
-    jsonRoot: "data" 
-});
-
-// listen for node click?
-view.on("click", function(vw, index, node, e){
-    alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
-});
-
-// direct load of JSON data
-view.load("foobar.php");
-
-// Example from my blog list
-var tpl = new Roo.Template(
-    '&lt;div class="entry"&gt;' +
-    '&lt;a class="entry-title" href="{link}"&gt;{title}&lt;/a&gt;' +
-    "&lt;h4&gt;{date} by {author} | {comments} Comments&lt;/h4&gt;{description}" +
-    "&lt;/div&gt;&lt;hr /&gt;"
-);
-
-var moreView = new Roo.JsonView({
-    container :  "entry-list", 
-    template : tpl,
-    jsonRoot: "posts"
-});
-moreView.on("beforerender", this.sortEntries, this);
-moreView.load({
-    url: "/blog/get-posts.php",
-    params: "allposts=true",
-    text: "Loading Blog Entries..."
-});
-</code></pre>
-* 
-* Note: old code is supported with arguments : (container, template, config)
-* 
-* 
- * @constructor
- * Create a new JsonView
- * 
- * @param {Object} config The config object
- * 
- */
-Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
+    addxtype : function(e){
+        return this.add(e);  
+    },
     
+    /**
+     * Returns the Element for this toolbar.
+     * @return {Roo.Element}
+     */
+    getEl : function(){
+        return this.el;  
+    },
     
-    Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
+    /**
+     * Adds a separator
+     * @return {Roo.Toolbar.Item} The separator item
+     */
+    addSeparator : function(){
+        return this.addItem(new Roo.Toolbar.Separator());
+    },
 
-    var um = this.el.getUpdateManager();
-    um.setRenderer(this);
-    um.on("update", this.onLoad, this);
-    um.on("failure", this.onLoadException, this);
+    /**
+     * Adds a spacer element
+     * @return {Roo.Toolbar.Spacer} The spacer item
+     */
+    addSpacer : function(){
+        return this.addItem(new Roo.Toolbar.Spacer());
+    },
 
     /**
-     * @event beforerender
-     * Fires before rendering of the downloaded JSON data.
-     * @param {Roo.JsonView} this
-     * @param {Object} data The JSON data loaded
+     * Adds a fill element that forces subsequent additions to the right side of the toolbar
+     * @return {Roo.Toolbar.Fill} The fill item
      */
+    addFill : function(){
+        return this.addItem(new Roo.Toolbar.Fill());
+    },
+
     /**
-     * @event load
-     * Fires when data is loaded.
-     * @param {Roo.JsonView} this
-     * @param {Object} data The JSON data loaded
-     * @param {Object} response The raw Connect response object
+     * Adds any standard HTML element to the toolbar
+     * @param {String/HTMLElement/Element} el The element or id of the element to add
+     * @return {Roo.Toolbar.Item} The element's item
      */
+    addElement : function(el){
+        return this.addItem(new Roo.Toolbar.Item(el));
+    },
     /**
-     * @event loadexception
-     * Fires when loading fails.
-     * @param {Roo.JsonView} this
-     * @param {Object} response The raw Connect response object
+     * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
+     * @type Roo.util.MixedCollection  
      */
-    this.addEvents({
-        'beforerender' : true,
-        'load' : true,
-        'loadexception' : true
-    });
-};
-Roo.extend(Roo.JsonView, Roo.View, {
+    items : false,
+     
     /**
-     * @type {String} The root property in the loaded JSON object that contains the data
+     * Adds any Toolbar.Item or subclass
+     * @param {Roo.Toolbar.Item} item
+     * @return {Roo.Toolbar.Item} The item
      */
-    jsonRoot : "",
-
+    addItem : function(item){
+        var td = this.nextBlock();
+        item.render(td);
+        this.items.add(item);
+        return item;
+    },
+    
     /**
-     * Refreshes the view.
+     * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
+     * @param {Object/Array} config A button config or array of configs
+     * @return {Roo.Toolbar.Button/Array}
      */
-    refresh : function(){
-        this.clearSelections();
-        this.el.update("");
-        var html = [];
-        var o = this.jsonData;
-        if(o && o.length > 0){
-            for(var i = 0, len = o.length; i < len; i++){
-                var data = this.prepareData(o[i], i, o);
-                html[html.length] = this.tpl.apply(data);
+    addButton : function(config){
+        if(config instanceof Array){
+            var buttons = [];
+            for(var i = 0, len = config.length; i < len; i++) {
+                buttons.push(this.addButton(config[i]));
             }
-        }else{
-            html.push(this.emptyText);
+            return buttons;
         }
-        this.el.update(html.join(""));
-        this.nodes = this.el.dom.childNodes;
-        this.updateIndexes(0);
+        var b = config;
+        if(!(config instanceof Roo.Toolbar.Button)){
+            b = config.split ?
+                new Roo.Toolbar.SplitButton(config) :
+                new Roo.Toolbar.Button(config);
+        }
+        var td = this.nextBlock();
+        b.render(td);
+        this.items.add(b);
+        return b;
     },
-
+    
     /**
-     * Performs an async HTTP request, and loads the JSON from the response. If <i>params</i> are specified it uses POST, otherwise it uses GET.
-     * @param {Object/String/Function} url The URL for this request, or a function to call to get the URL, or a config object containing any of the following options:
-     <pre><code>
-     view.load({
-         url: "your-url.php",
-         params: {param1: "foo", param2: "bar"}, // or a URL encoded string
-         callback: yourFunction,
-         scope: yourObject, //(optional scope)
-         discardUrl: false,
-         nocache: false,
-         text: "Loading...",
-         timeout: 30,
-         scripts: false
-     });
-     </code></pre>
-     * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
-     * are respectively shorthand for <i>disableCaching</i>, <i>indicatorText</i>, and <i>loadScripts</i> and are used to set their associated property on this UpdateManager instance.
-     * @param {String/Object} params (optional) The parameters to pass, as either a URL encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
-     * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
-     * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used URL. If true, it will not store the URL.
+     * Adds text to the toolbar
+     * @param {String} text The text to add
+     * @return {Roo.Toolbar.Item} The element's item
      */
-    load : function(){
-        var um = this.el.getUpdateManager();
-        um.update.apply(um, arguments);
+    addText : function(text){
+        return this.addItem(new Roo.Toolbar.TextItem(text));
     },
-
-    render : function(el, response){
-        this.clearSelections();
-        this.el.update("");
-        var o;
-        try{
-            o = Roo.util.JSON.decode(response.responseText);
-            if(this.jsonRoot){
-                
-                o = o[this.jsonRoot];
+    
+    /**
+     * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
+     * @param {Number} index The index where the item is to be inserted
+     * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
+     * @return {Roo.Toolbar.Button/Item}
+     */
+    insertButton : function(index, item){
+        if(item instanceof Array){
+            var buttons = [];
+            for(var i = 0, len = item.length; i < len; i++) {
+               buttons.push(this.insertButton(index + i, item[i]));
             }
-        } catch(e){
+            return buttons;
         }
-        /**
-         * The current JSON data or null
-         */
-        this.jsonData = o;
-        this.beforeRender();
-        this.refresh();
+        if (!(item instanceof Roo.Toolbar.Button)){
+           item = new Roo.Toolbar.Button(item);
+        }
+        var td = document.createElement("td");
+        this.tr.insertBefore(td, this.tr.childNodes[index]);
+        item.render(td);
+        this.items.insert(index, item);
+        return item;
     },
-
-/**
- * Get the number of records in the current JSON dataset
- * @return {Number}
- */
-    getCount : function(){
-        return this.jsonData ? this.jsonData.length : 0;
+    
+    /**
+     * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
+     * @param {Object} config
+     * @return {Roo.Toolbar.Item} The element's item
+     */
+    addDom : function(config, returnEl){
+        var td = this.nextBlock();
+        Roo.DomHelper.overwrite(td, config);
+        var ti = new Roo.Toolbar.Item(td.firstChild);
+        ti.render(td);
+        this.items.add(ti);
+        return ti;
     },
 
-/**
- * Returns the JSON object for the specified node(s)
- * @param {HTMLElement/Array} node The node or an array of nodes
- * @return {Object/Array} If you pass in an array, you get an array back, otherwise
- * you get the JSON object for the node
- */
-    getNodeData : function(node){
-        if(node instanceof Array){
-            var data = [];
-            for(var i = 0, len = node.length; i < len; i++){
-                data.push(this.getNodeData(node[i]));
-            }
-            return data;
-        }
-        return this.jsonData[this.indexOf(node)] || null;
-    },
+    /**
+     * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
+     * @type Roo.util.MixedCollection  
+     */
+    fields : false,
+    
+    /**
+     * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
+     * Note: the field should not have been rendered yet. For a field that has already been
+     * rendered, use {@link #addElement}.
+     * @param {Roo.form.Field} field
+     * @return {Roo.ToolbarItem}
+     */
+     
+      
+    addField : function(field) {
+        if (!this.fields) {
+            var autoId = 0;
+            this.fields = new Roo.util.MixedCollection(false, function(o){
+                return o.id || ("item" + (++autoId));
+            });
 
-    beforeRender : function(){
-        this.snapshot = this.jsonData;
-        if(this.sortInfo){
-            this.sort.apply(this, this.sortInfo);
         }
-        this.fireEvent("beforerender", this, this.jsonData);
+        
+        var td = this.nextBlock();
+        field.render(td);
+        var ti = new Roo.Toolbar.Item(td.firstChild);
+        ti.render(td);
+        this.items.add(ti);
+        this.fields.add(field);
+        return ti;
     },
-
-    onLoad : function(el, o){
-        this.fireEvent("load", this, this.jsonData, o);
+    /**
+     * Hide the toolbar
+     * @method hide
+     */
+     
+      
+    hide : function()
+    {
+        this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
+        this.el.child('div').hide();
     },
-
-    onLoadException : function(el, o){
-        this.fireEvent("loadexception", this, o);
+    /**
+     * Show the toolbar
+     * @method show
+     */
+    show : function()
+    {
+        this.el.child('div').show();
+    },
+      
+    // private
+    nextBlock : function(){
+        var td = document.createElement("td");
+        this.tr.appendChild(td);
+        return td;
     },
 
-/**
- * Filter the data by a specific property.
- * @param {String} property A property on your JSON objects
- * @param {String/RegExp} value Either string that the property values
- * should start with, or a RegExp to test against the property
- */
-    filter : function(property, value){
-        if(this.jsonData){
-            var data = [];
-            var ss = this.snapshot;
-            if(typeof value == "string"){
-                var vlen = value.length;
-                if(vlen == 0){
-                    this.clearFilter();
-                    return;
-                }
-                value = value.toLowerCase();
-                for(var i = 0, len = ss.length; i < len; i++){
-                    var o = ss[i];
-                    if(o[property].substr(0, vlen).toLowerCase() == value){
-                        data.push(o);
-                    }
-                }
-            } else if(value.exec){ // regex?
-                for(var i = 0, len = ss.length; i < len; i++){
-                    var o = ss[i];
-                    if(value.test(o[property])){
-                        data.push(o);
-                    }
-                }
-            } else{
-                return;
-            }
-            this.jsonData = data;
-            this.refresh();
+    // private
+    destroy : function(){
+        if(this.items){ // rendered?
+            Roo.destroy.apply(Roo, this.items.items);
         }
-    },
+        if(this.fields){ // rendered?
+            Roo.destroy.apply(Roo, this.fields.items);
+        }
+        Roo.Element.uncache(this.el, this.tr);
+    }
+};
 
 /**
- * Filter by a function. The passed function will be called with each
- * object in the current dataset. If the function returns true the value is kept,
- * otherwise it is filtered.
- * @param {Function} fn
- * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
+ * @class Roo.Toolbar.Item
+ * The base class that other classes should extend in order to get some basic common toolbar item functionality.
+ * @constructor
+ * Creates a new Item
+ * @param {HTMLElement} el 
  */
-    filterBy : function(fn, scope){
-        if(this.jsonData){
-            var data = [];
-            var ss = this.snapshot;
-            for(var i = 0, len = ss.length; i < len; i++){
-                var o = ss[i];
-                if(fn.call(scope || this, o)){
-                    data.push(o);
-                }
-            }
-            this.jsonData = data;
-            this.refresh();
-        }
+Roo.Toolbar.Item = function(el){
+    var cfg = {};
+    if (typeof (el.xtype) != 'undefined') {
+        cfg = el;
+        el = cfg.el;
+    }
+    
+    this.el = Roo.getDom(el);
+    this.id = Roo.id(this.el);
+    this.hidden = false;
+    
+    this.addEvents({
+         /**
+            * @event render
+            * Fires when the button is rendered
+            * @param {Button} this
+            */
+        'render': true
+    });
+    Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
+};
+Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
+//Roo.Toolbar.Item.prototype = {
+    
+    /**
+     * Get this item's HTML Element
+     * @return {HTMLElement}
+     */
+    getEl : function(){
+       return this.el;  
     },
 
-/**
- * Clears the current filter.
- */
-    clearFilter : function(){
-        if(this.snapshot && this.jsonData != this.snapshot){
-            this.jsonData = this.snapshot;
-            this.refresh();
+    // private
+    render : function(td){
+        
+         this.td = td;
+        td.appendChild(this.el);
+        
+        this.fireEvent('render', this);
+    },
+    
+    /**
+     * Removes and destroys this item.
+     */
+    destroy : function(){
+        this.td.parentNode.removeChild(this.td);
+    },
+    
+    /**
+     * Shows this item.
+     */
+    show: function(){
+        this.hidden = false;
+        this.td.style.display = "";
+    },
+    
+    /**
+     * Hides this item.
+     */
+    hide: function(){
+        this.hidden = true;
+        this.td.style.display = "none";
+    },
+    
+    /**
+     * Convenience function for boolean show/hide.
+     * @param {Boolean} visible true to show/false to hide
+     */
+    setVisible: function(visible){
+        if(visible) {
+            this.show();
+        }else{
+            this.hide();
         }
     },
+    
+    /**
+     * Try to focus this item.
+     */
+    focus : function(){
+        Roo.fly(this.el).focus();
+    },
+    
+    /**
+     * Disables this item.
+     */
+    disable : function(){
+        Roo.fly(this.td).addClass("x-item-disabled");
+        this.disabled = true;
+        this.el.disabled = true;
+    },
+    
+    /**
+     * Enables this item.
+     */
+    enable : function(){
+        Roo.fly(this.td).removeClass("x-item-disabled");
+        this.disabled = false;
+        this.el.disabled = false;
+    }
+});
 
 
 /**
- * Sorts the data for this view and refreshes it.
- * @param {String} property A property on your JSON objects to sort on
- * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
- * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
+ * @class Roo.Toolbar.Separator
+ * @extends Roo.Toolbar.Item
+ * A simple toolbar separator class
+ * @constructor
+ * Creates a new Separator
  */
-    sort : function(property, dir, sortType){
-        this.sortInfo = Array.prototype.slice.call(arguments, 0);
-        if(this.jsonData){
-            var p = property;
-            var dsc = dir && dir.toLowerCase() == "desc";
-            var f = function(o1, o2){
-                var v1 = sortType ? sortType(o1[p]) : o1[p];
-                var v2 = sortType ? sortType(o2[p]) : o2[p];
-                ;
-                if(v1 < v2){
-                    return dsc ? +1 : -1;
-                } else if(v1 > v2){
-                    return dsc ? -1 : +1;
-                } else{
-                    return 0;
-                }
-            };
-            this.jsonData.sort(f);
-            this.refresh();
-            if(this.jsonData != this.snapshot){
-                this.snapshot.sort(f);
-            }
-        }
+Roo.Toolbar.Separator = function(cfg){
+    
+    var s = document.createElement("span");
+    s.className = "ytb-sep";
+    if (cfg) {
+        cfg.el = s;
     }
-});/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
+    
+    Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
+};
+Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
+    enable:Roo.emptyFn,
+    disable:Roo.emptyFn,
+    focus:Roo.emptyFn
+});
 
 /**
- * @class Roo.ColorPalette
- * @extends Roo.Component
- * Simple color palette class for choosing colors.  The palette can be rendered to any container.<br />
- * Here's an example of typical usage:
- * <pre><code>
-var cp = new Roo.ColorPalette({value:'993300'});  // initial selected color
-cp.render('my-div');
-
-cp.on('select', function(palette, selColor){
-    // do something with selColor
+ * @class Roo.Toolbar.Spacer
+ * @extends Roo.Toolbar.Item
+ * A simple element that adds extra horizontal space to a toolbar.
+ * @constructor
+ * Creates a new Spacer
+ */
+Roo.Toolbar.Spacer = function(cfg){
+    var s = document.createElement("div");
+    s.className = "ytb-spacer";
+    if (cfg) {
+        cfg.el = s;
+    }
+    Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
+};
+Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
+    enable:Roo.emptyFn,
+    disable:Roo.emptyFn,
+    focus:Roo.emptyFn
 });
-</code></pre>
+
+/**
+ * @class Roo.Toolbar.Fill
+ * @extends Roo.Toolbar.Spacer
+ * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
  * @constructor
- * Create a new ColorPalette
- * @param {Object} config The config object
+ * Creates a new Spacer
  */
-Roo.ColorPalette = function(config){
-    Roo.ColorPalette.superclass.constructor.call(this, config);
-    this.addEvents({
-        /**
-            * @event select
-            * Fires when a color is selected
-            * @param {ColorPalette} this
-            * @param {String} color The 6-digit color hex code (without the # symbol)
-            */
-        select: true
-    });
+Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
+    // private
+    render : function(td){
+        td.style.width = '100%';
+        Roo.Toolbar.Fill.superclass.render.call(this, td);
+    }
+});
 
-    if(this.handler){
-        this.on("select", this.handler, this.scope, true);
+/**
+ * @class Roo.Toolbar.TextItem
+ * @extends Roo.Toolbar.Item
+ * A simple class that renders text directly into a toolbar.
+ * @constructor
+ * Creates a new TextItem
+ * @param {String} text
+ */
+Roo.Toolbar.TextItem = function(cfg){
+    var  text = cfg || "";
+    if (typeof(cfg) == 'object') {
+        text = cfg.text || "";
+    }  else {
+        cfg = null;
+    }
+    var s = document.createElement("span");
+    s.className = "ytb-text";
+    s.innerHTML = text;
+    if (cfg) {
+        cfg.el  = s;
     }
+    
+    Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg ||  s);
 };
-Roo.extend(Roo.ColorPalette, Roo.Component, {
+Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
+    
+     
+    enable:Roo.emptyFn,
+    disable:Roo.emptyFn,
+    focus:Roo.emptyFn
+});
+
+/**
+ * @class Roo.Toolbar.Button
+ * @extends Roo.Button
+ * A button that renders into a toolbar.
+ * @constructor
+ * Creates a new Button
+ * @param {Object} config A standard {@link Roo.Button} config object
+ */
+Roo.Toolbar.Button = function(config){
+    Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
+};
+Roo.extend(Roo.Toolbar.Button, Roo.Button, {
+    render : function(td){
+        this.td = td;
+        Roo.Toolbar.Button.superclass.render.call(this, td);
+    },
+    
     /**
-     * @cfg {String} itemCls
-     * The CSS class to apply to the containing element (defaults to "x-color-palette")
+     * Removes and destroys this button
      */
-    itemCls : "x-color-palette",
+    destroy : function(){
+        Roo.Toolbar.Button.superclass.destroy.call(this);
+        this.td.parentNode.removeChild(this.td);
+    },
+    
     /**
-     * @cfg {String} value
-     * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol).  Note that
-     * the hex codes are case-sensitive.
+     * Shows this button
      */
-    value : null,
-    clickEvent:'click',
-    // private
-    ctype: "Roo.ColorPalette",
-
+    show: function(){
+        this.hidden = false;
+        this.td.style.display = "";
+    },
+    
     /**
-     * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
+     * Hides this button
      */
-    allowReselect : false,
+    hide: function(){
+        this.hidden = true;
+        this.td.style.display = "none";
+    },
 
     /**
-     * <p>An array of 6-digit color hex code strings (without the # symbol).  This array can contain any number
-     * of colors, and each hex code should be unique.  The width of the palette is controlled via CSS by adjusting
-     * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
-     * of colors with the width setting until the box is symmetrical.</p>
-     * <p>You can override individual colors if needed:</p>
-     * <pre><code>
-var cp = new Roo.ColorPalette();
-cp.colors[0] = "FF0000";  // change the first box to red
-</code></pre>
+     * Disables this item
+     */
+    disable : function(){
+        Roo.fly(this.td).addClass("x-item-disabled");
+        this.disabled = true;
+    },
 
-Or you can provide a custom array of your own for complete control:
-<pre><code>
-var cp = new Roo.ColorPalette();
-cp.colors = ["000000", "993300", "333300"];
-</code></pre>
-     * @type Array
+    /**
+     * Enables this item
      */
-    colors : [
-        "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
-        "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
-        "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
-        "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
-        "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
-    ],
+    enable : function(){
+        Roo.fly(this.td).removeClass("x-item-disabled");
+        this.disabled = false;
+    }
+});
+// backwards compat
+Roo.ToolbarButton = Roo.Toolbar.Button;
 
-    // private
-    onRender : function(container, position){
-        var t = new Roo.MasterTemplate(
-            '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on">&#160;</span></em></a></tpl>'
-        );
-        var c = this.colors;
-        for(var i = 0, len = c.length; i < len; i++){
-            t.add([c[i]]);
-        }
-        var el = document.createElement("div");
-        el.className = this.itemCls;
-        t.overwrite(el);
-        container.dom.insertBefore(el, position);
-        this.el = Roo.get(el);
-        this.el.on(this.clickEvent, this.handleClick,  this, {delegate: "a"});
-        if(this.clickEvent != 'click'){
-            this.el.on('click', Roo.emptyFn,  this, {delegate: "a", preventDefault:true});
-        }
+/**
+ * @class Roo.Toolbar.SplitButton
+ * @extends Roo.SplitButton
+ * A menu button that renders into a toolbar.
+ * @constructor
+ * Creates a new SplitButton
+ * @param {Object} config A standard {@link Roo.SplitButton} config object
+ */
+Roo.Toolbar.SplitButton = function(config){
+    Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
+};
+Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
+    render : function(td){
+        this.td = td;
+        Roo.Toolbar.SplitButton.superclass.render.call(this, td);
     },
-
-    // private
-    afterRender : function(){
-        Roo.ColorPalette.superclass.afterRender.call(this);
-        if(this.value){
-            var s = this.value;
-            this.value = null;
-            this.select(s);
-        }
+    
+    /**
+     * Removes and destroys this button
+     */
+    destroy : function(){
+        Roo.Toolbar.SplitButton.superclass.destroy.call(this);
+        this.td.parentNode.removeChild(this.td);
     },
-
-    // private
-    handleClick : function(e, t){
-        e.preventDefault();
-        if(!this.disabled){
-            var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
-            this.select(c.toUpperCase());
-        }
+    
+    /**
+     * Shows this button
+     */
+    show: function(){
+        this.hidden = false;
+        this.td.style.display = "";
     },
-
+    
     /**
-     * Selects the specified color in the palette (fires the select event)
-     * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
+     * Hides this button
      */
-    select : function(color){
-        color = color.replace("#", "");
-        if(color != this.value || this.allowReselect){
-            var el = this.el;
-            if(this.value){
-                el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
-            }
-            el.child("a.color-"+color).addClass("x-color-palette-sel");
-            this.value = color;
-            this.fireEvent("select", this, color);
-        }
+    hide: function(){
+        this.hidden = true;
+        this.td.style.display = "none";
     }
-});/*
+});
+
+// backwards compat
+Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -9498,657 +8100,987 @@ cp.colors = ["000000", "993300", "333300"];
  */
  
 /**
- * @class Roo.DatePicker
- * @extends Roo.Component
- * Simple date picker class.
+ * @class Roo.PagingToolbar
+ * @extends Roo.Toolbar
+ * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
  * @constructor
- * Create a new DatePicker
+ * Create a new PagingToolbar
  * @param {Object} config The config object
  */
-Roo.DatePicker = function(config){
-    Roo.DatePicker.superclass.constructor.call(this, config);
+Roo.PagingToolbar = function(el, ds, config)
+{
+    // old args format still supported... - xtype is prefered..
+    if (typeof(el) == 'object' && el.xtype) {
+        // created from xtype...
+        config = el;
+        ds = el.dataSource;
+        el = config.container;
+    }
+    var items = [];
+    if (config.items) {
+        items = config.items;
+        config.items = [];
+    }
+    
+    Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
+    this.ds = ds;
+    this.cursor = 0;
+    this.renderButtons(this.el);
+    this.bind(ds);
+    
+    // supprot items array.
+   
+    Roo.each(items, function(e) {
+        this.add(Roo.factory(e));
+    },this);
+    
+};
 
-    this.value = config && config.value ?
-                 config.value.clearTime() : new Date().clearTime();
-
-    this.addEvents({
-        /**
-            * @event select
-            * Fires when a date is selected
-            * @param {DatePicker} this
-            * @param {Date} date The selected date
-            */
-        'select': true,
-        /**
-            * @event monthchange
-            * Fires when the displayed month changes 
-            * @param {DatePicker} this
-            * @param {Date} date The selected month
-            */
-        'monthchange': true
-    });
-
-    if(this.handler){
-        this.on("select", this.handler,  this.scope || this);
-    }
-    // build the disabledDatesRE
-    if(!this.disabledDatesRE && this.disabledDates){
-        var dd = this.disabledDates;
-        var re = "(?:";
-        for(var i = 0; i < dd.length; i++){
-            re += dd[i];
-            if(i != dd.length-1) re += "|";
-        }
-        this.disabledDatesRE = new RegExp(re + ")");
-    }
-};
-
-Roo.extend(Roo.DatePicker, Roo.Component, {
-    /**
-     * @cfg {String} todayText
-     * The text to display on the button that selects the current date (defaults to "Today")
-     */
-    todayText : "Today",
-    /**
-     * @cfg {String} okText
-     * The text to display on the ok button
-     */
-    okText : "&#160;OK&#160;", // &#160; to give the user extra clicking room
-    /**
-     * @cfg {String} cancelText
-     * The text to display on the cancel button
-     */
-    cancelText : "Cancel",
-    /**
-     * @cfg {String} todayTip
-     * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
-     */
-    todayTip : "{0} (Spacebar)",
-    /**
-     * @cfg {Date} minDate
-     * Minimum allowable date (JavaScript date object, defaults to null)
-     */
-    minDate : null,
-    /**
-     * @cfg {Date} maxDate
-     * Maximum allowable date (JavaScript date object, defaults to null)
-     */
-    maxDate : null,
-    /**
-     * @cfg {String} minText
-     * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
-     */
-    minText : "This date is before the minimum date",
-    /**
-     * @cfg {String} maxText
-     * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
-     */
-    maxText : "This date is after the maximum date",
-    /**
-     * @cfg {String} format
-     * The default date format string which can be overriden for localization support.  The format must be
-     * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
-     */
-    format : "m/d/y",
-    /**
-     * @cfg {Array} disabledDays
-     * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
-     */
-    disabledDays : null,
+Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
     /**
-     * @cfg {String} disabledDaysText
-     * The tooltip to display when the date falls on a disabled day (defaults to "")
+     * @cfg {Roo.data.Store} dataSource
+     * The underlying data store providing the paged data
      */
-    disabledDaysText : "",
     /**
-     * @cfg {RegExp} disabledDatesRE
-     * JavaScript regular expression used to disable a pattern of dates (defaults to null)
+     * @cfg {String/HTMLElement/Element} container
+     * container The id or element that will contain the toolbar
      */
-    disabledDatesRE : null,
     /**
-     * @cfg {String} disabledDatesText
-     * The tooltip text to display when the date falls on a disabled date (defaults to "")
+     * @cfg {Boolean} displayInfo
+     * True to display the displayMsg (defaults to false)
      */
-    disabledDatesText : "",
     /**
-     * @cfg {Boolean} constrainToViewport
-     * True to constrain the date picker to the viewport (defaults to true)
+     * @cfg {Number} pageSize
+     * The number of records to display per page (defaults to 20)
      */
-    constrainToViewport : true,
+    pageSize: 20,
     /**
-     * @cfg {Array} monthNames
-     * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
+     * @cfg {String} displayMsg
+     * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
      */
-    monthNames : Date.monthNames,
+    displayMsg : 'Displaying {0} - {1} of {2}',
     /**
-     * @cfg {Array} dayNames
-     * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
+     * @cfg {String} emptyMsg
+     * The message to display when no records are found (defaults to "No data to display")
      */
-    dayNames : Date.dayNames,
+    emptyMsg : 'No data to display',
     /**
-     * @cfg {String} nextText
-     * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
+     * Customizable piece of the default paging text (defaults to "Page")
+     * @type String
      */
-    nextText: 'Next Month (Control+Right)',
+    beforePageText : "Page",
     /**
-     * @cfg {String} prevText
-     * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
+     * Customizable piece of the default paging text (defaults to "of %0")
+     * @type String
      */
-    prevText: 'Previous Month (Control+Left)',
+    afterPageText : "of {0}",
     /**
-     * @cfg {String} monthYearText
-     * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
+     * Customizable piece of the default paging text (defaults to "First Page")
+     * @type String
      */
-    monthYearText: 'Choose a month (Control+Up/Down to move years)',
+    firstText : "First Page",
     /**
-     * @cfg {Number} startDay
-     * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
+     * Customizable piece of the default paging text (defaults to "Previous Page")
+     * @type String
      */
-    startDay : 0,
+    prevText : "Previous Page",
     /**
-     * @cfg {Bool} showClear
-     * Show a clear button (usefull for date form elements that can be blank.)
+     * Customizable piece of the default paging text (defaults to "Next Page")
+     * @type String
      */
-    
-    showClear: false,
-    
+    nextText : "Next Page",
     /**
-     * Sets the value of the date field
-     * @param {Date} value The date to set
+     * Customizable piece of the default paging text (defaults to "Last Page")
+     * @type String
      */
-    setValue : function(value){
-        var old = this.value;
-        
-        if (typeof(value) == 'string') {
-         
-            value = Date.parseDate(value, this.format);
-        }
-        if (!value) {
-            value = new Date();
-        }
-        
-        this.value = value.clearTime(true);
-        if(this.el){
-            this.update(this.value);
-        }
-    },
-
+    lastText : "Last Page",
     /**
-     * Gets the current selected value of the date field
-     * @return {Date} The selected date
+     * Customizable piece of the default paging text (defaults to "Refresh")
+     * @type String
      */
-    getValue : function(){
-        return this.value;
-    },
+    refreshText : "Refresh",
 
     // private
-    focus : function(){
-        if(this.el){
-            this.update(this.activeDate);
-        }
-    },
-
-    // privateval
-    onRender : function(container, position){
-        
-        var m = [
-             '<table cellspacing="0">',
-                '<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'">&#160;</a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'">&#160;</a></td></tr>',
-                '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
-        var dn = this.dayNames;
-        for(var i = 0; i < 7; i++){
-            var d = this.startDay+i;
-            if(d > 6){
-                d = d-7;
-            }
-            m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
-        }
-        m[m.length] = "</tr></thead><tbody><tr>";
-        for(var i = 0; i < 42; i++) {
-            if(i % 7 == 0 && i != 0){
-                m[m.length] = "</tr><tr>";
-            }
-            m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
-        }
-        m[m.length] = '</tr></tbody></table></td></tr><tr>'+
-            '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
-
-        var el = document.createElement("div");
-        el.className = "x-date-picker";
-        el.innerHTML = m.join("");
-
-        container.dom.insertBefore(el, position);
-
-        this.el = Roo.get(el);
-        this.eventEl = Roo.get(el.firstChild);
-
-        new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
-            handler: this.showPrevMonth,
-            scope: this,
-            preventDefault:true,
-            stopDefault:true
+    renderButtons : function(el){
+        Roo.PagingToolbar.superclass.render.call(this, el);
+        this.first = this.addButton({
+            tooltip: this.firstText,
+            cls: "x-btn-icon x-grid-page-first",
+            disabled: true,
+            handler: this.onClick.createDelegate(this, ["first"])
         });
-
-        new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
-            handler: this.showNextMonth,
-            scope: this,
-            preventDefault:true,
-            stopDefault:true
+        this.prev = this.addButton({
+            tooltip: this.prevText,
+            cls: "x-btn-icon x-grid-page-prev",
+            disabled: true,
+            handler: this.onClick.createDelegate(this, ["prev"])
         });
-
-        this.eventEl.on("mousewheel", this.handleMouseWheel,  this);
-
-        this.monthPicker = this.el.down('div.x-date-mp');
-        this.monthPicker.enableDisplayMode('block');
-        
-        var kn = new Roo.KeyNav(this.eventEl, {
-            "left" : function(e){
-                e.ctrlKey ?
-                    this.showPrevMonth() :
-                    this.update(this.activeDate.add("d", -1));
-            },
-
-            "right" : function(e){
-                e.ctrlKey ?
-                    this.showNextMonth() :
-                    this.update(this.activeDate.add("d", 1));
-            },
-
-            "up" : function(e){
-                e.ctrlKey ?
-                    this.showNextYear() :
-                    this.update(this.activeDate.add("d", -7));
-            },
-
-            "down" : function(e){
-                e.ctrlKey ?
-                    this.showPrevYear() :
-                    this.update(this.activeDate.add("d", 7));
-            },
-
-            "pageUp" : function(e){
-                this.showNextMonth();
-            },
-
-            "pageDown" : function(e){
-                this.showPrevMonth();
-            },
-
-            "enter" : function(e){
-                e.stopPropagation();
-                return true;
-            },
-
-            scope : this
+        //this.addSeparator();
+        this.add(this.beforePageText);
+        this.field = Roo.get(this.addDom({
+           tag: "input",
+           type: "text",
+           size: "3",
+           value: "1",
+           cls: "x-grid-page-number"
+        }).el);
+        this.field.on("keydown", this.onPagingKeydown, this);
+        this.field.on("focus", function(){this.dom.select();});
+        this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
+        this.field.setHeight(18);
+        //this.addSeparator();
+        this.next = this.addButton({
+            tooltip: this.nextText,
+            cls: "x-btn-icon x-grid-page-next",
+            disabled: true,
+            handler: this.onClick.createDelegate(this, ["next"])
         });
-
-        this.eventEl.on("click", this.handleDateClick,  this, {delegate: "a.x-date-date"});
-
-        this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday,  this);
-
-        this.el.unselectable();
-        
-        this.cells = this.el.select("table.x-date-inner tbody td");
-        this.textNodes = this.el.query("table.x-date-inner tbody span");
-
-        this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
-            text: "&#160;",
-            tooltip: this.monthYearText
+        this.last = this.addButton({
+            tooltip: this.lastText,
+            cls: "x-btn-icon x-grid-page-last",
+            disabled: true,
+            handler: this.onClick.createDelegate(this, ["last"])
         });
-
-        this.mbtn.on('click', this.showMonthPicker, this);
-        this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
-
-
-        var today = (new Date()).dateFormat(this.format);
-        
-        var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
-        if (this.showClear) {
-            baseTb.add( new Roo.Toolbar.Fill());
-        }
-        baseTb.add({
-            text: String.format(this.todayText, today),
-            tooltip: String.format(this.todayTip, today),
-            handler: this.selectToday,
-            scope: this
+        //this.addSeparator();
+        this.loading = this.addButton({
+            tooltip: this.refreshText,
+            cls: "x-btn-icon x-grid-loading",
+            handler: this.onClick.createDelegate(this, ["refresh"])
         });
-        
-        //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
-            
-        //});
-        if (this.showClear) {
-            
-            baseTb.add( new Roo.Toolbar.Fill());
-            baseTb.add({
-                text: '&#160;',
-                cls: 'x-btn-icon x-btn-clear',
-                handler: function() {
-                    //this.value = '';
-                    this.fireEvent("select", this, '');
-                },
-                scope: this
-            });
-        }
-        
-        
-        if(Roo.isIE){
-            this.el.repaint();
+
+        if(this.displayInfo){
+            this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
         }
-        this.update(this.value);
     },
 
-    createMonthPicker : function(){
-        if(!this.monthPicker.dom.firstChild){
-            var buf = ['<table border="0" cellspacing="0">'];
-            for(var i = 0; i < 6; i++){
-                buf.push(
-                    '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
-                    '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
-                    i == 0 ?
-                    '<td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-prev"></a></td><td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-next"></a></td></tr>' :
-                    '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
+    // private
+    updateInfo : function(){
+        if(this.displayEl){
+            var count = this.ds.getCount();
+            var msg = count == 0 ?
+                this.emptyMsg :
+                String.format(
+                    this.displayMsg,
+                    this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
                 );
-            }
-            buf.push(
-                '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
-                    this.okText,
-                    '</button><button type="button" class="x-date-mp-cancel">',
-                    this.cancelText,
-                    '</button></td></tr>',
-                '</table>'
-            );
-            this.monthPicker.update(buf.join(''));
-            this.monthPicker.on('click', this.onMonthClick, this);
-            this.monthPicker.on('dblclick', this.onMonthDblClick, this);
-
-            this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
-            this.mpYears = this.monthPicker.select('td.x-date-mp-year');
-
-            this.mpMonths.each(function(m, a, i){
-                i += 1;
-                if((i%2) == 0){
-                    m.dom.xmonth = 5 + Math.round(i * .5);
-                }else{
-                    m.dom.xmonth = Math.round((i-1) * .5);
-                }
-            });
+            this.displayEl.update(msg);
         }
     },
 
-    showMonthPicker : function(){
-        this.createMonthPicker();
-        var size = this.el.getSize();
-        this.monthPicker.setSize(size);
-        this.monthPicker.child('table').setSize(size);
+    // private
+    onLoad : function(ds, r, o){
+       this.cursor = o.params ? o.params.start : 0;
+       var d = this.getPageData(), ap = d.activePage, ps = d.pages;
 
-        this.mpSelMonth = (this.activeDate || this.value).getMonth();
-        this.updateMPMonth(this.mpSelMonth);
-        this.mpSelYear = (this.activeDate || this.value).getFullYear();
-        this.updateMPYear(this.mpSelYear);
+       this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
+       this.field.dom.value = ap;
+       this.first.setDisabled(ap == 1);
+       this.prev.setDisabled(ap == 1);
+       this.next.setDisabled(ap == ps);
+       this.last.setDisabled(ap == ps);
+       this.loading.enable();
+       this.updateInfo();
+    },
 
-        this.monthPicker.slideIn('t', {duration:.2});
+    // private
+    getPageData : function(){
+        var total = this.ds.getTotalCount();
+        return {
+            total : total,
+            activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
+            pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
+        };
     },
 
-    updateMPYear : function(y){
-        this.mpyear = y;
-        var ys = this.mpYears.elements;
-        for(var i = 1; i <= 10; i++){
-            var td = ys[i-1], y2;
-            if((i%2) == 0){
-                y2 = y + Math.round(i * .5);
-                td.firstChild.innerHTML = y2;
-                td.xyear = y2;
-            }else{
-                y2 = y - (5-Math.round(i * .5));
-                td.firstChild.innerHTML = y2;
-                td.xyear = y2;
+    // private
+    onLoadError : function(){
+        this.loading.enable();
+    },
+
+    // private
+    onPagingKeydown : function(e){
+        var k = e.getKey();
+        var d = this.getPageData();
+        if(k == e.RETURN){
+            var v = this.field.dom.value, pageNum;
+            if(!v || isNaN(pageNum = parseInt(v, 10))){
+                this.field.dom.value = d.activePage;
+                return;
             }
-            this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
+            pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
+            this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
+            e.stopEvent();
+        }
+        else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
+        {
+          var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
+          this.field.dom.value = pageNum;
+          this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
+          e.stopEvent();
+        }
+        else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
+        {
+          var v = this.field.dom.value, pageNum; 
+          var increment = (e.shiftKey) ? 10 : 1;
+          if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
+            increment *= -1;
+          }
+          if(!v || isNaN(pageNum = parseInt(v, 10))) {
+            this.field.dom.value = d.activePage;
+            return;
+          }
+          else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
+          {
+            this.field.dom.value = parseInt(v, 10) + increment;
+            pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
+            this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
+          }
+          e.stopEvent();
         }
     },
 
-    updateMPMonth : function(sm){
-        this.mpMonths.each(function(m, a, i){
-            m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
-        });
+    // private
+    beforeLoad : function(){
+        if(this.loading){
+            this.loading.disable();
+        }
     },
 
-    selectMPMonth: function(m){
-        
+    // private
+    onClick : function(which){
+        var ds = this.ds;
+        switch(which){
+            case "first":
+                ds.load({params:{start: 0, limit: this.pageSize}});
+            break;
+            case "prev":
+                ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
+            break;
+            case "next":
+                ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
+            break;
+            case "last":
+                var total = ds.getTotalCount();
+                var extra = total % this.pageSize;
+                var lastStart = extra ? (total - extra) : total-this.pageSize;
+                ds.load({params:{start: lastStart, limit: this.pageSize}});
+            break;
+            case "refresh":
+                ds.load({params:{start: this.cursor, limit: this.pageSize}});
+            break;
+        }
     },
 
-    onMonthClick : function(e, t){
-        e.stopEvent();
-        var el = new Roo.Element(t), pn;
-        if(el.is('button.x-date-mp-cancel')){
-            this.hideMonthPicker();
-        }
-        else if(el.is('button.x-date-mp-ok')){
-            this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
-            this.hideMonthPicker();
-        }
-        else if(pn = el.up('td.x-date-mp-month', 2)){
-            this.mpMonths.removeClass('x-date-mp-sel');
-            pn.addClass('x-date-mp-sel');
-            this.mpSelMonth = pn.dom.xmonth;
+    /**
+     * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
+     * @param {Roo.data.Store} store The data store to unbind
+     */
+    unbind : function(ds){
+        ds.un("beforeload", this.beforeLoad, this);
+        ds.un("load", this.onLoad, this);
+        ds.un("loadexception", this.onLoadError, this);
+        ds.un("remove", this.updateInfo, this);
+        ds.un("add", this.updateInfo, this);
+        this.ds = undefined;
+    },
+
+    /**
+     * Binds the paging toolbar to the specified {@link Roo.data.Store}
+     * @param {Roo.data.Store} store The data store to bind
+     */
+    bind : function(ds){
+        ds.on("beforeload", this.beforeLoad, this);
+        ds.on("load", this.onLoad, this);
+        ds.on("loadexception", this.onLoadError, this);
+        ds.on("remove", this.updateInfo, this);
+        ds.on("add", this.updateInfo, this);
+        this.ds = ds;
+    }
+});/*
+ * 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.Resizable
+ * @extends Roo.util.Observable
+ * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
+ * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
+ * the textarea in a div and set "resizeChild" to true (or to the id of the element), <b>or</b> set wrap:true in your config and
+ * the element will be wrapped for you automatically.</p>
+ * <p>Here is the list of valid resize handles:</p>
+ * <pre>
+Value   Description
+------  -------------------
+ 'n'     north
+ 's'     south
+ 'e'     east
+ 'w'     west
+ 'nw'    northwest
+ 'sw'    southwest
+ 'se'    southeast
+ 'ne'    northeast
+ 'hd'    horizontal drag
+ 'all'   all
+</pre>
+ * <p>Here's an example showing the creation of a typical Resizable:</p>
+ * <pre><code>
+var resizer = new Roo.Resizable("element-id", {
+    handles: 'all',
+    minWidth: 200,
+    minHeight: 100,
+    maxWidth: 500,
+    maxHeight: 400,
+    pinned: true
+});
+resizer.on("resize", myHandler);
+</code></pre>
+ * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
+ * resizer.east.setDisplayed(false);</p>
+ * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
+ * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
+ * resize operation's new size (defaults to [0, 0])
+ * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
+ * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
+ * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
+ * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
+ * @cfg {Boolean} enabled False to disable resizing (defaults to true)
+ * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
+ * @cfg {Number} width The width of the element in pixels (defaults to null)
+ * @cfg {Number} height The height of the element in pixels (defaults to null)
+ * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
+ * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
+ * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
+ * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
+ * @cfg {Boolean} multiDirectional <b>Deprecated</b>.  The old style of adding multi-direction resize handles, deprecated
+ * in favor of the handles config option (defaults to false)
+ * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
+ * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
+ * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
+ * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
+ * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
+ * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
+ * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
+ * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
+ * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
+ * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
+ * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
+ * @constructor
+ * Create a new resizable component
+ * @param {String/HTMLElement/Roo.Element} el The id or element to resize
+ * @param {Object} config configuration options
+  */
+Roo.Resizable = function(el, config)
+{
+    this.el = Roo.get(el);
+
+    if(config && config.wrap){
+        config.resizeChild = this.el;
+        this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
+        this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
+        this.el.setStyle("overflow", "hidden");
+        this.el.setPositioning(config.resizeChild.getPositioning());
+        config.resizeChild.clearPositioning();
+        if(!config.width || !config.height){
+            var csize = config.resizeChild.getSize();
+            this.el.setSize(csize.width, csize.height);
         }
-        else if(pn = el.up('td.x-date-mp-year', 2)){
-            this.mpYears.removeClass('x-date-mp-sel');
-            pn.addClass('x-date-mp-sel');
-            this.mpSelYear = pn.dom.xyear;
+        if(config.pinned && !config.adjustments){
+            config.adjustments = "auto";
         }
-        else if(el.is('a.x-date-mp-prev')){
-            this.updateMPYear(this.mpyear-10);
+    }
+
+    this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
+    this.proxy.unselectable();
+    this.proxy.enableDisplayMode('block');
+
+    Roo.apply(this, config);
+
+    if(this.pinned){
+        this.disableTrackOver = true;
+        this.el.addClass("x-resizable-pinned");
+    }
+    // if the element isn't positioned, make it relative
+    var position = this.el.getStyle("position");
+    if(position != "absolute" && position != "fixed"){
+        this.el.setStyle("position", "relative");
+    }
+    if(!this.handles){ // no handles passed, must be legacy style
+        this.handles = 's,e,se';
+        if(this.multiDirectional){
+            this.handles += ',n,w';
         }
-        else if(el.is('a.x-date-mp-next')){
-            this.updateMPYear(this.mpyear+10);
+    }
+    if(this.handles == "all"){
+        this.handles = "n s e w ne nw se sw";
+    }
+    var hs = this.handles.split(/\s*?[,;]\s*?| /);
+    var ps = Roo.Resizable.positions;
+    for(var i = 0, len = hs.length; i < len; i++){
+        if(hs[i] && ps[hs[i]]){
+            var pos = ps[hs[i]];
+            this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
         }
-    },
+    }
+    // legacy
+    this.corner = this.southeast;
+    
+    // updateBox = the box can move..
+    if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
+        this.updateBox = true;
+    }
 
-    onMonthDblClick : function(e, t){
-        e.stopEvent();
-        var el = new Roo.Element(t), pn;
-        if(pn = el.up('td.x-date-mp-month', 2)){
-            this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
-            this.hideMonthPicker();
+    this.activeHandle = null;
+
+    if(this.resizeChild){
+        if(typeof this.resizeChild == "boolean"){
+            this.resizeChild = Roo.get(this.el.dom.firstChild, true);
+        }else{
+            this.resizeChild = Roo.get(this.resizeChild, true);
         }
-        else if(pn = el.up('td.x-date-mp-year', 2)){
-            this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
-            this.hideMonthPicker();
+    }
+    
+    if(this.adjustments == "auto"){
+        var rc = this.resizeChild;
+        var hw = this.west, he = this.east, hn = this.north, hs = this.south;
+        if(rc && (hw || hn)){
+            rc.position("relative");
+            rc.setLeft(hw ? hw.el.getWidth() : 0);
+            rc.setTop(hn ? hn.el.getHeight() : 0);
         }
-    },
+        this.adjustments = [
+            (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
+            (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
+        ];
+    }
 
-    hideMonthPicker : function(disableAnim){
-        if(this.monthPicker){
-            if(disableAnim === true){
-                this.monthPicker.hide();
-            }else{
-                this.monthPicker.slideOut('t', {duration:.2});
-            }
-        }
+    if(this.draggable){
+        this.dd = this.dynamic ?
+            this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
+        this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
+    }
+
+    // public events
+    this.addEvents({
+        /**
+         * @event beforeresize
+         * Fired before resize is allowed. Set enabled to false to cancel resize.
+         * @param {Roo.Resizable} this
+         * @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.
+         * @param {Roo.Resizable} this
+         * @param {Number} width The new width
+         * @param {Number} height The new height
+         * @param {Roo.EventObject} e The mouseup event
+         */
+        "resize" : true
+    });
+
+    if(this.width !== null && this.height !== null){
+        this.resizeTo(this.width, this.height);
+    }else{
+        this.updateChildSize();
+    }
+    if(Roo.isIE){
+        this.el.dom.style.zoom = 1;
+    }
+    Roo.Resizable.superclass.constructor.call(this);
+};
+
+Roo.extend(Roo.Resizable, Roo.util.Observable, {
+        resizeChild : false,
+        adjustments : [0, 0],
+        minWidth : 5,
+        minHeight : 5,
+        maxWidth : 10000,
+        maxHeight : 10000,
+        enabled : true,
+        animate : false,
+        duration : .35,
+        dynamic : false,
+        handles : false,
+        multiDirectional : false,
+        disableTrackOver : false,
+        easing : 'easeOutStrong',
+        widthIncrement : 0,
+        heightIncrement : 0,
+        pinned : false,
+        width : null,
+        height : null,
+        preserveRatio : false,
+        transparent: false,
+        minX: 0,
+        minY: 0,
+        draggable: false,
+
+        /**
+         * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
+         */
+        constrainTo: undefined,
+        /**
+         * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
+         */
+        resizeRegion: undefined,
+
+
+    /**
+     * Perform a manual resize
+     * @param {Number} width
+     * @param {Number} height
+     */
+    resizeTo : function(width, height){
+        this.el.setSize(width, height);
+        this.updateChildSize();
+        this.fireEvent("resize", this, width, height, null);
     },
 
     // private
-    showPrevMonth : function(e){
-        this.update(this.activeDate.add("mo", -1));
+    startSizing : function(e, handle){
+        this.fireEvent("beforeresize", this, e);
+        if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
+
+            if(!this.overlay){
+                this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: "&#160;"});
+                this.overlay.unselectable();
+                this.overlay.enableDisplayMode("block");
+                this.overlay.on("mousemove", this.onMouseMove, this);
+                this.overlay.on("mouseup", this.onMouseUp, this);
+            }
+            this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
+
+            this.resizing = true;
+            this.startBox = this.el.getBox();
+            this.startPoint = e.getXY();
+            this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
+                            (this.startBox.y + this.startBox.height) - this.startPoint[1]];
+
+            this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
+            this.overlay.show();
+
+            if(this.constrainTo) {
+                var ct = Roo.get(this.constrainTo);
+                this.resizeRegion = ct.getRegion().adjust(
+                    ct.getFrameWidth('t'),
+                    ct.getFrameWidth('l'),
+                    -ct.getFrameWidth('b'),
+                    -ct.getFrameWidth('r')
+                );
+            }
+
+            this.proxy.setStyle('visibility', 'hidden'); // workaround display none
+            this.proxy.show();
+            this.proxy.setBox(this.startBox);
+            if(!this.dynamic){
+                this.proxy.setStyle('visibility', 'visible');
+            }
+        }
     },
 
     // private
-    showNextMonth : function(e){
-        this.update(this.activeDate.add("mo", 1));
+    onMouseDown : function(handle, e){
+        if(this.enabled){
+            e.stopEvent();
+            this.activeHandle = handle;
+            this.startSizing(e, handle);
+        }
     },
 
     // private
-    showPrevYear : function(){
-        this.update(this.activeDate.add("y", -1));
+    onMouseUp : function(e){
+        var size = this.resizeElement();
+        this.resizing = false;
+        this.handleOut();
+        this.overlay.hide();
+        this.proxy.hide();
+        this.fireEvent("resize", this, size.width, size.height, e);
     },
 
     // private
-    showNextYear : function(){
-        this.update(this.activeDate.add("y", 1));
+    updateChildSize : function(){
+        
+        if(this.resizeChild){
+            var el = this.el;
+            var child = this.resizeChild;
+            var adj = this.adjustments;
+            if(el.dom.offsetWidth){
+                var b = el.getSize(true);
+                child.setSize(b.width+adj[0], b.height+adj[1]);
+            }
+            // Second call here for IE
+            // The first call enables instant resizing and
+            // the second call corrects scroll bars if they
+            // exist
+            if(Roo.isIE){
+                setTimeout(function(){
+                    if(el.dom.offsetWidth){
+                        var b = el.getSize(true);
+                        child.setSize(b.width+adj[0], b.height+adj[1]);
+                    }
+                }, 10);
+            }
+        }
     },
 
     // private
-    handleMouseWheel : function(e){
-        var delta = e.getWheelDelta();
-        if(delta > 0){
-            this.showPrevMonth();
-            e.stopEvent();
-        } else if(delta < 0){
-            this.showNextMonth();
-            e.stopEvent();
+    snap : function(value, inc, min){
+        if(!inc || !value) {
+            return value;
         }
+        var newValue = value;
+        var m = value % inc;
+        if(m > 0){
+            if(m > (inc/2)){
+                newValue = value + (inc-m);
+            }else{
+                newValue = value - m;
+            }
+        }
+        return Math.max(min, newValue);
     },
 
     // private
-    handleDateClick : function(e, t){
-        e.stopEvent();
-        if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
-            this.setValue(new Date(t.dateValue));
-            this.fireEvent("select", this, this.value);
+    resizeElement : function(){
+        var box = this.proxy.getBox();
+        if(this.updateBox){
+            this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
+        }else{
+            this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
+        }
+        this.updateChildSize();
+        if(!this.dynamic){
+            this.proxy.hide();
         }
+        return box;
     },
 
     // private
-    selectToday : function(){
-        this.setValue(new Date().clearTime());
-        this.fireEvent("select", this, this.value);
+    constrain : function(v, diff, m, mx){
+        if(v - diff < m){
+            diff = v - m;
+        }else if(v - diff > mx){
+            diff = mx - v;
+        }
+        return diff;
     },
 
     // private
-    update : function(date)
-    {
-        var vd = this.activeDate;
-        this.activeDate = date;
-        if(vd && this.el){
-            var t = date.getTime();
-            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
-                this.cells.removeClass("x-date-selected");
-                this.cells.each(function(c){
-                   if(c.dom.firstChild.dateValue == t){
-                       c.addClass("x-date-selected");
-                       setTimeout(function(){
-                            try{c.dom.firstChild.focus();}catch(e){}
-                       }, 50);
-                       return false;
-                   }
-                });
-                return;
-            }
-        }
+    onMouseMove : function(e){
         
-        var days = date.getDaysInMonth();
-        var firstOfMonth = date.getFirstDateOfMonth();
-        var startingPos = firstOfMonth.getDay()-this.startDay;
+        if(this.enabled){
+            try{// try catch so if something goes wrong the user doesn't get hung
 
-        if(startingPos <= this.startDay){
-            startingPos += 7;
-        }
+            if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
+               return;
+            }
 
-        var pm = date.add("mo", -1);
-        var prevStart = pm.getDaysInMonth()-startingPos;
+            //var curXY = this.startPoint;
+            var curSize = this.curSize || this.startBox;
+            var x = this.startBox.x, y = this.startBox.y;
+            var ox = x, oy = y;
+            var w = curSize.width, h = curSize.height;
+            var ow = w, oh = h;
+            var mw = this.minWidth, mh = this.minHeight;
+            var mxw = this.maxWidth, mxh = this.maxHeight;
+            var wi = this.widthIncrement;
+            var hi = this.heightIncrement;
 
-        var cells = this.cells.elements;
-        var textEls = this.textNodes;
-        days += startingPos;
+            var eventXY = e.getXY();
+            var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
+            var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
 
-        // convert everything to numbers so it's fast
-        var day = 86400000;
-        var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
-        var today = new Date().clearTime().getTime();
-        var sel = date.clearTime().getTime();
-        var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
-        var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
-        var ddMatch = this.disabledDatesRE;
-        var ddText = this.disabledDatesText;
-        var ddays = this.disabledDays ? this.disabledDays.join("") : false;
-        var ddaysText = this.disabledDaysText;
-        var format = this.format;
+            var pos = this.activeHandle.position;
 
-        var setCellClass = function(cal, cell){
-            cell.title = "";
-            var t = d.getTime();
-            cell.firstChild.dateValue = t;
-            if(t == today){
-                cell.className += " x-date-today";
-                cell.title = cal.todayText;
-            }
-            if(t == sel){
-                cell.className += " x-date-selected";
-                setTimeout(function(){
-                    try{cell.firstChild.focus();}catch(e){}
-                }, 50);
-            }
-            // disabling
-            if(t < min) {
-                cell.className = " x-date-disabled";
-                cell.title = cal.minText;
-                return;
-            }
-            if(t > max) {
-                cell.className = " x-date-disabled";
-                cell.title = cal.maxText;
-                return;
+            switch(pos){
+                case "east":
+                    w += diffX;
+                    w = Math.min(Math.max(mw, w), mxw);
+                    break;
+             
+                case "south":
+                    h += diffY;
+                    h = Math.min(Math.max(mh, h), mxh);
+                    break;
+                case "southeast":
+                    w += diffX;
+                    h += diffY;
+                    w = Math.min(Math.max(mw, w), mxw);
+                    h = Math.min(Math.max(mh, h), mxh);
+                    break;
+                case "north":
+                    diffY = this.constrain(h, diffY, mh, mxh);
+                    y += diffY;
+                    h -= diffY;
+                    break;
+                case "hdrag":
+                    
+                    if (wi) {
+                        var adiffX = Math.abs(diffX);
+                        var sub = (adiffX % wi); // how much 
+                        if (sub > (wi/2)) { // far enough to snap
+                            diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
+                        } else {
+                            // remove difference.. 
+                            diffX = (diffX > 0) ? diffX-sub : diffX+sub;
+                        }
+                    }
+                    x += diffX;
+                    x = Math.max(this.minX, x);
+                    break;
+                case "west":
+                    diffX = this.constrain(w, diffX, mw, mxw);
+                    x += diffX;
+                    w -= diffX;
+                    break;
+                case "northeast":
+                    w += diffX;
+                    w = Math.min(Math.max(mw, w), mxw);
+                    diffY = this.constrain(h, diffY, mh, mxh);
+                    y += diffY;
+                    h -= diffY;
+                    break;
+                case "northwest":
+                    diffX = this.constrain(w, diffX, mw, mxw);
+                    diffY = this.constrain(h, diffY, mh, mxh);
+                    y += diffY;
+                    h -= diffY;
+                    x += diffX;
+                    w -= diffX;
+                    break;
+               case "southwest":
+                    diffX = this.constrain(w, diffX, mw, mxw);
+                    h += diffY;
+                    h = Math.min(Math.max(mh, h), mxh);
+                    x += diffX;
+                    w -= diffX;
+                    break;
             }
-            if(ddays){
-                if(ddays.indexOf(d.getDay()) != -1){
-                    cell.title = ddaysText;
-                    cell.className = " x-date-disabled";
+
+            var sw = this.snap(w, wi, mw);
+            var sh = this.snap(h, hi, mh);
+            if(sw != w || sh != h){
+                switch(pos){
+                    case "northeast":
+                        y -= sh - h;
+                    break;
+                    case "north":
+                        y -= sh - h;
+                        break;
+                    case "southwest":
+                        x -= sw - w;
+                    break;
+                    case "west":
+                        x -= sw - w;
+                        break;
+                    case "northwest":
+                        x -= sw - w;
+                        y -= sh - h;
+                    break;
                 }
+                w = sw;
+                h = sh;
             }
-            if(ddMatch && format){
-                var fvalue = d.dateFormat(format);
-                if(ddMatch.test(fvalue)){
-                    cell.title = ddText.replace("%0", fvalue);
-                    cell.className = " x-date-disabled";
+
+            if(this.preserveRatio){
+                switch(pos){
+                    case "southeast":
+                    case "east":
+                        h = oh * (w/ow);
+                        h = Math.min(Math.max(mh, h), mxh);
+                        w = ow * (h/oh);
+                       break;
+                    case "south":
+                        w = ow * (h/oh);
+                        w = Math.min(Math.max(mw, w), mxw);
+                        h = oh * (w/ow);
+                        break;
+                    case "northeast":
+                        w = ow * (h/oh);
+                        w = Math.min(Math.max(mw, w), mxw);
+                        h = oh * (w/ow);
+                    break;
+                    case "north":
+                        var tw = w;
+                        w = ow * (h/oh);
+                        w = Math.min(Math.max(mw, w), mxw);
+                        h = oh * (w/ow);
+                        x += (tw - w) / 2;
+                        break;
+                    case "southwest":
+                        h = oh * (w/ow);
+                        h = Math.min(Math.max(mh, h), mxh);
+                        var tw = w;
+                        w = ow * (h/oh);
+                        x += tw - w;
+                        break;
+                    case "west":
+                        var th = h;
+                        h = oh * (w/ow);
+                        h = Math.min(Math.max(mh, h), mxh);
+                        y += (th - h) / 2;
+                        var tw = w;
+                        w = ow * (h/oh);
+                        x += tw - w;
+                       break;
+                    case "northwest":
+                        var tw = w;
+                        var th = h;
+                        h = oh * (w/ow);
+                        h = Math.min(Math.max(mh, h), mxh);
+                        w = ow * (h/oh);
+                        y += th - h;
+                        x += tw - w;
+                       break;
+
                 }
             }
-        };
-
-        var i = 0;
-        for(; i < startingPos; i++) {
-            textEls[i].innerHTML = (++prevStart);
-            d.setDate(d.getDate()+1);
-            cells[i].className = "x-date-prevday";
-            setCellClass(this, cells[i]);
+            if (pos == 'hdrag') {
+                w = ow;
+            }
+            this.proxy.setBounds(x, y, w, h);
+            if(this.dynamic){
+                this.resizeElement();
+            }
+            }catch(e){}
         }
-        for(; i < days; i++){
-            intDay = i - startingPos + 1;
-            textEls[i].innerHTML = (intDay);
-            d.setDate(d.getDate()+1);
-            cells[i].className = "x-date-active";
-            setCellClass(this, cells[i]);
+        this.fireEvent("resizing", this, x, y, w, h, e);
+    },
+
+    // private
+    handleOver : function(){
+        if(this.enabled){
+            this.el.addClass("x-resizable-over");
         }
-        var extraDays = 0;
-        for(; i < 42; i++) {
-             textEls[i].innerHTML = (++extraDays);
-             d.setDate(d.getDate()+1);
-             cells[i].className = "x-date-nextday";
-             setCellClass(this, cells[i]);
+    },
+
+    // private
+    handleOut : function(){
+        if(!this.resizing){
+            this.el.removeClass("x-resizable-over");
         }
+    },
 
-        this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
-        this.fireEvent('monthchange', this, date);
+    /**
+     * Returns the element this component is bound to.
+     * @return {Roo.Element}
+     */
+    getEl : function(){
+        return this.el;
+    },
+
+    /**
+     * Returns the resizeChild element (or null).
+     * @return {Roo.Element}
+     */
+    getResizeChild : function(){
+        return this.resizeChild;
+    },
+    groupHandler : function()
+    {
         
-        if(!this.internalRender){
-            var main = this.el.dom.firstChild;
-            var w = main.offsetWidth;
-            this.el.setWidth(w + this.el.getBorderWidth("lr"));
-            Roo.fly(main).setWidth(w);
-            this.internalRender = true;
-            // opera does not respect the auto grow header center column
-            // then, after it gets a width opera refuses to recalculate
-            // without a second pass
-            if(Roo.isOpera && !this.secondPass){
-                main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
-                this.secondPass = true;
-                this.update.defer(10, this, [date]);
+    },
+    /**
+     * Destroys this resizable. If the element was wrapped and
+     * removeEl is not true then the element remains.
+     * @param {Boolean} removeEl (optional) true to remove the element from the DOM
+     */
+    destroy : function(removeEl){
+        this.proxy.remove();
+        if(this.overlay){
+            this.overlay.removeAllListeners();
+            this.overlay.remove();
+        }
+        var ps = Roo.Resizable.positions;
+        for(var k in ps){
+            if(typeof ps[k] != "function" && this[ps[k]]){
+                var h = this[ps[k]];
+                h.el.removeAllListeners();
+                h.el.remove();
             }
         }
-        
-        
+        if(removeEl){
+            this.el.update("");
+            this.el.remove();
+        }
     }
-});        /*
+});
+
+// private
+// hash to map config positions to true positions
+Roo.Resizable.positions = {
+    n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast", 
+    hd: "hdrag"
+};
+
+// private
+Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
+    if(!this.tpl){
+        // only initialize the template if resizable is used
+        var tpl = Roo.DomHelper.createTemplate(
+            {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
+        );
+        tpl.compile();
+        Roo.Resizable.Handle.prototype.tpl = tpl;
+    }
+    this.position = pos;
+    this.rz = rz;
+    // show north drag fro topdra
+    var handlepos = pos == 'hdrag' ? 'north' : pos;
+    
+    this.el = this.tpl.append(rz.el.dom, [handlepos], true);
+    if (pos == 'hdrag') {
+        this.el.setStyle('cursor', 'pointer');
+    }
+    this.el.unselectable();
+    if(transparent){
+        this.el.setOpacity(0);
+    }
+    this.el.on("mousedown", this.onMouseDown, this);
+    if(!disableTrackOver){
+        this.el.on("mouseover", this.onMouseOver, this);
+        this.el.on("mouseout", this.onMouseOut, this);
+    }
+};
+
+// private
+Roo.Resizable.Handle.prototype = {
+    afterResize : function(rz){
+        Roo.log('after?');
+        // do nothing
+    },
+    // private
+    onMouseDown : function(e){
+        this.rz.onMouseDown(this, e);
+    },
+    // private
+    onMouseOver : function(e){
+        this.rz.handleOver(this, e);
+    },
+    // private
+    onMouseOut : function(e){
+        this.rz.handleOut(this, e);
+    }
+};/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -10158,1529 +9090,1592 @@ Roo.extend(Roo.DatePicker, Roo.Component, {
  * Fork - LGPL
  * <script type="text/javascript">
  */
-/**
- * @class Roo.TabPanel
- * @extends Roo.util.Observable
- * A lightweight tab container.
- * <br><br>
- * Usage:
- * <pre><code>
-// basic tabs 1, built from existing content
-var tabs = new Roo.TabPanel("tabs1");
-tabs.addTab("script", "View Script");
-tabs.addTab("markup", "View Markup");
-tabs.activate("script");
-
-// more advanced tabs, built from javascript
-var jtabs = new Roo.TabPanel("jtabs");
-jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
-
-// set up the UpdateManager
-var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
-var updater = tab2.getUpdateManager();
-updater.setDefaultUrl("ajax1.htm");
-tab2.on('activate', updater.refresh, updater, true);
-
-// Use setUrl for Ajax loading
-var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
-tab3.setUrl("ajax2.htm", null, true);
-
-// Disabled tab
-var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
-tab4.disable();
 
-jtabs.activate("jtabs-1");
- * </code></pre>
+/**
+ * @class Roo.Editor
+ * @extends Roo.Component
+ * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
  * @constructor
- * Create a new TabPanel.
- * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
- * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
+ * Create a new Editor
+ * @param {Roo.form.Field} field The Field object (or descendant)
+ * @param {Object} config The config object
  */
-Roo.TabPanel = function(container, config){
-    /**
-    * The container element for this TabPanel.
-    * @type Roo.Element
-    */
-    this.el = Roo.get(container, true);
-    if(config){
-        if(typeof config == "boolean"){
-            this.tabPosition = config ? "bottom" : "top";
-        }else{
-            Roo.apply(this, config);
-        }
-    }
-    if(this.tabPosition == "bottom"){
-        this.bodyEl = Roo.get(this.createBody(this.el.dom));
-        this.el.addClass("x-tabs-bottom");
-    }
-    this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
-    this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
-    this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
-    if(Roo.isIE){
-        Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
-    }
-    if(this.tabPosition != "bottom"){
-        /** The body element that contains {@link Roo.TabPanelItem} bodies. +
-         * @type Roo.Element
-         */
-        this.bodyEl = Roo.get(this.createBody(this.el.dom));
-        this.el.addClass("x-tabs-top");
-    }
-    this.items = [];
-
-    this.bodyEl.setStyle("position", "relative");
-
-    this.active = null;
-    this.activateDelegate = this.activate.createDelegate(this);
-
+Roo.Editor = function(field, config){
+    Roo.Editor.superclass.constructor.call(this, config);
+    this.field = field;
     this.addEvents({
         /**
-         * @event tabchange
-         * Fires when the active tab changes
-         * @param {Roo.TabPanel} this
-         * @param {Roo.TabPanelItem} activePanel The new active tab
-         */
-        "tabchange": true,
+            * @event beforestartedit
+            * Fires when editing is initiated, but before the value changes.  Editing can be canceled by returning
+            * false from the handler of this event.
+            * @param {Editor} this
+            * @param {Roo.Element} boundEl The underlying element bound to this editor
+            * @param {Mixed} value The field value being set
+            */
+        "beforestartedit" : true,
         /**
-         * @event beforetabchange
-         * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
-         * @param {Roo.TabPanel} this
-         * @param {Object} e Set cancel to true on this object to cancel the tab change
-         * @param {Roo.TabPanelItem} tab The tab being changed to
+            * @event startedit
+            * Fires when this editor is displayed
+            * @param {Roo.Element} boundEl The underlying element bound to this editor
+            * @param {Mixed} value The starting field value
+            */
+        "startedit" : true,
+        /**
+            * @event beforecomplete
+            * Fires after a change has been made to the field, but before the change is reflected in the underlying
+            * field.  Saving the change to the field can be canceled by returning false from the handler of this event.
+            * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
+            * event will not fire since no edit actually occurred.
+            * @param {Editor} this
+            * @param {Mixed} value The current field value
+            * @param {Mixed} startValue The original field value
+            */
+        "beforecomplete" : true,
+        /**
+            * @event complete
+            * Fires after editing is complete and any changed value has been written to the underlying field.
+            * @param {Editor} this
+            * @param {Mixed} value The current field value
+            * @param {Mixed} startValue The original field value
+            */
+        "complete" : true,
+        /**
+         * @event specialkey
+         * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
+         * {@link Roo.EventObject#getKey} to determine which key was pressed.
+         * @param {Roo.form.Field} this
+         * @param {Roo.EventObject} e The event object
          */
-        "beforetabchange" : true
+        "specialkey" : true
     });
-
-    Roo.EventManager.onWindowResize(this.onResize, this);
-    this.cpad = this.el.getPadding("lr");
-    this.hiddenCount = 0;
-
-
-    // toolbar on the tabbar support...
-    if (this.toolbar) {
-        var tcfg = this.toolbar;
-        tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');  
-        this.toolbar = new Roo.Toolbar(tcfg);
-        if (Roo.isSafari) {
-            var tbl = tcfg.container.child('table', true);
-            tbl.setAttribute('width', '100%');
-        }
-        
-    }
-   
-
-
-    Roo.TabPanel.superclass.constructor.call(this);
 };
 
-Roo.extend(Roo.TabPanel, Roo.util.Observable, {
-    /*
-     *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
+Roo.extend(Roo.Editor, Roo.Component, {
+    /**
+     * @cfg {Boolean/String} autosize
+     * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
+     * or "height" to adopt the height only (defaults to false)
      */
-    tabPosition : "top",
-    /*
-     *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
-     */
-    currentTabWidth : 0,
-    /*
-     *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
+    /**
+     * @cfg {Boolean} revertInvalid
+     * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
+     * validation fails (defaults to true)
      */
-    minTabWidth : 40,
-    /*
-     *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
+    /**
+     * @cfg {Boolean} ignoreNoChange
+     * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
+     * the value has not changed (defaults to false).  Applies only to string values - edits for other data types
+     * will never be ignored.
      */
-    maxTabWidth : 250,
-    /*
-     *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
+    /**
+     * @cfg {Boolean} hideEl
+     * False to keep the bound element visible while the editor is displayed (defaults to true)
      */
-    preferredTabWidth : 175,
-    /*
-     *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
+    /**
+     * @cfg {Mixed} value
+     * The data value of the underlying field (defaults to "")
      */
-    resizeTabs : false,
-    /*
-     *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
+    value : "",
+    /**
+     * @cfg {String} alignment
+     * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
      */
-    monitorResize : true,
-    /*
-     *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar. 
+    alignment: "c-c?",
+    /**
+     * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
+     * for bottom-right shadow (defaults to "frame")
      */
-    toolbar : false,
-
+    shadow : "frame",
     /**
-     * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
-     * @param {String} id The id of the div to use <b>or create</b>
-     * @param {String} text The text for the tab
-     * @param {String} content (optional) Content to put in the TabPanelItem body
-     * @param {Boolean} closable (optional) True to create a close icon on the tab
-     * @return {Roo.TabPanelItem} The created TabPanelItem
+     * @cfg {Boolean} constrain True to constrain the editor to the viewport
      */
-    addTab : function(id, text, content, closable){
-        var item = new Roo.TabPanelItem(this, id, text, closable);
-        this.addTabItem(item);
-        if(content){
-            item.setContent(content);
-        }
-        return item;
-    },
-
+    constrain : false,
     /**
-     * Returns the {@link Roo.TabPanelItem} with the specified id/index
-     * @param {String/Number} id The id or index of the TabPanelItem to fetch.
-     * @return {Roo.TabPanelItem}
+     * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
      */
-    getTab : function(id){
-        return this.items[id];
-    },
-
+    completeOnEnter : false,
     /**
-     * Hides the {@link Roo.TabPanelItem} with the specified id/index
-     * @param {String/Number} id The id or index of the TabPanelItem to hide.
+     * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
      */
-    hideTab : function(id){
-        var t = this.items[id];
-        if(!t.isHidden()){
-           t.setHidden(true);
-           this.hiddenCount++;
-           this.autoSizeTabs();
-        }
-    },
-
+    cancelOnEsc : false,
     /**
-     * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
-     * @param {String/Number} id The id or index of the TabPanelItem to unhide.
+     * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
      */
-    unhideTab : function(id){
-        var t = this.items[id];
-        if(t.isHidden()){
-           t.setHidden(false);
-           this.hiddenCount--;
-           this.autoSizeTabs();
+    updateEl : false,
+
+    // private
+    onRender : function(ct, position){
+        this.el = new Roo.Layer({
+            shadow: this.shadow,
+            cls: "x-editor",
+            parentEl : ct,
+            shim : this.shim,
+            shadowOffset:4,
+            id: this.id,
+            constrain: this.constrain
+        });
+        this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
+        if(this.field.msgTarget != 'title'){
+            this.field.msgTarget = 'qtip';
+        }
+        this.field.render(this.el);
+        if(Roo.isGecko){
+            this.field.el.dom.setAttribute('autocomplete', 'off');
+        }
+        this.field.on("specialkey", this.onSpecialKey, this);
+        if(this.swallowKeys){
+            this.field.el.swallowEvent(['keydown','keypress']);
+        }
+        this.field.show();
+        this.field.on("blur", this.onBlur, this);
+        if(this.field.grow){
+            this.field.on("autosize", this.el.sync,  this.el, {delay:1});
         }
     },
 
-    /**
-     * Adds an existing {@link Roo.TabPanelItem}.
-     * @param {Roo.TabPanelItem} item The TabPanelItem to add
-     */
-    addTabItem : function(item){
-        this.items[item.id] = item;
-        this.items.push(item);
-        if(this.resizeTabs){
-           item.setWidth(this.currentTabWidth || this.preferredTabWidth);
-           this.autoSizeTabs();
-        }else{
-            item.autoSize();
+    onSpecialKey : function(field, e)
+    {
+        //Roo.log('editor onSpecialKey');
+        if(this.completeOnEnter && e.getKey() == e.ENTER){
+            e.stopEvent();
+            this.completeEdit();
+            return;
+        }
+        // do not fire special key otherwise it might hide close the editor...
+        if(e.getKey() == e.ENTER){    
+            return;
         }
+        if(this.cancelOnEsc && e.getKey() == e.ESC){
+            this.cancelEdit();
+            return;
+        } 
+        this.fireEvent('specialkey', field, e);
+    
     },
 
     /**
-     * Removes a {@link Roo.TabPanelItem}.
-     * @param {String/Number} id The id or index of the TabPanelItem to remove.
+     * Starts the editing process and shows the editor.
+     * @param {String/HTMLElement/Element} el The element to edit
+     * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
+      * to the innerHTML of el.
      */
-    removeTab : function(id){
-        var items = this.items;
-        var tab = items[id];
-        if(!tab) { return; }
-        var index = items.indexOf(tab);
-        if(this.active == tab && items.length > 1){
-            var newTab = this.getNextAvailable(index);
-            if(newTab) {
-                newTab.activate();
-            }
+    startEdit : function(el, value){
+        if(this.editing){
+            this.completeEdit();
         }
-        this.stripEl.dom.removeChild(tab.pnode.dom);
-        if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
-            this.bodyEl.dom.removeChild(tab.bodyEl.dom);
+        this.boundEl = Roo.get(el);
+        var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
+        if(!this.rendered){
+            this.render(this.parentEl || document.body);
         }
-        items.splice(index, 1);
-        delete this.items[tab.id];
-        tab.fireEvent("close", tab);
-        tab.purgeListeners();
-        this.autoSizeTabs();
-    },
-
-    getNextAvailable : function(start){
-        var items = this.items;
-        var index = start;
-        // look for a next tab that will slide over to
-        // replace the one being removed
-        while(index < items.length){
-            var item = items[++index];
-            if(item && !item.isHidden()){
-                return item;
-            }
+        if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
+            return;
         }
-        // if one isn't found select the previous tab (on the left)
-        index = start;
-        while(index >= 0){
-            var item = items[--index];
-            if(item && !item.isHidden()){
-                return item;
+        this.startValue = v;
+        this.field.setValue(v);
+        if(this.autoSize){
+            var sz = this.boundEl.getSize();
+            switch(this.autoSize){
+                case "width":
+                this.setSize(sz.width,  "");
+                break;
+                case "height":
+                this.setSize("",  sz.height);
+                break;
+                default:
+                this.setSize(sz.width,  sz.height);
             }
         }
-        return null;
+        this.el.alignTo(this.boundEl, this.alignment);
+        this.editing = true;
+        if(Roo.QuickTips){
+            Roo.QuickTips.disable();
+        }
+        this.show();
     },
 
     /**
-     * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
-     * @param {String/Number} id The id or index of the TabPanelItem to disable.
+     * Sets the height and width of this editor.
+     * @param {Number} width The new width
+     * @param {Number} height The new height
      */
-    disableTab : function(id){
-        var tab = this.items[id];
-        if(tab && this.active != tab){
-            tab.disable();
+    setSize : function(w, h){
+        this.field.setSize(w, h);
+        if(this.el){
+            this.el.sync();
         }
     },
 
     /**
-     * Enables a {@link Roo.TabPanelItem} that is disabled.
-     * @param {String/Number} id The id or index of the TabPanelItem to enable.
+     * Realigns the editor to the bound field based on the current alignment config value.
      */
-    enableTab : function(id){
-        var tab = this.items[id];
-        tab.enable();
+    realign : function(){
+        this.el.alignTo(this.boundEl, this.alignment);
     },
 
     /**
-     * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
-     * @param {String/Number} id The id or index of the TabPanelItem to activate.
-     * @return {Roo.TabPanelItem} The TabPanelItem.
+     * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
+     * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
      */
-    activate : function(id){
-        var tab = this.items[id];
-        if(!tab){
-            return null;
+    completeEdit : function(remainVisible){
+        if(!this.editing){
+            return;
         }
-        if(tab == this.active || tab.disabled){
-            return tab;
+        var v = this.getValue();
+        if(this.revertInvalid !== false && !this.field.isValid()){
+            v = this.startValue;
+            this.cancelEdit(true);
         }
-        var e = {};
-        this.fireEvent("beforetabchange", this, e, tab);
-        if(e.cancel !== true && !tab.disabled){
-            if(this.active){
-                this.active.hide();
+        if(String(v) === String(this.startValue) && this.ignoreNoChange){
+            this.editing = false;
+            this.hide();
+            return;
+        }
+        if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
+            this.editing = false;
+            if(this.updateEl && this.boundEl){
+                this.boundEl.update(v);
             }
-            this.active = this.items[id];
-            this.active.show();
-            this.fireEvent("tabchange", this, this.active);
+            if(remainVisible !== true){
+                this.hide();
+            }
+            this.fireEvent("complete", this, v, this.startValue);
         }
-        return tab;
-    },
-
-    /**
-     * Gets the active {@link Roo.TabPanelItem}.
-     * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
-     */
-    getActiveTab : function(){
-        return this.active;
     },
 
-    /**
-     * Updates the tab body element to fit the height of the container element
-     * for overflow scrolling
-     * @param {Number} targetHeight (optional) Override the starting height from the elements height
-     */
-    syncHeight : function(targetHeight){
-        var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
-        var bm = this.bodyEl.getMargins();
-        var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
-        this.bodyEl.setHeight(newHeight);
-        return newHeight;
+    // private
+    onShow : function(){
+        this.el.show();
+        if(this.hideEl !== false){
+            this.boundEl.hide();
+        }
+        this.field.show();
+        if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
+            this.fixIEFocus = true;
+            this.deferredFocus.defer(50, this);
+        }else{
+            this.field.focus();
+        }
+        this.fireEvent("startedit", this.boundEl, this.startValue);
     },
 
-    onResize : function(){
-        if(this.monitorResize){
-            this.autoSizeTabs();
+    deferredFocus : function(){
+        if(this.editing){
+            this.field.focus();
         }
     },
 
     /**
-     * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
+     * Cancels the editing process and hides the editor without persisting any changes.  The field value will be
+     * reverted to the original starting value.
+     * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
+     * cancel (defaults to false)
      */
-    beginUpdate : function(){
-        this.updating = true;
+    cancelEdit : function(remainVisible){
+        if(this.editing){
+            this.setValue(this.startValue);
+            if(remainVisible !== true){
+                this.hide();
+            }
+        }
     },
 
-    /**
-     * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
-     */
-    endUpdate : function(){
-        this.updating = false;
-        this.autoSizeTabs();
+    // private
+    onBlur : function(){
+        if(this.allowBlur !== true && this.editing){
+            this.completeEdit();
+        }
     },
 
-    /**
-     * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
-     */
-    autoSizeTabs : function(){
-        var count = this.items.length;
-        var vcount = count - this.hiddenCount;
-        if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
-        var w = Math.max(this.el.getWidth() - this.cpad, 10);
-        var availWidth = Math.floor(w / vcount);
-        var b = this.stripBody;
-        if(b.getWidth() > w){
-            var tabs = this.items;
-            this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
-            if(availWidth < this.minTabWidth){
-                /*if(!this.sleft){    // incomplete scrolling code
-                    this.createScrollButtons();
-                }
-                this.showScroll();
-                this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
-            }
-        }else{
-            if(this.currentTabWidth < this.preferredTabWidth){
-                this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
-            }
+    // private
+    onHide : function(){
+        if(this.editing){
+            this.completeEdit();
+            return;
+        }
+        this.field.blur();
+        if(this.field.collapse){
+            this.field.collapse();
+        }
+        this.el.hide();
+        if(this.hideEl !== false){
+            this.boundEl.show();
+        }
+        if(Roo.QuickTips){
+            Roo.QuickTips.enable();
         }
     },
 
     /**
-     * Returns the number of tabs in this TabPanel.
-     * @return {Number}
-     */
-     getCount : function(){
-         return this.items.length;
-     },
-
-    /**
-     * Resizes all the tabs to the passed width
-     * @param {Number} The new width
+     * Sets the data value of the editor
+     * @param {Mixed} value Any valid value supported by the underlying field
      */
-    setTabWidth : function(width){
-        this.currentTabWidth = width;
-        for(var i = 0, len = this.items.length; i < len; i++) {
-               if(!this.items[i].isHidden())this.items[i].setWidth(width);
-        }
+    setValue : function(v){
+        this.field.setValue(v);
     },
 
     /**
-     * Destroys this TabPanel
-     * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
+     * Gets the data value of the editor
+     * @return {Mixed} The data value
      */
-    destroy : function(removeEl){
-        Roo.EventManager.removeResizeListener(this.onResize, this);
-        for(var i = 0, len = this.items.length; i < len; i++){
-            this.items[i].purgeListeners();
-        }
-        if(removeEl === true){
-            this.el.update("");
-            this.el.remove();
-        }
+    getValue : function(){
+        return this.field.getValue();
     }
-});
-
+});/*
+ * 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.TabPanelItem
+ * @class Roo.BasicDialog
  * @extends Roo.util.Observable
- * Represents an individual item (tab plus body) in a TabPanel.
- * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
- * @param {String} id The id of this TabPanelItem
- * @param {String} text The text for the tab of this TabPanelItem
- * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
+ * Lightweight Dialog Class.  The code below shows the creation of a typical dialog using existing HTML markup:
+ * <pre><code>
+var dlg = new Roo.BasicDialog("my-dlg", {
+    height: 200,
+    width: 300,
+    minHeight: 100,
+    minWidth: 150,
+    modal: true,
+    proxyDrag: true,
+    shadow: true
+});
+dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
+dlg.addButton('OK', dlg.hide, dlg);    // Could call a save function instead of hiding
+dlg.addButton('Cancel', dlg.hide, dlg);
+dlg.show();
+</code></pre>
+  <b>A Dialog should always be a direct child of the body element.</b>
+ * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
+ * @cfg {String} title Default text to display in the title bar (defaults to null)
+ * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS).  Determined by browser if unspecified.
+ * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS).  Determined by browser if unspecified.
+ * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
+ * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
+ * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
+ * (defaults to null with no animation)
+ * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
+ * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
+ * property for valid values (defaults to 'all')
+ * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
+ * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
+ * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
+ * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
+ * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
+ * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
+ * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
+ * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
+ * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
+ * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
+ * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
+ * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
+ * draggable = true (defaults to false)
+ * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
+ * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
+ * shadow (defaults to false)
+ * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
+ * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
+ * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
+ * @cfg {Array} buttons Array of buttons
+ * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
+ * @constructor
+ * Create a new BasicDialog.
+ * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
+ * @param {Object} config Configuration options
  */
-Roo.TabPanelItem = function(tabPanel, id, text, closable){
-    /**
-     * The {@link Roo.TabPanel} this TabPanelItem belongs to
-     * @type Roo.TabPanel
-     */
-    this.tabPanel = tabPanel;
-    /**
-     * The id for this TabPanelItem
-     * @type String
-     */
-    this.id = id;
-    /** @private */
-    this.disabled = false;
-    /** @private */
-    this.text = text;
-    /** @private */
-    this.loaded = false;
-    this.closable = closable;
-
-    /**
-     * The body element for this TabPanelItem.
-     * @type Roo.Element
-     */
-    this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
-    this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
-    this.bodyEl.setStyle("display", "block");
-    this.bodyEl.setStyle("zoom", "1");
-    this.hideAction();
+Roo.BasicDialog = function(el, config){
+    this.el = Roo.get(el);
+    var dh = Roo.DomHelper;
+    if(!this.el && config && config.autoCreate){
+        if(typeof config.autoCreate == "object"){
+            if(!config.autoCreate.id){
+                config.autoCreate.id = el;
+            }
+            this.el = dh.append(document.body,
+                        config.autoCreate, true);
+        }else{
+            this.el = dh.append(document.body,
+                        {tag: "div", id: el, style:'visibility:hidden;'}, true);
+        }
+    }
+    el = this.el;
+    el.setDisplayed(true);
+    el.hide = this.hideAction;
+    this.id = el.id;
+    el.addClass("x-dlg");
 
-    var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
-    /** @private */
-    this.el = Roo.get(els.el, true);
-    this.inner = Roo.get(els.inner, true);
-    this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
-    this.pnode = Roo.get(els.el.parentNode, true);
-    this.el.on("mousedown", this.onTabMouseDown, this);
-    this.el.on("click", this.onTabClick, this);
-    /** @private */
-    if(closable){
-        var c = Roo.get(els.close, true);
-        c.dom.title = this.closeText;
-        c.addClassOnOver("close-over");
-        c.on("click", this.closeClick, this);
-     }
+    Roo.apply(this, config);
+
+    this.proxy = el.createProxy("x-dlg-proxy");
+    this.proxy.hide = this.hideAction;
+    this.proxy.setOpacity(.5);
+    this.proxy.hide();
+
+    if(config.width){
+        el.setWidth(config.width);
+    }
+    if(config.height){
+        el.setHeight(config.height);
+    }
+    this.size = el.getSize();
+    if(typeof config.x != "undefined" && typeof config.y != "undefined"){
+        this.xy = [config.x,config.y];
+    }else{
+        this.xy = el.getCenterXY(true);
+    }
+    /** The header element @type Roo.Element */
+    this.header = el.child("> .x-dlg-hd");
+    /** The body element @type Roo.Element */
+    this.body = el.child("> .x-dlg-bd");
+    /** The footer element @type Roo.Element */
+    this.footer = el.child("> .x-dlg-ft");
+
+    if(!this.header){
+        this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: "&#160;"}, this.body ? this.body.dom : null);
+    }
+    if(!this.body){
+        this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
+    }
+
+    this.header.unselectable();
+    if(this.title){
+        this.header.update(this.title);
+    }
+    // this element allows the dialog to be focused for keyboard event
+    this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
+    this.focusEl.swallowEvent("click", true);
+
+    this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
+
+    // wrap the body and footer for special rendering
+    this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
+    if(this.footer){
+        this.bwrap.dom.appendChild(this.footer.dom);
+    }
+
+    this.bg = this.el.createChild({
+        tag: "div", cls:"x-dlg-bg",
+        html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center">&#160;</div></div></div>'
+    });
+    this.centerBg = this.bg.child("div.x-dlg-bg-center");
+
+
+    if(this.autoScroll !== false && !this.autoTabs){
+        this.body.setStyle("overflow", "auto");
+    }
+
+    this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
 
+    if(this.closable !== false){
+        this.el.addClass("x-dlg-closable");
+        this.close = this.toolbox.createChild({cls:"x-dlg-close"});
+        this.close.on("click", this.closeClick, this);
+        this.close.addClassOnOver("x-dlg-close-over");
+    }
+    if(this.collapsible !== false){
+        this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
+        this.collapseBtn.on("click", this.collapseClick, this);
+        this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
+        this.header.on("dblclick", this.collapseClick, this);
+    }
+    if(this.resizable !== false){
+        this.el.addClass("x-dlg-resizable");
+        this.resizer = new Roo.Resizable(el, {
+            minWidth: this.minWidth || 80,
+            minHeight:this.minHeight || 80,
+            handles: this.resizeHandles || "all",
+            pinned: true
+        });
+        this.resizer.on("beforeresize", this.beforeResize, this);
+        this.resizer.on("resize", this.onResize, this);
+    }
+    if(this.draggable !== false){
+        el.addClass("x-dlg-draggable");
+        if (!this.proxyDrag) {
+            var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
+        }
+        else {
+            var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
+        }
+        dd.setHandleElId(this.header.id);
+        dd.endDrag = this.endMove.createDelegate(this);
+        dd.startDrag = this.startMove.createDelegate(this);
+        dd.onDrag = this.onDrag.createDelegate(this);
+        dd.scroll = false;
+        this.dd = dd;
+    }
+    if(this.modal){
+        this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
+        this.mask.enableDisplayMode("block");
+        this.mask.hide();
+        this.el.addClass("x-dlg-modal");
+    }
+    if(this.shadow){
+        this.shadow = new Roo.Shadow({
+            mode : typeof this.shadow == "string" ? this.shadow : "sides",
+            offset : this.shadowOffset
+        });
+    }else{
+        this.shadowOffset = 0;
+    }
+    if(Roo.useShims && this.shim !== false){
+        this.shim = this.el.createShim();
+        this.shim.hide = this.hideAction;
+        this.shim.hide();
+    }else{
+        this.shim = false;
+    }
+    if(this.autoTabs){
+        this.initTabs();
+    }
+    if (this.buttons) { 
+        var bts= this.buttons;
+        this.buttons = [];
+        Roo.each(bts, function(b) {
+            this.addButton(b);
+        }, this);
+    }
+    
+    
     this.addEvents({
-         /**
-         * @event activate
-         * Fires when this tab becomes the active tab.
-         * @param {Roo.TabPanel} tabPanel The parent TabPanel
-         * @param {Roo.TabPanelItem} this
+        /**
+         * @event keydown
+         * Fires when a key is pressed
+         * @param {Roo.BasicDialog} this
+         * @param {Roo.EventObject} e
          */
-        "activate": true,
+        "keydown" : true,
         /**
-         * @event beforeclose
-         * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
-         * @param {Roo.TabPanelItem} this
-         * @param {Object} e Set cancel to true on this object to cancel the close.
+         * @event move
+         * Fires when this dialog is moved by the user.
+         * @param {Roo.BasicDialog} this
+         * @param {Number} x The new page X
+         * @param {Number} y The new page Y
          */
-        "beforeclose": true,
+        "move" : true,
         /**
-         * @event close
-         * Fires when this tab is closed.
-         * @param {Roo.TabPanelItem} this
+         * @event resize
+         * Fires when this dialog is resized by the user.
+         * @param {Roo.BasicDialog} this
+         * @param {Number} width The new width
+         * @param {Number} height The new height
          */
-         "close": true,
+        "resize" : true,
         /**
-         * @event deactivate
-         * Fires when this tab is no longer the active tab.
-         * @param {Roo.TabPanel} tabPanel The parent TabPanel
-         * @param {Roo.TabPanelItem} this
+         * @event beforehide
+         * Fires before this dialog is hidden.
+         * @param {Roo.BasicDialog} this
          */
-         "deactivate" : true
+        "beforehide" : true,
+        /**
+         * @event hide
+         * Fires when this dialog is hidden.
+         * @param {Roo.BasicDialog} this
+         */
+        "hide" : true,
+        /**
+         * @event beforeshow
+         * Fires before this dialog is shown.
+         * @param {Roo.BasicDialog} this
+         */
+        "beforeshow" : true,
+        /**
+         * @event show
+         * Fires when this dialog is shown.
+         * @param {Roo.BasicDialog} this
+         */
+        "show" : true
     });
-    this.hidden = false;
-
-    Roo.TabPanelItem.superclass.constructor.call(this);
+    el.on("keydown", this.onKeyDown, this);
+    el.on("mousedown", this.toFront, this);
+    Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
+    this.el.hide();
+    Roo.DialogManager.register(this);
+    Roo.BasicDialog.superclass.constructor.call(this);
 };
 
-Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
-    purgeListeners : function(){
-       Roo.util.Observable.prototype.purgeListeners.call(this);
-       this.el.removeAllListeners();
-    },
-    /**
-     * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
-     */
-    show : function(){
-        this.pnode.addClass("on");
-        this.showAction();
-        if(Roo.isOpera){
-            this.tabPanel.stripWrap.repaint();
-        }
-        this.fireEvent("activate", this.tabPanel, this);
-    },
-
-    /**
-     * Returns true if this tab is the active tab.
-     * @return {Boolean}
-     */
-    isActive : function(){
-        return this.tabPanel.getActiveTab() == this;
-    },
+Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
+    shadowOffset: Roo.isIE ? 6 : 5,
+    minHeight: 80,
+    minWidth: 200,
+    minButtonWidth: 75,
+    defaultButton: null,
+    buttonAlign: "right",
+    tabTag: 'div',
+    firstShow: true,
 
     /**
-     * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
+     * Sets the dialog title text
+     * @param {String} text The title text to display
+     * @return {Roo.BasicDialog} this
      */
-    hide : function(){
-        this.pnode.removeClass("on");
-        this.hideAction();
-        this.fireEvent("deactivate", this.tabPanel, this);
+    setTitle : function(text){
+        this.header.update(text);
+        return this;
     },
 
-    hideAction : function(){
-        this.bodyEl.hide();
-        this.bodyEl.setStyle("position", "absolute");
-        this.bodyEl.setLeft("-20000px");
-        this.bodyEl.setTop("-20000px");
+    // private
+    closeClick : function(){
+        this.hide();
     },
 
-    showAction : function(){
-        this.bodyEl.setStyle("position", "relative");
-        this.bodyEl.setTop("");
-        this.bodyEl.setLeft("");
-        this.bodyEl.show();
+    // private
+    collapseClick : function(){
+        this[this.collapsed ? "expand" : "collapse"]();
     },
 
     /**
-     * Set the tooltip for the tab.
-     * @param {String} tooltip The tab's tooltip
+     * Collapses the dialog to its minimized state (only the title bar is visible).
+     * Equivalent to the user clicking the collapse dialog button.
      */
-    setTooltip : function(text){
-        if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
-            this.textEl.dom.qtip = text;
-            this.textEl.dom.removeAttribute('title');
-        }else{
-            this.textEl.dom.title = text;
+    collapse : function(){
+        if(!this.collapsed){
+            this.collapsed = true;
+            this.el.addClass("x-dlg-collapsed");
+            this.restoreHeight = this.el.getHeight();
+            this.resizeTo(this.el.getWidth(), this.header.getHeight());
         }
     },
 
-    onTabClick : function(e){
-        e.preventDefault();
-        this.tabPanel.activate(this.id);
-    },
-
-    onTabMouseDown : function(e){
-        e.preventDefault();
-        this.tabPanel.activate(this.id);
-    },
-
-    getWidth : function(){
-        return this.inner.getWidth();
-    },
-
-    setWidth : function(width){
-        var iwidth = width - this.pnode.getPadding("lr");
-        this.inner.setWidth(iwidth);
-        this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
-        this.pnode.setWidth(width);
-    },
-
     /**
-     * Show or hide the tab
-     * @param {Boolean} hidden True to hide or false to show.
+     * Expands a collapsed dialog back to its normal state.  Equivalent to the user
+     * clicking the expand dialog button.
      */
-    setHidden : function(hidden){
-        this.hidden = hidden;
-        this.pnode.setStyle("display", hidden ? "none" : "");
+    expand : function(){
+        if(this.collapsed){
+            this.collapsed = false;
+            this.el.removeClass("x-dlg-collapsed");
+            this.resizeTo(this.el.getWidth(), this.restoreHeight);
+        }
     },
 
     /**
-     * Returns true if this tab is "hidden"
-     * @return {Boolean}
+     * Reinitializes the tabs component, clearing out old tabs and finding new ones.
+     * @return {Roo.TabPanel} The tabs component
      */
-    isHidden : function(){
-        return this.hidden;
+    initTabs : function(){
+        var tabs = this.getTabs();
+        while(tabs.getTab(0)){
+            tabs.removeTab(0);
+        }
+        this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
+            var dom = el.dom;
+            tabs.addTab(Roo.id(dom), dom.title);
+            dom.title = "";
+        });
+        tabs.activate(0);
+        return tabs;
     },
 
-    /**
-     * Returns the text for this tab
-     * @return {String}
-     */
-    getText : function(){
-        return this.text;
+    // private
+    beforeResize : function(){
+        this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
     },
 
-    autoSize : function(){
-        //this.el.beginMeasure();
-        this.textEl.setWidth(1);
-        this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
-        //this.el.endMeasure();
+    // private
+    onResize : function(){
+        this.refreshSize();
+        this.syncBodyHeight();
+        this.adjustAssets();
+        this.focus();
+        this.fireEvent("resize", this, this.size.width, this.size.height);
     },
 
-    /**
-     * Sets the text for the tab (Note: this also sets the tooltip text)
-     * @param {String} text The tab's text and tooltip
-     */
-    setText : function(text){
-        this.text = text;
-        this.textEl.update(text);
-        this.setTooltip(text);
-        if(!this.tabPanel.resizeTabs){
-            this.autoSize();
+    // private
+    onKeyDown : function(e){
+        if(this.isVisible()){
+            this.fireEvent("keydown", this, e);
         }
     },
-    /**
-     * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
-     */
-    activate : function(){
-        this.tabPanel.activate(this.id);
-    },
 
     /**
-     * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
+     * Resizes the dialog.
+     * @param {Number} width
+     * @param {Number} height
+     * @return {Roo.BasicDialog} this
      */
-    disable : function(){
-        if(this.tabPanel.active != this){
-            this.disabled = true;
-            this.pnode.addClass("disabled");
+    resizeTo : function(width, height){
+        this.el.setSize(width, height);
+        this.size = {width: width, height: height};
+        this.syncBodyHeight();
+        if(this.fixedcenter){
+            this.center();
+        }
+        if(this.isVisible()){
+            this.constrainXY();
+            this.adjustAssets();
         }
+        this.fireEvent("resize", this, width, height);
+        return this;
     },
 
+
     /**
-     * Enables this TabPanelItem if it was previously disabled.
+     * Resizes the dialog to fit the specified content size.
+     * @param {Number} width
+     * @param {Number} height
+     * @return {Roo.BasicDialog} this
      */
-    enable : function(){
-        this.disabled = false;
-        this.pnode.removeClass("disabled");
+    setContentSize : function(w, h){
+        h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
+        w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
+        //if(!this.el.isBorderBox()){
+            h +=  this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
+            w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
+        //}
+        if(this.tabs){
+            h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
+            w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
+        }
+        this.resizeTo(w, h);
+        return this;
     },
 
     /**
-     * Sets the content for this TabPanelItem.
-     * @param {String} content The content
-     * @param {Boolean} loadScripts true to look for and load scripts
+     * Adds a key listener for when this dialog is displayed.  This allows you to hook in a function that will be
+     * executed in response to a particular key being pressed while the dialog is active.
+     * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
+     *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
+     * @param {Function} fn The function to call
+     * @param {Object} scope (optional) The scope of the function
+     * @return {Roo.BasicDialog} this
      */
-    setContent : function(content, loadScripts){
-        this.bodyEl.update(content, loadScripts);
+    addKeyListener : function(key, fn, scope){
+        var keyCode, shift, ctrl, alt;
+        if(typeof key == "object" && !(key instanceof Array)){
+            keyCode = key["key"];
+            shift = key["shift"];
+            ctrl = key["ctrl"];
+            alt = key["alt"];
+        }else{
+            keyCode = key;
+        }
+        var handler = function(dlg, e){
+            if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
+                var k = e.getKey();
+                if(keyCode instanceof Array){
+                    for(var i = 0, len = keyCode.length; i < len; i++){
+                        if(keyCode[i] == k){
+                          fn.call(scope || window, dlg, k, e);
+                          return;
+                        }
+                    }
+                }else{
+                    if(k == keyCode){
+                        fn.call(scope || window, dlg, k, e);
+                    }
+                }
+            }
+        };
+        this.on("keydown", handler);
+        return this;
     },
 
     /**
-     * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
-     * @return {Roo.UpdateManager} The UpdateManager
+     * Returns the TabPanel component (creates it if it doesn't exist).
+     * Note: If you wish to simply check for the existence of tabs without creating them,
+     * check for a null 'tabs' property.
+     * @return {Roo.TabPanel} The tabs component
      */
-    getUpdateManager : function(){
-        return this.bodyEl.getUpdateManager();
+    getTabs : function(){
+        if(!this.tabs){
+            this.el.addClass("x-dlg-auto-tabs");
+            this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
+            this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
+        }
+        return this.tabs;
     },
 
     /**
-     * Set a URL to be used to load the content for this TabPanelItem.
-     * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
-     * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
-     * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
-     * @return {Roo.UpdateManager} The UpdateManager
+     * Adds a button to the footer section of the dialog.
+     * @param {String/Object} config A string becomes the button text, an object can either be a Button config
+     * object or a valid Roo.DomHelper element config
+     * @param {Function} handler The function called when the button is clicked
+     * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
+     * @return {Roo.Button} The new button
      */
-    setUrl : function(url, params, loadOnce){
-        if(this.refreshDelegate){
-            this.un('activate', this.refreshDelegate);
+    addButton : function(config, handler, scope){
+        var dh = Roo.DomHelper;
+        if(!this.footer){
+            this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
         }
-        this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
-        this.on("activate", this.refreshDelegate);
-        return this.bodyEl.getUpdateManager();
-    },
+        if(!this.btnContainer){
+            var tb = this.footer.createChild({
 
-    /** @private */
-    _handleRefresh : function(url, params, loadOnce){
-        if(!loadOnce || !this.loaded){
-            var updater = this.bodyEl.getUpdateManager();
-            updater.update(url, params, this._setLoaded.createDelegate(this));
+                cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
+                html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
+            }, null, true);
+            this.btnContainer = tb.firstChild.firstChild.firstChild;
+        }
+        var bconfig = {
+            handler: handler,
+            scope: scope,
+            minWidth: this.minButtonWidth,
+            hideParent:true
+        };
+        if(typeof config == "string"){
+            bconfig.text = config;
+        }else{
+            if(config.tag){
+                bconfig.dhconfig = config;
+            }else{
+                Roo.apply(bconfig, config);
+            }
+        }
+        var fc = false;
+        if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
+            bconfig.position = Math.max(0, bconfig.position);
+            fc = this.btnContainer.childNodes[bconfig.position];
+        }
+         
+        var btn = new Roo.Button(
+            fc ? 
+                this.btnContainer.insertBefore(document.createElement("td"),fc)
+                : this.btnContainer.appendChild(document.createElement("td")),
+            //Roo.get(this.btnContainer).createChild( { tag: 'td'},  fc ),
+            bconfig
+        );
+        this.syncBodyHeight();
+        if(!this.buttons){
+            /**
+             * Array of all the buttons that have been added to this dialog via addButton
+             * @type Array
+             */
+            this.buttons = [];
         }
+        this.buttons.push(btn);
+        return btn;
     },
 
     /**
-     *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
-     *   Will fail silently if the setUrl method has not been called.
-     *   This does not activate the panel, just updates its content.
+     * Sets the default button to be focused when the dialog is displayed.
+     * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
+     * @return {Roo.BasicDialog} this
      */
-    refresh : function(){
-        if(this.refreshDelegate){
-           this.loaded = false;
-           this.refreshDelegate();
-        }
+    setDefaultButton : function(btn){
+        this.defaultButton = btn;
+        return this;
     },
 
-    /** @private */
-    _setLoaded : function(){
-        this.loaded = true;
+    // private
+    getHeaderFooterHeight : function(safe){
+        var height = 0;
+        if(this.header){
+           height += this.header.getHeight();
+        }
+        if(this.footer){
+           var fm = this.footer.getMargins();
+            height += (this.footer.getHeight()+fm.top+fm.bottom);
+        }
+        height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
+        height += this.centerBg.getPadding("tb");
+        return height;
     },
 
-    /** @private */
-    closeClick : function(e){
-        var o = {};
-        e.stopEvent();
-        this.fireEvent("beforeclose", this, o);
-        if(o.cancel !== true){
-            this.tabPanel.removeTab(this.id);
+    // private
+    syncBodyHeight : function()
+    {
+        var bd = this.body, // the text
+            cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
+            bw = this.bwrap;
+        var height = this.size.height - this.getHeaderFooterHeight(false);
+        bd.setHeight(height-bd.getMargins("tb"));
+        var hh = this.header.getHeight();
+        var h = this.size.height-hh;
+        cb.setHeight(h);
+        
+        bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
+        bw.setHeight(h-cb.getPadding("tb"));
+        
+        bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
+        bd.setWidth(bw.getWidth(true));
+        if(this.tabs){
+            this.tabs.syncHeight();
+            if(Roo.isIE){
+                this.tabs.el.repaint();
+            }
         }
     },
+
     /**
-     * The text displayed in the tooltip for the close icon.
-     * @type String
+     * Restores the previous state of the dialog if Roo.state is configured.
+     * @return {Roo.BasicDialog} this
      */
-    closeText : "Close this tab"
-});
+    restoreState : function(){
+        var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
+        if(box && box.width){
+            this.xy = [box.x, box.y];
+            this.resizeTo(box.width, box.height);
+        }
+        return this;
+    },
 
-/** @private */
-Roo.TabPanel.prototype.createStrip = function(container){
-    var strip = document.createElement("div");
-    strip.className = "x-tabs-wrap";
-    container.appendChild(strip);
-    return strip;
-};
-/** @private */
-Roo.TabPanel.prototype.createStripList = function(strip){
-    // div wrapper for retard IE
-    // returns the "tr" element.
-    strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
-        '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
-        '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
-    return strip.firstChild.firstChild.firstChild.firstChild;
-};
-/** @private */
-Roo.TabPanel.prototype.createBody = function(container){
-    var body = document.createElement("div");
-    Roo.id(body, "tab-body");
-    Roo.fly(body).addClass("x-tabs-body");
-    container.appendChild(body);
-    return body;
-};
-/** @private */
-Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
-    var body = Roo.getDom(id);
-    if(!body){
-        body = document.createElement("div");
-        body.id = id;
-    }
-    Roo.fly(body).addClass("x-tabs-item-body");
-    bodyEl.insertBefore(body, bodyEl.firstChild);
-    return body;
-};
-/** @private */
-Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
-    var td = document.createElement("td");
-    stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
-    //stripEl.appendChild(td);
-    if(closable){
-        td.className = "x-tabs-closable";
-        if(!this.closeTpl){
-            this.closeTpl = new Roo.Template(
-               '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
-               '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
-               '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
-            );
+    // private
+    beforeShow : function(){
+        this.expand();
+        if(this.fixedcenter){
+            this.xy = this.el.getCenterXY(true);
         }
-        var el = this.closeTpl.overwrite(td, {"text": text});
-        var close = el.getElementsByTagName("div")[0];
-        var inner = el.getElementsByTagName("em")[0];
-        return {"el": el, "close": close, "inner": inner};
-    } else {
-        if(!this.tabTpl){
-            this.tabTpl = new Roo.Template(
-               '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
-               '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
-            );
+        if(this.modal){
+            Roo.get(document.body).addClass("x-body-masked");
+            this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
+            this.mask.show();
         }
-        var el = this.tabTpl.overwrite(td, {"text": text});
-        var inner = el.getElementsByTagName("em")[0];
-        return {"el": el, "inner": inner};
-    }
-};/*
- * 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.Button
- * @extends Roo.util.Observable
- * Simple Button class
- * @cfg {String} text The button text
- * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
- * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
- * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
- * @cfg {Object} scope The scope of the handler
- * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
- * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
- * @cfg {Boolean} hidden True to start hidden (defaults to false)
- * @cfg {Boolean} disabled True to start disabled (defaults to false)
- * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
- * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
-   applies if enableToggle = true)
- * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
- * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
-  an {@link Roo.util.ClickRepeater} config object (defaults to false).
- * @constructor
- * Create a new button
- * @param {Object} config The config object
- */
-Roo.Button = function(renderTo, config)
-{
-    if (!config) {
-        config = renderTo;
-        renderTo = config.renderTo || false;
-    }
-    
-    Roo.apply(this, config);
-    this.addEvents({
-        /**
-            * @event click
-            * Fires when this button is clicked
-            * @param {Button} this
-            * @param {EventObject} e The click event
-            */
-           "click" : true,
-        /**
-            * @event toggle
-            * Fires when the "pressed" state of this button changes (only if enableToggle = true)
-            * @param {Button} this
-            * @param {Boolean} pressed
-            */
-           "toggle" : true,
-        /**
-            * @event mouseover
-            * Fires when the mouse hovers over the button
-            * @param {Button} this
-            * @param {Event} e The event object
-            */
-        'mouseover' : true,
-        /**
-            * @event mouseout
-            * Fires when the mouse exits the button
-            * @param {Button} this
-            * @param {Event} e The event object
-            */
-        'mouseout': true,
-         /**
-            * @event render
-            * Fires when the button is rendered
-            * @param {Button} this
-            */
-        'render': true
-    });
-    if(this.menu){
-        this.menu = Roo.menu.MenuMgr.get(this.menu);
-    }
-    // register listeners first!!  - so render can be captured..
-    Roo.util.Observable.call(this);
-    if(renderTo){
-        this.render(renderTo);
-    }
-    
-  
-};
-
-Roo.extend(Roo.Button, Roo.util.Observable, {
-    /**
-     * 
-     */
-    
-    /**
-     * Read-only. True if this button is hidden
-     * @type Boolean
-     */
-    hidden : false,
-    /**
-     * Read-only. True if this button is disabled
-     * @type Boolean
-     */
-    disabled : false,
-    /**
-     * Read-only. True if this button is pressed (only if enableToggle = true)
-     * @type Boolean
-     */
-    pressed : false,
-
-    /**
-     * @cfg {Number} tabIndex 
-     * The DOM tabIndex for this button (defaults to undefined)
-     */
-    tabIndex : undefined,
-
-    /**
-     * @cfg {Boolean} enableToggle
-     * True to enable pressed/not pressed toggling (defaults to false)
-     */
-    enableToggle: false,
-    /**
-     * @cfg {Mixed} menu
-     * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
-     */
-    menu : undefined,
-    /**
-     * @cfg {String} menuAlign
-     * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
-     */
-    menuAlign : "tl-bl?",
-
-    /**
-     * @cfg {String} iconCls
-     * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
-     */
-    iconCls : undefined,
-    /**
-     * @cfg {String} type
-     * The button's type, corresponding to the DOM input element type attribute.  Either "submit," "reset" or "button" (default).
-     */
-    type : 'button',
+        this.constrainXY();
+    },
 
     // private
-    menuClassTarget: 'tr',
-
-    /**
-     * @cfg {String} clickEvent
-     * The type of event to map to the button's event handler (defaults to 'click')
-     */
-    clickEvent : 'click',
+    animShow : function(){
+        var b = Roo.get(this.animateTarget).getBox();
+        this.proxy.setSize(b.width, b.height);
+        this.proxy.setLocation(b.x, b.y);
+        this.proxy.show();
+        this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
+                    true, .35, this.showEl.createDelegate(this));
+    },
 
     /**
-     * @cfg {Boolean} handleMouseEvents
-     * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
+     * Shows the dialog.
+     * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
+     * @return {Roo.BasicDialog} this
      */
-    handleMouseEvents : true,
+    show : function(animateTarget){
+        if (this.fireEvent("beforeshow", this) === false){
+            return;
+        }
+        if(this.syncHeightBeforeShow){
+            this.syncBodyHeight();
+        }else if(this.firstShow){
+            this.firstShow = false;
+            this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
+        }
+        this.animateTarget = animateTarget || this.animateTarget;
+        if(!this.el.isVisible()){
+            this.beforeShow();
+            if(this.animateTarget && Roo.get(this.animateTarget)){
+                this.animShow();
+            }else{
+                this.showEl();
+            }
+        }
+        return this;
+    },
 
-    /**
-     * @cfg {String} tooltipType
-     * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
-     */
-    tooltipType : 'qtip',
+    // private
+    showEl : function(){
+        this.proxy.hide();
+        this.el.setXY(this.xy);
+        this.el.show();
+        this.adjustAssets(true);
+        this.toFront();
+        this.focus();
+        // IE peekaboo bug - fix found by Dave Fenwick
+        if(Roo.isIE){
+            this.el.repaint();
+        }
+        this.fireEvent("show", this);
+    },
 
     /**
-     * @cfg {String} cls
-     * A CSS class to apply to the button's main element.
-     */
-    
-    /**
-     * @cfg {Roo.Template} template (Optional)
-     * An {@link Roo.Template} with which to create the Button's main element. This Template must
-     * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
-     * require code modifications if required elements (e.g. a button) aren't present.
+     * Focuses the dialog.  If a defaultButton is set, it will receive focus, otherwise the
+     * dialog itself will receive focus.
      */
+    focus : function(){
+        if(this.defaultButton){
+            this.defaultButton.focus();
+        }else{
+            this.focusEl.focus();
+        }
+    },
 
     // private
-    render : function(renderTo){
-        var btn;
-        if(this.hideParent){
-            this.parentEl = Roo.get(renderTo);
-        }
-        if(!this.dhconfig){
-            if(!this.template){
-                if(!Roo.Button.buttonTemplate){
-                    // hideous table template
-                    Roo.Button.buttonTemplate = new Roo.Template(
-                        '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
-                        '<td class="x-btn-left"><i>&#160;</i></td><td class="x-btn-center"><em unselectable="on"><button class="x-btn-text" type="{1}">{0}</button></em></td><td class="x-btn-right"><i>&#160;</i></td>',
-                        "</tr></tbody></table>");
+    constrainXY : function(){
+        if(this.constraintoviewport !== false){
+            if(!this.viewSize){
+                if(this.container){
+                    var s = this.container.getSize();
+                    this.viewSize = [s.width, s.height];
+                }else{
+                    this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
                 }
-                this.template = Roo.Button.buttonTemplate;
             }
-            btn = this.template.append(renderTo, [this.text || '&#160;', this.type], true);
-            var btnEl = btn.child("button:first");
-            btnEl.on('focus', this.onFocus, this);
-            btnEl.on('blur', this.onBlur, this);
-            if(this.cls){
-                btn.addClass(this.cls);
+            var s = Roo.get(this.container||document).getScroll();
+
+            var x = this.xy[0], y = this.xy[1];
+            var w = this.size.width, h = this.size.height;
+            var vw = this.viewSize[0], vh = this.viewSize[1];
+            // only move it if it needs it
+            var moved = false;
+            // first validate right/bottom
+            if(x + w > vw+s.left){
+                x = vw - w;
+                moved = true;
             }
-            if(this.icon){
-                btnEl.setStyle('background-image', 'url(' +this.icon +')');
+            if(y + h > vh+s.top){
+                y = vh - h;
+                moved = true;
             }
-            if(this.iconCls){
-                btnEl.addClass(this.iconCls);
-                if(!this.cls){
-                    btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
-                }
+            // then make sure top/left isn't negative
+            if(x < s.left){
+                x = s.left;
+                moved = true;
             }
-            if(this.tabIndex !== undefined){
-                btnEl.dom.tabIndex = this.tabIndex;
+            if(y < s.top){
+                y = s.top;
+                moved = true;
             }
-            if(this.tooltip){
-                if(typeof this.tooltip == 'object'){
-                    Roo.QuickTips.tips(Roo.apply({
-                          target: btnEl.id
-                    }, this.tooltip));
-                } else {
-                    btnEl.dom[this.tooltipType] = this.tooltip;
+            if(moved){
+                // cache xy
+                this.xy = [x, y];
+                if(this.isVisible()){
+                    this.el.setLocation(x, y);
+                    this.adjustAssets();
                 }
             }
-        }else{
-            btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
-        }
-        this.el = btn;
-        if(this.id){
-            this.el.dom.id = this.el.id = this.id;
         }
-        if(this.menu){
-            this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
-            this.menu.on("show", this.onMenuShow, this);
-            this.menu.on("hide", this.onMenuHide, this);
+    },
+
+    // private
+    onDrag : function(){
+        if(!this.proxyDrag){
+            this.xy = this.el.getXY();
+            this.adjustAssets();
         }
-        btn.addClass("x-btn");
-        if(Roo.isIE && !Roo.isIE7){
-            this.autoWidth.defer(1, this);
-        }else{
-            this.autoWidth();
+    },
+
+    // private
+    adjustAssets : function(doShow){
+        var x = this.xy[0], y = this.xy[1];
+        var w = this.size.width, h = this.size.height;
+        if(doShow === true){
+            if(this.shadow){
+                this.shadow.show(this.el);
+            }
+            if(this.shim){
+                this.shim.show();
+            }
         }
-        if(this.handleMouseEvents){
-            btn.on("mouseover", this.onMouseOver, this);
-            btn.on("mouseout", this.onMouseOut, this);
-            btn.on("mousedown", this.onMouseDown, this);
+        if(this.shadow && this.shadow.isVisible()){
+            this.shadow.show(this.el);
         }
-        btn.on(this.clickEvent, this.onClick, this);
-        //btn.on("mouseup", this.onMouseUp, this);
-        if(this.hidden){
-            this.hide();
+        if(this.shim && this.shim.isVisible()){
+            this.shim.setBounds(x, y, w, h);
         }
-        if(this.disabled){
-            this.disable();
+    },
+
+    // private
+    adjustViewport : function(w, h){
+        if(!w || !h){
+            w = Roo.lib.Dom.getViewWidth();
+            h = Roo.lib.Dom.getViewHeight();
         }
-        Roo.ButtonToggleMgr.register(this);
-        if(this.pressed){
-            this.el.addClass("x-btn-pressed");
+        // cache the size
+        this.viewSize = [w, h];
+        if(this.modal && this.mask.isVisible()){
+            this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
+            this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
         }
-        if(this.repeat){
-            var repeater = new Roo.util.ClickRepeater(btn,
-                typeof this.repeat == "object" ? this.repeat : {}
-            );
-            repeater.on("click", this.onClick,  this);
+        if(this.isVisible()){
+            this.constrainXY();
         }
-        
-        this.fireEvent('render', this);
-        
-    },
-    /**
-     * Returns the button's underlying element
-     * @return {Roo.Element} The element
-     */
-    getEl : function(){
-        return this.el;  
     },
-    
+
     /**
-     * Destroys this Button and removes any listeners.
+     * Destroys this dialog and all its supporting elements (including any tabs, shim,
+     * shadow, proxy, mask, etc.)  Also removes all event listeners.
+     * @param {Boolean} removeEl (optional) true to remove the element from the DOM
      */
-    destroy : function(){
-        Roo.ButtonToggleMgr.unregister(this);
+    destroy : function(removeEl){
+        if(this.isVisible()){
+            this.animateTarget = null;
+            this.hide();
+        }
+        Roo.EventManager.removeResizeListener(this.adjustViewport, this);
+        if(this.tabs){
+            this.tabs.destroy(removeEl);
+        }
+        Roo.destroy(
+             this.shim,
+             this.proxy,
+             this.resizer,
+             this.close,
+             this.mask
+        );
+        if(this.dd){
+            this.dd.unreg();
+        }
+        if(this.buttons){
+           for(var i = 0, len = this.buttons.length; i < len; i++){
+               this.buttons[i].destroy();
+           }
+        }
         this.el.removeAllListeners();
-        this.purgeListeners();
-        this.el.remove();
+        if(removeEl === true){
+            this.el.update("");
+            this.el.remove();
+        }
+        Roo.DialogManager.unregister(this);
     },
 
     // private
-    autoWidth : function(){
-        if(this.el){
-            this.el.setWidth("auto");
-            if(Roo.isIE7 && Roo.isStrict){
-                var ib = this.el.child('button');
-                if(ib && ib.getWidth() > 20){
-                    ib.clip();
-                    ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
-                }
-            }
-            if(this.minWidth){
-                if(this.hidden){
-                    this.el.beginMeasure();
-                }
-                if(this.el.getWidth() < this.minWidth){
-                    this.el.setWidth(this.minWidth);
-                }
-                if(this.hidden){
-                    this.el.endMeasure();
-                }
-            }
+    startMove : function(){
+        if(this.proxyDrag){
+            this.proxy.show();
+        }
+        if(this.constraintoviewport !== false){
+            this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
         }
     },
 
-    /**
-     * Assigns this button's click handler
-     * @param {Function} handler The function to call when the button is clicked
-     * @param {Object} scope (optional) Scope for the function passed in
-     */
-    setHandler : function(handler, scope){
-        this.handler = handler;
-        this.scope = scope;  
-    },
-    
-    /**
-     * Sets this button's text
-     * @param {String} text The button text
-     */
-    setText : function(text){
-        this.text = text;
-        if(this.el){
-            this.el.child("td.x-btn-center button.x-btn-text").update(text);
+    // private
+    endMove : function(){
+        if(!this.proxyDrag){
+            Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
+        }else{
+            Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
+            this.proxy.hide();
         }
-        this.autoWidth();
-    },
-    
-    /**
-     * Gets the text for this button
-     * @return {String} The button text
-     */
-    getText : function(){
-        return this.text;  
+        this.refreshSize();
+        this.adjustAssets();
+        this.focus();
+        this.fireEvent("move", this, this.xy[0], this.xy[1]);
     },
-    
+
     /**
-     * Show this button
+     * Brings this dialog to the front of any other visible dialogs
+     * @return {Roo.BasicDialog} this
      */
-    show: function(){
-        this.hidden = false;
-        if(this.el){
-            this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
-        }
+    toFront : function(){
+        Roo.DialogManager.bringToFront(this);
+        return this;
     },
-    
+
     /**
-     * Hide this button
+     * Sends this dialog to the back (under) of any other visible dialogs
+     * @return {Roo.BasicDialog} this
      */
-    hide: function(){
-        this.hidden = true;
-        if(this.el){
-            this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
-        }
+    toBack : function(){
+        Roo.DialogManager.sendToBack(this);
+        return this;
     },
-    
+
     /**
-     * Convenience function for boolean show/hide
-     * @param {Boolean} visible True to show, false to hide
+     * Centers this dialog in the viewport
+     * @return {Roo.BasicDialog} this
      */
-    setVisible: function(visible){
-        if(visible) {
-            this.show();
-        }else{
-            this.hide();
-        }
+    center : function(){
+        var xy = this.el.getCenterXY(true);
+        this.moveTo(xy[0], xy[1]);
+        return this;
     },
-    
+
     /**
-     * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
-     * @param {Boolean} state (optional) Force a particular state
+     * Moves the dialog's top-left corner to the specified point
+     * @param {Number} x
+     * @param {Number} y
+     * @return {Roo.BasicDialog} this
      */
-    toggle : function(state){
-        state = state === undefined ? !this.pressed : state;
-        if(state != this.pressed){
-            if(state){
-                this.el.addClass("x-btn-pressed");
-                this.pressed = true;
-                this.fireEvent("toggle", this, true);
-            }else{
-                this.el.removeClass("x-btn-pressed");
-                this.pressed = false;
-                this.fireEvent("toggle", this, false);
-            }
-            if(this.toggleHandler){
-                this.toggleHandler.call(this.scope || this, this, state);
-            }
+    moveTo : function(x, y){
+        this.xy = [x,y];
+        if(this.isVisible()){
+            this.el.setXY(this.xy);
+            this.adjustAssets();
         }
+        return this;
     },
-    
-    /**
-     * Focus the button
-     */
-    focus : function(){
-        this.el.child('button:first').focus();
-    },
-    
+
     /**
-     * Disable this button
+     * Aligns the dialog to the specified element
+     * @param {String/HTMLElement/Roo.Element} element The element to align to.
+     * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
+     * @param {Array} offsets (optional) Offset the positioning by [x, y]
+     * @return {Roo.BasicDialog} this
      */
-    disable : function(){
-        if(this.el){
-            this.el.addClass("x-btn-disabled");
+    alignTo : function(element, position, offsets){
+        this.xy = this.el.getAlignToXY(element, position, offsets);
+        if(this.isVisible()){
+            this.el.setXY(this.xy);
+            this.adjustAssets();
         }
-        this.disabled = true;
+        return this;
     },
-    
+
     /**
-     * Enable this button
+     * Anchors an element to another element and realigns it when the window is resized.
+     * @param {String/HTMLElement/Roo.Element} element The element to align to.
+     * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
+     * @param {Array} offsets (optional) Offset the positioning by [x, y]
+     * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
+     * is a number, it is used as the buffer delay (defaults to 50ms).
+     * @return {Roo.BasicDialog} this
      */
-    enable : function(){
-        if(this.el){
-            this.el.removeClass("x-btn-disabled");
+    anchorTo : function(el, alignment, offsets, monitorScroll){
+        var action = function(){
+            this.alignTo(el, alignment, offsets);
+        };
+        Roo.EventManager.onWindowResize(action, this);
+        var tm = typeof monitorScroll;
+        if(tm != 'undefined'){
+            Roo.EventManager.on(window, 'scroll', action, this,
+                {buffer: tm == 'number' ? monitorScroll : 50});
         }
-        this.disabled = false;
+        action.call(this);
+        return this;
     },
 
     /**
-     * Convenience function for boolean enable/disable
-     * @param {Boolean} enabled True to enable, false to disable
+     * Returns true if the dialog is visible
+     * @return {Boolean}
      */
-    setDisabled : function(v){
-        this[v !== true ? "enable" : "disable"]();
+    isVisible : function(){
+        return this.el.isVisible();
     },
 
     // private
-    onClick : function(e){
-        if(e){
-            e.preventDefault();
-        }
-        if(e.button != 0){
+    animHide : function(callback){
+        var b = Roo.get(this.animateTarget).getBox();
+        this.proxy.show();
+        this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
+        this.el.hide();
+        this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
+                    this.hideEl.createDelegate(this, [callback]));
+    },
+
+    /**
+     * Hides the dialog.
+     * @param {Function} callback (optional) Function to call when the dialog is hidden
+     * @return {Roo.BasicDialog} this
+     */
+    hide : function(callback){
+        if (this.fireEvent("beforehide", this) === false){
             return;
         }
-        if(!this.disabled){
-            if(this.enableToggle){
-                this.toggle();
-            }
-            if(this.menu && !this.menu.isVisible()){
-                this.menu.show(this.el, this.menuAlign);
-            }
-            this.fireEvent("click", this, e);
-            if(this.handler){
-                this.el.removeClass("x-btn-over");
-                this.handler.call(this.scope || this, this, e);
-            }
+        if(this.shadow){
+            this.shadow.hide();
         }
-    },
-    // private
-    onMouseOver : function(e){
-        if(!this.disabled){
-            this.el.addClass("x-btn-over");
-            this.fireEvent('mouseover', this, e);
+        if(this.shim) {
+          this.shim.hide();
         }
-    },
-    // private
-    onMouseOut : function(e){
-        if(!e.within(this.el,  true)){
-            this.el.removeClass("x-btn-over");
-            this.fireEvent('mouseout', this, e);
+        // sometimes animateTarget seems to get set.. causing problems...
+        // this just double checks..
+        if(this.animateTarget && Roo.get(this.animateTarget)) {
+           this.animHide(callback);
+        }else{
+            this.el.hide();
+            this.hideEl(callback);
         }
+        return this;
     },
+
     // private
-    onFocus : function(e){
-        if(!this.disabled){
-            this.el.addClass("x-btn-focus");
+    hideEl : function(callback){
+        this.proxy.hide();
+        if(this.modal){
+            this.mask.hide();
+            Roo.get(document.body).removeClass("x-body-masked");
+        }
+        this.fireEvent("hide", this);
+        if(typeof callback == "function"){
+            callback();
         }
     },
+
     // private
-    onBlur : function(e){
-        this.el.removeClass("x-btn-focus");
+    hideAction : function(){
+        this.setLeft("-10000px");
+        this.setTop("-10000px");
+        this.setStyle("visibility", "hidden");
     },
+
     // private
-    onMouseDown : function(e){
-        if(!this.disabled && e.button == 0){
-            this.el.addClass("x-btn-click");
-            Roo.get(document).on('mouseup', this.onMouseUp, this);
-        }
+    refreshSize : function(){
+        this.size = this.el.getSize();
+        this.xy = this.el.getXY();
+        Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
     },
+
     // private
-    onMouseUp : function(e){
-        if(e.button == 0){
-            this.el.removeClass("x-btn-click");
-            Roo.get(document).un('mouseup', this.onMouseUp, this);
+    // z-index is managed by the DialogManager and may be overwritten at any time
+    setZIndex : function(index){
+        if(this.modal){
+            this.mask.setStyle("z-index", index);
         }
+        if(this.shim){
+            this.shim.setStyle("z-index", ++index);
+        }
+        if(this.shadow){
+            this.shadow.setZIndex(++index);
+        }
+        this.el.setStyle("z-index", ++index);
+        if(this.proxy){
+            this.proxy.setStyle("z-index", ++index);
+        }
+        if(this.resizer){
+            this.resizer.proxy.setStyle("z-index", ++index);
+        }
+
+        this.lastZIndex = index;
     },
-    // private
-    onMenuShow : function(e){
-        this.el.addClass("x-btn-menu-active");
-    },
-    // private
-    onMenuHide : function(e){
-        this.el.removeClass("x-btn-menu-active");
-    }   
-});
 
-// Private utility class used by Button
-Roo.ButtonToggleMgr = function(){
-   var groups = {};
-   
-   function toggleGroup(btn, state){
-       if(state){
-           var g = groups[btn.toggleGroup];
-           for(var i = 0, l = g.length; i < l; i++){
-               if(g[i] != btn){
-                   g[i].toggle(false);
-               }
-           }
-       }
-   }
-   
-   return {
-       register : function(btn){
-           if(!btn.toggleGroup){
-               return;
-           }
-           var g = groups[btn.toggleGroup];
-           if(!g){
-               g = groups[btn.toggleGroup] = [];
-           }
-           g.push(btn);
-           btn.on("toggle", toggleGroup);
-       },
-       
-       unregister : function(btn){
-           if(!btn.toggleGroup){
-               return;
-           }
-           var g = groups[btn.toggleGroup];
-           if(g){
-               g.remove(btn);
-               btn.un("toggle", toggleGroup);
-           }
-       }
-   };
-}();/*
- * 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.SplitButton
- * @extends Roo.Button
- * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
- * click event of the button.  Typically this would be used to display a dropdown menu that provides additional
- * options to the primary button action, but any custom handler can provide the arrowclick implementation.
- * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
- * @cfg {String} arrowTooltip The title attribute of the arrow
- * @constructor
- * Create a new menu button
- * @param {String/HTMLElement/Element} renderTo The element to append the button to
- * @param {Object} config The config object
- */
-Roo.SplitButton = function(renderTo, config){
-    Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
     /**
-     * @event arrowclick
-     * Fires when this button's arrow is clicked
-     * @param {SplitButton} this
-     * @param {EventObject} e The click event
+     * Returns the element for this dialog
+     * @return {Roo.Element} The underlying dialog Element
      */
-    this.addEvents({"arrowclick":true});
-};
+    getEl : function(){
+        return this.el;
+    }
+});
 
-Roo.extend(Roo.SplitButton, Roo.Button, {
-    render : function(renderTo){
-        // this is one sweet looking template!
-        var tpl = new Roo.Template(
-            '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
-            '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
-            '<tr><td class="x-btn-left"><i>&#160;</i></td><td class="x-btn-center"><button class="x-btn-text" type="{1}">{0}</button></td></tr>',
-            "</tbody></table></td><td>",
-            '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
-            '<tr><td class="x-btn-center"><button class="x-btn-menu-arrow-el" type="button">&#160;</button></td><td class="x-btn-right"><i>&#160;</i></td></tr>',
-            "</tbody></table></td></tr></table>"
-        );
-        var btn = tpl.append(renderTo, [this.text, this.type], true);
-        var btnEl = btn.child("button");
-        if(this.cls){
-            btn.addClass(this.cls);
-        }
-        if(this.icon){
-            btnEl.setStyle('background-image', 'url(' +this.icon +')');
-        }
-        if(this.iconCls){
-            btnEl.addClass(this.iconCls);
-            if(!this.cls){
-                btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
-            }
-        }
-        this.el = btn;
-        if(this.handleMouseEvents){
-            btn.on("mouseover", this.onMouseOver, this);
-            btn.on("mouseout", this.onMouseOut, this);
-            btn.on("mousedown", this.onMouseDown, this);
-            btn.on("mouseup", this.onMouseUp, this);
-        }
-        btn.on(this.clickEvent, this.onClick, this);
-        if(this.tooltip){
-            if(typeof this.tooltip == 'object'){
-                Roo.QuickTips.tips(Roo.apply({
-                      target: btnEl.id
-                }, this.tooltip));
-            } else {
-                btnEl.dom[this.tooltipType] = this.tooltip;
-            }
-        }
-        if(this.arrowTooltip){
-            btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
-        }
-        if(this.hidden){
-            this.hide();
-        }
-        if(this.disabled){
-            this.disable();
-        }
-        if(this.pressed){
-            this.el.addClass("x-btn-pressed");
-        }
-        if(Roo.isIE && !Roo.isIE7){
-            this.autoWidth.defer(1, this);
-        }else{
-            this.autoWidth();
-        }
-        if(this.menu){
-            this.menu.on("show", this.onMenuShow, this);
-            this.menu.on("hide", this.onMenuHide, this);
-        }
-        this.fireEvent('render', this);
-    },
+/**
+ * @class Roo.DialogManager
+ * Provides global access to BasicDialogs that have been created and
+ * support for z-indexing (layering) multiple open dialogs.
+ */
+Roo.DialogManager = function(){
+    var list = {};
+    var accessList = [];
+    var front = null;
 
     // private
-    autoWidth : function(){
-        if(this.el){
-            var tbl = this.el.child("table:first");
-            var tbl2 = this.el.child("table:last");
-            this.el.setWidth("auto");
-            tbl.setWidth("auto");
-            if(Roo.isIE7 && Roo.isStrict){
-                var ib = this.el.child('button:first');
-                if(ib && ib.getWidth() > 20){
-                    ib.clip();
-                    ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
-                }
+    var sortDialogs = function(d1, d2){
+        return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
+    };
+
+    // private
+    var orderDialogs = function(){
+        accessList.sort(sortDialogs);
+        var seed = Roo.DialogManager.zseed;
+        for(var i = 0, len = accessList.length; i < len; i++){
+            var dlg = accessList[i];
+            if(dlg){
+                dlg.setZIndex(seed + (i*10));
             }
-            if(this.minWidth){
-                if(this.hidden){
-                    this.el.beginMeasure();
+        }
+    };
+
+    return {
+        /**
+         * The starting z-index for BasicDialogs (defaults to 9000)
+         * @type Number The z-index value
+         */
+        zseed : 9000,
+
+        // private
+        register : function(dlg){
+            list[dlg.id] = dlg;
+            accessList.push(dlg);
+        },
+
+        // private
+        unregister : function(dlg){
+            delete list[dlg.id];
+            var i=0;
+            var len=0;
+            if(!accessList.indexOf){
+                for(  i = 0, len = accessList.length; i < len; i++){
+                    if(accessList[i] == dlg){
+                        accessList.splice(i, 1);
+                        return;
+                    }
                 }
-                if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
-                    tbl.setWidth(this.minWidth-tbl2.getWidth());
+            }else{
+                 i = accessList.indexOf(dlg);
+                if(i != -1){
+                    accessList.splice(i, 1);
                 }
-                if(this.hidden){
-                    this.el.endMeasure();
+            }
+        },
+
+        /**
+         * Gets a registered dialog by id
+         * @param {String/Object} id The id of the dialog or a dialog
+         * @return {Roo.BasicDialog} this
+         */
+        get : function(id){
+            return typeof id == "object" ? id : list[id];
+        },
+
+        /**
+         * Brings the specified dialog to the front
+         * @param {String/Object} dlg The id of the dialog or a dialog
+         * @return {Roo.BasicDialog} this
+         */
+        bringToFront : function(dlg){
+            dlg = this.get(dlg);
+            if(dlg != front){
+                front = dlg;
+                dlg._lastAccess = new Date().getTime();
+                orderDialogs();
+            }
+            return dlg;
+        },
+
+        /**
+         * Sends the specified dialog to the back
+         * @param {String/Object} dlg The id of the dialog or a dialog
+         * @return {Roo.BasicDialog} this
+         */
+        sendToBack : function(dlg){
+            dlg = this.get(dlg);
+            dlg._lastAccess = -(new Date().getTime());
+            orderDialogs();
+            return dlg;
+        },
+
+        /**
+         * Hides all dialogs
+         */
+        hideAll : function(){
+            for(var id in list){
+                if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
+                    list[id].hide();
                 }
             }
-            this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
-        } 
-    },
+        }
+    };
+}();
+
+/**
+ * @class Roo.LayoutDialog
+ * @extends Roo.BasicDialog
+ * Dialog which provides adjustments for working with a layout in a Dialog.
+ * Add your necessary layout config options to the dialog's config.<br>
+ * Example usage (including a nested layout):
+ * <pre><code>
+if(!dialog){
+    dialog = new Roo.LayoutDialog("download-dlg", {
+        modal: true,
+        width:600,
+        height:450,
+        shadow:true,
+        minWidth:500,
+        minHeight:350,
+        autoTabs:true,
+        proxyDrag:true,
+        // layout config merges with the dialog config
+        center:{
+            tabPosition: "top",
+            alwaysShowTabs: true
+        }
+    });
+    dialog.addKeyListener(27, dialog.hide, dialog);
+    dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
+    dialog.addButton("Build It!", this.getDownload, this);
+
+    // we can even add nested layouts
+    var innerLayout = new Roo.BorderLayout("dl-inner", {
+        east: {
+            initialSize: 200,
+            autoScroll:true,
+            split:true
+        },
+        center: {
+            autoScroll:true
+        }
+    });
+    innerLayout.beginUpdate();
+    innerLayout.add("east", new Roo.ContentPanel("dl-details"));
+    innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
+    innerLayout.endUpdate(true);
+
+    var layout = dialog.getLayout();
+    layout.beginUpdate();
+    layout.add("center", new Roo.ContentPanel("standard-panel",
+                        {title: "Download the Source", fitToFrame:true}));
+    layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
+               {title: "Build your own roo.js"}));
+    layout.getRegion("center").showPanel(sp);
+    layout.endUpdate();
+}
+</code></pre>
+    * @constructor
+    * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
+    * @param {Object} config configuration options
+  */
+Roo.LayoutDialog = function(el, cfg){
+    
+    var config=  cfg;
+    if (typeof(cfg) == 'undefined') {
+        config = Roo.apply({}, el);
+        // not sure why we use documentElement here.. - it should always be body.
+        // IE7 borks horribly if we use documentElement.
+        // webkit also does not like documentElement - it creates a body element...
+        el = Roo.get( document.body || document.documentElement ).createChild();
+        //config.autoCreate = true;
+    }
+    
+    
+    config.autoTabs = false;
+    Roo.LayoutDialog.superclass.constructor.call(this, el, config);
+    this.body.setStyle({overflow:"hidden", position:"relative"});
+    this.layout = new Roo.BorderLayout(this.body.dom, config);
+    this.layout.monitorWindowResize = false;
+    this.el.addClass("x-dlg-auto-layout");
+    // fix case when center region overwrites center function
+    this.center = Roo.BasicDialog.prototype.center;
+    this.on("show", this.layout.layout, this.layout, true);
+    if (config.items) {
+        var xitems = config.items;
+        delete config.items;
+        Roo.each(xitems, this.addxtype, this);
+    }
+    
+    
+};
+Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
     /**
-     * Sets this button's click handler
-     * @param {Function} handler The function to call when the button is clicked
-     * @param {Object} scope (optional) Scope for the function passed above
+     * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
+     * @deprecated
      */
-    setHandler : function(handler, scope){
-        this.handler = handler;
-        this.scope = scope;  
+    endUpdate : function(){
+        this.layout.endUpdate();
     },
-    
+
     /**
-     * Sets this button's arrow click handler
-     * @param {Function} handler The function to call when the arrow is clicked
-     * @param {Object} scope (optional) Scope for the function passed above
+     * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
+     *  @deprecated
      */
-    setArrowHandler : function(handler, scope){
-        this.arrowHandler = handler;
-        this.scope = scope;  
+    beginUpdate : function(){
+        this.layout.beginUpdate();
     },
-    
+
     /**
-     * Focus the button
+     * Get the BorderLayout for this dialog
+     * @return {Roo.BorderLayout}
      */
-    focus : function(){
-        if(this.el){
-            this.el.child("button:first").focus();
-        }
+    getLayout : function(){
+        return this.layout;
     },
 
-    // private
-    onClick : function(e){
-        e.preventDefault();
-        if(!this.disabled){
-            if(e.getTarget(".x-btn-menu-arrow-wrap")){
-                if(this.menu && !this.menu.isVisible()){
-                    this.menu.show(this.el, this.menuAlign);
-                }
-                this.fireEvent("arrowclick", this, e);
-                if(this.arrowHandler){
-                    this.arrowHandler.call(this.scope || this, this, e);
-                }
-            }else{
-                this.fireEvent("click", this, e);
-                if(this.handler){
-                    this.handler.call(this.scope || this, this, e);
-                }
-            }
+    showEl : function(){
+        Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
+        if(Roo.isIE7){
+            this.layout.layout();
         }
     },
+
     // private
-    onMouseDown : function(e){
-        if(!this.disabled){
-            Roo.fly(e.getTarget("table")).addClass("x-btn-click");
-        }
+    // Use the syncHeightBeforeShow config option to control this automatically
+    syncBodyHeight : function(){
+        Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
+        if(this.layout){this.layout.layout();}
     },
-    // private
-    onMouseUp : function(e){
-        Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
-    }   
-});
-
-
-// backwards compat
-Roo.MenuButton = Roo.SplitButton;/*
+    
+      /**
+     * Add an xtype element (actually adds to the layout.)
+     * @return {Object} xdata xtype object data.
+     */
+    
+    addxtype : function(c) {
+        return this.layout.addxtype(c);
+    }
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -11690,3279 +10685,77 @@ Roo.MenuButton = Roo.SplitButton;/*
  * Fork - LGPL
  * <script type="text/javascript">
  */
-
 /**
- * @class Roo.Toolbar
- * Basic Toolbar class.
- * @constructor
- * Creates a new Toolbar
- * @param {Object} container The config object
- */ 
-Roo.Toolbar = function(container, buttons, config)
-{
-    /// old consturctor format still supported..
-    if(container instanceof Array){ // omit the container for later rendering
-        buttons = container;
-        config = buttons;
-        container = null;
-    }
-    if (typeof(container) == 'object' && container.xtype) {
-        config = container;
-        container = config.container;
-        buttons = config.buttons || []; // not really - use items!!
-    }
-    var xitems = [];
-    if (config && config.items) {
-        xitems = config.items;
-        delete config.items;
-    }
-    Roo.apply(this, config);
-    this.buttons = buttons;
-    
-    if(container){
-        this.render(container);
+ * @class Roo.MessageBox
+ * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
+ * Example usage:
+ *<pre><code>
+// Basic alert:
+Roo.Msg.alert('Status', 'Changes saved successfully.');
+
+// Prompt for user data:
+Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
+    if (btn == 'ok'){
+        // process text value...
     }
-    this.xitems = xitems;
-    Roo.each(xitems, function(b) {
-        this.add(b);
-    }, this);
-    
-};
+});
+
+// Show a dialog using config options:
+Roo.Msg.show({
+   title:'Save Changes?',
+   msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
+   buttons: Roo.Msg.YESNOCANCEL,
+   fn: processResult,
+   animEl: 'elId'
+});
+</code></pre>
+ * @singleton
+ */
+Roo.MessageBox = function(){
+    var dlg, opt, mask, waitTimer;
+    var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
+    var buttons, activeTextEl, bwidth;
 
-Roo.Toolbar.prototype = {
-    /**
-     * @cfg {Array} items
-     * array of button configs or elements to add (will be converted to a MixedCollection)
-     */
-    
-    /**
-     * @cfg {String/HTMLElement/Element} container
-     * The id or element that will contain the toolbar
-     */
     // private
-    render : function(ct){
-        this.el = Roo.get(ct);
-        if(this.cls){
-            this.el.addClass(this.cls);
+    var handleButton = function(button){
+        dlg.hide();
+        Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
+    };
+
+    // private
+    var handleHide = function(){
+        if(opt && opt.cls){
+            dlg.el.removeClass(opt.cls);
         }
-        // using a table allows for vertical alignment
-        // 100% width is needed by Safari...
-        this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
-        this.tr = this.el.child("tr", true);
-        var autoId = 0;
-        this.items = new Roo.util.MixedCollection(false, function(o){
-            return o.id || ("item" + (++autoId));
-        });
-        if(this.buttons){
-            this.add.apply(this, this.buttons);
-            delete this.buttons;
+        if(waitTimer){
+            Roo.TaskMgr.stop(waitTimer);
+            waitTimer = null;
         }
-    },
+    };
 
-    /**
-     * Adds element(s) to the toolbar -- this function takes a variable number of 
-     * arguments of mixed type and adds them to the toolbar.
-     * @param {Mixed} arg1 The following types of arguments are all valid:<br />
-     * <ul>
-     * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
-     * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
-     * <li>Field: Any form field (equivalent to {@link #addField})</li>
-     * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
-     * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
-     * Note that there are a few special strings that are treated differently as explained nRoo.</li>
-     * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
-     * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
-     * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
-     * </ul>
-     * @param {Mixed} arg2
-     * @param {Mixed} etc.
-     */
-    add : function(){
-        var a = arguments, l = a.length;
-        for(var i = 0; i < l; i++){
-            this._add(a[i]);
+    // private
+    var updateButtons = function(b){
+        var width = 0;
+        if(!b){
+            buttons["ok"].hide();
+            buttons["cancel"].hide();
+            buttons["yes"].hide();
+            buttons["no"].hide();
+            dlg.footer.dom.style.display = 'none';
+            return width;
         }
-    },
-    // private..
-    _add : function(el) {
-        
-        if (el.xtype) {
-            el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
-        }
-        
-        if (el.applyTo){ // some kind of form field
-            return this.addField(el);
-        } 
-        if (el.render){ // some kind of Toolbar.Item
-            return this.addItem(el);
-        }
-        if (typeof el == "string"){ // string
-            if(el == "separator" || el == "-"){
-                return this.addSeparator();
-            }
-            if (el == " "){
-                return this.addSpacer();
-            }
-            if(el == "->"){
-                return this.addFill();
-            }
-            return this.addText(el);
-            
-        }
-        if(el.tagName){ // element
-            return this.addElement(el);
-        }
-        if(typeof el == "object"){ // must be button config?
-            return this.addButton(el);
-        }
-        // and now what?!?!
-        return false;
-        
-    },
-    
-    /**
-     * Add an Xtype element
-     * @param {Object} xtype Xtype Object
-     * @return {Object} created Object
-     */
-    addxtype : function(e){
-        return this.add(e);  
-    },
-    
-    /**
-     * Returns the Element for this toolbar.
-     * @return {Roo.Element}
-     */
-    getEl : function(){
-        return this.el;  
-    },
-    
-    /**
-     * Adds a separator
-     * @return {Roo.Toolbar.Item} The separator item
-     */
-    addSeparator : function(){
-        return this.addItem(new Roo.Toolbar.Separator());
-    },
-
-    /**
-     * Adds a spacer element
-     * @return {Roo.Toolbar.Spacer} The spacer item
-     */
-    addSpacer : function(){
-        return this.addItem(new Roo.Toolbar.Spacer());
-    },
-
-    /**
-     * Adds a fill element that forces subsequent additions to the right side of the toolbar
-     * @return {Roo.Toolbar.Fill} The fill item
-     */
-    addFill : function(){
-        return this.addItem(new Roo.Toolbar.Fill());
-    },
-
-    /**
-     * Adds any standard HTML element to the toolbar
-     * @param {String/HTMLElement/Element} el The element or id of the element to add
-     * @return {Roo.Toolbar.Item} The element's item
-     */
-    addElement : function(el){
-        return this.addItem(new Roo.Toolbar.Item(el));
-    },
-    /**
-     * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
-     * @type Roo.util.MixedCollection  
-     */
-    items : false,
-     
-    /**
-     * Adds any Toolbar.Item or subclass
-     * @param {Roo.Toolbar.Item} item
-     * @return {Roo.Toolbar.Item} The item
-     */
-    addItem : function(item){
-        var td = this.nextBlock();
-        item.render(td);
-        this.items.add(item);
-        return item;
-    },
-    
-    /**
-     * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
-     * @param {Object/Array} config A button config or array of configs
-     * @return {Roo.Toolbar.Button/Array}
-     */
-    addButton : function(config){
-        if(config instanceof Array){
-            var buttons = [];
-            for(var i = 0, len = config.length; i < len; i++) {
-                buttons.push(this.addButton(config[i]));
-            }
-            return buttons;
-        }
-        var b = config;
-        if(!(config instanceof Roo.Toolbar.Button)){
-            b = config.split ?
-                new Roo.Toolbar.SplitButton(config) :
-                new Roo.Toolbar.Button(config);
-        }
-        var td = this.nextBlock();
-        b.render(td);
-        this.items.add(b);
-        return b;
-    },
-    
-    /**
-     * Adds text to the toolbar
-     * @param {String} text The text to add
-     * @return {Roo.Toolbar.Item} The element's item
-     */
-    addText : function(text){
-        return this.addItem(new Roo.Toolbar.TextItem(text));
-    },
-    
-    /**
-     * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
-     * @param {Number} index The index where the item is to be inserted
-     * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
-     * @return {Roo.Toolbar.Button/Item}
-     */
-    insertButton : function(index, item){
-        if(item instanceof Array){
-            var buttons = [];
-            for(var i = 0, len = item.length; i < len; i++) {
-               buttons.push(this.insertButton(index + i, item[i]));
-            }
-            return buttons;
-        }
-        if (!(item instanceof Roo.Toolbar.Button)){
-           item = new Roo.Toolbar.Button(item);
-        }
-        var td = document.createElement("td");
-        this.tr.insertBefore(td, this.tr.childNodes[index]);
-        item.render(td);
-        this.items.insert(index, item);
-        return item;
-    },
-    
-    /**
-     * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
-     * @param {Object} config
-     * @return {Roo.Toolbar.Item} The element's item
-     */
-    addDom : function(config, returnEl){
-        var td = this.nextBlock();
-        Roo.DomHelper.overwrite(td, config);
-        var ti = new Roo.Toolbar.Item(td.firstChild);
-        ti.render(td);
-        this.items.add(ti);
-        return ti;
-    },
-
-    /**
-     * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
-     * @type Roo.util.MixedCollection  
-     */
-    fields : false,
-    
-    /**
-     * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
-     * Note: the field should not have been rendered yet. For a field that has already been
-     * rendered, use {@link #addElement}.
-     * @param {Roo.form.Field} field
-     * @return {Roo.ToolbarItem}
-     */
-     
-      
-    addField : function(field) {
-        if (!this.fields) {
-            var autoId = 0;
-            this.fields = new Roo.util.MixedCollection(false, function(o){
-                return o.id || ("item" + (++autoId));
-            });
-
-        }
-        
-        var td = this.nextBlock();
-        field.render(td);
-        var ti = new Roo.Toolbar.Item(td.firstChild);
-        ti.render(td);
-        this.items.add(ti);
-        this.fields.add(field);
-        return ti;
-    },
-    /**
-     * Hide the toolbar
-     * @method hide
-     */
-     
-      
-    hide : function()
-    {
-        this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
-        this.el.child('div').hide();
-    },
-    /**
-     * Show the toolbar
-     * @method show
-     */
-    show : function()
-    {
-        this.el.child('div').show();
-    },
-      
-    // private
-    nextBlock : function(){
-        var td = document.createElement("td");
-        this.tr.appendChild(td);
-        return td;
-    },
-
-    // private
-    destroy : function(){
-        if(this.items){ // rendered?
-            Roo.destroy.apply(Roo, this.items.items);
-        }
-        if(this.fields){ // rendered?
-            Roo.destroy.apply(Roo, this.fields.items);
-        }
-        Roo.Element.uncache(this.el, this.tr);
-    }
-};
-
-/**
- * @class Roo.Toolbar.Item
- * The base class that other classes should extend in order to get some basic common toolbar item functionality.
- * @constructor
- * Creates a new Item
- * @param {HTMLElement} el 
- */
-Roo.Toolbar.Item = function(el){
-    this.el = Roo.getDom(el);
-    this.id = Roo.id(this.el);
-    this.hidden = false;
-};
-
-Roo.Toolbar.Item.prototype = {
-    
-    /**
-     * Get this item's HTML Element
-     * @return {HTMLElement}
-     */
-    getEl : function(){
-       return this.el;  
-    },
-
-    // private
-    render : function(td){
-        this.td = td;
-        td.appendChild(this.el);
-    },
-    
-    /**
-     * Removes and destroys this item.
-     */
-    destroy : function(){
-        this.td.parentNode.removeChild(this.td);
-    },
-    
-    /**
-     * Shows this item.
-     */
-    show: function(){
-        this.hidden = false;
-        this.td.style.display = "";
-    },
-    
-    /**
-     * Hides this item.
-     */
-    hide: function(){
-        this.hidden = true;
-        this.td.style.display = "none";
-    },
-    
-    /**
-     * Convenience function for boolean show/hide.
-     * @param {Boolean} visible true to show/false to hide
-     */
-    setVisible: function(visible){
-        if(visible) {
-            this.show();
-        }else{
-            this.hide();
-        }
-    },
-    
-    /**
-     * Try to focus this item.
-     */
-    focus : function(){
-        Roo.fly(this.el).focus();
-    },
-    
-    /**
-     * Disables this item.
-     */
-    disable : function(){
-        Roo.fly(this.td).addClass("x-item-disabled");
-        this.disabled = true;
-        this.el.disabled = true;
-    },
-    
-    /**
-     * Enables this item.
-     */
-    enable : function(){
-        Roo.fly(this.td).removeClass("x-item-disabled");
-        this.disabled = false;
-        this.el.disabled = false;
-    }
-};
-
-
-/**
- * @class Roo.Toolbar.Separator
- * @extends Roo.Toolbar.Item
- * A simple toolbar separator class
- * @constructor
- * Creates a new Separator
- */
-Roo.Toolbar.Separator = function(){
-    var s = document.createElement("span");
-    s.className = "ytb-sep";
-    Roo.Toolbar.Separator.superclass.constructor.call(this, s);
-};
-Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
-    enable:Roo.emptyFn,
-    disable:Roo.emptyFn,
-    focus:Roo.emptyFn
-});
-
-/**
- * @class Roo.Toolbar.Spacer
- * @extends Roo.Toolbar.Item
- * A simple element that adds extra horizontal space to a toolbar.
- * @constructor
- * Creates a new Spacer
- */
-Roo.Toolbar.Spacer = function(){
-    var s = document.createElement("div");
-    s.className = "ytb-spacer";
-    Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
-};
-Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
-    enable:Roo.emptyFn,
-    disable:Roo.emptyFn,
-    focus:Roo.emptyFn
-});
-
-/**
- * @class Roo.Toolbar.Fill
- * @extends Roo.Toolbar.Spacer
- * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
- * @constructor
- * Creates a new Spacer
- */
-Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
-    // private
-    render : function(td){
-        td.style.width = '100%';
-        Roo.Toolbar.Fill.superclass.render.call(this, td);
-    }
-});
-
-/**
- * @class Roo.Toolbar.TextItem
- * @extends Roo.Toolbar.Item
- * A simple class that renders text directly into a toolbar.
- * @constructor
- * Creates a new TextItem
- * @param {String} text
- */
-Roo.Toolbar.TextItem = function(text){
-    if (typeof(text) == 'object') {
-        text = text.text;
-    }
-    var s = document.createElement("span");
-    s.className = "ytb-text";
-    s.innerHTML = text;
-    Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
-};
-Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
-    enable:Roo.emptyFn,
-    disable:Roo.emptyFn,
-    focus:Roo.emptyFn
-});
-
-/**
- * @class Roo.Toolbar.Button
- * @extends Roo.Button
- * A button that renders into a toolbar.
- * @constructor
- * Creates a new Button
- * @param {Object} config A standard {@link Roo.Button} config object
- */
-Roo.Toolbar.Button = function(config){
-    Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
-};
-Roo.extend(Roo.Toolbar.Button, Roo.Button, {
-    render : function(td){
-        this.td = td;
-        Roo.Toolbar.Button.superclass.render.call(this, td);
-    },
-    
-    /**
-     * Removes and destroys this button
-     */
-    destroy : function(){
-        Roo.Toolbar.Button.superclass.destroy.call(this);
-        this.td.parentNode.removeChild(this.td);
-    },
-    
-    /**
-     * Shows this button
-     */
-    show: function(){
-        this.hidden = false;
-        this.td.style.display = "";
-    },
-    
-    /**
-     * Hides this button
-     */
-    hide: function(){
-        this.hidden = true;
-        this.td.style.display = "none";
-    },
-
-    /**
-     * Disables this item
-     */
-    disable : function(){
-        Roo.fly(this.td).addClass("x-item-disabled");
-        this.disabled = true;
-    },
-
-    /**
-     * Enables this item
-     */
-    enable : function(){
-        Roo.fly(this.td).removeClass("x-item-disabled");
-        this.disabled = false;
-    }
-});
-// backwards compat
-Roo.ToolbarButton = Roo.Toolbar.Button;
-
-/**
- * @class Roo.Toolbar.SplitButton
- * @extends Roo.SplitButton
- * A menu button that renders into a toolbar.
- * @constructor
- * Creates a new SplitButton
- * @param {Object} config A standard {@link Roo.SplitButton} config object
- */
-Roo.Toolbar.SplitButton = function(config){
-    Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
-};
-Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
-    render : function(td){
-        this.td = td;
-        Roo.Toolbar.SplitButton.superclass.render.call(this, td);
-    },
-    
-    /**
-     * Removes and destroys this button
-     */
-    destroy : function(){
-        Roo.Toolbar.SplitButton.superclass.destroy.call(this);
-        this.td.parentNode.removeChild(this.td);
-    },
-    
-    /**
-     * Shows this button
-     */
-    show: function(){
-        this.hidden = false;
-        this.td.style.display = "";
-    },
-    
-    /**
-     * Hides this button
-     */
-    hide: function(){
-        this.hidden = true;
-        this.td.style.display = "none";
-    }
-});
-
-// backwards compat
-Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
- * 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.PagingToolbar
- * @extends Roo.Toolbar
- * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
- * @constructor
- * Create a new PagingToolbar
- * @param {Object} config The config object
- */
-Roo.PagingToolbar = function(el, ds, config)
-{
-    // old args format still supported... - xtype is prefered..
-    if (typeof(el) == 'object' && el.xtype) {
-        // created from xtype...
-        config = el;
-        ds = el.dataSource;
-        el = config.container;
-    }
-    var items = [];
-    if (config.items) {
-        items = config.items;
-        config.items = [];
-    }
-    
-    Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
-    this.ds = ds;
-    this.cursor = 0;
-    this.renderButtons(this.el);
-    this.bind(ds);
-    
-    // supprot items array.
-   
-    Roo.each(items, function(e) {
-        this.add(Roo.factory(e));
-    },this);
-    
-};
-
-Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
-    /**
-     * @cfg {Roo.data.Store} dataSource
-     * The underlying data store providing the paged data
-     */
-    /**
-     * @cfg {String/HTMLElement/Element} container
-     * container The id or element that will contain the toolbar
-     */
-    /**
-     * @cfg {Boolean} displayInfo
-     * True to display the displayMsg (defaults to false)
-     */
-    /**
-     * @cfg {Number} pageSize
-     * The number of records to display per page (defaults to 20)
-     */
-    pageSize: 20,
-    /**
-     * @cfg {String} displayMsg
-     * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
-     */
-    displayMsg : 'Displaying {0} - {1} of {2}',
-    /**
-     * @cfg {String} emptyMsg
-     * The message to display when no records are found (defaults to "No data to display")
-     */
-    emptyMsg : 'No data to display',
-    /**
-     * Customizable piece of the default paging text (defaults to "Page")
-     * @type String
-     */
-    beforePageText : "Page",
-    /**
-     * Customizable piece of the default paging text (defaults to "of %0")
-     * @type String
-     */
-    afterPageText : "of {0}",
-    /**
-     * Customizable piece of the default paging text (defaults to "First Page")
-     * @type String
-     */
-    firstText : "First Page",
-    /**
-     * Customizable piece of the default paging text (defaults to "Previous Page")
-     * @type String
-     */
-    prevText : "Previous Page",
-    /**
-     * Customizable piece of the default paging text (defaults to "Next Page")
-     * @type String
-     */
-    nextText : "Next Page",
-    /**
-     * Customizable piece of the default paging text (defaults to "Last Page")
-     * @type String
-     */
-    lastText : "Last Page",
-    /**
-     * Customizable piece of the default paging text (defaults to "Refresh")
-     * @type String
-     */
-    refreshText : "Refresh",
-
-    // private
-    renderButtons : function(el){
-        Roo.PagingToolbar.superclass.render.call(this, el);
-        this.first = this.addButton({
-            tooltip: this.firstText,
-            cls: "x-btn-icon x-grid-page-first",
-            disabled: true,
-            handler: this.onClick.createDelegate(this, ["first"])
-        });
-        this.prev = this.addButton({
-            tooltip: this.prevText,
-            cls: "x-btn-icon x-grid-page-prev",
-            disabled: true,
-            handler: this.onClick.createDelegate(this, ["prev"])
-        });
-        //this.addSeparator();
-        this.add(this.beforePageText);
-        this.field = Roo.get(this.addDom({
-           tag: "input",
-           type: "text",
-           size: "3",
-           value: "1",
-           cls: "x-grid-page-number"
-        }).el);
-        this.field.on("keydown", this.onPagingKeydown, this);
-        this.field.on("focus", function(){this.dom.select();});
-        this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
-        this.field.setHeight(18);
-        //this.addSeparator();
-        this.next = this.addButton({
-            tooltip: this.nextText,
-            cls: "x-btn-icon x-grid-page-next",
-            disabled: true,
-            handler: this.onClick.createDelegate(this, ["next"])
-        });
-        this.last = this.addButton({
-            tooltip: this.lastText,
-            cls: "x-btn-icon x-grid-page-last",
-            disabled: true,
-            handler: this.onClick.createDelegate(this, ["last"])
-        });
-        //this.addSeparator();
-        this.loading = this.addButton({
-            tooltip: this.refreshText,
-            cls: "x-btn-icon x-grid-loading",
-            handler: this.onClick.createDelegate(this, ["refresh"])
-        });
-
-        if(this.displayInfo){
-            this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
-        }
-    },
-
-    // private
-    updateInfo : function(){
-        if(this.displayEl){
-            var count = this.ds.getCount();
-            var msg = count == 0 ?
-                this.emptyMsg :
-                String.format(
-                    this.displayMsg,
-                    this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
-                );
-            this.displayEl.update(msg);
-        }
-    },
-
-    // private
-    onLoad : function(ds, r, o){
-       this.cursor = o.params ? o.params.start : 0;
-       var d = this.getPageData(), ap = d.activePage, ps = d.pages;
-
-       this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
-       this.field.dom.value = ap;
-       this.first.setDisabled(ap == 1);
-       this.prev.setDisabled(ap == 1);
-       this.next.setDisabled(ap == ps);
-       this.last.setDisabled(ap == ps);
-       this.loading.enable();
-       this.updateInfo();
-    },
-
-    // private
-    getPageData : function(){
-        var total = this.ds.getTotalCount();
-        return {
-            total : total,
-            activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
-            pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
-        };
-    },
-
-    // private
-    onLoadError : function(){
-        this.loading.enable();
-    },
-
-    // private
-    onPagingKeydown : function(e){
-        var k = e.getKey();
-        var d = this.getPageData();
-        if(k == e.RETURN){
-            var v = this.field.dom.value, pageNum;
-            if(!v || isNaN(pageNum = parseInt(v, 10))){
-                this.field.dom.value = d.activePage;
-                return;
-            }
-            pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
-            this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
-            e.stopEvent();
-        }
-        else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
-        {
-          var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
-          this.field.dom.value = pageNum;
-          this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
-          e.stopEvent();
-        }
-        else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
-        {
-          var v = this.field.dom.value, pageNum; 
-          var increment = (e.shiftKey) ? 10 : 1;
-          if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
-            increment *= -1;
-          if(!v || isNaN(pageNum = parseInt(v, 10))) {
-            this.field.dom.value = d.activePage;
-            return;
-          }
-          else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
-          {
-            this.field.dom.value = parseInt(v, 10) + increment;
-            pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
-            this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
-          }
-          e.stopEvent();
-        }
-    },
-
-    // private
-    beforeLoad : function(){
-        if(this.loading){
-            this.loading.disable();
-        }
-    },
-
-    // private
-    onClick : function(which){
-        var ds = this.ds;
-        switch(which){
-            case "first":
-                ds.load({params:{start: 0, limit: this.pageSize}});
-            break;
-            case "prev":
-                ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
-            break;
-            case "next":
-                ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
-            break;
-            case "last":
-                var total = ds.getTotalCount();
-                var extra = total % this.pageSize;
-                var lastStart = extra ? (total - extra) : total-this.pageSize;
-                ds.load({params:{start: lastStart, limit: this.pageSize}});
-            break;
-            case "refresh":
-                ds.load({params:{start: this.cursor, limit: this.pageSize}});
-            break;
-        }
-    },
-
-    /**
-     * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
-     * @param {Roo.data.Store} store The data store to unbind
-     */
-    unbind : function(ds){
-        ds.un("beforeload", this.beforeLoad, this);
-        ds.un("load", this.onLoad, this);
-        ds.un("loadexception", this.onLoadError, this);
-        ds.un("remove", this.updateInfo, this);
-        ds.un("add", this.updateInfo, this);
-        this.ds = undefined;
-    },
-
-    /**
-     * Binds the paging toolbar to the specified {@link Roo.data.Store}
-     * @param {Roo.data.Store} store The data store to bind
-     */
-    bind : function(ds){
-        ds.on("beforeload", this.beforeLoad, this);
-        ds.on("load", this.onLoad, this);
-        ds.on("loadexception", this.onLoadError, this);
-        ds.on("remove", this.updateInfo, this);
-        ds.on("add", this.updateInfo, this);
-        this.ds = ds;
-    }
-});/*
- * 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.Resizable
- * @extends Roo.util.Observable
- * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
- * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
- * the textarea in a div and set "resizeChild" to true (or to the id of the element), <b>or</b> set wrap:true in your config and
- * the element will be wrapped for you automatically.</p>
- * <p>Here is the list of valid resize handles:</p>
- * <pre>
-Value   Description
-------  -------------------
- 'n'     north
- 's'     south
- 'e'     east
- 'w'     west
- 'nw'    northwest
- 'sw'    southwest
- 'se'    southeast
- 'ne'    northeast
- 'hd'    horizontal drag
- 'all'   all
-</pre>
- * <p>Here's an example showing the creation of a typical Resizable:</p>
- * <pre><code>
-var resizer = new Roo.Resizable("element-id", {
-    handles: 'all',
-    minWidth: 200,
-    minHeight: 100,
-    maxWidth: 500,
-    maxHeight: 400,
-    pinned: true
-});
-resizer.on("resize", myHandler);
-</code></pre>
- * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
- * resizer.east.setDisplayed(false);</p>
- * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
- * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
- * resize operation's new size (defaults to [0, 0])
- * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
- * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
- * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
- * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
- * @cfg {Boolean} enabled False to disable resizing (defaults to true)
- * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
- * @cfg {Number} width The width of the element in pixels (defaults to null)
- * @cfg {Number} height The height of the element in pixels (defaults to null)
- * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
- * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
- * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
- * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
- * @cfg {Boolean} multiDirectional <b>Deprecated</b>.  The old style of adding multi-direction resize handles, deprecated
- * in favor of the handles config option (defaults to false)
- * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
- * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
- * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
- * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
- * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
- * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
- * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
- * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
- * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
- * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
- * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
- * @constructor
- * Create a new resizable component
- * @param {String/HTMLElement/Roo.Element} el The id or element to resize
- * @param {Object} config configuration options
-  */
-Roo.Resizable = function(el, config)
-{
-    this.el = Roo.get(el);
-
-    if(config && config.wrap){
-        config.resizeChild = this.el;
-        this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
-        this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
-        this.el.setStyle("overflow", "hidden");
-        this.el.setPositioning(config.resizeChild.getPositioning());
-        config.resizeChild.clearPositioning();
-        if(!config.width || !config.height){
-            var csize = config.resizeChild.getSize();
-            this.el.setSize(csize.width, csize.height);
-        }
-        if(config.pinned && !config.adjustments){
-            config.adjustments = "auto";
-        }
-    }
-
-    this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
-    this.proxy.unselectable();
-    this.proxy.enableDisplayMode('block');
-
-    Roo.apply(this, config);
-
-    if(this.pinned){
-        this.disableTrackOver = true;
-        this.el.addClass("x-resizable-pinned");
-    }
-    // if the element isn't positioned, make it relative
-    var position = this.el.getStyle("position");
-    if(position != "absolute" && position != "fixed"){
-        this.el.setStyle("position", "relative");
-    }
-    if(!this.handles){ // no handles passed, must be legacy style
-        this.handles = 's,e,se';
-        if(this.multiDirectional){
-            this.handles += ',n,w';
-        }
-    }
-    if(this.handles == "all"){
-        this.handles = "n s e w ne nw se sw";
-    }
-    var hs = this.handles.split(/\s*?[,;]\s*?| /);
-    var ps = Roo.Resizable.positions;
-    for(var i = 0, len = hs.length; i < len; i++){
-        if(hs[i] && ps[hs[i]]){
-            var pos = ps[hs[i]];
-            this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
-        }
-    }
-    // legacy
-    this.corner = this.southeast;
-    
-    // updateBox = the box can move..
-    if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
-        this.updateBox = true;
-    }
-
-    this.activeHandle = null;
-
-    if(this.resizeChild){
-        if(typeof this.resizeChild == "boolean"){
-            this.resizeChild = Roo.get(this.el.dom.firstChild, true);
-        }else{
-            this.resizeChild = Roo.get(this.resizeChild, true);
-        }
-    }
-    
-    if(this.adjustments == "auto"){
-        var rc = this.resizeChild;
-        var hw = this.west, he = this.east, hn = this.north, hs = this.south;
-        if(rc && (hw || hn)){
-            rc.position("relative");
-            rc.setLeft(hw ? hw.el.getWidth() : 0);
-            rc.setTop(hn ? hn.el.getHeight() : 0);
-        }
-        this.adjustments = [
-            (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
-            (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
-        ];
-    }
-
-    if(this.draggable){
-        this.dd = this.dynamic ?
-            this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
-        this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
-    }
-
-    // public events
-    this.addEvents({
-        /**
-         * @event beforeresize
-         * Fired before resize is allowed. Set enabled to false to cancel resize.
-         * @param {Roo.Resizable} this
-         * @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.
-         * @param {Roo.Resizable} this
-         * @param {Number} width The new width
-         * @param {Number} height The new height
-         * @param {Roo.EventObject} e The mouseup event
-         */
-        "resize" : true
-    });
-
-    if(this.width !== null && this.height !== null){
-        this.resizeTo(this.width, this.height);
-    }else{
-        this.updateChildSize();
-    }
-    if(Roo.isIE){
-        this.el.dom.style.zoom = 1;
-    }
-    Roo.Resizable.superclass.constructor.call(this);
-};
-
-Roo.extend(Roo.Resizable, Roo.util.Observable, {
-        resizeChild : false,
-        adjustments : [0, 0],
-        minWidth : 5,
-        minHeight : 5,
-        maxWidth : 10000,
-        maxHeight : 10000,
-        enabled : true,
-        animate : false,
-        duration : .35,
-        dynamic : false,
-        handles : false,
-        multiDirectional : false,
-        disableTrackOver : false,
-        easing : 'easeOutStrong',
-        widthIncrement : 0,
-        heightIncrement : 0,
-        pinned : false,
-        width : null,
-        height : null,
-        preserveRatio : false,
-        transparent: false,
-        minX: 0,
-        minY: 0,
-        draggable: false,
-
-        /**
-         * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
-         */
-        constrainTo: undefined,
-        /**
-         * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
-         */
-        resizeRegion: undefined,
-
-
-    /**
-     * Perform a manual resize
-     * @param {Number} width
-     * @param {Number} height
-     */
-    resizeTo : function(width, height){
-        this.el.setSize(width, height);
-        this.updateChildSize();
-        this.fireEvent("resize", this, width, height, null);
-    },
-
-    // private
-    startSizing : function(e, handle){
-        this.fireEvent("beforeresize", this, e);
-        if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
-
-            if(!this.overlay){
-                this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: "&#160;"});
-                this.overlay.unselectable();
-                this.overlay.enableDisplayMode("block");
-                this.overlay.on("mousemove", this.onMouseMove, this);
-                this.overlay.on("mouseup", this.onMouseUp, this);
-            }
-            this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
-
-            this.resizing = true;
-            this.startBox = this.el.getBox();
-            this.startPoint = e.getXY();
-            this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
-                            (this.startBox.y + this.startBox.height) - this.startPoint[1]];
-
-            this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
-            this.overlay.show();
-
-            if(this.constrainTo) {
-                var ct = Roo.get(this.constrainTo);
-                this.resizeRegion = ct.getRegion().adjust(
-                    ct.getFrameWidth('t'),
-                    ct.getFrameWidth('l'),
-                    -ct.getFrameWidth('b'),
-                    -ct.getFrameWidth('r')
-                );
-            }
-
-            this.proxy.setStyle('visibility', 'hidden'); // workaround display none
-            this.proxy.show();
-            this.proxy.setBox(this.startBox);
-            if(!this.dynamic){
-                this.proxy.setStyle('visibility', 'visible');
-            }
-        }
-    },
-
-    // private
-    onMouseDown : function(handle, e){
-        if(this.enabled){
-            e.stopEvent();
-            this.activeHandle = handle;
-            this.startSizing(e, handle);
-        }
-    },
-
-    // private
-    onMouseUp : function(e){
-        var size = this.resizeElement();
-        this.resizing = false;
-        this.handleOut();
-        this.overlay.hide();
-        this.proxy.hide();
-        this.fireEvent("resize", this, size.width, size.height, e);
-    },
-
-    // private
-    updateChildSize : function(){
-        
-        if(this.resizeChild){
-            var el = this.el;
-            var child = this.resizeChild;
-            var adj = this.adjustments;
-            if(el.dom.offsetWidth){
-                var b = el.getSize(true);
-                child.setSize(b.width+adj[0], b.height+adj[1]);
-            }
-            // Second call here for IE
-            // The first call enables instant resizing and
-            // the second call corrects scroll bars if they
-            // exist
-            if(Roo.isIE){
-                setTimeout(function(){
-                    if(el.dom.offsetWidth){
-                        var b = el.getSize(true);
-                        child.setSize(b.width+adj[0], b.height+adj[1]);
-                    }
-                }, 10);
-            }
-        }
-    },
-
-    // private
-    snap : function(value, inc, min){
-        if(!inc || !value) return value;
-        var newValue = value;
-        var m = value % inc;
-        if(m > 0){
-            if(m > (inc/2)){
-                newValue = value + (inc-m);
-            }else{
-                newValue = value - m;
-            }
-        }
-        return Math.max(min, newValue);
-    },
-
-    // private
-    resizeElement : function(){
-        var box = this.proxy.getBox();
-        if(this.updateBox){
-            this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
-        }else{
-            this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
-        }
-        this.updateChildSize();
-        if(!this.dynamic){
-            this.proxy.hide();
-        }
-        return box;
-    },
-
-    // private
-    constrain : function(v, diff, m, mx){
-        if(v - diff < m){
-            diff = v - m;
-        }else if(v - diff > mx){
-            diff = mx - v;
-        }
-        return diff;
-    },
-
-    // private
-    onMouseMove : function(e){
-        
-        if(this.enabled){
-            try{// try catch so if something goes wrong the user doesn't get hung
-
-            if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
-               return;
-            }
-
-            //var curXY = this.startPoint;
-            var curSize = this.curSize || this.startBox;
-            var x = this.startBox.x, y = this.startBox.y;
-            var ox = x, oy = y;
-            var w = curSize.width, h = curSize.height;
-            var ow = w, oh = h;
-            var mw = this.minWidth, mh = this.minHeight;
-            var mxw = this.maxWidth, mxh = this.maxHeight;
-            var wi = this.widthIncrement;
-            var hi = this.heightIncrement;
-
-            var eventXY = e.getXY();
-            var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
-            var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
-
-            var pos = this.activeHandle.position;
-
-            switch(pos){
-                case "east":
-                    w += diffX;
-                    w = Math.min(Math.max(mw, w), mxw);
-                    break;
-             
-                case "south":
-                    h += diffY;
-                    h = Math.min(Math.max(mh, h), mxh);
-                    break;
-                case "southeast":
-                    w += diffX;
-                    h += diffY;
-                    w = Math.min(Math.max(mw, w), mxw);
-                    h = Math.min(Math.max(mh, h), mxh);
-                    break;
-                case "north":
-                    diffY = this.constrain(h, diffY, mh, mxh);
-                    y += diffY;
-                    h -= diffY;
-                    break;
-                case "hdrag":
-                    
-                    if (wi) {
-                        var adiffX = Math.abs(diffX);
-                        var sub = (adiffX % wi); // how much 
-                        if (sub > (wi/2)) { // far enough to snap
-                            diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
-                        } else {
-                            // remove difference.. 
-                            diffX = (diffX > 0) ? diffX-sub : diffX+sub;
-                        }
-                    }
-                    x += diffX;
-                    x = Math.max(this.minX, x);
-                    break;
-                case "west":
-                    diffX = this.constrain(w, diffX, mw, mxw);
-                    x += diffX;
-                    w -= diffX;
-                    break;
-                case "northeast":
-                    w += diffX;
-                    w = Math.min(Math.max(mw, w), mxw);
-                    diffY = this.constrain(h, diffY, mh, mxh);
-                    y += diffY;
-                    h -= diffY;
-                    break;
-                case "northwest":
-                    diffX = this.constrain(w, diffX, mw, mxw);
-                    diffY = this.constrain(h, diffY, mh, mxh);
-                    y += diffY;
-                    h -= diffY;
-                    x += diffX;
-                    w -= diffX;
-                    break;
-               case "southwest":
-                    diffX = this.constrain(w, diffX, mw, mxw);
-                    h += diffY;
-                    h = Math.min(Math.max(mh, h), mxh);
-                    x += diffX;
-                    w -= diffX;
-                    break;
-            }
-
-            var sw = this.snap(w, wi, mw);
-            var sh = this.snap(h, hi, mh);
-            if(sw != w || sh != h){
-                switch(pos){
-                    case "northeast":
-                        y -= sh - h;
-                    break;
-                    case "north":
-                        y -= sh - h;
-                        break;
-                    case "southwest":
-                        x -= sw - w;
-                    break;
-                    case "west":
-                        x -= sw - w;
-                        break;
-                    case "northwest":
-                        x -= sw - w;
-                        y -= sh - h;
-                    break;
-                }
-                w = sw;
-                h = sh;
-            }
-
-            if(this.preserveRatio){
-                switch(pos){
-                    case "southeast":
-                    case "east":
-                        h = oh * (w/ow);
-                        h = Math.min(Math.max(mh, h), mxh);
-                        w = ow * (h/oh);
-                       break;
-                    case "south":
-                        w = ow * (h/oh);
-                        w = Math.min(Math.max(mw, w), mxw);
-                        h = oh * (w/ow);
-                        break;
-                    case "northeast":
-                        w = ow * (h/oh);
-                        w = Math.min(Math.max(mw, w), mxw);
-                        h = oh * (w/ow);
-                    break;
-                    case "north":
-                        var tw = w;
-                        w = ow * (h/oh);
-                        w = Math.min(Math.max(mw, w), mxw);
-                        h = oh * (w/ow);
-                        x += (tw - w) / 2;
-                        break;
-                    case "southwest":
-                        h = oh * (w/ow);
-                        h = Math.min(Math.max(mh, h), mxh);
-                        var tw = w;
-                        w = ow * (h/oh);
-                        x += tw - w;
-                        break;
-                    case "west":
-                        var th = h;
-                        h = oh * (w/ow);
-                        h = Math.min(Math.max(mh, h), mxh);
-                        y += (th - h) / 2;
-                        var tw = w;
-                        w = ow * (h/oh);
-                        x += tw - w;
-                       break;
-                    case "northwest":
-                        var tw = w;
-                        var th = h;
-                        h = oh * (w/ow);
-                        h = Math.min(Math.max(mh, h), mxh);
-                        w = ow * (h/oh);
-                        y += th - h;
-                        x += tw - w;
-                       break;
-
-                }
-            }
-            if (pos == 'hdrag') {
-                w = ow;
-            }
-            this.proxy.setBounds(x, y, w, h);
-            if(this.dynamic){
-                this.resizeElement();
-            }
-            }catch(e){}
-        }
-        this.fireEvent("resizing", this, x, y, w, h, e);
-    },
-
-    // private
-    handleOver : function(){
-        if(this.enabled){
-            this.el.addClass("x-resizable-over");
-        }
-    },
-
-    // private
-    handleOut : function(){
-        if(!this.resizing){
-            this.el.removeClass("x-resizable-over");
-        }
-    },
-
-    /**
-     * Returns the element this component is bound to.
-     * @return {Roo.Element}
-     */
-    getEl : function(){
-        return this.el;
-    },
-
-    /**
-     * Returns the resizeChild element (or null).
-     * @return {Roo.Element}
-     */
-    getResizeChild : function(){
-        return this.resizeChild;
-    },
-    groupHandler : function()
-    {
-        
-    },
-    /**
-     * Destroys this resizable. If the element was wrapped and
-     * removeEl is not true then the element remains.
-     * @param {Boolean} removeEl (optional) true to remove the element from the DOM
-     */
-    destroy : function(removeEl){
-        this.proxy.remove();
-        if(this.overlay){
-            this.overlay.removeAllListeners();
-            this.overlay.remove();
-        }
-        var ps = Roo.Resizable.positions;
-        for(var k in ps){
-            if(typeof ps[k] != "function" && this[ps[k]]){
-                var h = this[ps[k]];
-                h.el.removeAllListeners();
-                h.el.remove();
-            }
-        }
-        if(removeEl){
-            this.el.update("");
-            this.el.remove();
-        }
-    }
-});
-
-// private
-// hash to map config positions to true positions
-Roo.Resizable.positions = {
-    n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast", 
-    hd: "hdrag"
-};
-
-// private
-Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
-    if(!this.tpl){
-        // only initialize the template if resizable is used
-        var tpl = Roo.DomHelper.createTemplate(
-            {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
-        );
-        tpl.compile();
-        Roo.Resizable.Handle.prototype.tpl = tpl;
-    }
-    this.position = pos;
-    this.rz = rz;
-    // show north drag fro topdra
-    var handlepos = pos == 'hdrag' ? 'north' : pos;
-    
-    this.el = this.tpl.append(rz.el.dom, [handlepos], true);
-    if (pos == 'hdrag') {
-        this.el.setStyle('cursor', 'pointer');
-    }
-    this.el.unselectable();
-    if(transparent){
-        this.el.setOpacity(0);
-    }
-    this.el.on("mousedown", this.onMouseDown, this);
-    if(!disableTrackOver){
-        this.el.on("mouseover", this.onMouseOver, this);
-        this.el.on("mouseout", this.onMouseOut, this);
-    }
-};
-
-// private
-Roo.Resizable.Handle.prototype = {
-    afterResize : function(rz){
-        Roo.log('after?');
-        // do nothing
-    },
-    // private
-    onMouseDown : function(e){
-        this.rz.onMouseDown(this, e);
-    },
-    // private
-    onMouseOver : function(e){
-        this.rz.handleOver(this, e);
-    },
-    // private
-    onMouseOut : function(e){
-        this.rz.handleOut(this, e);
-    }
-};/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-
-/**
- * @class Roo.Editor
- * @extends Roo.Component
- * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
- * @constructor
- * Create a new Editor
- * @param {Roo.form.Field} field The Field object (or descendant)
- * @param {Object} config The config object
- */
-Roo.Editor = function(field, config){
-    Roo.Editor.superclass.constructor.call(this, config);
-    this.field = field;
-    this.addEvents({
-        /**
-            * @event beforestartedit
-            * Fires when editing is initiated, but before the value changes.  Editing can be canceled by returning
-            * false from the handler of this event.
-            * @param {Editor} this
-            * @param {Roo.Element} boundEl The underlying element bound to this editor
-            * @param {Mixed} value The field value being set
-            */
-        "beforestartedit" : true,
-        /**
-            * @event startedit
-            * Fires when this editor is displayed
-            * @param {Roo.Element} boundEl The underlying element bound to this editor
-            * @param {Mixed} value The starting field value
-            */
-        "startedit" : true,
-        /**
-            * @event beforecomplete
-            * Fires after a change has been made to the field, but before the change is reflected in the underlying
-            * field.  Saving the change to the field can be canceled by returning false from the handler of this event.
-            * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
-            * event will not fire since no edit actually occurred.
-            * @param {Editor} this
-            * @param {Mixed} value The current field value
-            * @param {Mixed} startValue The original field value
-            */
-        "beforecomplete" : true,
-        /**
-            * @event complete
-            * Fires after editing is complete and any changed value has been written to the underlying field.
-            * @param {Editor} this
-            * @param {Mixed} value The current field value
-            * @param {Mixed} startValue The original field value
-            */
-        "complete" : true,
-        /**
-         * @event specialkey
-         * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
-         * {@link Roo.EventObject#getKey} to determine which key was pressed.
-         * @param {Roo.form.Field} this
-         * @param {Roo.EventObject} e The event object
-         */
-        "specialkey" : true
-    });
-};
-
-Roo.extend(Roo.Editor, Roo.Component, {
-    /**
-     * @cfg {Boolean/String} autosize
-     * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
-     * or "height" to adopt the height only (defaults to false)
-     */
-    /**
-     * @cfg {Boolean} revertInvalid
-     * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
-     * validation fails (defaults to true)
-     */
-    /**
-     * @cfg {Boolean} ignoreNoChange
-     * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
-     * the value has not changed (defaults to false).  Applies only to string values - edits for other data types
-     * will never be ignored.
-     */
-    /**
-     * @cfg {Boolean} hideEl
-     * False to keep the bound element visible while the editor is displayed (defaults to true)
-     */
-    /**
-     * @cfg {Mixed} value
-     * The data value of the underlying field (defaults to "")
-     */
-    value : "",
-    /**
-     * @cfg {String} alignment
-     * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
-     */
-    alignment: "c-c?",
-    /**
-     * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
-     * for bottom-right shadow (defaults to "frame")
-     */
-    shadow : "frame",
-    /**
-     * @cfg {Boolean} constrain True to constrain the editor to the viewport
-     */
-    constrain : false,
-    /**
-     * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
-     */
-    completeOnEnter : false,
-    /**
-     * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
-     */
-    cancelOnEsc : false,
-    /**
-     * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
-     */
-    updateEl : false,
-
-    // private
-    onRender : function(ct, position){
-        this.el = new Roo.Layer({
-            shadow: this.shadow,
-            cls: "x-editor",
-            parentEl : ct,
-            shim : this.shim,
-            shadowOffset:4,
-            id: this.id,
-            constrain: this.constrain
-        });
-        this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
-        if(this.field.msgTarget != 'title'){
-            this.field.msgTarget = 'qtip';
-        }
-        this.field.render(this.el);
-        if(Roo.isGecko){
-            this.field.el.dom.setAttribute('autocomplete', 'off');
-        }
-        this.field.on("specialkey", this.onSpecialKey, this);
-        if(this.swallowKeys){
-            this.field.el.swallowEvent(['keydown','keypress']);
-        }
-        this.field.show();
-        this.field.on("blur", this.onBlur, this);
-        if(this.field.grow){
-            this.field.on("autosize", this.el.sync,  this.el, {delay:1});
-        }
-    },
-
-    onSpecialKey : function(field, e)
-    {
-        //Roo.log('editor onSpecialKey');
-        if(this.completeOnEnter && e.getKey() == e.ENTER){
-            e.stopEvent();
-            this.completeEdit();
-            return;
-        }
-        // do not fire special key otherwise it might hide close the editor...
-        if(e.getKey() == e.ENTER){    
-            return;
-        }
-        if(this.cancelOnEsc && e.getKey() == e.ESC){
-            this.cancelEdit();
-            return;
-        } 
-        this.fireEvent('specialkey', field, e);
-    
-    },
-
-    /**
-     * Starts the editing process and shows the editor.
-     * @param {String/HTMLElement/Element} el The element to edit
-     * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
-      * to the innerHTML of el.
-     */
-    startEdit : function(el, value){
-        if(this.editing){
-            this.completeEdit();
-        }
-        this.boundEl = Roo.get(el);
-        var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
-        if(!this.rendered){
-            this.render(this.parentEl || document.body);
-        }
-        if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
-            return;
-        }
-        this.startValue = v;
-        this.field.setValue(v);
-        if(this.autoSize){
-            var sz = this.boundEl.getSize();
-            switch(this.autoSize){
-                case "width":
-                this.setSize(sz.width,  "");
-                break;
-                case "height":
-                this.setSize("",  sz.height);
-                break;
-                default:
-                this.setSize(sz.width,  sz.height);
-            }
-        }
-        this.el.alignTo(this.boundEl, this.alignment);
-        this.editing = true;
-        if(Roo.QuickTips){
-            Roo.QuickTips.disable();
-        }
-        this.show();
-    },
-
-    /**
-     * Sets the height and width of this editor.
-     * @param {Number} width The new width
-     * @param {Number} height The new height
-     */
-    setSize : function(w, h){
-        this.field.setSize(w, h);
-        if(this.el){
-            this.el.sync();
-        }
-    },
-
-    /**
-     * Realigns the editor to the bound field based on the current alignment config value.
-     */
-    realign : function(){
-        this.el.alignTo(this.boundEl, this.alignment);
-    },
-
-    /**
-     * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
-     * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
-     */
-    completeEdit : function(remainVisible){
-        if(!this.editing){
-            return;
-        }
-        var v = this.getValue();
-        if(this.revertInvalid !== false && !this.field.isValid()){
-            v = this.startValue;
-            this.cancelEdit(true);
-        }
-        if(String(v) === String(this.startValue) && this.ignoreNoChange){
-            this.editing = false;
-            this.hide();
-            return;
-        }
-        if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
-            this.editing = false;
-            if(this.updateEl && this.boundEl){
-                this.boundEl.update(v);
-            }
-            if(remainVisible !== true){
-                this.hide();
-            }
-            this.fireEvent("complete", this, v, this.startValue);
-        }
-    },
-
-    // private
-    onShow : function(){
-        this.el.show();
-        if(this.hideEl !== false){
-            this.boundEl.hide();
-        }
-        this.field.show();
-        if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
-            this.fixIEFocus = true;
-            this.deferredFocus.defer(50, this);
-        }else{
-            this.field.focus();
-        }
-        this.fireEvent("startedit", this.boundEl, this.startValue);
-    },
-
-    deferredFocus : function(){
-        if(this.editing){
-            this.field.focus();
-        }
-    },
-
-    /**
-     * Cancels the editing process and hides the editor without persisting any changes.  The field value will be
-     * reverted to the original starting value.
-     * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
-     * cancel (defaults to false)
-     */
-    cancelEdit : function(remainVisible){
-        if(this.editing){
-            this.setValue(this.startValue);
-            if(remainVisible !== true){
-                this.hide();
-            }
-        }
-    },
-
-    // private
-    onBlur : function(){
-        if(this.allowBlur !== true && this.editing){
-            this.completeEdit();
-        }
-    },
-
-    // private
-    onHide : function(){
-        if(this.editing){
-            this.completeEdit();
-            return;
-        }
-        this.field.blur();
-        if(this.field.collapse){
-            this.field.collapse();
-        }
-        this.el.hide();
-        if(this.hideEl !== false){
-            this.boundEl.show();
-        }
-        if(Roo.QuickTips){
-            Roo.QuickTips.enable();
-        }
-    },
-
-    /**
-     * Sets the data value of the editor
-     * @param {Mixed} value Any valid value supported by the underlying field
-     */
-    setValue : function(v){
-        this.field.setValue(v);
-    },
-
-    /**
-     * Gets the data value of the editor
-     * @return {Mixed} The data value
-     */
-    getValue : function(){
-        return this.field.getValue();
-    }
-});/*
- * 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.BasicDialog
- * @extends Roo.util.Observable
- * Lightweight Dialog Class.  The code below shows the creation of a typical dialog using existing HTML markup:
- * <pre><code>
-var dlg = new Roo.BasicDialog("my-dlg", {
-    height: 200,
-    width: 300,
-    minHeight: 100,
-    minWidth: 150,
-    modal: true,
-    proxyDrag: true,
-    shadow: true
-});
-dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
-dlg.addButton('OK', dlg.hide, dlg);    // Could call a save function instead of hiding
-dlg.addButton('Cancel', dlg.hide, dlg);
-dlg.show();
-</code></pre>
-  <b>A Dialog should always be a direct child of the body element.</b>
- * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
- * @cfg {String} title Default text to display in the title bar (defaults to null)
- * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS).  Determined by browser if unspecified.
- * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS).  Determined by browser if unspecified.
- * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
- * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
- * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
- * (defaults to null with no animation)
- * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
- * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
- * property for valid values (defaults to 'all')
- * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
- * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
- * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
- * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
- * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
- * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
- * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
- * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
- * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
- * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
- * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
- * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
- * draggable = true (defaults to false)
- * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
- * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
- * shadow (defaults to false)
- * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
- * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
- * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
- * @cfg {Array} buttons Array of buttons
- * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
- * @constructor
- * Create a new BasicDialog.
- * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
- * @param {Object} config Configuration options
- */
-Roo.BasicDialog = function(el, config){
-    this.el = Roo.get(el);
-    var dh = Roo.DomHelper;
-    if(!this.el && config && config.autoCreate){
-        if(typeof config.autoCreate == "object"){
-            if(!config.autoCreate.id){
-                config.autoCreate.id = el;
-            }
-            this.el = dh.append(document.body,
-                        config.autoCreate, true);
-        }else{
-            this.el = dh.append(document.body,
-                        {tag: "div", id: el, style:'visibility:hidden;'}, true);
-        }
-    }
-    el = this.el;
-    el.setDisplayed(true);
-    el.hide = this.hideAction;
-    this.id = el.id;
-    el.addClass("x-dlg");
-
-    Roo.apply(this, config);
-
-    this.proxy = el.createProxy("x-dlg-proxy");
-    this.proxy.hide = this.hideAction;
-    this.proxy.setOpacity(.5);
-    this.proxy.hide();
-
-    if(config.width){
-        el.setWidth(config.width);
-    }
-    if(config.height){
-        el.setHeight(config.height);
-    }
-    this.size = el.getSize();
-    if(typeof config.x != "undefined" && typeof config.y != "undefined"){
-        this.xy = [config.x,config.y];
-    }else{
-        this.xy = el.getCenterXY(true);
-    }
-    /** The header element @type Roo.Element */
-    this.header = el.child("> .x-dlg-hd");
-    /** The body element @type Roo.Element */
-    this.body = el.child("> .x-dlg-bd");
-    /** The footer element @type Roo.Element */
-    this.footer = el.child("> .x-dlg-ft");
-
-    if(!this.header){
-        this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: "&#160;"}, this.body ? this.body.dom : null);
-    }
-    if(!this.body){
-        this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
-    }
-
-    this.header.unselectable();
-    if(this.title){
-        this.header.update(this.title);
-    }
-    // this element allows the dialog to be focused for keyboard event
-    this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
-    this.focusEl.swallowEvent("click", true);
-
-    this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
-
-    // wrap the body and footer for special rendering
-    this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
-    if(this.footer){
-        this.bwrap.dom.appendChild(this.footer.dom);
-    }
-
-    this.bg = this.el.createChild({
-        tag: "div", cls:"x-dlg-bg",
-        html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center">&#160;</div></div></div>'
-    });
-    this.centerBg = this.bg.child("div.x-dlg-bg-center");
-
-
-    if(this.autoScroll !== false && !this.autoTabs){
-        this.body.setStyle("overflow", "auto");
-    }
-
-    this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
-
-    if(this.closable !== false){
-        this.el.addClass("x-dlg-closable");
-        this.close = this.toolbox.createChild({cls:"x-dlg-close"});
-        this.close.on("click", this.closeClick, this);
-        this.close.addClassOnOver("x-dlg-close-over");
-    }
-    if(this.collapsible !== false){
-        this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
-        this.collapseBtn.on("click", this.collapseClick, this);
-        this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
-        this.header.on("dblclick", this.collapseClick, this);
-    }
-    if(this.resizable !== false){
-        this.el.addClass("x-dlg-resizable");
-        this.resizer = new Roo.Resizable(el, {
-            minWidth: this.minWidth || 80,
-            minHeight:this.minHeight || 80,
-            handles: this.resizeHandles || "all",
-            pinned: true
-        });
-        this.resizer.on("beforeresize", this.beforeResize, this);
-        this.resizer.on("resize", this.onResize, this);
-    }
-    if(this.draggable !== false){
-        el.addClass("x-dlg-draggable");
-        if (!this.proxyDrag) {
-            var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
-        }
-        else {
-            var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
-        }
-        dd.setHandleElId(this.header.id);
-        dd.endDrag = this.endMove.createDelegate(this);
-        dd.startDrag = this.startMove.createDelegate(this);
-        dd.onDrag = this.onDrag.createDelegate(this);
-        dd.scroll = false;
-        this.dd = dd;
-    }
-    if(this.modal){
-        this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
-        this.mask.enableDisplayMode("block");
-        this.mask.hide();
-        this.el.addClass("x-dlg-modal");
-    }
-    if(this.shadow){
-        this.shadow = new Roo.Shadow({
-            mode : typeof this.shadow == "string" ? this.shadow : "sides",
-            offset : this.shadowOffset
-        });
-    }else{
-        this.shadowOffset = 0;
-    }
-    if(Roo.useShims && this.shim !== false){
-        this.shim = this.el.createShim();
-        this.shim.hide = this.hideAction;
-        this.shim.hide();
-    }else{
-        this.shim = false;
-    }
-    if(this.autoTabs){
-        this.initTabs();
-    }
-    if (this.buttons) { 
-        var bts= this.buttons;
-        this.buttons = [];
-        Roo.each(bts, function(b) {
-            this.addButton(b);
-        }, this);
-    }
-    
-    
-    this.addEvents({
-        /**
-         * @event keydown
-         * Fires when a key is pressed
-         * @param {Roo.BasicDialog} this
-         * @param {Roo.EventObject} e
-         */
-        "keydown" : true,
-        /**
-         * @event move
-         * Fires when this dialog is moved by the user.
-         * @param {Roo.BasicDialog} this
-         * @param {Number} x The new page X
-         * @param {Number} y The new page Y
-         */
-        "move" : true,
-        /**
-         * @event resize
-         * Fires when this dialog is resized by the user.
-         * @param {Roo.BasicDialog} this
-         * @param {Number} width The new width
-         * @param {Number} height The new height
-         */
-        "resize" : true,
-        /**
-         * @event beforehide
-         * Fires before this dialog is hidden.
-         * @param {Roo.BasicDialog} this
-         */
-        "beforehide" : true,
-        /**
-         * @event hide
-         * Fires when this dialog is hidden.
-         * @param {Roo.BasicDialog} this
-         */
-        "hide" : true,
-        /**
-         * @event beforeshow
-         * Fires before this dialog is shown.
-         * @param {Roo.BasicDialog} this
-         */
-        "beforeshow" : true,
-        /**
-         * @event show
-         * Fires when this dialog is shown.
-         * @param {Roo.BasicDialog} this
-         */
-        "show" : true
-    });
-    el.on("keydown", this.onKeyDown, this);
-    el.on("mousedown", this.toFront, this);
-    Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
-    this.el.hide();
-    Roo.DialogManager.register(this);
-    Roo.BasicDialog.superclass.constructor.call(this);
-};
-
-Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
-    shadowOffset: Roo.isIE ? 6 : 5,
-    minHeight: 80,
-    minWidth: 200,
-    minButtonWidth: 75,
-    defaultButton: null,
-    buttonAlign: "right",
-    tabTag: 'div',
-    firstShow: true,
-
-    /**
-     * Sets the dialog title text
-     * @param {String} text The title text to display
-     * @return {Roo.BasicDialog} this
-     */
-    setTitle : function(text){
-        this.header.update(text);
-        return this;
-    },
-
-    // private
-    closeClick : function(){
-        this.hide();
-    },
-
-    // private
-    collapseClick : function(){
-        this[this.collapsed ? "expand" : "collapse"]();
-    },
-
-    /**
-     * Collapses the dialog to its minimized state (only the title bar is visible).
-     * Equivalent to the user clicking the collapse dialog button.
-     */
-    collapse : function(){
-        if(!this.collapsed){
-            this.collapsed = true;
-            this.el.addClass("x-dlg-collapsed");
-            this.restoreHeight = this.el.getHeight();
-            this.resizeTo(this.el.getWidth(), this.header.getHeight());
-        }
-    },
-
-    /**
-     * Expands a collapsed dialog back to its normal state.  Equivalent to the user
-     * clicking the expand dialog button.
-     */
-    expand : function(){
-        if(this.collapsed){
-            this.collapsed = false;
-            this.el.removeClass("x-dlg-collapsed");
-            this.resizeTo(this.el.getWidth(), this.restoreHeight);
-        }
-    },
-
-    /**
-     * Reinitializes the tabs component, clearing out old tabs and finding new ones.
-     * @return {Roo.TabPanel} The tabs component
-     */
-    initTabs : function(){
-        var tabs = this.getTabs();
-        while(tabs.getTab(0)){
-            tabs.removeTab(0);
-        }
-        this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
-            var dom = el.dom;
-            tabs.addTab(Roo.id(dom), dom.title);
-            dom.title = "";
-        });
-        tabs.activate(0);
-        return tabs;
-    },
-
-    // private
-    beforeResize : function(){
-        this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
-    },
-
-    // private
-    onResize : function(){
-        this.refreshSize();
-        this.syncBodyHeight();
-        this.adjustAssets();
-        this.focus();
-        this.fireEvent("resize", this, this.size.width, this.size.height);
-    },
-
-    // private
-    onKeyDown : function(e){
-        if(this.isVisible()){
-            this.fireEvent("keydown", this, e);
-        }
-    },
-
-    /**
-     * Resizes the dialog.
-     * @param {Number} width
-     * @param {Number} height
-     * @return {Roo.BasicDialog} this
-     */
-    resizeTo : function(width, height){
-        this.el.setSize(width, height);
-        this.size = {width: width, height: height};
-        this.syncBodyHeight();
-        if(this.fixedcenter){
-            this.center();
-        }
-        if(this.isVisible()){
-            this.constrainXY();
-            this.adjustAssets();
-        }
-        this.fireEvent("resize", this, width, height);
-        return this;
-    },
-
-
-    /**
-     * Resizes the dialog to fit the specified content size.
-     * @param {Number} width
-     * @param {Number} height
-     * @return {Roo.BasicDialog} this
-     */
-    setContentSize : function(w, h){
-        h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
-        w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
-        //if(!this.el.isBorderBox()){
-            h +=  this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
-            w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
-        //}
-        if(this.tabs){
-            h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
-            w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
-        }
-        this.resizeTo(w, h);
-        return this;
-    },
-
-    /**
-     * Adds a key listener for when this dialog is displayed.  This allows you to hook in a function that will be
-     * executed in response to a particular key being pressed while the dialog is active.
-     * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
-     *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
-     * @param {Function} fn The function to call
-     * @param {Object} scope (optional) The scope of the function
-     * @return {Roo.BasicDialog} this
-     */
-    addKeyListener : function(key, fn, scope){
-        var keyCode, shift, ctrl, alt;
-        if(typeof key == "object" && !(key instanceof Array)){
-            keyCode = key["key"];
-            shift = key["shift"];
-            ctrl = key["ctrl"];
-            alt = key["alt"];
-        }else{
-            keyCode = key;
-        }
-        var handler = function(dlg, e){
-            if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
-                var k = e.getKey();
-                if(keyCode instanceof Array){
-                    for(var i = 0, len = keyCode.length; i < len; i++){
-                        if(keyCode[i] == k){
-                          fn.call(scope || window, dlg, k, e);
-                          return;
-                        }
-                    }
-                }else{
-                    if(k == keyCode){
-                        fn.call(scope || window, dlg, k, e);
-                    }
-                }
-            }
-        };
-        this.on("keydown", handler);
-        return this;
-    },
-
-    /**
-     * Returns the TabPanel component (creates it if it doesn't exist).
-     * Note: If you wish to simply check for the existence of tabs without creating them,
-     * check for a null 'tabs' property.
-     * @return {Roo.TabPanel} The tabs component
-     */
-    getTabs : function(){
-        if(!this.tabs){
-            this.el.addClass("x-dlg-auto-tabs");
-            this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
-            this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
-        }
-        return this.tabs;
-    },
-
-    /**
-     * Adds a button to the footer section of the dialog.
-     * @param {String/Object} config A string becomes the button text, an object can either be a Button config
-     * object or a valid Roo.DomHelper element config
-     * @param {Function} handler The function called when the button is clicked
-     * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
-     * @return {Roo.Button} The new button
-     */
-    addButton : function(config, handler, scope){
-        var dh = Roo.DomHelper;
-        if(!this.footer){
-            this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
-        }
-        if(!this.btnContainer){
-            var tb = this.footer.createChild({
-
-                cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
-                html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
-            }, null, true);
-            this.btnContainer = tb.firstChild.firstChild.firstChild;
-        }
-        var bconfig = {
-            handler: handler,
-            scope: scope,
-            minWidth: this.minButtonWidth,
-            hideParent:true
-        };
-        if(typeof config == "string"){
-            bconfig.text = config;
-        }else{
-            if(config.tag){
-                bconfig.dhconfig = config;
-            }else{
-                Roo.apply(bconfig, config);
-            }
-        }
-        var fc = false;
-        if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
-            bconfig.position = Math.max(0, bconfig.position);
-            fc = this.btnContainer.childNodes[bconfig.position];
-        }
-         
-        var btn = new Roo.Button(
-            fc ? 
-                this.btnContainer.insertBefore(document.createElement("td"),fc)
-                : this.btnContainer.appendChild(document.createElement("td")),
-            //Roo.get(this.btnContainer).createChild( { tag: 'td'},  fc ),
-            bconfig
-        );
-        this.syncBodyHeight();
-        if(!this.buttons){
-            /**
-             * Array of all the buttons that have been added to this dialog via addButton
-             * @type Array
-             */
-            this.buttons = [];
-        }
-        this.buttons.push(btn);
-        return btn;
-    },
-
-    /**
-     * Sets the default button to be focused when the dialog is displayed.
-     * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
-     * @return {Roo.BasicDialog} this
-     */
-    setDefaultButton : function(btn){
-        this.defaultButton = btn;
-        return this;
-    },
-
-    // private
-    getHeaderFooterHeight : function(safe){
-        var height = 0;
-        if(this.header){
-           height += this.header.getHeight();
-        }
-        if(this.footer){
-           var fm = this.footer.getMargins();
-            height += (this.footer.getHeight()+fm.top+fm.bottom);
-        }
-        height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
-        height += this.centerBg.getPadding("tb");
-        return height;
-    },
-
-    // private
-    syncBodyHeight : function()
-    {
-        var bd = this.body, // the text
-            cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
-            bw = this.bwrap;
-        var height = this.size.height - this.getHeaderFooterHeight(false);
-        bd.setHeight(height-bd.getMargins("tb"));
-        var hh = this.header.getHeight();
-        var h = this.size.height-hh;
-        cb.setHeight(h);
-        
-        bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
-        bw.setHeight(h-cb.getPadding("tb"));
-        
-        bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
-        bd.setWidth(bw.getWidth(true));
-        if(this.tabs){
-            this.tabs.syncHeight();
-            if(Roo.isIE){
-                this.tabs.el.repaint();
-            }
-        }
-    },
-
-    /**
-     * Restores the previous state of the dialog if Roo.state is configured.
-     * @return {Roo.BasicDialog} this
-     */
-    restoreState : function(){
-        var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
-        if(box && box.width){
-            this.xy = [box.x, box.y];
-            this.resizeTo(box.width, box.height);
-        }
-        return this;
-    },
-
-    // private
-    beforeShow : function(){
-        this.expand();
-        if(this.fixedcenter){
-            this.xy = this.el.getCenterXY(true);
-        }
-        if(this.modal){
-            Roo.get(document.body).addClass("x-body-masked");
-            this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
-            this.mask.show();
-        }
-        this.constrainXY();
-    },
-
-    // private
-    animShow : function(){
-        var b = Roo.get(this.animateTarget).getBox();
-        this.proxy.setSize(b.width, b.height);
-        this.proxy.setLocation(b.x, b.y);
-        this.proxy.show();
-        this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
-                    true, .35, this.showEl.createDelegate(this));
-    },
-
-    /**
-     * Shows the dialog.
-     * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
-     * @return {Roo.BasicDialog} this
-     */
-    show : function(animateTarget){
-        if (this.fireEvent("beforeshow", this) === false){
-            return;
-        }
-        if(this.syncHeightBeforeShow){
-            this.syncBodyHeight();
-        }else if(this.firstShow){
-            this.firstShow = false;
-            this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
-        }
-        this.animateTarget = animateTarget || this.animateTarget;
-        if(!this.el.isVisible()){
-            this.beforeShow();
-            if(this.animateTarget && Roo.get(this.animateTarget)){
-                this.animShow();
-            }else{
-                this.showEl();
-            }
-        }
-        return this;
-    },
-
-    // private
-    showEl : function(){
-        this.proxy.hide();
-        this.el.setXY(this.xy);
-        this.el.show();
-        this.adjustAssets(true);
-        this.toFront();
-        this.focus();
-        // IE peekaboo bug - fix found by Dave Fenwick
-        if(Roo.isIE){
-            this.el.repaint();
-        }
-        this.fireEvent("show", this);
-    },
-
-    /**
-     * Focuses the dialog.  If a defaultButton is set, it will receive focus, otherwise the
-     * dialog itself will receive focus.
-     */
-    focus : function(){
-        if(this.defaultButton){
-            this.defaultButton.focus();
-        }else{
-            this.focusEl.focus();
-        }
-    },
-
-    // private
-    constrainXY : function(){
-        if(this.constraintoviewport !== false){
-            if(!this.viewSize){
-                if(this.container){
-                    var s = this.container.getSize();
-                    this.viewSize = [s.width, s.height];
-                }else{
-                    this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
-                }
-            }
-            var s = Roo.get(this.container||document).getScroll();
-
-            var x = this.xy[0], y = this.xy[1];
-            var w = this.size.width, h = this.size.height;
-            var vw = this.viewSize[0], vh = this.viewSize[1];
-            // only move it if it needs it
-            var moved = false;
-            // first validate right/bottom
-            if(x + w > vw+s.left){
-                x = vw - w;
-                moved = true;
-            }
-            if(y + h > vh+s.top){
-                y = vh - h;
-                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){
-                // cache xy
-                this.xy = [x, y];
-                if(this.isVisible()){
-                    this.el.setLocation(x, y);
-                    this.adjustAssets();
-                }
-            }
-        }
-    },
-
-    // private
-    onDrag : function(){
-        if(!this.proxyDrag){
-            this.xy = this.el.getXY();
-            this.adjustAssets();
-        }
-    },
-
-    // private
-    adjustAssets : function(doShow){
-        var x = this.xy[0], y = this.xy[1];
-        var w = this.size.width, h = this.size.height;
-        if(doShow === true){
-            if(this.shadow){
-                this.shadow.show(this.el);
-            }
-            if(this.shim){
-                this.shim.show();
-            }
-        }
-        if(this.shadow && this.shadow.isVisible()){
-            this.shadow.show(this.el);
-        }
-        if(this.shim && this.shim.isVisible()){
-            this.shim.setBounds(x, y, w, h);
-        }
-    },
-
-    // private
-    adjustViewport : function(w, h){
-        if(!w || !h){
-            w = Roo.lib.Dom.getViewWidth();
-            h = Roo.lib.Dom.getViewHeight();
-        }
-        // cache the size
-        this.viewSize = [w, h];
-        if(this.modal && this.mask.isVisible()){
-            this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
-            this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
-        }
-        if(this.isVisible()){
-            this.constrainXY();
-        }
-    },
-
-    /**
-     * Destroys this dialog and all its supporting elements (including any tabs, shim,
-     * shadow, proxy, mask, etc.)  Also removes all event listeners.
-     * @param {Boolean} removeEl (optional) true to remove the element from the DOM
-     */
-    destroy : function(removeEl){
-        if(this.isVisible()){
-            this.animateTarget = null;
-            this.hide();
-        }
-        Roo.EventManager.removeResizeListener(this.adjustViewport, this);
-        if(this.tabs){
-            this.tabs.destroy(removeEl);
-        }
-        Roo.destroy(
-             this.shim,
-             this.proxy,
-             this.resizer,
-             this.close,
-             this.mask
-        );
-        if(this.dd){
-            this.dd.unreg();
-        }
-        if(this.buttons){
-           for(var i = 0, len = this.buttons.length; i < len; i++){
-               this.buttons[i].destroy();
-           }
-        }
-        this.el.removeAllListeners();
-        if(removeEl === true){
-            this.el.update("");
-            this.el.remove();
-        }
-        Roo.DialogManager.unregister(this);
-    },
-
-    // private
-    startMove : function(){
-        if(this.proxyDrag){
-            this.proxy.show();
-        }
-        if(this.constraintoviewport !== false){
-            this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
-        }
-    },
-
-    // private
-    endMove : function(){
-        if(!this.proxyDrag){
-            Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
-        }else{
-            Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
-            this.proxy.hide();
-        }
-        this.refreshSize();
-        this.adjustAssets();
-        this.focus();
-        this.fireEvent("move", this, this.xy[0], this.xy[1]);
-    },
-
-    /**
-     * Brings this dialog to the front of any other visible dialogs
-     * @return {Roo.BasicDialog} this
-     */
-    toFront : function(){
-        Roo.DialogManager.bringToFront(this);
-        return this;
-    },
-
-    /**
-     * Sends this dialog to the back (under) of any other visible dialogs
-     * @return {Roo.BasicDialog} this
-     */
-    toBack : function(){
-        Roo.DialogManager.sendToBack(this);
-        return this;
-    },
-
-    /**
-     * Centers this dialog in the viewport
-     * @return {Roo.BasicDialog} this
-     */
-    center : function(){
-        var xy = this.el.getCenterXY(true);
-        this.moveTo(xy[0], xy[1]);
-        return this;
-    },
-
-    /**
-     * Moves the dialog's top-left corner to the specified point
-     * @param {Number} x
-     * @param {Number} y
-     * @return {Roo.BasicDialog} this
-     */
-    moveTo : function(x, y){
-        this.xy = [x,y];
-        if(this.isVisible()){
-            this.el.setXY(this.xy);
-            this.adjustAssets();
-        }
-        return this;
-    },
-
-    /**
-     * Aligns the dialog to the specified element
-     * @param {String/HTMLElement/Roo.Element} element The element to align to.
-     * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
-     * @param {Array} offsets (optional) Offset the positioning by [x, y]
-     * @return {Roo.BasicDialog} this
-     */
-    alignTo : function(element, position, offsets){
-        this.xy = this.el.getAlignToXY(element, position, offsets);
-        if(this.isVisible()){
-            this.el.setXY(this.xy);
-            this.adjustAssets();
-        }
-        return this;
-    },
-
-    /**
-     * Anchors an element to another element and realigns it when the window is resized.
-     * @param {String/HTMLElement/Roo.Element} element The element to align to.
-     * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
-     * @param {Array} offsets (optional) Offset the positioning by [x, y]
-     * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
-     * is a number, it is used as the buffer delay (defaults to 50ms).
-     * @return {Roo.BasicDialog} this
-     */
-    anchorTo : function(el, alignment, offsets, monitorScroll){
-        var action = function(){
-            this.alignTo(el, alignment, offsets);
-        };
-        Roo.EventManager.onWindowResize(action, this);
-        var tm = typeof monitorScroll;
-        if(tm != 'undefined'){
-            Roo.EventManager.on(window, 'scroll', action, this,
-                {buffer: tm == 'number' ? monitorScroll : 50});
-        }
-        action.call(this);
-        return this;
-    },
-
-    /**
-     * Returns true if the dialog is visible
-     * @return {Boolean}
-     */
-    isVisible : function(){
-        return this.el.isVisible();
-    },
-
-    // private
-    animHide : function(callback){
-        var b = Roo.get(this.animateTarget).getBox();
-        this.proxy.show();
-        this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
-        this.el.hide();
-        this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
-                    this.hideEl.createDelegate(this, [callback]));
-    },
-
-    /**
-     * Hides the dialog.
-     * @param {Function} callback (optional) Function to call when the dialog is hidden
-     * @return {Roo.BasicDialog} this
-     */
-    hide : function(callback){
-        if (this.fireEvent("beforehide", this) === false){
-            return;
-        }
-        if(this.shadow){
-            this.shadow.hide();
-        }
-        if(this.shim) {
-          this.shim.hide();
-        }
-        // sometimes animateTarget seems to get set.. causing problems...
-        // this just double checks..
-        if(this.animateTarget && Roo.get(this.animateTarget)) {
-           this.animHide(callback);
-        }else{
-            this.el.hide();
-            this.hideEl(callback);
-        }
-        return this;
-    },
-
-    // private
-    hideEl : function(callback){
-        this.proxy.hide();
-        if(this.modal){
-            this.mask.hide();
-            Roo.get(document.body).removeClass("x-body-masked");
-        }
-        this.fireEvent("hide", this);
-        if(typeof callback == "function"){
-            callback();
-        }
-    },
-
-    // private
-    hideAction : function(){
-        this.setLeft("-10000px");
-        this.setTop("-10000px");
-        this.setStyle("visibility", "hidden");
-    },
-
-    // private
-    refreshSize : function(){
-        this.size = this.el.getSize();
-        this.xy = this.el.getXY();
-        Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
-    },
-
-    // private
-    // z-index is managed by the DialogManager and may be overwritten at any time
-    setZIndex : function(index){
-        if(this.modal){
-            this.mask.setStyle("z-index", index);
-        }
-        if(this.shim){
-            this.shim.setStyle("z-index", ++index);
-        }
-        if(this.shadow){
-            this.shadow.setZIndex(++index);
-        }
-        this.el.setStyle("z-index", ++index);
-        if(this.proxy){
-            this.proxy.setStyle("z-index", ++index);
-        }
-        if(this.resizer){
-            this.resizer.proxy.setStyle("z-index", ++index);
-        }
-
-        this.lastZIndex = index;
-    },
-
-    /**
-     * Returns the element for this dialog
-     * @return {Roo.Element} The underlying dialog Element
-     */
-    getEl : function(){
-        return this.el;
-    }
-});
-
-/**
- * @class Roo.DialogManager
- * Provides global access to BasicDialogs that have been created and
- * support for z-indexing (layering) multiple open dialogs.
- */
-Roo.DialogManager = function(){
-    var list = {};
-    var accessList = [];
-    var front = null;
-
-    // private
-    var sortDialogs = function(d1, d2){
-        return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
-    };
-
-    // private
-    var orderDialogs = function(){
-        accessList.sort(sortDialogs);
-        var seed = Roo.DialogManager.zseed;
-        for(var i = 0, len = accessList.length; i < len; i++){
-            var dlg = accessList[i];
-            if(dlg){
-                dlg.setZIndex(seed + (i*10));
-            }
-        }
-    };
-
-    return {
-        /**
-         * The starting z-index for BasicDialogs (defaults to 9000)
-         * @type Number The z-index value
-         */
-        zseed : 9000,
-
-        // private
-        register : function(dlg){
-            list[dlg.id] = dlg;
-            accessList.push(dlg);
-        },
-
-        // private
-        unregister : function(dlg){
-            delete list[dlg.id];
-            var i=0;
-            var len=0;
-            if(!accessList.indexOf){
-                for(  i = 0, len = accessList.length; i < len; i++){
-                    if(accessList[i] == dlg){
-                        accessList.splice(i, 1);
-                        return;
-                    }
-                }
-            }else{
-                 i = accessList.indexOf(dlg);
-                if(i != -1){
-                    accessList.splice(i, 1);
-                }
-            }
-        },
-
-        /**
-         * Gets a registered dialog by id
-         * @param {String/Object} id The id of the dialog or a dialog
-         * @return {Roo.BasicDialog} this
-         */
-        get : function(id){
-            return typeof id == "object" ? id : list[id];
-        },
-
-        /**
-         * Brings the specified dialog to the front
-         * @param {String/Object} dlg The id of the dialog or a dialog
-         * @return {Roo.BasicDialog} this
-         */
-        bringToFront : function(dlg){
-            dlg = this.get(dlg);
-            if(dlg != front){
-                front = dlg;
-                dlg._lastAccess = new Date().getTime();
-                orderDialogs();
-            }
-            return dlg;
-        },
-
-        /**
-         * Sends the specified dialog to the back
-         * @param {String/Object} dlg The id of the dialog or a dialog
-         * @return {Roo.BasicDialog} this
-         */
-        sendToBack : function(dlg){
-            dlg = this.get(dlg);
-            dlg._lastAccess = -(new Date().getTime());
-            orderDialogs();
-            return dlg;
-        },
-
-        /**
-         * Hides all dialogs
-         */
-        hideAll : function(){
-            for(var id in list){
-                if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
-                    list[id].hide();
-                }
-            }
-        }
-    };
-}();
-
-/**
- * @class Roo.LayoutDialog
- * @extends Roo.BasicDialog
- * Dialog which provides adjustments for working with a layout in a Dialog.
- * Add your necessary layout config options to the dialog's config.<br>
- * Example usage (including a nested layout):
- * <pre><code>
-if(!dialog){
-    dialog = new Roo.LayoutDialog("download-dlg", {
-        modal: true,
-        width:600,
-        height:450,
-        shadow:true,
-        minWidth:500,
-        minHeight:350,
-        autoTabs:true,
-        proxyDrag:true,
-        // layout config merges with the dialog config
-        center:{
-            tabPosition: "top",
-            alwaysShowTabs: true
-        }
-    });
-    dialog.addKeyListener(27, dialog.hide, dialog);
-    dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
-    dialog.addButton("Build It!", this.getDownload, this);
-
-    // we can even add nested layouts
-    var innerLayout = new Roo.BorderLayout("dl-inner", {
-        east: {
-            initialSize: 200,
-            autoScroll:true,
-            split:true
-        },
-        center: {
-            autoScroll:true
-        }
-    });
-    innerLayout.beginUpdate();
-    innerLayout.add("east", new Roo.ContentPanel("dl-details"));
-    innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
-    innerLayout.endUpdate(true);
-
-    var layout = dialog.getLayout();
-    layout.beginUpdate();
-    layout.add("center", new Roo.ContentPanel("standard-panel",
-                        {title: "Download the Source", fitToFrame:true}));
-    layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
-               {title: "Build your own roo.js"}));
-    layout.getRegion("center").showPanel(sp);
-    layout.endUpdate();
-}
-</code></pre>
-    * @constructor
-    * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
-    * @param {Object} config configuration options
-  */
-Roo.LayoutDialog = function(el, cfg){
-    
-    var config=  cfg;
-    if (typeof(cfg) == 'undefined') {
-        config = Roo.apply({}, el);
-        // not sure why we use documentElement here.. - it should always be body.
-        // IE7 borks horribly if we use documentElement.
-        // webkit also does not like documentElement - it creates a body element...
-        el = Roo.get( document.body || document.documentElement ).createChild();
-        //config.autoCreate = true;
-    }
-    
-    
-    config.autoTabs = false;
-    Roo.LayoutDialog.superclass.constructor.call(this, el, config);
-    this.body.setStyle({overflow:"hidden", position:"relative"});
-    this.layout = new Roo.BorderLayout(this.body.dom, config);
-    this.layout.monitorWindowResize = false;
-    this.el.addClass("x-dlg-auto-layout");
-    // fix case when center region overwrites center function
-    this.center = Roo.BasicDialog.prototype.center;
-    this.on("show", this.layout.layout, this.layout, true);
-    if (config.items) {
-        var xitems = config.items;
-        delete config.items;
-        Roo.each(xitems, this.addxtype, this);
-    }
-    
-    
-};
-Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
-    /**
-     * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
-     * @deprecated
-     */
-    endUpdate : function(){
-        this.layout.endUpdate();
-    },
-
-    /**
-     * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
-     *  @deprecated
-     */
-    beginUpdate : function(){
-        this.layout.beginUpdate();
-    },
-
-    /**
-     * Get the BorderLayout for this dialog
-     * @return {Roo.BorderLayout}
-     */
-    getLayout : function(){
-        return this.layout;
-    },
-
-    showEl : function(){
-        Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
-        if(Roo.isIE7){
-            this.layout.layout();
-        }
-    },
-
-    // private
-    // Use the syncHeightBeforeShow config option to control this automatically
-    syncBodyHeight : function(){
-        Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
-        if(this.layout){this.layout.layout();}
-    },
-    
-      /**
-     * Add an xtype element (actually adds to the layout.)
-     * @return {Object} xdata xtype object data.
-     */
-    
-    addxtype : function(c) {
-        return this.layout.addxtype(c);
-    }
-});/*
- * 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.MessageBox
- * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
- * Example usage:
- *<pre><code>
-// Basic alert:
-Roo.Msg.alert('Status', 'Changes saved successfully.');
-
-// Prompt for user data:
-Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
-    if (btn == 'ok'){
-        // process text value...
-    }
-});
-
-// Show a dialog using config options:
-Roo.Msg.show({
-   title:'Save Changes?',
-   msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
-   buttons: Roo.Msg.YESNOCANCEL,
-   fn: processResult,
-   animEl: 'elId'
-});
-</code></pre>
- * @singleton
- */
-Roo.MessageBox = function(){
-    var dlg, opt, mask, waitTimer;
-    var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
-    var buttons, activeTextEl, bwidth;
-
-    // private
-    var handleButton = function(button){
-        dlg.hide();
-        Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
-    };
-
-    // private
-    var handleHide = function(){
-        if(opt && opt.cls){
-            dlg.el.removeClass(opt.cls);
-        }
-        if(waitTimer){
-            Roo.TaskMgr.stop(waitTimer);
-            waitTimer = null;
-        }
-    };
-
-    // private
-    var updateButtons = function(b){
-        var width = 0;
-        if(!b){
-            buttons["ok"].hide();
-            buttons["cancel"].hide();
-            buttons["yes"].hide();
-            buttons["no"].hide();
-            dlg.footer.dom.style.display = 'none';
-            return width;
-        }
-        dlg.footer.dom.style.display = '';
-        for(var k in buttons){
-            if(typeof buttons[k] != "function"){
-                if(b[k]){
-                    buttons[k].show();
-                    buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
-                    width += buttons[k].el.getWidth()+15;
-                }else{
-                    buttons[k].hide();
-                }
-            }
+        dlg.footer.dom.style.display = '';
+        for(var k in buttons){
+            if(typeof buttons[k] != "function"){
+                if(b[k]){
+                    buttons[k].show();
+                    buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
+                    width += buttons[k].el.getWidth()+15;
+                }else{
+                    buttons[k].hide();
+                }
+            }
         }
         return width;
     };
@@ -15479,12 +11272,12 @@ Roo.QuickTips = function(){
             t.removeAttribute("title");
             e.preventDefault();
         }else{
-            ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
+            ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
         }
         if(ttp){
             showProc = show.defer(tm.showDelay, tm, [{
                 el: t, 
-                text: ttp
+                text: ttp.replace(/\\n/g,'<br/>'),
                 width: et.getAttributeNS(ns, cfg.width),
                 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
                 title: et.getAttributeNS(ns, cfg.title),
@@ -15820,7 +11613,8 @@ target      Element/String/Array   An Element, id or array of ids that this quic
 
         // private
        tagConfig : {
-           namespace : "ext",
+           namespace : "roo", // was ext?? this may break..
+           alt_namespace : "ext",
            attribute : "qtip",
            width : "width",
            target : "target",
@@ -16073,7 +11867,15 @@ Roo.tree.TreePanel = function(el, config){
         * </ul>
         * @param {Object} dragOverEvent
         */
-       "nodedragover" : true
+       "nodedragover" : true,
+       /**
+        * @event appendnode
+        * Fires when append node to the tree
+        * @param {Roo.tree.TreePanel} this
+        * @param {Roo.tree.TreeNode} node
+        * @param {Number} index The index of the newly appended node
+        */
+       "appendnode" : true
         
     });
     if(this.singleExpand){
@@ -16651,7 +12453,7 @@ Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
  * @cfg {Boolean} allowDrop false if this node cannot be drop on
  * @cfg {Boolean} disabled true to start the node disabled
  * @cfg {String} icon The path to an icon for the node. The preferred way to do this
- * is to use the cls or iconCls attributes and add the icon via a CSS background image.
+ *    is to use the cls or iconCls attributes and add the icon via a CSS background image.
  * @cfg {String} cls A css class to be added to the node
  * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
  * @cfg {String} href URL of the link used for the node (defaults to #)
@@ -16934,7 +12736,8 @@ Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
                 this.renderChildren();
             }
             this.expanded = true;
-            if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
+            
+            if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
                 this.ui.animExpand(function(){
                     this.fireEvent("expand", this);
                     if(typeof callback == "function"){
@@ -17385,7 +13188,7 @@ Roo.tree.TreeNodeUI.prototype = {
             this.addClass("x-tree-node-disabled");
         }
         var ot = this.node.getOwnerTree();
-        var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
+        var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
         if(dd && (!this.node.isRoot || ot.rootVisible)){
             Roo.dd.Registry.register(this.elNode, {
                 node: this.node,
@@ -17628,11 +13431,11 @@ Roo.tree.TreeNodeUI.prototype = {
         // add some indent caching, this helps performance when rendering a large tree
         this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
         var t = n.getOwnerTree();
-        var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
+        var txt = t && t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
         if (typeof(n.attributes.html) != 'undefined') {
             txt = n.attributes.html;
         }
-        var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
+        var tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
         var cb = typeof a.checked == 'boolean';
         var href = a.href ? a.href : Roo.isGecko ? "" : "#";
         var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
@@ -17818,7 +13621,9 @@ Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
     myTreeLoader.on("beforeload", function(treeLoader, node) {
         this.baseParams.category = node.attributes.category;
     }, this);
-</code></pre><
+    
+</code></pre>
+ *
  * This would pass an HTTP parameter called "category" to the server containing
  * the value of the Node's "category" attribute.
  * @constructor
@@ -19023,7 +14828,9 @@ Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
  * @param {Object} config Configuration options
  */
 Roo.menu.Menu = function(config){
-    Roo.apply(this, config);
+    
+    Roo.menu.Menu.superclass.constructor.call(this, config);
+    
     this.id = this.id || Roo.id();
     this.addEvents({
         /**
@@ -19150,7 +14957,11 @@ Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
             tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
         });
         var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
-        ul.on("click", this.onClick, this);
+        //disabling touch- as it's causing issues ..
+        //ul.on(Roo.isTouch ? 'touchstart' : 'click'   , this.onClick, this);
+        ul.on('click'   , this.onClick, this);
+        
+        
         ul.on("mouseover", this.onMouseOver, this);
         ul.on("mouseout", this.onMouseOut, this);
         this.items.each(function(item){
@@ -19203,11 +15014,28 @@ Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
 
     // private
     onClick : function(e){
-        var t;
-        if(t = this.findTargetItem(e)){
-            t.onClick(e);
-            this.fireEvent("click", this, t, e);
+        Roo.log("menu.onClick");
+        var t = this.findTargetItem(e);
+        if(!t){
+            return;
+        }
+        Roo.log(e);
+        if (Roo.isTouch && e.type == 'touchstart' && t.menu  && !t.disabled) {
+            if(t == this.activeItem && t.shouldDeactivate(e)){
+                this.activeItem.deactivate();
+                delete this.activeItem;
+                return;
+            }
+            if(t.canActivate){
+                this.setActiveItem(t, true);
+            }
+            return;
+            
+            
         }
+        
+        t.onClick(e);
+        this.fireEvent("click", this, t, e);
     },
 
     // private
@@ -20483,6 +16311,69 @@ Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
  * <script type="text/javascript">
  */
  
+/**
+ * @class Roo.form.TextItem
+ * @extends Roo.BoxComponent
+ * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
+ * @constructor
+ * Creates a new TextItem
+ * @param {Object} config Configuration options
+ */
+Roo.form.TextItem = function(config){
+    Roo.form.TextItem.superclass.constructor.call(this, config);
+};
+
+Roo.extend(Roo.form.TextItem, Roo.BoxComponent,  {
+    
+    /**
+     * @cfg {String} tag the tag for this item (default div)
+     */
+    tag : 'div',
+    /**
+     * @cfg {String} html the content for this item
+     */
+    html : '',
+    
+    getAutoCreate : function()
+    {
+        var cfg = {
+            id: this.id,
+            tag: this.tag,
+            html: this.html,
+            cls: 'x-form-item'
+        };
+        
+        return cfg;
+        
+    },
+    
+    onRender : function(ct, position)
+    {
+        Roo.form.TextItem.superclass.onRender.call(this, ct, position);
+        
+        if(!this.el){
+            var cfg = this.getAutoCreate();
+            if(!cfg.name){
+                cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
+            }
+            if (!cfg.name.length) {
+                delete cfg.name;
+            }
+            this.el = ct.createChild(cfg, position);
+        }
+    }
+    
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
 /**
  * @class Roo.form.Field
  * @extends Roo.BoxComponent
@@ -20532,7 +16423,7 @@ Roo.extend(Roo.form.Field, Roo.BoxComponent,  {
      * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
      * {tag: "input", type: "text", size: "20", autocomplete: "off"})
      */
-    defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
+    defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
     /**
      * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
      */
@@ -20595,7 +16486,10 @@ side          Add an error icon to the right of the field with a popup on hover
     /**
      * @cfg {String} cls A CSS class to apply to the field's underlying element.
      */
-
+    // private
+    loadedValue : false,
+     
+     
        // private ??
        initComponent : function(){
         Roo.form.Field.superclass.initComponent.call(this);
@@ -20716,6 +16610,7 @@ side          Add an error icon to the right of the field with a popup on hover
 
     /**
      * Returns true if this field has been changed since it was originally loaded and is not disabled.
+     * DEPRICATED  - it never worked well - use hasChanged/resetHasChanged.
      */
     isDirty : function() {
         if(this.disabled) {
@@ -20724,6 +16619,27 @@ side          Add an error icon to the right of the field with a popup on hover
         return String(this.getValue()) !== String(this.originalValue);
     },
 
+    /**
+     * stores the current value in loadedValue
+     */
+    resetHasChanged : function()
+    {
+        this.loadedValue = String(this.getValue());
+    },
+    /**
+     * checks the current value against the 'loaded' value.
+     * Note - will return false if 'resetHasChanged' has not been called first.
+     */
+    hasChanged : function()
+    {
+        if(this.disabled || this.readOnly) {
+            return false;
+        }
+        return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
+    },
+    
+    
+    
     // private
     afterRender : function(){
         Roo.form.Field.superclass.afterRender.call(this);
@@ -20743,6 +16659,7 @@ side          Add an error icon to the right of the field with a popup on hover
      */
     reset : function(){
         this.setValue(this.resetValue);
+        this.originalValue = this.getValue();
         this.clearInvalid();
     },
 
@@ -21112,6 +17029,10 @@ Roo.extend(Roo.form.TextField, Roo.form.Field,  {
      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
      */
     selectOnFocus : false,
+    /**
+     * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space 
+     */    
+    allowLeadingSpace : false,
     /**
      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
      */
@@ -21156,8 +17077,11 @@ Roo.extend(Roo.form.TextField, Roo.form.Field,  {
         
         if(this.selectOnFocus){
             this.on("focus", this.preFocus, this);
-            
         }
+       if (!this.allowLeadingSpace) {
+           this.on('blur', this.cleanLeadingSpace, this);
+       }
+       
         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
             this.el.on("keypress", this.filterKeys, this);
         }
@@ -21193,7 +17117,15 @@ Roo.extend(Roo.form.TextField, Roo.form.Field,  {
             this.autoSize();
         }
     },
-
+    // private - clean the leading white space
+    cleanLeadingSpace : function(e)
+    {
+        if ( this.inputType == 'file') {
+            return;
+        }
+        
+        this.setValue((this.getValue() + '').replace(/^\s+/,''));
+    },
     /**
      * Resets the current field value to the originally-loaded value and clears any validation messages.
      *  
@@ -21201,9 +17133,7 @@ Roo.extend(Roo.form.TextField, Roo.form.Field,  {
     reset : function(){
         Roo.form.TextField.superclass.reset.call(this);
        
-    },
-
-    
+    }, 
     // private
     preFocus : function(){
         
@@ -21341,12 +17271,14 @@ Roo.extend(Roo.form.TextField, Roo.form.Field,  {
             return;
         }
         
-        if(isSelectAll){ // backspace and delete key
+        if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
             
             event.preventDefault();
             // this is very hacky as keydown always get's upper case.
-            //
+            
             var cc = String.fromCharCode(event.getCharCode());
+            
+            
             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
             
         }
@@ -21442,7 +17374,7 @@ Roo.extend(Roo.form.TriggerField, Roo.form.TextField,  {
      * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
      * {tag: "input", type: "text", size: "16", autocomplete: "off"})
      */
-    defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
+    defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
     /**
      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
      */
@@ -21722,7 +17654,7 @@ Roo.extend(Roo.form.TextArea, Roo.form.TextField,  {
             this.defaultAutoCreate = {
                 tag: "textarea",
                 style:"width:300px;height:60px;",
-                autocomplete: "off"
+                autocomplete: "new-password"
             };
         }
         Roo.form.TextArea.superclass.onRender.call(this, ct, position);
@@ -21953,7 +17885,8 @@ Roo.extend(Roo.form.NumberField, Roo.form.TextField,  {
 * Create a new DateField
 * @param {Object} config
  */
-Roo.form.DateField = function(config){
+Roo.form.DateField = function(config)
+{
     Roo.form.DateField.superclass.constructor.call(this, config);
     
       this.addEvents({
@@ -21969,15 +17902,21 @@ Roo.form.DateField = function(config){
     });
     
     
-    if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
-    if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
+    if(typeof this.minValue == "string") {
+        this.minValue = this.parseDate(this.minValue);
+    }
+    if(typeof this.maxValue == "string") {
+        this.maxValue = this.parseDate(this.maxValue);
+    }
     this.ddMatch = null;
     if(this.disabledDates){
         var dd = this.disabledDates;
         var re = "(?:";
         for(var i = 0; i < dd.length; i++){
             re += dd[i];
-            if(i != dd.length-1) re += "|";
+            if(i != dd.length-1) {
+                re += "|";
+            }
         }
         this.ddMatch = new RegExp(re + ")");
     }
@@ -22295,7 +18234,13 @@ dateField.setValue('2006-5-4');
         
         return String(this.getValue()) !== String(this.startValue);
         
+    },
+    // @overide
+    cleanLeadingSpace : function(e)
+    {
+       return;
     }
+    
 });/*
  * Based on:
  * Ext JS Library 1.1.1
@@ -22332,15 +18277,21 @@ Roo.form.MonthField = function(config){
     });
     
     
-    if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
-    if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
+    if(typeof this.minValue == "string") {
+        this.minValue = this.parseDate(this.minValue);
+    }
+    if(typeof this.maxValue == "string") {
+        this.maxValue = this.parseDate(this.maxValue);
+    }
     this.ddMatch = null;
     if(this.disabledDates){
         var dd = this.disabledDates;
         var re = "(?:";
         for(var i = 0; i < dd.length; i++){
             re += dd[i];
-            if(i != dd.length-1) re += "|";
+            if(i != dd.length-1) {
+                re += "|";
+            }
         }
         this.ddMatch = new RegExp(re + ")");
     }
@@ -22440,7 +18391,7 @@ Roo.extend(Roo.form.MonthField, Roo.form.TriggerField,  {
      * {tag: "input", type: "text", size: "10", autocomplete: "off"})
      */ 
     // private
-    defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
+    defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
     
     // private
     hiddenField: false,
@@ -23002,9 +18953,11 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
     // element that contains real text value.. (when hidden is used..)
      
     // private
-    onRender : function(ct, position){
+    onRender : function(ct, position)
+    {
         Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
-        if(this.hiddenName){
+        
+       if(this.hiddenName){
             this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id:  (this.hiddenId||this.hiddenName)},
                     'before', true);
             this.hiddenField.value =
@@ -23016,6 +18969,7 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
              
              
         }
+       
         if(Roo.isGecko){
             this.el.dom.setAttribute('autocomplete', 'off');
         }
@@ -23076,7 +19030,9 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
         }
 
         this.view = new Roo.View(this.innerList, this.tpl, {
-            singleSelect:true, store: this.store, selectedClass: this.selectedClass
+            singleSelect:true,
+           store: this.store,
+           selectedClass: this.selectedClass
         });
 
         this.view.on('click', this.onViewClick, this);
@@ -23341,9 +19297,8 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
     getValue : function(){
         if(this.valueField){
             return typeof this.value != 'undefined' ? this.value : '';
-        }else{
-            return Roo.form.ComboBox.superclass.getValue.call(this);
         }
+        return Roo.form.ComboBox.superclass.getValue.call(this);
     },
 
     /**
@@ -23426,6 +19381,7 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
     reset : function(){
         // overridden so that last data is reset..
         this.setValue(this.resetValue);
+        this.originalValue = this.getValue();
         this.clearInvalid();
         this.lastData = false;
         if (this.view) {
@@ -23761,9 +19717,9 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
         }
         // scroll to?
         this.view.select(match);
-        var sn = Roo.get(this.view.getSelectedNodes()[0])
+        var sn = Roo.get(this.view.getSelectedNodes()[0]);
         sn.scrollIntoView(sn.dom.parentNode, false);
-    }
+    } 
 
     /** 
     * @cfg {Boolean} grow 
@@ -23819,6 +19775,24 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
 
 Roo.form.ComboBoxArray = function(config)
 {
+    this.addEvents({
+        /**
+         * @event beforeremove
+         * Fires before remove the value from the list
+            * @param {Roo.form.ComboBoxArray} _self This combo box array
+             * @param {Roo.form.ComboBoxArray.Item} item removed item
+            */
+        'beforeremove' : true,
+        /**
+         * @event remove
+         * Fires when remove the value from the list
+            * @param {Roo.form.ComboBoxArray} _self This combo box array
+             * @param {Roo.form.ComboBoxArray.Item} item removed item
+            */
+        'remove' : true
+        
+        
+    });
     
     Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
     
@@ -23859,7 +19833,10 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
      * @cfg {String} hiddenName    The hidden name of the field, often contains an comma seperated list of names
      */
     hiddenName : false,
-    
+      /**
+     * @cfg {String} seperator    The value seperator normally ',' 
+     */
+    seperator : ',',
     
     // private the array of items that are displayed..
     items  : false,
@@ -23880,7 +19857,7 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
         
         // give fake names to child combo;
         this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
-        this.combo.name = this.name? (this.name+'-subcombo') : this.name;
+        this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
         
         this.combo = Roo.factory(this.combo, Roo.form);
         this.combo.onRender(ct, position);
@@ -24001,6 +19978,7 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
     {
         var valueField = this.combo.valueField;
         var displayField = this.combo.displayField;
+       
         if (this.items.indexOfKey(rec[valueField]) > -1) {
             //console.log("GOT " + rec.data.id);
             return;
@@ -24032,18 +20010,19 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
         
         this.items.each(function(f) {
             ar.push(f.data[idField]);
-           
         });
-        this.hiddenEl.dom.value = ar.join(',');
+        this.hiddenEl.dom.value = ar.join(this.seperator);
         this.validate();
     },
     
     reset : function()
     {
-        //Roo.form.ComboBoxArray.superclass.reset.call(this); 
-        this.items.each(function(f) {
-           f.remove(); 
+        this.items.clear();
+        
+        Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
+           el.remove();
         });
+        
         this.el.dom.value = '';
         if (this.hiddenEl) {
             this.hiddenEl.dom.value = '';
@@ -24056,17 +20035,15 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
     },
     setValue: function(v) // not a valid action - must use addItems..
     {
-         
-        this.reset();
-        
-        
         
+        this.reset();
+         
         if (this.store.isLocal && (typeof(v) == 'string')) {
             // then we can use the store to find the values..
             // comma seperated at present.. this needs to allow JSON based encoding..
             this.hiddenEl.value  = v;
             var v_ar = [];
-            Roo.each(v.split(','), function(k) {
+            Roo.each(v.split(this.seperator), function(k) {
                 Roo.log("CHECK " + this.valueField + ',' + k);
                 var li = this.store.query(this.valueField, k);
                 if (!li.length) {
@@ -24080,7 +20057,7 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
             }, this) 
              
         }
-        if (typeof(v) == 'object') {
+        if (typeof(v) == 'object' ) {
             // then let's assume it's an array of objects..
             Roo.each(v, function(l) {
                 this.addItem(l);
@@ -24105,10 +20082,9 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
         dv = typeof(dv) != 'string' ? '' : dv;
         
         
-        var keys = kv.split(',');
-        var display = dv.split(',');
+        var keys = kv.split(this.seperator);
+        var display = dv.split(this.seperator);
         for (var i = 0 ; i < keys.length; i++) {
-            
             add = {};
             add[this.valueField] = keys[i];
             add[this.displayField] = display[i];
@@ -24156,7 +20132,7 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
             originalValue.push(d[i][this.valueField]);
         }
         
-        return String(this.getValue()) !== String(originalValue.join(','));
+        return String(this.getValue()) !== String(originalValue.join(this.seperator));
         
     }
     
@@ -24230,12 +20206,448 @@ Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
    
     remove : function()
     {
+        if(this.cb.disabled){
+            return;
+        }
         
-        this.cb.items.remove(this);
-        this.el.child('img').un('click', this.remove, this);
-        this.el.remove();
-        this.cb.updateHiddenEl();
+        if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
+            this.cb.items.remove(this);
+            this.el.child('img').un('click', this.remove, this);
+            this.el.remove();
+            this.cb.updateHiddenEl();
+
+            this.cb.fireEvent('remove', this.cb, this);
+        }
+        
+    }
+});/*
+ * RooJS Library 1.1.1
+ * Copyright(c) 2008-2011  Alan Knowles
+ *
+ * License - LGPL
+ */
+
+/**
+ * @class Roo.form.ComboNested
+ * @extends Roo.form.ComboBox
+ * A combobox for that allows selection of nested items in a list,
+ * eg.
+ *
+ *  Book
+ *    -> red
+ *    -> green
+ *  Table
+ *    -> square
+ *      ->red
+ *      ->green
+ *    -> rectangle
+ *      ->green
+ *      
+ * 
+ * @constructor
+ * Create a new ComboNested
+ * @param {Object} config Configuration options
+ */
+Roo.form.ComboNested = function(config){
+    Roo.form.ComboCheck.superclass.constructor.call(this, config);
+    // should verify some data...
+    // like
+    // hiddenName = required..
+    // displayField = required
+    // valudField == required
+    var req= [ 'hiddenName', 'displayField', 'valueField' ];
+    var _t = this;
+    Roo.each(req, function(e) {
+        if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
+            throw "Roo.form.ComboNested : missing value for: " + e;
+        }
+    });
+     
+    
+};
+
+Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
+   
+    /*
+     * @config {Number} max Number of columns to show
+     */
+    
+    maxColumns : 3,
+   
+    list : null, // the outermost div..
+    innerLists : null, // the
+    views : null,
+    stores : null,
+    // private
+    loadingChildren : false,
+    
+    onRender : function(ct, position)
+    {
+        Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
+        
+        if(this.hiddenName){
+            this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id:  (this.hiddenId||this.hiddenName)},
+                    'before', true);
+            this.hiddenField.value =
+                this.hiddenValue !== undefined ? this.hiddenValue :
+                this.value !== undefined ? this.value : '';
+
+            // prevent input submission
+            this.el.dom.removeAttribute('name');
+             
+             
+        }
+       
+        if(Roo.isGecko){
+            this.el.dom.setAttribute('autocomplete', 'off');
+        }
+
+        var cls = 'x-combo-list';
+
+        this.list = new Roo.Layer({
+            shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
+        });
+
+        var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
+        this.list.setWidth(lw);
+        this.list.swallowEvent('mousewheel');
+        this.assetHeight = 0;
+
+        if(this.title){
+            this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
+            this.assetHeight += this.header.getHeight();
+        }
+        this.innerLists = [];
+        this.views = [];
+        this.stores = [];
+        for (var i =0 ; i < this.maxColumns; i++) {
+            this.onRenderList( cls, i);
+        }
+        
+        // always needs footer, as we are going to have an 'OK' button.
+        this.footer = this.list.createChild({cls:cls+'-ft'});
+        this.pageTb = new Roo.Toolbar(this.footer);  
+        var _this = this;
+        this.pageTb.add(  {
+            
+            text: 'Done',
+            handler: function()
+            {
+                _this.collapse();
+            }
+        });
+        
+        if ( this.allowBlank && !this.disableClear) {
+            
+            this.pageTb.add(new Roo.Toolbar.Fill(), {
+                cls: 'x-btn-icon x-btn-clear',
+                text: '&#160;',
+                handler: function()
+                {
+                    _this.collapse();
+                    _this.clearValue();
+                    _this.onSelect(false, -1);
+                }
+            });
+        }
+        if (this.footer) {
+            this.assetHeight += this.footer.getHeight();
+        }
+        
+    },
+    onRenderList : function (  cls, i)
+    {
+        
+        var lw = Math.floor(
+                ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
+        );
+        
+        this.list.setWidth(lw); // default to '1'
+
+        var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
+        //il.on('mouseover', this.onViewOver, this, { list:  i });
+        //il.on('mousemove', this.onViewMove, this, { list:  i });
+        il.setWidth(lw);
+        il.setStyle({ 'overflow-x' : 'hidden'});
+
+        if(!this.tpl){
+            this.tpl = new Roo.Template({
+                html :  '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
+                isEmpty: function (value, allValues) {
+                    //Roo.log(value);
+                    var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
+                    return dl ? 'has-children' : 'no-children'
+                }
+            });
+        }
+        
+        var store  = this.store;
+        if (i > 0) {
+            store  = new Roo.data.SimpleStore({
+                //fields : this.store.reader.meta.fields,
+                reader : this.store.reader,
+                data : [ ]
+            });
+        }
+        this.stores[i]  = store;
+                  
+        var view = this.views[i] = new Roo.View(
+            il,
+            this.tpl,
+            {
+                singleSelect:true,
+                store: store,
+                selectedClass: this.selectedClass
+            }
+        );
+        view.getEl().setWidth(lw);
+        view.getEl().setStyle({
+            position: i < 1 ? 'relative' : 'absolute',
+            top: 0,
+            left: (i * lw ) + 'px',
+            display : i > 0 ? 'none' : 'block'
+        });
+        view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
+        view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
+        //view.on('click', this.onViewClick, this, { list : i });
+
+        store.on('beforeload', this.onBeforeLoad, this);
+        store.on('load',  this.onLoad, this, { list  : i});
+        store.on('loadexception', this.onLoadException, this);
+
+        // hide the other vies..
+        
+        
+        
+    },
+      
+    restrictHeight : function()
+    {
+        var mh = 0;
+        Roo.each(this.innerLists, function(il,i) {
+            var el = this.views[i].getEl();
+            el.dom.style.height = '';
+            var inner = el.dom;
+            var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
+            // only adjust heights on other ones..
+            mh = Math.max(h, mh);
+            if (i < 1) {
+                
+                el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
+                il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
+               
+            }
+            
+            
+        }, this);
+        
+        this.list.beginUpdate();
+        this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
+        this.list.alignTo(this.el, this.listAlign);
+        this.list.endUpdate();
+        
+    },
+     
+    
+    // -- store handlers..
+    // private
+    onBeforeLoad : function()
+    {
+        if(!this.hasFocus){
+            return;
+        }
+        this.innerLists[0].update(this.loadingText ?
+               '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
+        this.restrictHeight();
+        this.selectedIndex = -1;
+    },
+    // private
+    onLoad : function(a,b,c,d)
+    {
+        if (!this.loadingChildren) {
+            // then we are loading the top level. - hide the children
+            for (var i = 1;i < this.views.length; i++) {
+                this.views[i].getEl().setStyle({ display : 'none' });
+            }
+            var lw = Math.floor(
+                ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
+            );
+        
+             this.list.setWidth(lw); // default to '1'
+
+            
+        }
+        if(!this.hasFocus){
+            return;
+        }
+        
+        if(this.store.getCount() > 0) {
+            this.expand();
+            this.restrictHeight();   
+        } else {
+            this.onEmptyResults();
+        }
+        
+        if (!this.loadingChildren) {
+            this.selectActive();
+        }
+        /*
+        this.stores[1].loadData([]);
+        this.stores[2].loadData([]);
+        this.views
+        */    
+    
+        //this.el.focus();
+    },
+    
+    
+    // private
+    onLoadException : function()
+    {
+        this.collapse();
+        Roo.log(this.store.reader.jsonData);
+        if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
+            Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
+        }
+        
+        
+    },
+    // no cleaning of leading spaces on blur here.
+    cleanLeadingSpace : function(e) { },
+    
+
+    onSelectChange : function (view, sels, opts )
+    {
+        var ix = view.getSelectedIndexes();
+         
+        if (opts.list > this.maxColumns - 2) {
+            if (view.store.getCount()<  1) {
+                this.views[opts.list ].getEl().setStyle({ display :   'none' });
+
+            } else  {
+                if (ix.length) {
+                    // used to clear ?? but if we are loading unselected 
+                    this.setFromData(view.store.getAt(ix[0]).data);
+                }
+                
+            }
+            
+            return;
+        }
+        
+        if (!ix.length) {
+            // this get's fired when trigger opens..
+           // this.setFromData({});
+            var str = this.stores[opts.list+1];
+            str.data.clear(); // removeall wihtout the fire events..
+            return;
+        }
+        
+        var rec = view.store.getAt(ix[0]);
+         
+        this.setFromData(rec.data);
+        this.fireEvent('select', this, rec, ix[0]);
+        
+        var lw = Math.floor(
+             (
+                (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
+             ) / this.maxColumns
+        );
+        this.loadingChildren = true;
+        this.stores[opts.list+1].loadDataFromChildren( rec );
+        this.loadingChildren = false;
+        var dl = this.stores[opts.list+1]. getTotalCount();
+        
+        this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
+        
+        this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
+        for (var i = opts.list+2; i < this.views.length;i++) {
+            this.views[i].getEl().setStyle({ display : 'none' });
+        }
+        
+        this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
+        this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
+        
+        if (this.isLoading) {
+           // this.selectActive(opts.list);
+        }
+         
+    },
+    
+    
+    
+    
+    onDoubleClick : function()
+    {
+        this.collapse(); //??
+    },
+    
+     
+    
+    
+    
+    // private
+    recordToStack : function(store, prop, value, stack)
+    {
+        var cstore = new Roo.data.SimpleStore({
+            //fields : this.store.reader.meta.fields, // we need array reader.. for
+            reader : this.store.reader,
+            data : [ ]
+        });
+        var _this = this;
+        var record  = false;
+        var srec = false;
+        if(store.getCount() < 1){
+            return false;
+        }
+        store.each(function(r){
+            if(r.data[prop] == value){
+                record = r;
+            srec = r;
+                return false;
+            }
+            if (r.data.cn && r.data.cn.length) {
+                cstore.loadDataFromChildren( r);
+                var cret = _this.recordToStack(cstore, prop, value, stack);
+                if (cret !== false) {
+                    record = cret;
+                    srec = r;
+                    return false;
+                }
+            }
+             
+            return true;
+        });
+        if (record == false) {
+            return false
+        }
+        stack.unshift(srec);
+        return record;
+    },
+    
+    /*
+     * find the stack of stores that match our value.
+     *
+     * 
+     */
+    
+    selectActive : function ()
+    {
+       // if store is not loaded, then we will need to wait for that to happen first.
+        var stack = [];
+        this.recordToStack(this.store, this.valueField, this.getValue(), stack);
+        for (var i = 0; i < stack.length; i++ ) {
+            this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
+        }
+       
     }
+       
+        
+    
+    
+    
+    
 });/*
  * Based on:
  * Ext JS Library 1.1.1
@@ -24384,6 +20796,9 @@ Roo.extend(Roo.form.Checkbox, Roo.form.Field,  {
 
        // private
     onClick : function(){ 
+        if (this.disabled) {
+            return;
+        }
         this.setChecked(!this.checked);
 
         //if(this.el.dom.checked != this.checked){
@@ -24447,6 +20862,11 @@ Roo.extend(Roo.form.Checkbox, Roo.form.Field,  {
         }
          
         Roo.form.Checkbox.superclass.onDestroy.call(this);
+    },
+    
+    setBoxLabel : function(str)
+    {
+        this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
     }
 
 });/*
@@ -24517,50 +20937,99 @@ Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
 });//<script type="text/javascript">
 
 /*
- * Ext JS Library 1.1.1
+ * Based  Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
- * licensing@extjs.com
- * 
- * http://www.extjs.com/license
+ * LGPL
+ *
  */
  
- /*
-  * 
-  * Known bugs:
-  * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
-  * - IE ? - no idea how much works there.
-  * 
-  * 
-  * 
-  */
-
 /**
- * @class Ext.form.HtmlEditor
- * @extends Ext.form.Field
- * Provides a lightweight HTML Editor component.
+ * @class Roo.HtmlEditorCore
+ * @extends Roo.Component
+ * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
  *
- * This has been tested on Fireforx / Chrome.. IE may not be so great..
- * 
- * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
- * supported by this editor.</b><br/><br/>
- * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
  */
-Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
-      /**
-     * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
-     */
-    toolbars : false,
-    /**
-     * @cfg {String} createLinkText The default text for the create link prompt
-     */
-    createLinkText : 'Please enter the URL for the link:',
-    /**
-     * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
+
+Roo.HtmlEditorCore = function(config){
+    
+    
+    Roo.HtmlEditorCore.superclass.constructor.call(this, config);
+    
+    
+    this.addEvents({
+        /**
+         * @event initialize
+         * Fires when the editor is fully initialized (including the iframe)
+         * @param {Roo.HtmlEditorCore} this
+         */
+        initialize: true,
+        /**
+         * @event activate
+         * Fires when the editor is first receives the focus. Any insertion must wait
+         * until after this event.
+         * @param {Roo.HtmlEditorCore} this
+         */
+        activate: true,
+         /**
+         * @event beforesync
+         * Fires before the textarea is updated with content from the editor iframe. Return false
+         * to cancel the sync.
+         * @param {Roo.HtmlEditorCore} this
+         * @param {String} html
+         */
+        beforesync: true,
+         /**
+         * @event beforepush
+         * Fires before the iframe editor is updated with content from the textarea. Return false
+         * to cancel the push.
+         * @param {Roo.HtmlEditorCore} this
+         * @param {String} html
+         */
+        beforepush: true,
+         /**
+         * @event sync
+         * Fires when the textarea is updated with content from the editor iframe.
+         * @param {Roo.HtmlEditorCore} this
+         * @param {String} html
+         */
+        sync: true,
+         /**
+         * @event push
+         * Fires when the iframe editor is updated with content from the textarea.
+         * @param {Roo.HtmlEditorCore} this
+         * @param {String} html
+         */
+        push: true,
+        
+        /**
+         * @event editorevent
+         * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
+         * @param {Roo.HtmlEditorCore} this
+         */
+        editorevent: true
+        
+    });
+    
+    // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
+    
+    // defaults : white / black...
+    this.applyBlacklists();
+    
+    
+    
+};
+
+
+Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
+
+
+     /**
+     * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
      */
-    defaultLinkValue : 'http:/'+'/',
-   
+    
+    owner : false,
+    
      /**
      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
      *                        Roo.resizable.
@@ -24594,100 +21063,13 @@ Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
     iframePad:3,
     hideMode:'offsets',
     
-    defaultAutoCreate : { // modified by initCompnoent..
-        tag: "textarea",
-        style:"width:500px;height:300px;",
-        autocomplete: "off"
-    },
-
-    // private
-    initComponent : function(){
-        this.addEvents({
-            /**
-             * @event initialize
-             * Fires when the editor is fully initialized (including the iframe)
-             * @param {HtmlEditor} this
-             */
-            initialize: true,
-            /**
-             * @event activate
-             * Fires when the editor is first receives the focus. Any insertion must wait
-             * until after this event.
-             * @param {HtmlEditor} this
-             */
-            activate: true,
-             /**
-             * @event beforesync
-             * Fires before the textarea is updated with content from the editor iframe. Return false
-             * to cancel the sync.
-             * @param {HtmlEditor} this
-             * @param {String} html
-             */
-            beforesync: true,
-             /**
-             * @event beforepush
-             * Fires before the iframe editor is updated with content from the textarea. Return false
-             * to cancel the push.
-             * @param {HtmlEditor} this
-             * @param {String} html
-             */
-            beforepush: true,
-             /**
-             * @event sync
-             * Fires when the textarea is updated with content from the editor iframe.
-             * @param {HtmlEditor} this
-             * @param {String} html
-             */
-            sync: true,
-             /**
-             * @event push
-             * Fires when the iframe editor is updated with content from the textarea.
-             * @param {HtmlEditor} this
-             * @param {String} html
-             */
-            push: true,
-             /**
-             * @event editmodechange
-             * Fires when the editor switches edit modes
-             * @param {HtmlEditor} this
-             * @param {Boolean} sourceEdit True if source edit, false if standard editing.
-             */
-            editmodechange: true,
-            /**
-             * @event editorevent
-             * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
-             * @param {HtmlEditor} this
-             */
-            editorevent: true
-        });
-        this.defaultAutoCreate =  {
-            tag: "textarea",
-            style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
-            autocomplete: "off"
-        };
-    },
-
-    /**
-     * Protected method that will not generally be called directly. It
-     * is called when the editor creates its toolbar. Override this method if you need to
-     * add custom toolbar buttons.
-     * @param {HtmlEditor} editor
-     */
-    createToolbar : function(editor){
-        if (!editor.toolbars || !editor.toolbars.length) {
-            editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
-        }
-        
-        for (var i =0 ; i < editor.toolbars.length;i++) {
-            editor.toolbars[i] = Roo.factory(
-                    typeof(editor.toolbars[i]) == 'string' ?
-                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
-                Roo.form.HtmlEditor);
-            editor.toolbars[i].init(editor);
-        }
-         
-        
-    },
+    clearUp: true,
+    
+    // blacklist + whitelisted elements..
+    black: false,
+    white: false,
+     
+    bodyCls : '',
 
     /**
      * Protected method that will not generally be called directly. It
@@ -24697,6 +21079,8 @@ Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
     getDocMarkup : function(){
         // body styles..
         var st = '';
+        
+        // inherit styels from page...?? 
         if (this.stylesheets === false) {
             
             Roo.get(document.head).select('style').each(function(node) {
@@ -24712,1077 +21096,2152 @@ Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
                 st = '<style type="text/css">' +
                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
                    '</style>';
-        } else {
-            Roo.each(this.stylesheets, function(s) {
-                st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
-            });
-            
+        } else { 
+            st = '<style type="text/css">' +
+                    this.stylesheets +
+                '</style>';
         }
         
         st +=  '<style type="text/css">' +
             'IMG { cursor: pointer } ' +
         '</style>';
 
+        var cls = 'roo-htmleditor-body';
+        
+        if(this.bodyCls.length){
+            cls += ' ' + this.bodyCls;
+        }
         
         return '<html><head>' + st  +
             //<style type="text/css">' +
             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
             //'</style>' +
-            ' </head><body class="roo-htmleditor-body"></body></html>';
+            ' </head><body class="' +  cls + '"></body></html>';
     },
 
     // private
     onRender : function(ct, position)
     {
         var _t = this;
-        Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
+        //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
+        this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
+        
+        
         this.el.dom.style.border = '0 none';
         this.el.dom.setAttribute('tabIndex', -1);
-        this.el.addClass('x-hidden');
+        this.el.addClass('x-hidden hide');
+        
+        
+        
         if(Roo.isIE){ // fix IE 1px bogus margin
             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
         }
-        this.wrap = this.el.wrap({
-            cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
-        });
+       
         
-        if (this.resizable) {
-            this.resizeEl = new Roo.Resizable(this.wrap, {
-                pinned : true,
-                wrap: true,
-                dynamic : true,
-                minHeight : this.height,
-                height: this.height,
-                handles : this.resizable,
-                width: this.width,
-                listeners : {
-                    resize : function(r, w, h) {
-                        _t.onResize(w,h); // -something
+        this.frameId = Roo.id();
+        
+         
+        
+        var iframe = this.owner.wrap.createChild({
+            tag: 'iframe',
+            cls: 'form-control', // bootstrap..
+            id: this.frameId,
+            name: this.frameId,
+            frameBorder : 'no',
+            'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
+        }, this.el
+        );
+        
+        
+        this.iframe = iframe.dom;
+
+         this.assignDocWin();
+        
+        this.doc.designMode = 'on';
+       
+        this.doc.open();
+        this.doc.write(this.getDocMarkup());
+        this.doc.close();
+
+        
+        var task = { // must defer to wait for browser to be ready
+            run : function(){
+                //console.log("run task?" + this.doc.readyState);
+                this.assignDocWin();
+                if(this.doc.body || this.doc.readyState == 'complete'){
+                    try {
+                        this.doc.designMode="on";
+                    } catch (e) {
+                        return;
                     }
+                    Roo.TaskMgr.stop(task);
+                    this.initEditor.defer(10, this);
+                }
+            },
+            interval : 10,
+            duration: 10000,
+            scope: this
+        };
+        Roo.TaskMgr.start(task);
+
+    },
+
+    // private
+    onResize : function(w, h)
+    {
+         Roo.log('resize: ' +w + ',' + h );
+        //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
+        if(!this.iframe){
+            return;
+        }
+        if(typeof w == 'number'){
+            
+            this.iframe.style.width = w + 'px';
+        }
+        if(typeof h == 'number'){
+            
+            this.iframe.style.height = h + 'px';
+            if(this.doc){
+                (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
+            }
+        }
+        
+    },
+
+    /**
+     * Toggles the editor between standard and source edit mode.
+     * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
+     */
+    toggleSourceEdit : function(sourceEditMode){
+        
+        this.sourceEditMode = sourceEditMode === true;
+        
+        if(this.sourceEditMode){
+            Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
+            
+        }else{
+            Roo.get(this.iframe).removeClass(['x-hidden','hide']);
+            //this.iframe.className = '';
+            this.deferFocus();
+        }
+        //this.setSize(this.owner.wrap.getSize());
+        //this.fireEvent('editmodechange', this, this.sourceEditMode);
+    },
+
+    
+  
+
+    /**
+     * Protected method that will not generally be called directly. If you need/want
+     * custom HTML cleanup, this is the method you should override.
+     * @param {String} html The HTML to be cleaned
+     * return {String} The cleaned HTML
+     */
+    cleanHtml : function(html){
+        html = String(html);
+        if(html.length > 5){
+            if(Roo.isSafari){ // strip safari nonsense
+                html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
+            }
+        }
+        if(html == '&nbsp;'){
+            html = '';
+        }
+        return html;
+    },
+
+    /**
+     * HTML Editor -> Textarea
+     * Protected method that will not generally be called directly. Syncs the contents
+     * of the editor iframe with the textarea.
+     */
+    syncValue : function(){
+        if(this.initialized){
+            var bd = (this.doc.body || this.doc.documentElement);
+            //this.cleanUpPaste(); -- this is done else where and causes havoc..
+            var html = bd.innerHTML;
+            if(Roo.isSafari){
+                var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
+                var m = bs ? bs.match(/text-align:(.*?);/i) : false;
+                if(m && m[1]){
+                    html = '<div style="'+m[0]+'">' + html + '</div>';
                 }
+            }
+            html = this.cleanHtml(html);
+            // fix up the special chars.. normaly like back quotes in word...
+            // however we do not want to do this with chinese..
+            html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
+                
+                var cc = match.charCodeAt();
+
+                // Get the character value, handling surrogate pairs
+                if (match.length == 2) {
+                    // It's a surrogate pair, calculate the Unicode code point
+                    var high = match.charCodeAt(0) - 0xD800;
+                    var low  = match.charCodeAt(1) - 0xDC00;
+                    cc = (high * 0x400) + low + 0x10000;
+                }  else if (
+                    (cc >= 0x4E00 && cc < 0xA000 ) ||
+                    (cc >= 0x3400 && cc < 0x4E00 ) ||
+                    (cc >= 0xf900 && cc < 0xfb00 )
+                ) {
+                        return match;
+                }  
+         
+                // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
+                return "&#" + cc + ";";
+                
+                
             });
             
+            
+             
+            if(this.owner.fireEvent('beforesync', this, html) !== false){
+                this.el.dom.value = html;
+                this.owner.fireEvent('sync', this, html);
+            }
+        }
+    },
+
+    /**
+     * Protected method that will not generally be called directly. Pushes the value of the textarea
+     * into the iframe editor.
+     */
+    pushValue : function(){
+        if(this.initialized){
+            var v = this.el.dom.value.trim();
+            
+//            if(v.length < 1){
+//                v = '&#160;';
+//            }
+            
+            if(this.owner.fireEvent('beforepush', this, v) !== false){
+                var d = (this.doc.body || this.doc.documentElement);
+                d.innerHTML = v;
+                this.cleanUpPaste();
+                this.el.dom.value = d.innerHTML;
+                this.owner.fireEvent('push', this, v);
+            }
+        }
+    },
+
+    // private
+    deferFocus : function(){
+        this.focus.defer(10, this);
+    },
+
+    // doc'ed in Field
+    focus : function(){
+        if(this.win && !this.sourceEditMode){
+            this.win.focus();
+        }else{
+            this.el.focus();
+        }
+    },
+    
+    assignDocWin: function()
+    {
+        var iframe = this.iframe;
+        
+         if(Roo.isIE){
+            this.doc = iframe.contentWindow.document;
+            this.win = iframe.contentWindow;
+        } else {
+//            if (!Roo.get(this.frameId)) {
+//                return;
+//            }
+//            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
+//            this.win = Roo.get(this.frameId).dom.contentWindow;
+            
+            if (!Roo.get(this.frameId) && !iframe.contentDocument) {
+                return;
+            }
+            
+            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
+            this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
+        }
+    },
+    
+    // private
+    initEditor : function(){
+        //console.log("INIT EDITOR");
+        this.assignDocWin();
+        
+        
+        
+        this.doc.designMode="on";
+        this.doc.open();
+        this.doc.write(this.getDocMarkup());
+        this.doc.close();
+        
+        var dbody = (this.doc.body || this.doc.documentElement);
+        //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
+        // this copies styles from the containing element into thsi one..
+        // not sure why we need all of this..
+        //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
+        
+        //var ss = this.el.getStyles( 'background-image', 'background-repeat');
+        //ss['background-attachment'] = 'fixed'; // w3c
+        dbody.bgProperties = 'fixed'; // ie
+        //Roo.DomHelper.applyStyles(dbody, ss);
+        Roo.EventManager.on(this.doc, {
+            //'mousedown': this.onEditorEvent,
+            'mouseup': this.onEditorEvent,
+            'dblclick': this.onEditorEvent,
+            'click': this.onEditorEvent,
+            'keyup': this.onEditorEvent,
+            buffer:100,
+            scope: this
+        });
+        if(Roo.isGecko){
+            Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
+        }
+        if(Roo.isIE || Roo.isSafari || Roo.isOpera){
+            Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
+        }
+        this.initialized = true;
+
+        this.owner.fireEvent('initialize', this);
+        this.pushValue();
+    },
+
+    // private
+    onDestroy : function(){
+        
+        
+        
+        if(this.rendered){
+            
+            //for (var i =0; i < this.toolbars.length;i++) {
+            //    // fixme - ask toolbars for heights?
+            //    this.toolbars[i].onDestroy();
+           // }
+            
+            //this.wrap.dom.innerHTML = '';
+            //this.wrap.remove();
+        }
+    },
+
+    // private
+    onFirstFocus : function(){
+        
+        this.assignDocWin();
+        
+        
+        this.activated = true;
+         
+    
+        if(Roo.isGecko){ // prevent silly gecko errors
+            this.win.focus();
+            var s = this.win.getSelection();
+            if(!s.focusNode || s.focusNode.nodeType != 3){
+                var r = s.getRangeAt(0);
+                r.selectNodeContents((this.doc.body || this.doc.documentElement));
+                r.collapse(true);
+                this.deferFocus();
+            }
+            try{
+                this.execCmd('useCSS', true);
+                this.execCmd('styleWithCSS', false);
+            }catch(e){}
+        }
+        this.owner.fireEvent('activate', this);
+    },
+
+    // private
+    adjustFont: function(btn){
+        var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
+        //if(Roo.isSafari){ // safari
+        //    adjust *= 2;
+       // }
+        var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
+        if(Roo.isSafari){ // safari
+            var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
+            v =  (v < 10) ? 10 : v;
+            v =  (v > 48) ? 48 : v;
+            v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
+            
+        }
+        
+        
+        v = Math.max(1, v+adjust);
+        
+        this.execCmd('FontSize', v  );
+    },
+
+    onEditorEvent : function(e)
+    {
+        this.owner.fireEvent('editorevent', this, e);
+      //  this.updateToolbar();
+        this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
+    },
+
+    insertTag : function(tg)
+    {
+        // could be a bit smarter... -> wrap the current selected tRoo..
+        if (tg.toLowerCase() == 'span' ||
+            tg.toLowerCase() == 'code' ||
+            tg.toLowerCase() == 'sup' ||
+            tg.toLowerCase() == 'sub' 
+            ) {
+            
+            range = this.createRange(this.getSelection());
+            var wrappingNode = this.doc.createElement(tg.toLowerCase());
+            wrappingNode.appendChild(range.extractContents());
+            range.insertNode(wrappingNode);
+
+            return;
+            
+            
+            
+        }
+        this.execCmd("formatblock",   tg);
+        
+    },
+    
+    insertText : function(txt)
+    {
+        
+        
+        var range = this.createRange();
+        range.deleteContents();
+               //alert(Sender.getAttribute('label'));
+               
+        range.insertNode(this.doc.createTextNode(txt));
+    } ,
+    
+     
+
+    /**
+     * Executes a Midas editor command on the editor document and performs necessary focus and
+     * toolbar updates. <b>This should only be called after the editor is initialized.</b>
+     * @param {String} cmd The Midas command
+     * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
+     */
+    relayCmd : function(cmd, value){
+        this.win.focus();
+        this.execCmd(cmd, value);
+        this.owner.fireEvent('editorevent', this);
+        //this.updateToolbar();
+        this.owner.deferFocus();
+    },
+
+    /**
+     * Executes a Midas editor command directly on the editor document.
+     * For visual commands, you should use {@link #relayCmd} instead.
+     * <b>This should only be called after the editor is initialized.</b>
+     * @param {String} cmd The Midas command
+     * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
+     */
+    execCmd : function(cmd, value){
+        this.doc.execCommand(cmd, false, value === undefined ? null : value);
+        this.syncValue();
+    },
+   
+    /**
+     * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
+     * to insert tRoo.
+     * @param {String} text | dom node.. 
+     */
+    insertAtCursor : function(text)
+    {
+        
+        if(!this.activated){
+            return;
+        }
+        /*
+        if(Roo.isIE){
+            this.win.focus();
+            var r = this.doc.selection.createRange();
+            if(r){
+                r.collapse(true);
+                r.pasteHTML(text);
+                this.syncValue();
+                this.deferFocus();
+            
+            }
+            return;
+        }
+        */
+        if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
+            this.win.focus();
+            
+            
+            // from jquery ui (MIT licenced)
+            var range, node;
+            var win = this.win;
+            
+            if (win.getSelection && win.getSelection().getRangeAt) {
+                range = win.getSelection().getRangeAt(0);
+                node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
+                range.insertNode(node);
+            } else if (win.document.selection && win.document.selection.createRange) {
+                // no firefox support
+                var txt = typeof(text) == 'string' ? text : text.outerHTML;
+                win.document.selection.createRange().pasteHTML(txt);
+            } else {
+                // no firefox support
+                var txt = typeof(text) == 'string' ? text : text.outerHTML;
+                this.execCmd('InsertHTML', txt);
+            } 
+            
+            this.syncValue();
+            
+            this.deferFocus();
         }
-
-        this.frameId = Roo.id();
-        
-        this.createToolbar(this);
-        
-      
-        
-        var iframe = this.wrap.createChild({
-            tag: 'iframe',
-            id: this.frameId,
-            name: this.frameId,
-            frameBorder : 'no',
-            'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
-        }, this.el
-        );
-        
-       // console.log(iframe);
-        //this.wrap.dom.appendChild(iframe);
-
-        this.iframe = iframe.dom;
-
-         this.assignDocWin();
-        
-        this.doc.designMode = 'on';
-       
-        this.doc.open();
-        this.doc.write(this.getDocMarkup());
-        this.doc.close();
-
-        
-        var task = { // must defer to wait for browser to be ready
-            run : function(){
-                //console.log("run task?" + this.doc.readyState);
-                this.assignDocWin();
-                if(this.doc.body || this.doc.readyState == 'complete'){
-                    try {
-                        this.doc.designMode="on";
-                    } catch (e) {
+    },
+ // private
+    mozKeyPress : function(e){
+        if(e.ctrlKey){
+            var c = e.getCharCode(), cmd;
+          
+            if(c > 0){
+                c = String.fromCharCode(c).toLowerCase();
+                switch(c){
+                    case 'b':
+                        cmd = 'bold';
+                        break;
+                    case 'i':
+                        cmd = 'italic';
+                        break;
+                    
+                    case 'u':
+                        cmd = 'underline';
+                        break;
+                    
+                    case 'v':
+                        this.cleanUpPaste.defer(100, this);
                         return;
-                    }
-                    Roo.TaskMgr.stop(task);
-                    this.initEditor.defer(10, this);
+                        
                 }
-            },
-            interval : 10,
-            duration:10000,
-            scope: this
-        };
-        Roo.TaskMgr.start(task);
-
-        if(!this.width){
-            this.setSize(this.wrap.getSize());
-        }
-        if (this.resizeEl) {
-            this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
-            // should trigger onReize..
+                if(cmd){
+                    this.win.focus();
+                    this.execCmd(cmd);
+                    this.deferFocus();
+                    e.preventDefault();
+                }
+                
+            }
         }
     },
 
     // private
-    onResize : function(w, h)
-    {
-        //Roo.log('resize: ' +w + ',' + h );
-        Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
-        if(this.el && this.iframe){
-            if(typeof w == 'number'){
-                var aw = w - this.wrap.getFrameWidth('lr');
-                this.el.setWidth(this.adjustWidth('textarea', aw));
-                this.iframe.style.width = aw + 'px';
-            }
-            if(typeof h == 'number'){
-                var tbh = 0;
-                for (var i =0; i < this.toolbars.length;i++) {
-                    // fixme - ask toolbars for heights?
-                    tbh += this.toolbars[i].tb.el.getHeight();
-                    if (this.toolbars[i].footer) {
-                        tbh += this.toolbars[i].footer.el.getHeight();
+    fixKeys : function(){ // load time branching for fastest keydown performance
+        if(Roo.isIE){
+            return function(e){
+                var k = e.getKey(), r;
+                if(k == e.TAB){
+                    e.stopEvent();
+                    r = this.doc.selection.createRange();
+                    if(r){
+                        r.collapse(true);
+                        r.pasteHTML('&#160;&#160;&#160;&#160;');
+                        this.deferFocus();
+                    }
+                    return;
+                }
+                
+                if(k == e.ENTER){
+                    r = this.doc.selection.createRange();
+                    if(r){
+                        var target = r.parentElement();
+                        if(!target || target.tagName.toLowerCase() != 'li'){
+                            e.stopEvent();
+                            r.pasteHTML('<br />');
+                            r.collapse(false);
+                            r.select();
+                        }
                     }
                 }
+                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
+                    this.cleanUpPaste.defer(100, this);
+                    return;
+                }
                 
                 
+            };
+        }else if(Roo.isOpera){
+            return function(e){
+                var k = e.getKey();
+                if(k == e.TAB){
+                    e.stopEvent();
+                    this.win.focus();
+                    this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
+                    this.deferFocus();
+                }
+                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
+                    this.cleanUpPaste.defer(100, this);
+                    return;
+                }
                 
+            };
+        }else if(Roo.isSafari){
+            return function(e){
+                var k = e.getKey();
                 
-                var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
-                ah -= 5; // knock a few pixes off for look..
-                this.el.setHeight(this.adjustWidth('textarea', ah));
-                this.iframe.style.height = ah + 'px';
-                if(this.doc){
-                    (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
+                if(k == e.TAB){
+                    e.stopEvent();
+                    this.execCmd('InsertText','\t');
+                    this.deferFocus();
+                    return;
                 }
-            }
+               if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
+                    this.cleanUpPaste.defer(100, this);
+                    return;
+                }
+                
+             };
+        }
+    }(),
+    
+    getAllAncestors: function()
+    {
+        var p = this.getSelectedNode();
+        var a = [];
+        if (!p) {
+            a.push(p); // push blank onto stack..
+            p = this.getParentElement();
         }
-    },
-
-    /**
-     * Toggles the editor between standard and source edit mode.
-     * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
-     */
-    toggleSourceEdit : function(sourceEditMode){
         
-        this.sourceEditMode = sourceEditMode === true;
         
-        if(this.sourceEditMode){
-//            Roo.log('in');
-//            Roo.log(this.syncValue());
-            this.syncValue();
-            this.iframe.className = 'x-hidden';
-            this.el.removeClass('x-hidden');
-            this.el.dom.removeAttribute('tabIndex');
-            this.el.focus();
-        }else{
-//            Roo.log('out')
-//            Roo.log(this.pushValue()); 
-            this.pushValue();
-            this.iframe.className = '';
-            this.el.addClass('x-hidden');
-            this.el.dom.setAttribute('tabIndex', -1);
-            this.deferFocus();
-        }
-        this.setSize(this.wrap.getSize());
-        this.fireEvent('editmodechange', this, this.sourceEditMode);
-    },
-
-    // private used internally
-    createLink : function(){
-        var url = prompt(this.createLinkText, this.defaultLinkValue);
-        if(url && url != 'http:/'+'/'){
-            this.relayCmd('createlink', url);
+        while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
+            a.push(p);
+            p = p.parentNode;
         }
+        a.push(this.doc.body);
+        return a;
     },
-
-    // private (for BoxComponent)
-    adjustSize : Roo.BoxComponent.prototype.adjustSize,
-
-    // private (for BoxComponent)
-    getResizeEl : function(){
-        return this.wrap;
-    },
-
-    // private (for BoxComponent)
-    getPositionEl : function(){
-        return this.wrap;
-    },
-
-    // private
-    initEvents : function(){
-        this.originalValue = this.getValue();
-    },
-
-    /**
-     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
-     * @method
-     */
-    markInvalid : Roo.emptyFn,
-    /**
-     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
-     * @method
-     */
-    clearInvalid : Roo.emptyFn,
-
-    setValue : function(v){
-        Roo.form.HtmlEditor.superclass.setValue.call(this, v);
-        this.pushValue();
+    lastSel : false,
+    lastSelNode : false,
+    
+    
+    getSelection : function() 
+    {
+        this.assignDocWin();
+        return Roo.isIE ? this.doc.selection : this.win.getSelection();
     },
-
-    /**
-     * Protected method that will not generally be called directly. If you need/want
-     * custom HTML cleanup, this is the method you should override.
-     * @param {String} html The HTML to be cleaned
-     * return {String} The cleaned HTML
-     */
-    cleanHtml : function(html){
-        html = String(html);
-        if(html.length > 5){
-            if(Roo.isSafari){ // strip safari nonsense
-                html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
+    
+    getSelectedNode: function() 
+    {
+        // this may only work on Gecko!!!
+        
+        // should we cache this!!!!
+        
+        
+        
+         
+        var range = this.createRange(this.getSelection()).cloneRange();
+        
+        if (Roo.isIE) {
+            var parent = range.parentElement();
+            while (true) {
+                var testRange = range.duplicate();
+                testRange.moveToElementText(parent);
+                if (testRange.inRange(range)) {
+                    break;
+                }
+                if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
+                    break;
+                }
+                parent = parent.parentElement;
             }
+            return parent;
         }
-        if(html == '&nbsp;'){
-            html = '';
+        
+        // is ancestor a text element.
+        var ac =  range.commonAncestorContainer;
+        if (ac.nodeType == 3) {
+            ac = ac.parentNode;
         }
-        return html;
-    },
-
-    /**
-     * Protected method that will not generally be called directly. Syncs the contents
-     * of the editor iframe with the textarea.
-     */
-    syncValue : function(){
-        if(this.initialized){
-            var bd = (this.doc.body || this.doc.documentElement);
-            //this.cleanUpPaste(); -- this is done else where and causes havoc..
-            var html = bd.innerHTML;
-            if(Roo.isSafari){
-                var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
-                var m = bs.match(/text-align:(.*?);/i);
-                if(m && m[1]){
-                    html = '<div style="'+m[0]+'">' + html + '</div>';
-                }
+        
+        var ar = ac.childNodes;
+         
+        var nodes = [];
+        var other_nodes = [];
+        var has_other_nodes = false;
+        for (var i=0;i<ar.length;i++) {
+            if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
+                continue;
             }
-            html = this.cleanHtml(html);
-            // fix up the special chars.. normaly like back quotes in word...
-            // however we do not want to do this with chinese..
-            html = html.replace(/([\x80-\uffff])/g, function (a, b) {
-                var cc = b.charCodeAt();
-                if (
-                    (cc >= 0x4E00 && cc < 0xA000 ) ||
-                    (cc >= 0x3400 && cc < 0x4E00 ) ||
-                    (cc >= 0xf900 && cc < 0xfb00 )
-                ) {
-                        return b;
-                }
-                return "&#"+cc+";" 
-            });
-            if(this.fireEvent('beforesync', this, html) !== false){
-                this.el.dom.value = html;
-                this.fireEvent('sync', this, html);
+            // fullly contained node.
+            
+            if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
+                nodes.push(ar[i]);
+                continue;
             }
-        }
-    },
-
-    /**
-     * Protected method that will not generally be called directly. Pushes the value of the textarea
-     * into the iframe editor.
-     */
-    pushValue : function(){
-        if(this.initialized){
-            var v = this.el.dom.value;
             
-            if(v.length < 1){
-                v = '&#160;';
+            // probably selected..
+            if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
+                other_nodes.push(ar[i]);
+                continue;
+            }
+            // outer..
+            if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
+                continue;
             }
             
-            if(this.fireEvent('beforepush', this, v) !== false){
-                var d = (this.doc.body || this.doc.documentElement);
-                d.innerHTML = v;
-                this.cleanUpPaste();
-                this.el.dom.value = d.innerHTML;
-                this.fireEvent('push', this, v);
+            
+            has_other_nodes = true;
+        }
+        if (!nodes.length && other_nodes.length) {
+            nodes= other_nodes;
+        }
+        if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
+            return false;
+        }
+        
+        return nodes[0];
+    },
+    createRange: function(sel)
+    {
+        // this has strange effects when using with 
+        // top toolbar - not sure if it's a great idea.
+        //this.editor.contentWindow.focus();
+        if (typeof sel != "undefined") {
+            try {
+                return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
+            } catch(e) {
+                return this.doc.createRange();
             }
+        } else {
+            return this.doc.createRange();
         }
     },
-
-    // private
-    deferFocus : function(){
-        this.focus.defer(10, this);
+    getParentElement: function()
+    {
+        
+        this.assignDocWin();
+        var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
+        
+        var range = this.createRange(sel);
+         
+        try {
+            var p = range.commonAncestorContainer;
+            while (p.nodeType == 3) { // text node
+                p = p.parentNode;
+            }
+            return p;
+        } catch (e) {
+            return null;
+        }
+    
+    },
+    /***
+     *
+     * Range intersection.. the hard stuff...
+     *  '-1' = before
+     *  '0' = hits..
+     *  '1' = after.
+     *         [ -- selected range --- ]
+     *   [fail]                        [fail]
+     *
+     *    basically..
+     *      if end is before start or  hits it. fail.
+     *      if start is after end or hits it fail.
+     *
+     *   if either hits (but other is outside. - then it's not 
+     *   
+     *    
+     **/
+    
+    
+    // @see http://www.thismuchiknow.co.uk/?p=64.
+    rangeIntersectsNode : function(range, node)
+    {
+        var nodeRange = node.ownerDocument.createRange();
+        try {
+            nodeRange.selectNode(node);
+        } catch (e) {
+            nodeRange.selectNodeContents(node);
+        }
+    
+        var rangeStartRange = range.cloneRange();
+        rangeStartRange.collapse(true);
+    
+        var rangeEndRange = range.cloneRange();
+        rangeEndRange.collapse(false);
+    
+        var nodeStartRange = nodeRange.cloneRange();
+        nodeStartRange.collapse(true);
+    
+        var nodeEndRange = nodeRange.cloneRange();
+        nodeEndRange.collapse(false);
+    
+        return rangeStartRange.compareBoundaryPoints(
+                 Range.START_TO_START, nodeEndRange) == -1 &&
+               rangeEndRange.compareBoundaryPoints(
+                 Range.START_TO_START, nodeStartRange) == 1;
+        
+         
+    },
+    rangeCompareNode : function(range, node)
+    {
+        var nodeRange = node.ownerDocument.createRange();
+        try {
+            nodeRange.selectNode(node);
+        } catch (e) {
+            nodeRange.selectNodeContents(node);
+        }
+        
+        
+        range.collapse(true);
+    
+        nodeRange.collapse(true);
+     
+        var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
+        var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
+         
+        //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
+        
+        var nodeIsBefore   =  ss == 1;
+        var nodeIsAfter    = ee == -1;
+        
+        if (nodeIsBefore && nodeIsAfter) {
+            return 0; // outer
+        }
+        if (!nodeIsBefore && nodeIsAfter) {
+            return 1; //right trailed.
+        }
+        
+        if (nodeIsBefore && !nodeIsAfter) {
+            return 2;  // left trailed.
+        }
+        // fully contined.
+        return 3;
     },
 
-    // doc'ed in Field
-    focus : function(){
-        if(this.win && !this.sourceEditMode){
-            this.win.focus();
-        }else{
-            this.el.focus();
+    // private? - in a new class?
+    cleanUpPaste :  function()
+    {
+        // cleans up the whole document..
+        Roo.log('cleanuppaste');
+        
+        this.cleanUpChildren(this.doc.body);
+        var clean = this.cleanWordChars(this.doc.body.innerHTML);
+        if (clean != this.doc.body.innerHTML) {
+            this.doc.body.innerHTML = clean;
+        }
+        
+    },
+    
+    cleanWordChars : function(input) {// change the chars to hex code
+        var he = Roo.HtmlEditorCore;
+        
+        var output = input;
+        Roo.each(he.swapCodes, function(sw) { 
+            var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
+            
+            output = output.replace(swapper, sw[1]);
+        });
+        
+        return output;
+    },
+    
+    
+    cleanUpChildren : function (n)
+    {
+        if (!n.childNodes.length) {
+            return;
+        }
+        for (var i = n.childNodes.length-1; i > -1 ; i--) {
+           this.cleanUpChild(n.childNodes[i]);
         }
     },
     
-    assignDocWin: function()
+    
+        
+    
+    cleanUpChild : function (node)
     {
-        var iframe = this.iframe;
+        var ed = this;
+        //console.log(node);
+        if (node.nodeName == "#text") {
+            // clean up silly Windows -- stuff?
+            return; 
+        }
+        if (node.nodeName == "#comment") {
+            node.parentNode.removeChild(node);
+            // clean up silly Windows -- stuff?
+            return; 
+        }
+        var lcname = node.tagName.toLowerCase();
+        // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
+        // whitelist of tags..
         
-         if(Roo.isIE){
-            this.doc = iframe.contentWindow.document;
-            this.win = iframe.contentWindow;
-        } else {
-            if (!Roo.get(this.frameId)) {
-                return;
-            }
-            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
-            this.win = Roo.get(this.frameId).dom.contentWindow;
+        if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
+            // remove node.
+            node.parentNode.removeChild(node);
+            return;
+            
         }
-    },
-    
-    // private
-    initEditor : function(){
-        //console.log("INIT EDITOR");
-        this.assignDocWin();
         
+        var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
         
+        // spans with no attributes - just remove them..
+        if ((!node.attributes || !node.attributes.length) && lcname == 'span') { 
+            remove_keep_children = true;
+        }
         
-        this.doc.designMode="on";
-        this.doc.open();
-        this.doc.write(this.getDocMarkup());
-        this.doc.close();
+        // remove <a name=....> as rendering on yahoo mailer is borked with this.
+        // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
         
-        var dbody = (this.doc.body || this.doc.documentElement);
-        //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
-        // this copies styles from the containing element into thsi one..
-        // not sure why we need all of this..
-        var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
-        ss['background-attachment'] = 'fixed'; // w3c
-        dbody.bgProperties = 'fixed'; // ie
-        Roo.DomHelper.applyStyles(dbody, ss);
-        Roo.EventManager.on(this.doc, {
-            //'mousedown': this.onEditorEvent,
-            'mouseup': this.onEditorEvent,
-            'dblclick': this.onEditorEvent,
-            'click': this.onEditorEvent,
-            'keyup': this.onEditorEvent,
-            buffer:100,
-            scope: this
-        });
-        if(Roo.isGecko){
-            Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
-        }
-        if(Roo.isIE || Roo.isSafari || Roo.isOpera){
-            Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
-        }
-        this.initialized = true;
-
-        this.fireEvent('initialize', this);
-        this.pushValue();
-    },
-
-    // private
-    onDestroy : function(){
+        //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
+        //    remove_keep_children = true;
+        //}
         
+        if (remove_keep_children) {
+            this.cleanUpChildren(node);
+            // inserts everything just before this node...
+            while (node.childNodes.length) {
+                var cn = node.childNodes[0];
+                node.removeChild(cn);
+                node.parentNode.insertBefore(cn, node);
+            }
+            node.parentNode.removeChild(node);
+            return;
+        }
         
+        if (!node.attributes || !node.attributes.length) {
+            
+          
+            
+            
+            this.cleanUpChildren(node);
+            return;
+        }
         
-        if(this.rendered){
+        function cleanAttr(n,v)
+        {
             
-            for (var i =0; i < this.toolbars.length;i++) {
-                // fixme - ask toolbars for heights?
-                this.toolbars[i].onDestroy();
+            if (v.match(/^\./) || v.match(/^\//)) {
+                return;
+            }
+            if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
+                return;
             }
+            if (v.match(/^#/)) {
+                return;
+            }
+//            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
+            node.removeAttribute(n);
             
-            this.wrap.dom.innerHTML = '';
-            this.wrap.remove();
         }
-    },
-
-    // private
-    onFirstFocus : function(){
-        
-        this.assignDocWin();
-        
         
-        this.activated = true;
-        for (var i =0; i < this.toolbars.length;i++) {
-            this.toolbars[i].onFirstFocus();
-        }
-       
-        if(Roo.isGecko){ // prevent silly gecko errors
-            this.win.focus();
-            var s = this.win.getSelection();
-            if(!s.focusNode || s.focusNode.nodeType != 3){
-                var r = s.getRangeAt(0);
-                r.selectNodeContents((this.doc.body || this.doc.documentElement));
-                r.collapse(true);
-                this.deferFocus();
+        var cwhite = this.cwhite;
+        var cblack = this.cblack;
+            
+        function cleanStyle(n,v)
+        {
+            if (v.match(/expression/)) { //XSS?? should we even bother..
+                node.removeAttribute(n);
+                return;
+            }
+            
+            var parts = v.split(/;/);
+            var clean = [];
+            
+            Roo.each(parts, function(p) {
+                p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
+                if (!p.length) {
+                    return true;
+                }
+                var l = p.split(':').shift().replace(/\s+/g,'');
+                l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
+                
+                if ( cwhite.length && cblack.indexOf(l) > -1) {
+//                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
+                    //node.removeAttribute(n);
+                    return true;
+                }
+                //Roo.log()
+                // only allow 'c whitelisted system attributes'
+                if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
+//                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
+                    //node.removeAttribute(n);
+                    return true;
+                }
+                
+                
+                 
+                
+                clean.push(p);
+                return true;
+            });
+            if (clean.length) { 
+                node.setAttribute(n, clean.join(';'));
+            } else {
+                node.removeAttribute(n);
             }
-            try{
-                this.execCmd('useCSS', true);
-                this.execCmd('styleWithCSS', false);
-            }catch(e){}
-        }
-        this.fireEvent('activate', this);
-    },
-
-    // private
-    adjustFont: function(btn){
-        var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
-        //if(Roo.isSafari){ // safari
-        //    adjust *= 2;
-       // }
-        var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
-        if(Roo.isSafari){ // safari
-            var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
-            v =  (v < 10) ? 10 : v;
-            v =  (v > 48) ? 48 : v;
-            v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
             
         }
         
         
-        v = Math.max(1, v+adjust);
-        
-        this.execCmd('FontSize', v  );
-    },
-
-    onEditorEvent : function(e){
-        this.fireEvent('editorevent', this, e);
-      //  this.updateToolbar();
-        this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
-    },
-
-    insertTag : function(tg)
-    {
-        // could be a bit smarter... -> wrap the current selected tRoo..
-        if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
+        for (var i = node.attributes.length-1; i > -1 ; i--) {
+            var a = node.attributes[i];
+            //console.log(a);
+            
+            if (a.name.toLowerCase().substr(0,2)=='on')  {
+                node.removeAttribute(a.name);
+                continue;
+            }
+            if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
+                node.removeAttribute(a.name);
+                continue;
+            }
+            if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
+                cleanAttr(a.name,a.value); // fixme..
+                continue;
+            }
+            if (a.name == 'style') {
+                cleanStyle(a.name,a.value);
+                continue;
+            }
+            /// clean up MS crap..
+            // tecnically this should be a list of valid class'es..
             
-            range = this.createRange(this.getSelection());
-            var wrappingNode = this.doc.createElement(tg.toLowerCase());
-            wrappingNode.appendChild(range.extractContents());
-            range.insertNode(wrappingNode);
-
-            return;
             
+            if (a.name == 'class') {
+                if (a.value.match(/^Mso/)) {
+                    node.removeAttribute('class');
+                }
+                
+                if (a.value.match(/^body$/)) {
+                    node.removeAttribute('class');
+                }
+                continue;
+            }
             
+            // style cleanup!?
+            // class cleanup?
             
         }
-        this.execCmd("formatblock",   tg);
         
-    },
-    
-    insertText : function(txt)
-    {
+        
+        this.cleanUpChildren(node);
         
         
-        var range = this.createRange();
-        range.deleteContents();
-               //alert(Sender.getAttribute('label'));
-               
-        range.insertNode(this.doc.createTextNode(txt));
-    } ,
-    
-    // private
-    relayBtnCmd : function(btn){
-        this.relayCmd(btn.cmd);
-    },
-
-    /**
-     * Executes a Midas editor command on the editor document and performs necessary focus and
-     * toolbar updates. <b>This should only be called after the editor is initialized.</b>
-     * @param {String} cmd The Midas command
-     * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
-     */
-    relayCmd : function(cmd, value){
-        this.win.focus();
-        this.execCmd(cmd, value);
-        this.fireEvent('editorevent', this);
-        //this.updateToolbar();
-        this.deferFocus();
-    },
-
-    /**
-     * Executes a Midas editor command directly on the editor document.
-     * For visual commands, you should use {@link #relayCmd} instead.
-     * <b>This should only be called after the editor is initialized.</b>
-     * @param {String} cmd The Midas command
-     * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
-     */
-    execCmd : function(cmd, value){
-        this.doc.execCommand(cmd, false, value === undefined ? null : value);
-        this.syncValue();
     },
-   
+    
     /**
-     * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
-     * to insert tRoo.
-     * @param {String} text | dom node.. 
+     * Clean up MS wordisms...
      */
-    insertAtCursor : function(text)
+    cleanWord : function(node)
     {
+        if (!node) {
+            this.cleanWord(this.doc.body);
+            return;
+        }
         
+        if(
+                node.nodeName == 'SPAN' &&
+                !node.hasAttributes() &&
+                node.childNodes.length == 1 &&
+                node.firstChild.nodeName == "#text"  
+        ) {
+            var textNode = node.firstChild;
+            node.removeChild(textNode);
+            if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
+                node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
+            }
+            node.parentNode.insertBefore(textNode, node);
+            if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
+                node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
+            }
+            node.parentNode.removeChild(node);
+        }
         
+        if (node.nodeName == "#text") {
+            // clean up silly Windows -- stuff?
+            return; 
+        }
+        if (node.nodeName == "#comment") {
+            node.parentNode.removeChild(node);
+            // clean up silly Windows -- stuff?
+            return; 
+        }
         
-        if(!this.activated){
+        if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
+            node.parentNode.removeChild(node);
             return;
         }
-        /*
-        if(Roo.isIE){
-            this.win.focus();
-            var r = this.doc.selection.createRange();
-            if(r){
-                r.collapse(true);
-                r.pasteHTML(text);
-                this.syncValue();
-                this.deferFocus();
-            
+        //Roo.log(node.tagName);
+        // remove - but keep children..
+        if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
+            //Roo.log('-- removed');
+            while (node.childNodes.length) {
+                var cn = node.childNodes[0];
+                node.removeChild(cn);
+                node.parentNode.insertBefore(cn, node);
+                // move node to parent - and clean it..
+                this.cleanWord(cn);
             }
+            node.parentNode.removeChild(node);
+            /// no need to iterate chidlren = it's got none..
+            //this.iterateChildren(node, this.cleanWord);
             return;
         }
-        */
-        if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
-            this.win.focus();
-            
+        // clean styles
+        if (node.className.length) {
             
-            // from jquery ui (MIT licenced)
-            var range, node;
-            var win = this.win;
-            
-            if (win.getSelection && win.getSelection().getRangeAt) {
-                range = win.getSelection().getRangeAt(0);
-                node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
-                range.insertNode(node);
-            } else if (win.document.selection && win.document.selection.createRange) {
-                // no firefox support
-                var txt = typeof(text) == 'string' ? text : text.outerHTML;
-                win.document.selection.createRange().pasteHTML(txt);
-            } else {
-                // no firefox support
-                var txt = typeof(text) == 'string' ? text : text.outerHTML;
-                this.execCmd('InsertHTML', txt);
-            } 
-            
-            this.syncValue();
-            
-            this.deferFocus();
+            var cn = node.className.split(/\W+/);
+            var cna = [];
+            Roo.each(cn, function(cls) {
+                if (cls.match(/Mso[a-zA-Z]+/)) {
+                    return;
+                }
+                cna.push(cls);
+            });
+            node.className = cna.length ? cna.join(' ') : '';
+            if (!cna.length) {
+                node.removeAttribute("class");
+            }
         }
-    },
- // private
-    mozKeyPress : function(e){
-        if(e.ctrlKey){
-            var c = e.getCharCode(), cmd;
-          
-            if(c > 0){
-                c = String.fromCharCode(c).toLowerCase();
-                switch(c){
-                    case 'b':
-                        cmd = 'bold';
-                        break;
-                    case 'i':
-                        cmd = 'italic';
-                        break;
-                    
-                    case 'u':
-                        cmd = 'underline';
-                        break;
-                    
-                    case 'v':
-                        this.cleanUpPaste.defer(100, this);
-                        return;
-                        
+        
+        if (node.hasAttribute("lang")) {
+            node.removeAttribute("lang");
+        }
+        
+        if (node.hasAttribute("style")) {
+            
+            var styles = node.getAttribute("style").split(";");
+            var nstyle = [];
+            Roo.each(styles, function(s) {
+                if (!s.match(/:/)) {
+                    return;
                 }
-                if(cmd){
-                    this.win.focus();
-                    this.execCmd(cmd);
-                    this.deferFocus();
-                    e.preventDefault();
+                var kv = s.split(":");
+                if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
+                    return;
                 }
-                
+                // what ever is left... we allow.
+                nstyle.push(s);
+            });
+            node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
+            if (!nstyle.length) {
+                node.removeAttribute('style');
             }
         }
+        this.iterateChildren(node, this.cleanWord);
+        
+        
+        
+    },
+    /**
+     * iterateChildren of a Node, calling fn each time, using this as the scole..
+     * @param {DomNode} node node to iterate children of.
+     * @param {Function} fn method of this class to call on each item.
+     */
+    iterateChildren : function(node, fn)
+    {
+        if (!node.childNodes.length) {
+                return;
+        }
+        for (var i = node.childNodes.length-1; i > -1 ; i--) {
+           fn.call(this, node.childNodes[i])
+        }
     },
-
-    // private
-    fixKeys : function(){ // load time branching for fastest keydown performance
-        if(Roo.isIE){
-            return function(e){
-                var k = e.getKey(), r;
-                if(k == e.TAB){
-                    e.stopEvent();
-                    r = this.doc.selection.createRange();
-                    if(r){
-                        r.collapse(true);
-                        r.pasteHTML('&#160;&#160;&#160;&#160;');
-                        this.deferFocus();
-                    }
+    
+    
+    /**
+     * cleanTableWidths.
+     *
+     * Quite often pasting from word etc.. results in tables with column and widths.
+     * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
+     *
+     */
+    cleanTableWidths : function(node)
+    {
+         
+         
+        if (!node) {
+            this.cleanTableWidths(this.doc.body);
+            return;
+        }
+        
+        // ignore list...
+        if (node.nodeName == "#text" || node.nodeName == "#comment") {
+            return; 
+        }
+        Roo.log(node.tagName);
+        if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
+            this.iterateChildren(node, this.cleanTableWidths);
+            return;
+        }
+        if (node.hasAttribute('width')) {
+            node.removeAttribute('width');
+        }
+        
+         
+        if (node.hasAttribute("style")) {
+            // pretty basic...
+            
+            var styles = node.getAttribute("style").split(";");
+            var nstyle = [];
+            Roo.each(styles, function(s) {
+                if (!s.match(/:/)) {
                     return;
                 }
-                
-                if(k == e.ENTER){
-                    r = this.doc.selection.createRange();
-                    if(r){
-                        var target = r.parentElement();
-                        if(!target || target.tagName.toLowerCase() != 'li'){
-                            e.stopEvent();
-                            r.pasteHTML('<br />');
-                            r.collapse(false);
-                            r.select();
-                        }
-                    }
-                }
-                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
-                    this.cleanUpPaste.defer(100, this);
+                var kv = s.split(":");
+                if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
                     return;
                 }
-                
-                
-            };
-        }else if(Roo.isOpera){
-            return function(e){
-                var k = e.getKey();
-                if(k == e.TAB){
-                    e.stopEvent();
-                    this.win.focus();
-                    this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
-                    this.deferFocus();
-                }
-                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
-                    this.cleanUpPaste.defer(100, this);
-                    return;
+                // what ever is left... we allow.
+                nstyle.push(s);
+            });
+            node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
+            if (!nstyle.length) {
+                node.removeAttribute('style');
+            }
+        }
+        
+        this.iterateChildren(node, this.cleanTableWidths);
+        
+        
+    },
+    
+    
+    
+    
+    domToHTML : function(currentElement, depth, nopadtext) {
+        
+        depth = depth || 0;
+        nopadtext = nopadtext || false;
+    
+        if (!currentElement) {
+            return this.domToHTML(this.doc.body);
+        }
+        
+        //Roo.log(currentElement);
+        var j;
+        var allText = false;
+        var nodeName = currentElement.nodeName;
+        var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
+        
+        if  (nodeName == '#text') {
+            
+            return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
+        }
+        
+        
+        var ret = '';
+        if (nodeName != 'BODY') {
+             
+            var i = 0;
+            // Prints the node tagName, such as <A>, <IMG>, etc
+            if (tagName) {
+                var attr = [];
+                for(i = 0; i < currentElement.attributes.length;i++) {
+                    // quoting?
+                    var aname = currentElement.attributes.item(i).name;
+                    if (!currentElement.attributes.item(i).value.length) {
+                        continue;
+                    }
+                    attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
                 }
                 
-            };
-        }else if(Roo.isSafari){
-            return function(e){
-                var k = e.getKey();
+                ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
+            } 
+            else {
                 
-                if(k == e.TAB){
-                    e.stopEvent();
-                    this.execCmd('InsertText','\t');
-                    this.deferFocus();
-                    return;
-                }
-               if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
-                    this.cleanUpPaste.defer(100, this);
-                    return;
+                // eack
+            }
+        } else {
+            tagName = false;
+        }
+        if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
+            return ret;
+        }
+        if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
+            nopadtext = true;
+        }
+        
+        
+        // Traverse the tree
+        i = 0;
+        var currentElementChild = currentElement.childNodes.item(i);
+        var allText = true;
+        var innerHTML  = '';
+        lastnode = '';
+        while (currentElementChild) {
+            // Formatting code (indent the tree so it looks nice on the screen)
+            var nopad = nopadtext;
+            if (lastnode == 'SPAN') {
+                nopad  = true;
+            }
+            // text
+            if  (currentElementChild.nodeName == '#text') {
+                var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
+                toadd = nopadtext ? toadd : toadd.trim();
+                if (!nopad && toadd.length > 80) {
+                    innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
                 }
+                innerHTML  += toadd;
                 
-             };
+                i++;
+                currentElementChild = currentElement.childNodes.item(i);
+                lastNode = '';
+                continue;
+            }
+            allText = false;
+            
+            innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
+                
+            // Recursively traverse the tree structure of the child node
+            innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
+            lastnode = currentElementChild.nodeName;
+            i++;
+            currentElementChild=currentElement.childNodes.item(i);
         }
-    }(),
-    
-    getAllAncestors: function()
-    {
-        var p = this.getSelectedNode();
-        var a = [];
-        if (!p) {
-            a.push(p); // push blank onto stack..
-            p = this.getParentElement();
+        
+        ret += innerHTML;
+        
+        if (!allText) {
+                // The remaining code is mostly for formatting the tree
+            ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
         }
         
         
-        while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
-            a.push(p);
-            p = p.parentNode;
+        if (tagName) {
+            ret+= "</"+tagName+">";
         }
-        a.push(this.doc.body);
-        return a;
-    },
-    lastSel : false,
-    lastSelNode : false,
-    
-    
-    getSelection : function() 
-    {
-        this.assignDocWin();
-        return Roo.isIE ? this.doc.selection : this.win.getSelection();
+        return ret;
+        
     },
-    
-    getSelectedNode: function() 
+        
+    applyBlacklists : function()
     {
-        // this may only work on Gecko!!!
+        var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
+        var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
         
-        // should we cache this!!!!
+        this.white = [];
+        this.black = [];
+        Roo.each(Roo.HtmlEditorCore.white, function(tag) {
+            if (b.indexOf(tag) > -1) {
+                return;
+            }
+            this.white.push(tag);
+            
+        }, this);
         
+        Roo.each(w, function(tag) {
+            if (b.indexOf(tag) > -1) {
+                return;
+            }
+            if (this.white.indexOf(tag) > -1) {
+                return;
+            }
+            this.white.push(tag);
+            
+        }, this);
         
         
-         
-        var range = this.createRange(this.getSelection()).cloneRange();
+        Roo.each(Roo.HtmlEditorCore.black, function(tag) {
+            if (w.indexOf(tag) > -1) {
+                return;
+            }
+            this.black.push(tag);
+            
+        }, this);
         
-        if (Roo.isIE) {
-            var parent = range.parentElement();
-            while (true) {
-                var testRange = range.duplicate();
-                testRange.moveToElementText(parent);
-                if (testRange.inRange(range)) {
-                    break;
-                }
-                if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
-                    break;
-                }
-                parent = parent.parentElement;
+        Roo.each(b, function(tag) {
+            if (w.indexOf(tag) > -1) {
+                return;
             }
-            return parent;
-        }
+            if (this.black.indexOf(tag) > -1) {
+                return;
+            }
+            this.black.push(tag);
+            
+        }, this);
         
-        // is ancestor a text element.
-        var ac =  range.commonAncestorContainer;
-        if (ac.nodeType == 3) {
-            ac = ac.parentNode;
-        }
         
-        var ar = ac.childNodes;
-         
-        var nodes = [];
-        var other_nodes = [];
-        var has_other_nodes = false;
-        for (var i=0;i<ar.length;i++) {
-            if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
-                continue;
+        w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
+        b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
+        
+        this.cwhite = [];
+        this.cblack = [];
+        Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
+            if (b.indexOf(tag) > -1) {
+                return;
             }
-            // fullly contained node.
+            this.cwhite.push(tag);
             
-            if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
-                nodes.push(ar[i]);
-                continue;
+        }, this);
+        
+        Roo.each(w, function(tag) {
+            if (b.indexOf(tag) > -1) {
+                return;
             }
+            if (this.cwhite.indexOf(tag) > -1) {
+                return;
+            }
+            this.cwhite.push(tag);
             
-            // probably selected..
-            if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
-                other_nodes.push(ar[i]);
-                continue;
+        }, this);
+        
+        
+        Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
+            if (w.indexOf(tag) > -1) {
+                return;
             }
-            // outer..
-            if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
-                continue;
+            this.cblack.push(tag);
+            
+        }, this);
+        
+        Roo.each(b, function(tag) {
+            if (w.indexOf(tag) > -1) {
+                return;
+            }
+            if (this.cblack.indexOf(tag) > -1) {
+                return;
             }
+            this.cblack.push(tag);
             
+        }, this);
+    },
+    
+    setStylesheets : function(stylesheets)
+    {
+        if(typeof(stylesheets) == 'string'){
+            Roo.get(this.iframe.contentDocument.head).createChild({
+                tag : 'link',
+                rel : 'stylesheet',
+                type : 'text/css',
+                href : stylesheets
+            });
             
-            has_other_nodes = true;
-        }
-        if (!nodes.length && other_nodes.length) {
-            nodes= other_nodes;
-        }
-        if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
-            return false;
+            return;
         }
+        var _this = this;
+     
+        Roo.each(stylesheets, function(s) {
+            if(!s.length){
+                return;
+            }
+            
+            Roo.get(_this.iframe.contentDocument.head).createChild({
+                tag : 'link',
+                rel : 'stylesheet',
+                type : 'text/css',
+                href : s
+            });
+        });
+
         
-        return nodes[0];
     },
-    createRange: function(sel)
+    
+    removeStylesheets : function()
     {
-        // this has strange effects when using with 
-        // top toolbar - not sure if it's a great idea.
-        //this.editor.contentWindow.focus();
-        if (typeof sel != "undefined") {
-            try {
-                return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
-            } catch(e) {
-                return this.doc.createRange();
-            }
-        } else {
-            return this.doc.createRange();
-        }
+        var _this = this;
+        
+        Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
+            s.remove();
+        });
     },
-    getParentElement: function()
+    
+    setStyle : function(style)
     {
+        Roo.get(this.iframe.contentDocument.head).createChild({
+            tag : 'style',
+            type : 'text/css',
+            html : style
+        });
+
+        return;
+    }
+    
+    // hide stuff that is not compatible
+    /**
+     * @event blur
+     * @hide
+     */
+    /**
+     * @event change
+     * @hide
+     */
+    /**
+     * @event focus
+     * @hide
+     */
+    /**
+     * @event specialkey
+     * @hide
+     */
+    /**
+     * @cfg {String} fieldClass @hide
+     */
+    /**
+     * @cfg {String} focusClass @hide
+     */
+    /**
+     * @cfg {String} autoCreate @hide
+     */
+    /**
+     * @cfg {String} inputType @hide
+     */
+    /**
+     * @cfg {String} invalidClass @hide
+     */
+    /**
+     * @cfg {String} invalidText @hide
+     */
+    /**
+     * @cfg {String} msgFx @hide
+     */
+    /**
+     * @cfg {String} validateOnBlur @hide
+     */
+});
+
+Roo.HtmlEditorCore.white = [
+        'area', 'br', 'img', 'input', 'hr', 'wbr',
         
-        this.assignDocWin();
-        var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
-        
-        var range = this.createRange(sel);
+       'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
+       'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
+       'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
+       'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
+       'table',   'ul',         'xmp', 
+       
+       'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
+      'thead',   'tr', 
+     
+      'dir', 'menu', 'ol', 'ul', 'dl',
+       
+      'embed',  'object'
+];
+
+
+Roo.HtmlEditorCore.black = [
+    //    'embed',  'object', // enable - backend responsiblity to clean thiese
+        'applet', // 
+        'base',   'basefont', 'bgsound', 'blink',  'body', 
+        'frame',  'frameset', 'head',    'html',   'ilayer', 
+        'iframe', 'layer',  'link',     'meta',    'object',   
+        'script', 'style' ,'title',  'xml' // clean later..
+];
+Roo.HtmlEditorCore.clean = [
+    'script', 'style', 'title', 'xml'
+];
+Roo.HtmlEditorCore.remove = [
+    'font'
+];
+// attributes..
+
+Roo.HtmlEditorCore.ablack = [
+    'on'
+];
+    
+Roo.HtmlEditorCore.aclean = [ 
+    'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
+];
+
+// protocols..
+Roo.HtmlEditorCore.pwhite= [
+        'http',  'https',  'mailto'
+];
+
+// white listed style attributes.
+Roo.HtmlEditorCore.cwhite= [
+      //  'text-align', /// default is to allow most things..
+      
          
-        try {
-            var p = range.commonAncestorContainer;
-            while (p.nodeType == 3) { // text node
-                p = p.parentNode;
-            }
-            return p;
-        } catch (e) {
-            return null;
-        }
+//        'font-size'//??
+];
+
+// black listed style attributes.
+Roo.HtmlEditorCore.cblack= [
+      //  'font-size' -- this can be set by the project 
+];
+
+
+Roo.HtmlEditorCore.swapCodes   =[ 
+    [    8211, "--" ], 
+    [    8212, "--" ], 
+    [    8216,  "'" ],  
+    [    8217, "'" ],  
+    [    8220, '"' ],  
+    [    8221, '"' ],  
+    [    8226, "*" ],  
+    [    8230, "..." ]
+]; 
+
+    //<script type="text/javascript">
+
+/*
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ * Licence LGPL
+ * 
+ */
+Roo.form.HtmlEditor = function(config){
     
-    },
-    /***
-     *
-     * Range intersection.. the hard stuff...
-     *  '-1' = before
-     *  '0' = hits..
-     *  '1' = after.
-     *         [ -- selected range --- ]
-     *   [fail]                        [fail]
-     *
-     *    basically..
-     *      if end is before start or  hits it. fail.
-     *      if start is after end or hits it fail.
-     *
-     *   if either hits (but other is outside. - then it's not 
-     *   
-     *    
-     **/
     
     
-    // @see http://www.thismuchiknow.co.uk/?p=64.
-    rangeIntersectsNode : function(range, node)
-    {
-        var nodeRange = node.ownerDocument.createRange();
-        try {
-            nodeRange.selectNode(node);
-        } catch (e) {
-            nodeRange.selectNodeContents(node);
-        }
+    Roo.form.HtmlEditor.superclass.constructor.call(this, config);
     
-        var rangeStartRange = range.cloneRange();
-        rangeStartRange.collapse(true);
+    if (!this.toolbars) {
+        this.toolbars = [];
+    }
+    this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
     
-        var rangeEndRange = range.cloneRange();
-        rangeEndRange.collapse(false);
     
-        var nodeStartRange = nodeRange.cloneRange();
-        nodeStartRange.collapse(true);
+};
+
+/**
+ * @class Roo.form.HtmlEditor
+ * @extends Roo.form.Field
+ * Provides a lightweight HTML Editor component.
+ *
+ * This has been tested on Fireforx / Chrome.. IE may not be so great..
+ * 
+ * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
+ * supported by this editor.</b><br/><br/>
+ * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
+ * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
+ */
+Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
+    /**
+     * @cfg {Boolean} clearUp
+     */
+    clearUp : true,
+      /**
+     * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
+     */
+    toolbars : false,
+   
+     /**
+     * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
+     *                        Roo.resizable.
+     */
+    resizable : false,
+     /**
+     * @cfg {Number} height (in pixels)
+     */   
+    height: 300,
+   /**
+     * @cfg {Number} width (in pixels)
+     */   
+    width: 500,
     
-        var nodeEndRange = nodeRange.cloneRange();
-        nodeEndRange.collapse(false);
+    /**
+     * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
+     * 
+     */
+    stylesheets: false,
     
-        return rangeStartRange.compareBoundaryPoints(
-                 Range.START_TO_START, nodeEndRange) == -1 &&
-               rangeEndRange.compareBoundaryPoints(
-                 Range.START_TO_START, nodeStartRange) == 1;
-        
-         
-    },
-    rangeCompareNode : function(range, node)
-    {
-        var nodeRange = node.ownerDocument.createRange();
-        try {
-            nodeRange.selectNode(node);
-        } catch (e) {
-            nodeRange.selectNodeContents(node);
-        }
-        
-        
-        range.collapse(true);
     
-        nodeRange.collapse(true);
-     
-        var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
-        var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
-         
-        //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
-        
-        var nodeIsBefore   =  ss == 1;
-        var nodeIsAfter    = ee == -1;
-        
-        if (nodeIsBefore && nodeIsAfter)
-            return 0; // outer
-        if (!nodeIsBefore && nodeIsAfter)
-            return 1; //right trailed.
-        
-        if (nodeIsBefore && !nodeIsAfter)
-            return 2;  // left trailed.
-        // fully contined.
-        return 3;
-    },
-
-    // private? - in a new class?
-    cleanUpPaste :  function()
-    {
-        // cleans up the whole document..
-         Roo.log('cleanuppaste');
-        this.cleanUpChildren(this.doc.body);
-        var clean = this.cleanWordChars(this.doc.body.innerHTML);
-        if (clean != this.doc.body.innerHTML) {
-            this.doc.body.innerHTML = clean;
-        }
-        
-    },
+     /**
+     * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
+     * 
+     */
+    cblack: false,
+    /**
+     * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
+     * 
+     */
+    cwhite: false,
     
-    cleanWordChars : function(input) {// change the chars to hex code
-        var he = Roo.form.HtmlEditor;
-        
-        var output = input;
-        Roo.each(he.swapCodes, function(sw) { 
-            var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
-            
-            output = output.replace(swapper, sw[1]);
-        });
-        
-        return output;
-    },
+     /**
+     * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
+     * 
+     */
+    black: false,
+    /**
+     * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
+     * 
+     */
+    white: false,
     
+    // id of frame..
+    frameId: false,
     
-    cleanUpChildren : function (n)
-    {
-        if (!n.childNodes.length) {
-            return;
-        }
-        for (var i = n.childNodes.length-1; i > -1 ; i--) {
-           this.cleanUpChild(n.childNodes[i]);
-        }
-    },
+    // private properties
+    validationEvent : false,
+    deferHeight: true,
+    initialized : false,
+    activated : false,
     
+    onFocus : Roo.emptyFn,
+    iframePad:3,
+    hideMode:'offsets',
     
-        
+    actionMode : 'container', // defaults to hiding it...
     
-    cleanUpChild : function (node)
-    {
-        var ed = this;
-        //console.log(node);
-        if (node.nodeName == "#text") {
-            // clean up silly Windows -- stuff?
-            return; 
-        }
-        if (node.nodeName == "#comment") {
-            node.parentNode.removeChild(node);
-            // clean up silly Windows -- stuff?
-            return; 
-        }
-        
-        if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
-            // remove node.
-            node.parentNode.removeChild(node);
-            return;
+    defaultAutoCreate : { // modified by initCompnoent..
+        tag: "textarea",
+        style:"width:500px;height:300px;",
+        autocomplete: "new-password"
+    },
+
+    // private
+    initComponent : function(){
+        this.addEvents({
+            /**
+             * @event initialize
+             * Fires when the editor is fully initialized (including the iframe)
+             * @param {HtmlEditor} this
+             */
+            initialize: true,
+            /**
+             * @event activate
+             * Fires when the editor is first receives the focus. Any insertion must wait
+             * until after this event.
+             * @param {HtmlEditor} this
+             */
+            activate: true,
+             /**
+             * @event beforesync
+             * Fires before the textarea is updated with content from the editor iframe. Return false
+             * to cancel the sync.
+             * @param {HtmlEditor} this
+             * @param {String} html
+             */
+            beforesync: true,
+             /**
+             * @event beforepush
+             * Fires before the iframe editor is updated with content from the textarea. Return false
+             * to cancel the push.
+             * @param {HtmlEditor} this
+             * @param {String} html
+             */
+            beforepush: true,
+             /**
+             * @event sync
+             * Fires when the textarea is updated with content from the editor iframe.
+             * @param {HtmlEditor} this
+             * @param {String} html
+             */
+            sync: true,
+             /**
+             * @event push
+             * Fires when the iframe editor is updated with content from the textarea.
+             * @param {HtmlEditor} this
+             * @param {String} html
+             */
+            push: true,
+             /**
+             * @event editmodechange
+             * Fires when the editor switches edit modes
+             * @param {HtmlEditor} this
+             * @param {Boolean} sourceEdit True if source edit, false if standard editing.
+             */
+            editmodechange: true,
+            /**
+             * @event editorevent
+             * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
+             * @param {HtmlEditor} this
+             */
+            editorevent: true,
+            /**
+             * @event firstfocus
+             * Fires when on first focus - needed by toolbars..
+             * @param {HtmlEditor} this
+             */
+            firstfocus: true,
+            /**
+             * @event autosave
+             * Auto save the htmlEditor value as a file into Events
+             * @param {HtmlEditor} this
+             */
+            autosave: true,
+            /**
+             * @event savedpreview
+             * preview the saved version of htmlEditor
+             * @param {HtmlEditor} this
+             */
+            savedpreview: true,
             
+            /**
+            * @event stylesheetsclick
+            * Fires when press the Sytlesheets button
+            * @param {Roo.HtmlEditorCore} this
+            */
+            stylesheetsclick: true
+        });
+        this.defaultAutoCreate =  {
+            tag: "textarea",
+            style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
+            autocomplete: "new-password"
+        };
+    },
+
+    /**
+     * Protected method that will not generally be called directly. It
+     * is called when the editor creates its toolbar. Override this method if you need to
+     * add custom toolbar buttons.
+     * @param {HtmlEditor} editor
+     */
+    createToolbar : function(editor){
+        Roo.log("create toolbars");
+        if (!editor.toolbars || !editor.toolbars.length) {
+            editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
         }
         
-        var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
+        for (var i =0 ; i < editor.toolbars.length;i++) {
+            editor.toolbars[i] = Roo.factory(
+                    typeof(editor.toolbars[i]) == 'string' ?
+                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
+                Roo.form.HtmlEditor);
+            editor.toolbars[i].init(editor);
+        }
+         
         
-        // remove <a name=....> as rendering on yahoo mailer is borked with this.
-        // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
+    },
+
+     
+    // private
+    onRender : function(ct, position)
+    {
+        var _t = this;
+        Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
         
-        //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
-        //    remove_keep_children = true;
-        //}
+        this.wrap = this.el.wrap({
+            cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
+        });
         
-        if (remove_keep_children) {
-            this.cleanUpChildren(node);
-            // inserts everything just before this node...
-            while (node.childNodes.length) {
-                var cn = node.childNodes[0];
-                node.removeChild(cn);
-                node.parentNode.insertBefore(cn, node);
-            }
-            node.parentNode.removeChild(node);
-            return;
+        this.editorcore.onRender(ct, position);
+         
+        if (this.resizable) {
+            this.resizeEl = new Roo.Resizable(this.wrap, {
+                pinned : true,
+                wrap: true,
+                dynamic : true,
+                minHeight : this.height,
+                height: this.height,
+                handles : this.resizable,
+                width: this.width,
+                listeners : {
+                    resize : function(r, w, h) {
+                        _t.onResize(w,h); // -something
+                    }
+                }
+            });
+            
         }
+        this.createToolbar(this);
+       
         
-        if (!node.attributes || !node.attributes.length) {
-            this.cleanUpChildren(node);
-            return;
+        if(!this.width){
+            this.setSize(this.wrap.getSize());
         }
-        
-        function cleanAttr(n,v)
-        {
-            
-            if (v.match(/^\./) || v.match(/^\//)) {
-                return;
-            }
-            if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
-                return;
-            }
-            if (v.match(/^#/)) {
-                return;
-            }
-//            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
-            node.removeAttribute(n);
-            
+        if (this.resizeEl) {
+            this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
+            // should trigger onReize..
         }
         
-        function cleanStyle(n,v)
-        {
-            if (v.match(/expression/)) { //XSS?? should we even bother..
-                node.removeAttribute(n);
-                return;
-            }
-            var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.form.HtmlEditor.cwhite : ed.cwhite;
-            var cblack = typeof(ed.cblack) == 'undefined' ? Roo.form.HtmlEditor.cblack : ed.cblack;
+        this.keyNav = new Roo.KeyNav(this.el, {
             
+            "tab" : function(e){
+                e.preventDefault();
+                
+                var value = this.getValue();
+                
+                var start = this.el.dom.selectionStart;
+                var end = this.el.dom.selectionEnd;
+                
+                if(!e.shiftKey){
+                    
+                    this.setValue(value.substring(0, start) + "\t" + value.substring(end));
+                    this.el.dom.setSelectionRange(end + 1, end + 1);
+                    return;
+                }
+                
+                var f = value.substring(0, start).split("\t");
+                
+                if(f.pop().length != 0){
+                    return;
+                }
+                
+                this.setValue(f.join("\t") + value.substring(end));
+                this.el.dom.setSelectionRange(start - 1, start - 1);
+                
+            },
             
-            var parts = v.split(/;/);
-            var clean = [];
+            "home" : function(e){
+                e.preventDefault();
+                
+                var curr = this.el.dom.selectionStart;
+                var lines = this.getValue().split("\n");
+                
+                if(!lines.length){
+                    return;
+                }
+                
+                if(e.ctrlKey){
+                    this.el.dom.setSelectionRange(0, 0);
+                    return;
+                }
+                
+                var pos = 0;
+                
+                for (var i = 0; i < lines.length;i++) {
+                    pos += lines[i].length;
+                    
+                    if(i != 0){
+                        pos += 1;
+                    }
+                    
+                    if(pos < curr){
+                        continue;
+                    }
+                    
+                    pos -= lines[i].length;
+                    
+                    break;
+                }
+                
+                if(!e.shiftKey){
+                    this.el.dom.setSelectionRange(pos, pos);
+                    return;
+                }
+                
+                this.el.dom.selectionStart = pos;
+                this.el.dom.selectionEnd = curr;
+            },
             
-            Roo.each(parts, function(p) {
-                p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
-                if (!p.length) {
-                    return true;
+            "end" : function(e){
+                e.preventDefault();
+                
+                var curr = this.el.dom.selectionStart;
+                var lines = this.getValue().split("\n");
+                
+                if(!lines.length){
+                    return;
                 }
-                var l = p.split(':').shift().replace(/\s+/g,'');
-                l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
                 
+                if(e.ctrlKey){
+                    this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
+                    return;
+                }
                 
-                if ( cblack.indexOf(l) > -1) {
-//                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
-                    //node.removeAttribute(n);
-                    return true;
+                var pos = 0;
+                
+                for (var i = 0; i < lines.length;i++) {
+                    
+                    pos += lines[i].length;
+                    
+                    if(i != 0){
+                        pos += 1;
+                    }
+                    
+                    if(pos < curr){
+                        continue;
+                    }
+                    
+                    break;
                 }
-                //Roo.log()
-                // only allow 'c whitelisted system attributes'
-                if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
-//                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
-                    //node.removeAttribute(n);
-                    return true;
+                
+                if(!e.shiftKey){
+                    this.el.dom.setSelectionRange(pos, pos);
+                    return;
+                }
+                
+                this.el.dom.selectionStart = curr;
+                this.el.dom.selectionEnd = pos;
+            },
+
+            scope : this,
+
+            doRelay : function(foo, bar, hname){
+                return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
+            },
+
+            forceKeyDown: true
+        });
+        
+//        if(this.autosave && this.w){
+//            this.autoSaveFn = setInterval(this.autosave, 1000);
+//        }
+    },
+
+    // private
+    onResize : function(w, h)
+    {
+        Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
+        var ew = false;
+        var eh = false;
+        
+        if(this.el ){
+            if(typeof w == 'number'){
+                var aw = w - this.wrap.getFrameWidth('lr');
+                this.el.setWidth(this.adjustWidth('textarea', aw));
+                ew = aw;
+            }
+            if(typeof h == 'number'){
+                var tbh = 0;
+                for (var i =0; i < this.toolbars.length;i++) {
+                    // fixme - ask toolbars for heights?
+                    tbh += this.toolbars[i].tb.el.getHeight();
+                    if (this.toolbars[i].footer) {
+                        tbh += this.toolbars[i].footer.el.getHeight();
+                    }
                 }
                 
                 
-                 
                 
-                clean.push(p);
-                return true;
-            });
-            if (clean.length) { 
-                node.setAttribute(n, clean.join(';'));
-            } else {
-                node.removeAttribute(n);
+                
+                var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
+                ah -= 5; // knock a few pixes off for look..
+//                Roo.log(ah);
+                this.el.setHeight(this.adjustWidth('textarea', ah));
+                var eh = ah;
             }
-            
         }
+        Roo.log('onResize:' + [w,h,ew,eh].join(',') );
+        this.editorcore.onResize(ew,eh);
         
+    },
+
+    /**
+     * Toggles the editor between standard and source edit mode.
+     * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
+     */
+    toggleSourceEdit : function(sourceEditMode)
+    {
+        this.editorcore.toggleSourceEdit(sourceEditMode);
         
-        for (var i = node.attributes.length-1; i > -1 ; i--) {
-            var a = node.attributes[i];
-            //console.log(a);
+        if(this.editorcore.sourceEditMode){
+            Roo.log('editor - showing textarea');
             
-            if (a.name.toLowerCase().substr(0,2)=='on')  {
-                node.removeAttribute(a.name);
-                continue;
-            }
-            if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
-                node.removeAttribute(a.name);
-                continue;
-            }
-            if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
-                cleanAttr(a.name,a.value); // fixme..
-                continue;
-            }
-            if (a.name == 'style') {
-                cleanStyle(a.name,a.value);
-                continue;
+//            Roo.log('in');
+//            Roo.log(this.syncValue());
+            this.editorcore.syncValue();
+            this.el.removeClass('x-hidden');
+            this.el.dom.removeAttribute('tabIndex');
+            this.el.focus();
+            
+            for (var i = 0; i < this.toolbars.length; i++) {
+                if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
+                    this.toolbars[i].tb.hide();
+                    this.toolbars[i].footer.hide();
+                }
             }
-            /// clean up MS crap..
-            // tecnically this should be a list of valid class'es..
             
+        }else{
+            Roo.log('editor - hiding textarea');
+//            Roo.log('out')
+//            Roo.log(this.pushValue()); 
+            this.editorcore.pushValue();
             
-            if (a.name == 'class') {
-                if (a.value.match(/^Mso/)) {
-                    node.className = '';
-                }
-                
-                if (a.value.match(/body/)) {
-                    node.className = '';
+            this.el.addClass('x-hidden');
+            this.el.dom.setAttribute('tabIndex', -1);
+            
+            for (var i = 0; i < this.toolbars.length; i++) {
+                if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
+                    this.toolbars[i].tb.show();
+                    this.toolbars[i].footer.show();
                 }
-                continue;
             }
             
-            // style cleanup!?
-            // class cleanup?
-            
+            //this.deferFocus();
         }
         
+        this.setSize(this.wrap.getSize());
+        this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
         
-        this.cleanUpChildren(node);
+        this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
+    },
+    // private (for BoxComponent)
+    adjustSize : Roo.BoxComponent.prototype.adjustSize,
+
+    // private (for BoxComponent)
+    getResizeEl : function(){
+        return this.wrap;
+    },
+
+    // private (for BoxComponent)
+    getPositionEl : function(){
+        return this.wrap;
+    },
+
+    // private
+    initEvents : function(){
+        this.originalValue = this.getValue();
+    },
+
+    /**
+     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
+     * @method
+     */
+    markInvalid : Roo.emptyFn,
+    /**
+     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
+     * @method
+     */
+    clearInvalid : Roo.emptyFn,
+
+    setValue : function(v){
+        Roo.form.HtmlEditor.superclass.setValue.call(this, v);
+        this.editorcore.pushValue();
+    },
+
+     
+    // private
+    deferFocus : function(){
+        this.focus.defer(10, this);
+    },
+
+    // doc'ed in Field
+    focus : function(){
+        this.editorcore.focus();
+        
+    },
+      
+
+    // private
+    onDestroy : function(){
         
         
-    }
+        
+        if(this.rendered){
+            
+            for (var i =0; i < this.toolbars.length;i++) {
+                // fixme - ask toolbars for heights?
+                this.toolbars[i].onDestroy();
+            }
+            
+            this.wrap.dom.innerHTML = '';
+            this.wrap.remove();
+        }
+    },
+
+    // private
+    onFirstFocus : function(){
+        //Roo.log("onFirstFocus");
+        this.editorcore.onFirstFocus();
+         for (var i =0; i < this.toolbars.length;i++) {
+            this.toolbars[i].onFirstFocus();
+        }
+        
+    },
+    
+    // private
+    syncValue : function()
+    {
+        this.editorcore.syncValue();
+    },
+    
+    pushValue : function()
+    {
+        this.editorcore.pushValue();
+    },
     
+    setStylesheets : function(stylesheets)
+    {
+        this.editorcore.setStylesheets(stylesheets);
+    },
+    
+    removeStylesheets : function()
+    {
+        this.editorcore.removeStylesheets();
+    }
+     
     
     // hide stuff that is not compatible
     /**
@@ -25826,79 +23285,7 @@ Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
      * @cfg {String} validateOnBlur @hide
      */
 });
-
-Roo.form.HtmlEditor.white = [
-        'area', 'br', 'img', 'input', 'hr', 'wbr',
-        
-       'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
-       'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
-       'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
-       'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
-       'table',   'ul',         'xmp', 
-       
-       'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
-      'thead',   'tr', 
-     
-      'dir', 'menu', 'ol', 'ul', 'dl',
-       
-      'embed',  'object'
-];
-
-
-Roo.form.HtmlEditor.black = [
-    //    'embed',  'object', // enable - backend responsiblity to clean thiese
-        'applet', // 
-        'base',   'basefont', 'bgsound', 'blink',  'body', 
-        'frame',  'frameset', 'head',    'html',   'ilayer', 
-        'iframe', 'layer',  'link',     'meta',    'object',   
-        'script', 'style' ,'title',  'xml' // clean later..
-];
-Roo.form.HtmlEditor.clean = [
-    'script', 'style', 'title', 'xml'
-];
-Roo.form.HtmlEditor.remove = [
-    'font'
-];
-// attributes..
-
-Roo.form.HtmlEditor.ablack = [
-    'on'
-];
-    
-Roo.form.HtmlEditor.aclean = [ 
-    'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
-];
-
-// protocols..
-Roo.form.HtmlEditor.pwhite= [
-        'http',  'https',  'mailto'
-];
-
-// white listed style attributes.
-Roo.form.HtmlEditor.cwhite= [
-      //  'text-align', /// default is to allow most things..
-      
-         
-//        'font-size'//??
-];
-
-// black listed style attributes.
-Roo.form.HtmlEditor.cblack= [
-      //  'font-size' -- this can be set by the project 
-];
-
-
-Roo.form.HtmlEditor.swapCodes   =[ 
-    [    8211, "--" ], 
-    [    8212, "--" ], 
-    [    8216,  "'" ],  
-    [    8217, "'" ],  
-    [    8220, '"' ],  
-    [    8221, '"' ],  
-    [    8226, "*" ],  
-    [    8230, "..." ]
-]; 
-
     // <script type="text/javascript">
 /*
  * Based on
@@ -25957,11 +23344,24 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
     rendered: false,
     
     editor : false,
+    editorcore : false,
     /**
      * @cfg {Object} disable  List of toolbar elements to disable
          
      */
     disable : false,
+    
+    
+     /**
+     * @cfg {String} createLinkText The default text for the create link prompt
+     */
+    createLinkText : 'Please enter the URL for the link:',
+    /**
+     * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
+     */
+    defaultLinkValue : 'http:/'+'/',
+   
+    
       /**
      * @cfg {Array} fontFamilies An array of available font families
      */
@@ -26020,7 +23420,8 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
         ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"], 
         ["pre"],[ "code"], 
         ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
-        ['div'],['span']
+        ['div'],['span'],
+        ['sup'],['sub']
     ],
     
     cleanStyles : [
@@ -26039,9 +23440,12 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
     init : function(editor)
     {
         this.editor = editor;
+        this.editorcore = editor.editorcore ? editor.editorcore : editor;
+        var editorcore = this.editorcore;
         
+        var _t = this;
         
-        var fid = editor.frameId;
+        var fid = editorcore.frameId;
         var etb = this;
         function btn(id, toggle, handler){
             var xid = fid + '-'+ id ;
@@ -26050,8 +23454,8 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
                 cmd : id,
                 cls : 'x-btn-icon x-edit-'+id,
                 enableToggle:toggle !== false,
-                scope: editor, // was editor...
-                handler:handler||editor.relayBtnCmd,
+                scope: _t, // was editor...
+                handler:handler||_t.relayBtnCmd,
                 clickEvent:'mousedown',
                 tooltip: etb.buttonTips[id] || undefined, ///tips ???
                 tabIndex:-1
@@ -26109,7 +23513,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
                 width:135,
                 listeners : {
                     'select': function(c, r, i) {
-                        editor.insertTag(r.get('tag'));
+                        editorcore.insertTag(r.get('tag'));
                         editor.focus();
                     }
                 }
@@ -26123,7 +23527,8 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
             tb.add(
                 btn('bold'),
                 btn('italic'),
-                btn('underline')
+                btn('underline'),
+                btn('strikethrough')
             );
         };
         if(!this.disable.fontSize){
@@ -26131,8 +23536,8 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
                 '-',
                 
                 
-                btn('increasefontsize', false, editor.adjustFont),
-                btn('decreasefontsize', false, editor.adjustFont)
+                btn('increasefontsize', false, editorcore.adjustFont),
+                btn('decreasefontsize', false, editorcore.adjustFont)
             );
         };
         
@@ -26140,7 +23545,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
         if(!this.disable.colors){
             tb.add(
                 '-', {
-                    id:editor.frameId +'-forecolor',
+                    id:editorcore.frameId +'-forecolor',
                     cls:'x-btn-icon x-edit-forecolor',
                     clickEvent:'mousedown',
                     tooltip: this.buttonTips['forecolor'] || undefined,
@@ -26151,14 +23556,14 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
                         value:'000000',
                         plain:true,
                         selectHandler: function(cp, color){
-                            editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
+                            editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
                             editor.deferFocus();
                         },
-                        scope: editor,
+                        scope: editorcore,
                         clickEvent:'mousedown'
                     })
                 }, {
-                    id:editor.frameId +'backcolor',
+                    id:editorcore.frameId +'backcolor',
                     cls:'x-btn-icon x-edit-backcolor',
                     clickEvent:'mousedown',
                     tooltip: this.buttonTips['backcolor'] || undefined,
@@ -26170,17 +23575,17 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
                         allowReselect: true,
                         selectHandler: function(cp, color){
                             if(Roo.isGecko){
-                                editor.execCmd('useCSS', false);
-                                editor.execCmd('hilitecolor', color);
-                                editor.execCmd('useCSS', true);
+                                editorcore.execCmd('useCSS', false);
+                                editorcore.execCmd('hilitecolor', color);
+                                editorcore.execCmd('useCSS', true);
                                 editor.deferFocus();
                             }else{
-                                editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor', 
+                                editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor', 
                                     Roo.isSafari || Roo.isIE ? '#'+color : color);
                                 editor.deferFocus();
                             }
                         },
-                        scope:editor,
+                        scope:editorcore,
                         clickEvent:'mousedown'
                     })
                 }
@@ -26202,7 +23607,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
             if(!this.disable.links){
                 tb.add(
                     '-',
-                    btn('createlink', false, editor.createLink)    /// MOVE TO HERE?!!?!?!?!
+                    btn('createlink', false, this.createLink)    /// MOVE TO HERE?!!?!?!?!
                 );
             };
 
@@ -26239,7 +23644,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
                     
                     html: this.specialChars[i],
                     handler: function(a,b) {
-                        editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
+                        editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
                         //editor.insertAtCursor(a.html);
                         
                     },
@@ -26267,17 +23672,75 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
                     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);
+//                        Roo.log(a);
+//                        Roo.log(b);
+                        var c = Roo.get(editorcore.doc.body);
                         c.select('[style]').each(function(s) {
                             s.dom.style.removeProperty(a.actiontype);
                         });
-                        
+                        editorcore.syncValue();
                     },
                     tabIndex:-1
                 });
             }
+             cmenu.menu.items.push({
+                actiontype : 'tablewidths',
+                html: 'Remove Table Widths',
+                handler: function(a,b) {
+                    editorcore.cleanTableWidths();
+                    editorcore.syncValue();
+                },
+                tabIndex:-1
+            });
+            cmenu.menu.items.push({
+                actiontype : 'word',
+                html: 'Remove MS Word Formating',
+                handler: function(a,b) {
+                    editorcore.cleanWord();
+                    editorcore.syncValue();
+                },
+                tabIndex:-1
+            });
+            
+            cmenu.menu.items.push({
+                actiontype : 'all',
+                html: 'Remove All Styles',
+                handler: function(a,b) {
+                    
+                    var c = Roo.get(editorcore.doc.body);
+                    c.select('[style]').each(function(s) {
+                        s.dom.removeAttribute('style');
+                    });
+                    editorcore.syncValue();
+                },
+                tabIndex:-1
+            });
+            
+            cmenu.menu.items.push({
+                actiontype : 'all',
+                html: 'Remove All CSS Classes',
+                handler: function(a,b) {
+                    
+                    var c = Roo.get(editorcore.doc.body);
+                    c.select('[class]').each(function(s) {
+                        s.dom.removeAttribute('class');
+                    });
+                    editorcore.cleanWord();
+                    editorcore.syncValue();
+                },
+                tabIndex:-1
+            });
+            
+             cmenu.menu.items.push({
+                actiontype : 'tidy',
+                html: 'Tidy HTML Source',
+                handler: function(a,b) {
+                    editorcore.doc.body.innerHTML = editorcore.domToHTML();
+                    editorcore.syncValue();
+                },
+                tabIndex:-1
+            });
+            
             
             tb.add(cmenu);
         }
@@ -26311,7 +23774,12 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
             for(var i =0; i< this.btns.length;i++) {
                 var b = Roo.factory(this.btns[i],Roo.form);
                 b.cls =  'x-edit-none';
-                b.scope = editor;
+                
+                if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
+                    b.cls += ' x-init-enable';
+                }
+                
+                b.scope = editorcore;
                 tb.add(b);
             }
         
@@ -26322,7 +23790,12 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
         // disable everything...
         
         this.tb.items.each(function(item){
-           if(item.id != editor.frameId+ '-sourceedit'){
+            
+           if(
+                item.id != editorcore.frameId+ '-sourceedit' && 
+                (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
+            ){
+                
                 item.disable();
             }
         });
@@ -26335,6 +23808,18 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
     },
     
     
+    relayBtnCmd : function(btn) {
+        this.editorcore.relayCmd(btn.cmd);
+    },
+    // private used internally
+    createLink : function(){
+        Roo.log("create link?");
+        var url = prompt(this.createLinkText, this.defaultLinkValue);
+        if(url && url != 'http:/'+'/'){
+            this.editorcore.relayCmd('createlink', url);
+        }
+    },
+
     
     /**
      * Protected method that will not generally be called directly. It triggers
@@ -26342,14 +23827,14 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
      */
     updateToolbar: function(){
 
-        if(!this.editor.activated){
+        if(!this.editorcore.activated){
             this.editor.onFirstFocus();
             return;
         }
 
         var btns = this.tb.items.map, 
-            doc = this.editor.doc,
-            frameId = this.editor.frameId;
+            doc = this.editorcore.doc,
+            frameId = this.editorcore.frameId;
 
         if(!this.disable.font && !Roo.isSafari){
             /*
@@ -26363,6 +23848,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
             btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
             btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
             btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
+            btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
         }
         if(!this.disable.alignments){
             btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
@@ -26374,7 +23860,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
             btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
         }
         
-        var ans = this.editor.getAllAncestors();
+        var ans = this.editorcore.getAllAncestors();
         if (this.formatCombo) {
             
             
@@ -26417,32 +23903,37 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
     },
     
     toggleSourceEdit : function(sourceEditMode){
+        
+        Roo.log("toolbar toogle");
         if(sourceEditMode === undefined){
             sourceEditMode = !this.sourceEditMode;
         }
         this.sourceEditMode = sourceEditMode === true;
-        var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
+        var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
         // just toggle the button?
-        if(btn.pressed !== this.editor.sourceEditMode){
-            btn.toggle(this.editor.sourceEditMode);
+        if(btn.pressed !== this.sourceEditMode){
+            btn.toggle(this.sourceEditMode);
             return;
         }
         
-        if(this.sourceEditMode){
+        if(sourceEditMode){
+            Roo.log("disabling buttons");
             this.tb.items.each(function(item){
-                if(item.cmd != 'sourceedit'){
+                if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
                     item.disable();
                 }
             });
           
         }else{
-            if(this.initialized){
+            Roo.log("enabling buttons");
+            if(this.editorcore.initialized){
                 this.tb.items.each(function(item){
                     item.enable();
                 });
             }
             
         }
+        Roo.log("calling toggole on editor");
         // tell the editor that it's been pressed..
         this.editor.toggleSourceEdit(sourceEditMode);
        
@@ -26483,6 +23974,11 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
             text: 'Underline the selected text.',
             cls: 'x-html-editor-tip'
         },
+        strikethrough : {
+            title: 'Strikethrough',
+            text: 'Strikethrough the selected text.',
+            cls: 'x-html-editor-tip'
+        },
         increasefontsize : {
             title: 'Grow Text',
             text: 'Increase the font size.',
@@ -26810,7 +24306,7 @@ Roo.form.HtmlEditor.ToolbarContext.options = {
 // fixme - these need to be configurable..
  
 
-Roo.form.HtmlEditor.ToolbarContext.types
+//Roo.form.HtmlEditor.ToolbarContext.types
 
 
 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
@@ -26820,6 +24316,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
     rendered: false,
     
     editor : false,
+    editorcore : false,
     /**
      * @cfg {Object} disable  List of toolbar elements to disable
          
@@ -26843,9 +24340,10 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
     init : function(editor)
     {
         this.editor = editor;
+        this.editorcore = editor.editorcore ? editor.editorcore : editor;
+        var editorcore = this.editorcore;
         
-        
-        var fid = editor.frameId;
+        var fid = editorcore.frameId;
         var etb = this;
         function btn(id, toggle, handler){
             var xid = fid + '-'+ id ;
@@ -26854,8 +24352,8 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
                 cmd : id,
                 cls : 'x-btn-icon x-edit-'+id,
                 enableToggle:toggle !== false,
-                scope: editor, // was editor...
-                handler:handler||editor.relayBtnCmd,
+                scope: editorcore, // was editor...
+                handler:handler||editorcore.relayBtnCmd,
                 clickEvent:'mousedown',
                 tooltip: etb.buttonTips[id] || undefined, ///tips ???
                 tabIndex:-1
@@ -26900,17 +24398,21 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
     /**
      * Protected method that will not generally be called directly. It triggers
      * a toolbar update by reading the markup state of the current selection in the editor.
+     *
+     * Note you can force an update by calling on('editorevent', scope, false)
      */
     updateToolbar: function(editor,ev,sel){
 
         //Roo.log(ev);
         // capture mouse up - this is handy for selecting images..
         // perhaps should go somewhere else...
-        if(!this.editor.activated){
+        if(!this.editorcore.activated){
              this.editor.onFirstFocus();
             return;
         }
         
+        
+        
         // http://developer.yahoo.com/yui/docs/simple-editor.js.html
         // selectNode - might want to handle IE?
         if (ev &&
@@ -26927,7 +24429,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
                 nodeRange.selectNodeContents(sel);
             }
             //nodeRange.collapse(true);
-            var s = editor.win.getSelection();
+            var s = this.editorcore.win.getSelection();
             s.removeAllRanges();
             s.addRange(nodeRange);
         }  
@@ -26936,15 +24438,15 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
         var updateFooter = sel ? false : true;
         
         
-        var ans = this.editor.getAllAncestors();
+        var ans = this.editorcore.getAllAncestors();
         
         // pick
         var ty= Roo.form.HtmlEditor.ToolbarContext.types;
         
         if (!sel) { 
-            sel = ans.length ? (ans[0] ?  ans[0]  : ans[1]) : this.editor.doc.body;
-            sel = sel ? sel : this.editor.doc.body;
-            sel = sel.tagName.length ? sel : this.editor.doc.body;
+            sel = ans.length ? (ans[0] ?  ans[0]  : ans[1]) : this.editorcore.doc.body;
+            sel = sel ? sel : this.editorcore.doc.body;
+            sel = sel.tagName.length ? sel : this.editorcore.doc.body;
             
         }
         // pick a menu that exists..
@@ -26953,12 +24455,13 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
         
         tn = sel.tagName.toUpperCase();
         
-        var lastSel = this.tb.selectedNode
+        var lastSel = this.tb.selectedNode;
         
         this.tb.selectedNode = sel;
         
         // if current menu does not match..
-        if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
+        
+        if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
                 
             this.tb.el.hide();
             ///console.log("show: " + tn);
@@ -27076,6 +24579,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
     buildToolbar: function(tlist, nm)
     {
         var editor = this.editor;
+        var editorcore = this.editorcore;
          // create a new element.
         var wdiv = editor.wrap.createChild({
                 tag: 'div'
@@ -27116,7 +24620,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
                     'select': function(c, r, i) {
                         // initial support only for on class per el..
                         tb.selectedNode.className =  r ? r.get('val') : '';
-                        editor.syncValue();
+                        editorcore.syncValue();
                     }
                 }
     
@@ -27192,13 +24696,31 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
                 listeners: {
                     'change' : function(f, nv, ov) {
                         tb.selectedNode.setAttribute(f.attrname, nv);
+                        editorcore.syncValue();
                     }
                 }
             }));
              
         }
-        tb.addFill();
+        
         var _this = this;
+        
+        if(nm == 'BODY'){
+            tb.addSeparator();
+        
+            tb.addButton( {
+                text: 'Stylesheets',
+
+                listeners : {
+                    click : function ()
+                    {
+                        _this.editor.fireEvent('stylesheetsclick', _this.editor);
+                    }
+                }
+            });
+        }
+        
+        tb.addFill();
         tb.addButton( {
             text: 'Remove Tag',
     
@@ -27222,14 +24744,14 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
                         
                     }
                     pn.removeChild(sn);
-                    var range = editor.createRange();
+                    var range = editorcore.createRange();
         
                     range.setStart(stn,0);
                     range.setEnd(en,0); //????
                     //range.selectNode(sel);
                     
                     
-                    var selection = editor.getSelection();
+                    var selection = editorcore.getSelection();
                     selection.removeAllRanges();
                     selection.addRange(range);
                     
@@ -27309,13 +24831,13 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype,  {
         var sel = ans[n];
         
          // pick
-        var range = this.editor.createRange();
+        var range = this.editorcore.createRange();
         
         range.selectNodeContents(sel);
         //range.selectNode(sel);
         
         
-        var selection = this.editor.getSelection();
+        var selection = this.editorcore.getSelection();
         selection.removeAllRanges();
         selection.addRange(range);
         
@@ -27395,6 +24917,8 @@ Roo.form.BasicForm = function(el, config){
         this.initEl(el);
     }
     Roo.form.BasicForm.superclass.constructor.call(this);
+    
+    Roo.form.BasicForm.popover.apply();
 };
 
 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
@@ -27460,6 +24984,21 @@ Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
      * @type Mixed
      */
     waitMsgTarget : false,
+    
+    /**
+     * @type Boolean
+     */
+    disableMask : false,
+    
+    /**
+     * @cfg {Boolean} errorMask (true|false) default false
+     */
+    errorMask : false,
+    
+    /**
+     * @cfg {Number} maskOffset Default 100
+     */
+    maskOffset : 100,
 
     // private
     initEl : function(el){
@@ -27480,16 +25019,28 @@ Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
      */
     isValid : function(){
         var valid = true;
+        var target = false;
         this.items.each(function(f){
-           if(!f.validate()){
-               valid = false;
-           }
+            if(f.validate()){
+                return;
+            }
+            
+            valid = false;
+                
+            if(!target && f.el.isVisible(true)){
+                target = f;
+            }
         });
+        
+        if(this.errorMask && !valid){
+            Roo.form.BasicForm.popover.mask(this, target);
+        }
+        
         return valid;
     },
 
     /**
-     * Returns true if any fields in this form have changed since their original load.
+     * DEPRICATED Returns true if any fields in this form have changed since their original load. 
      * @return Boolean
      */
     isDirty : function(){
@@ -27502,7 +25053,39 @@ Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
         });
         return dirty;
     },
-
+    
+    /**
+     * Returns true if any fields in this form have changed since their original load. (New version)
+     * @return Boolean
+     */
+    
+    hasChanged : function()
+    {
+        var dirty = false;
+        this.items.each(function(f){
+           if(f.hasChanged()){
+               dirty = true;
+               return false;
+           }
+        });
+        return dirty;
+        
+    },
+    /**
+     * Resets all hasChanged to 'false' -
+     * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
+     * So hasChanged storage is only to be used for this purpose
+     * @return Boolean
+     */
+    resetHasChanged : function()
+    {
+        this.items.each(function(f){
+           f.resetHasChanged();
+        });
+        
+    },
+    
+    
     /**
      * Performs a predefined action (submit or load) or custom actions you define on this form.
      * @param {String} actionName The name of the action type
@@ -27583,15 +25166,17 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
     beforeAction : function(action){
         var o = action.options;
         
-       
-        if(this.waitMsgTarget === true){
-            this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
-        }else if(this.waitMsgTarget){
-            this.waitMsgTarget = Roo.get(this.waitMsgTarget);
-            this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
-        }else {
-            Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
+        if(!this.disableMask) {
+            if(this.waitMsgTarget === true){
+                this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
+            }else if(this.waitMsgTarget){
+                this.waitMsgTarget = Roo.get(this.waitMsgTarget);
+                this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
+            }else {
+                Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
+            }
         }
+        
          
     },
 
@@ -27600,15 +25185,17 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
         this.activeAction = null;
         var o = action.options;
         
-        if(this.waitMsgTarget === true){
-            this.el.unmask();
-        }else if(this.waitMsgTarget){
-            this.waitMsgTarget.unmask();
-        }else{
-            Roo.MessageBox.updateProgress(1);
-            Roo.MessageBox.hide();
+        if(!this.disableMask) {
+            if(this.waitMsgTarget === true){
+                this.el.unmask();
+            }else if(this.waitMsgTarget){
+                this.waitMsgTarget.unmask();
+            }else{
+                Roo.MessageBox.updateProgress(1);
+                Roo.MessageBox.hide();
+            }
         }
-         
+        
         if(success){
             if(o.reset){
                 this.reset();
@@ -27786,14 +25373,17 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
                 }
             }
         }
-         
+        this.resetHasChanged();
+        
+        
         Roo.each(this.childForms || [], function (f) {
             f.setValues(values);
+            f.resetHasChanged();
         });
                 
         return this;
     },
-
     /**
      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
      * they are returned as an array.
@@ -27808,6 +25398,23 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
             }, this);
         }
         
+        // use formdata
+        if (typeof(FormData) != 'undefined' && asString !== true) {
+            // this relies on a 'recent' version of chrome apparently...
+            try {
+                var fd = (new FormData(this.el.dom)).entries();
+                var ret = {};
+                var ent = fd.next();
+                while (!ent.done) {
+                    ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
+                    ent = fd.next();
+                };
+                return ret;
+            } catch(e) {
+                
+            }
+            
+        }
         
         
         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
@@ -27895,7 +25502,7 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
         Roo.each(this.childForms || [], function (f) {
             f.reset();
         });
-       
+        this.resetHasChanged();
         
         return this;
     },
@@ -27963,7 +25570,153 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
 });
 
 // back compat
-Roo.BasicForm = Roo.form.BasicForm;/*
+Roo.BasicForm = Roo.form.BasicForm;
+
+Roo.apply(Roo.form.BasicForm, {
+    
+    popover : {
+        
+        padding : 5,
+        
+        isApplied : false,
+        
+        isMasked : false,
+        
+        form : false,
+        
+        target : false,
+        
+        intervalID : false,
+        
+        maskEl : false,
+        
+        apply : function()
+        {
+            if(this.isApplied){
+                return;
+            }
+            
+            this.maskEl = {
+                top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
+                left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
+                bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
+                right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
+            };
+            
+            this.maskEl.top.enableDisplayMode("block");
+            this.maskEl.left.enableDisplayMode("block");
+            this.maskEl.bottom.enableDisplayMode("block");
+            this.maskEl.right.enableDisplayMode("block");
+            
+            Roo.get(document.body).on('click', function(){
+                this.unmask();
+            }, this);
+            
+            Roo.get(document.body).on('touchstart', function(){
+                this.unmask();
+            }, this);
+            
+            this.isApplied = true
+        },
+        
+        mask : function(form, target)
+        {
+            this.form = form;
+            
+            this.target = target;
+            
+            if(!this.form.errorMask || !target.el){
+                return;
+            }
+            
+            var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
+            
+            var ot = this.target.el.calcOffsetsTo(scrollable);
+            
+            var scrollTo = ot[1] - this.form.maskOffset;
+            
+            scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
+            
+            scrollable.scrollTo('top', scrollTo);
+            
+            var el = this.target.wrap || this.target.el;
+            
+            var box = el.getBox();
+            
+            this.maskEl.top.setStyle('position', 'absolute');
+            this.maskEl.top.setStyle('z-index', 10000);
+            this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
+            this.maskEl.top.setLeft(0);
+            this.maskEl.top.setTop(0);
+            this.maskEl.top.show();
+            
+            this.maskEl.left.setStyle('position', 'absolute');
+            this.maskEl.left.setStyle('z-index', 10000);
+            this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
+            this.maskEl.left.setLeft(0);
+            this.maskEl.left.setTop(box.y - this.padding);
+            this.maskEl.left.show();
+
+            this.maskEl.bottom.setStyle('position', 'absolute');
+            this.maskEl.bottom.setStyle('z-index', 10000);
+            this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
+            this.maskEl.bottom.setLeft(0);
+            this.maskEl.bottom.setTop(box.bottom + this.padding);
+            this.maskEl.bottom.show();
+
+            this.maskEl.right.setStyle('position', 'absolute');
+            this.maskEl.right.setStyle('z-index', 10000);
+            this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
+            this.maskEl.right.setLeft(box.right + this.padding);
+            this.maskEl.right.setTop(box.y - this.padding);
+            this.maskEl.right.show();
+
+            this.intervalID = window.setInterval(function() {
+                Roo.form.BasicForm.popover.unmask();
+            }, 10000);
+
+            window.onwheel = function(){ return false;};
+            
+            (function(){ this.isMasked = true; }).defer(500, this);
+            
+        },
+        
+        unmask : function()
+        {
+            if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
+                return;
+            }
+            
+            this.maskEl.top.setStyle('position', 'absolute');
+            this.maskEl.top.setSize(0, 0).setXY([0, 0]);
+            this.maskEl.top.hide();
+
+            this.maskEl.left.setStyle('position', 'absolute');
+            this.maskEl.left.setSize(0, 0).setXY([0, 0]);
+            this.maskEl.left.hide();
+
+            this.maskEl.bottom.setStyle('position', 'absolute');
+            this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
+            this.maskEl.bottom.hide();
+
+            this.maskEl.right.setStyle('position', 'absolute');
+            this.maskEl.right.setSize(0, 0).setXY([0, 0]);
+            this.maskEl.right.hide();
+            
+            window.onwheel = function(){ return true;};
+            
+            if(this.intervalID){
+                window.clearInterval(this.intervalID);
+                this.intervalID = false;
+            }
+            
+            this.isMasked = false;
+            
+        }
+        
+    }
+    
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -28031,8 +25784,6 @@ Roo.form.Form = function(config){
     
     Roo.each(xitems, this.addxtype, this);
     
-    
-    
 };
 
 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
@@ -28075,7 +25826,13 @@ Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
      */
     
     progressUrl : false,
-  
+    /**
+     * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
+     * sending a formdata with extra parameters - eg uploaded elements.
+     */
+    
+    formData : false,
+    
     /**
      * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
      * fields are added and the column is closed. If no fields are passed the column remains open
@@ -28631,7 +26388,8 @@ Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
                 url:this.getUrl(!isPost),
                 method: method,
                 params:isPost ? this.getParams() : null,
-                isUpload: this.form.fileUpload
+                isUpload: this.form.fileUpload,
+                formData : this.form.formData
             }));
             
             this.uploadProgress();
@@ -29082,7 +26840,7 @@ Roo.form.VTypes = function(){
     // closure these in so they are only created once.
     var alpha = /^[a-zA-Z_]+$/;
     var alphanum = /^[a-zA-Z0-9_]+$/;
-    var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
+    var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
 
     // All these messages and functions are configurable
@@ -29211,7 +26969,7 @@ Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
             this.defaultAutoCreate = {
                 tag: "textarea",
                 style:"width:300px;height:60px;",
-                autocomplete: "off"
+                autocomplete: "new-password"
             };
         }
         Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
@@ -29384,8 +27142,9 @@ Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
     
     replaceTextarea : function()
     {
-        if ( document.getElementById( this.getId() + '___Frame' ) )
+        if ( document.getElementById( this.getId() + '___Frame' ) ) {
             return ;
+        }
         //if ( !this.checkBrowser || this._isCompatibleBrowser() )
         //{
             // We must check the elements firstly using the Id and then the name.
@@ -29534,7 +27293,7 @@ Roo.extend(Roo.form.GridField, Roo.form.Field,  {
      * {tag: "input", type: "checkbox", autocomplete: "off"})
      */
    // defaultAutoCreate : { tag: 'div' },
-    defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
+    defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
     /**
      * @cfg {String} addTitle Text to include for adding a title.
      */
@@ -29644,6 +27403,7 @@ Roo.extend(Roo.form.GridField, Roo.form.Field,  {
  * @class Roo.form.DisplayField
  * @extends Roo.form.Field
  * A generic Field to display non-editable data.
+ * @cfg {Boolean} closable (true|false) default false
  * @constructor
  * Creates a new Display Field item.
  * @param {Object} config Configuration options
@@ -29651,6 +27411,14 @@ Roo.extend(Roo.form.GridField, Roo.form.Field,  {
 Roo.form.DisplayField = function(config){
     Roo.form.DisplayField.superclass.constructor.call(this, config);
     
+    this.addEvents({
+        /**
+         * @event close
+         * Fires after the click the close btn
+            * @param {Roo.form.DisplayField} this
+            */
+        close : true
+    });
 };
 
 Roo.extend(Roo.form.DisplayField, Roo.form.TextField,  {
@@ -29680,7 +27448,9 @@ Roo.extend(Roo.form.DisplayField, Roo.form.TextField,  {
      */
      
  //   defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
-
+    closable : false,
+    
     onResize : function(){
         Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
         
@@ -29689,6 +27459,10 @@ Roo.extend(Roo.form.DisplayField, Roo.form.TextField,  {
     initEvents : function(){
         // Roo.form.Checkbox.superclass.initEvents.call(this);
         // has no events...
+        
+        if(this.closable){
+            this.closeEl.on('click', this.onClose, this);
+        }
        
     },
 
@@ -29710,6 +27484,10 @@ Roo.extend(Roo.form.DisplayField, Roo.form.TextField,  {
         
         this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
         
+        if(this.closable){
+            this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
+        }
+        
         if (this.bodyStyle) {
             this.viewEl.applyStyles(this.bodyStyle);
         }
@@ -29743,6 +27521,13 @@ Roo.extend(Roo.form.DisplayField, Roo.form.TextField,  {
         this.viewEl.dom.innerHTML = html;
         Roo.form.DisplayField.superclass.setValue.call(this, v);
 
+    },
+    
+    onClose : function(e)
+    {
+        e.preventDefault();
+        
+        this.fireEvent('close', this);
     }
 });/*
  * 
@@ -29777,7 +27562,7 @@ Roo.extend(Roo.form.DayPicker, Roo.form.Field,  {
      * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
      * {tag: "input", type: "checkbox", autocomplete: "off"})
      */
-    defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
+    defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
     
    
     actionMode : 'viewEl', 
@@ -30280,7 +28065,7 @@ Roo.extend(Roo.form.Signature, Roo.form.Field,  {
         pt.x = e.clientX; 
         pt.y = e.clientY;
         if (this.isTouchEvent(e)) {
-            pt.x =  e.targetTouches[0].clientX 
+            pt.x =  e.targetTouches[0].clientX;
             pt.y = e.targetTouches[0].clientY;
         }
         var a = this.svgEl.dom.getScreenCTM();
@@ -31757,7 +29542,9 @@ Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
      * Performs a layout update.
      */
     layout : function(){
-        if(this.updating) return;
+        if(this.updating) {
+            return;
+        }
         var size = this.getViewSize();
         var w = size.width;
         var h = size.height;
@@ -32109,6 +29896,7 @@ layout.addxtype({
                 if (typeof(Roo[cfg.xtype]) != 'undefined') {
                     
                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
+                    this.add(region, ret);
                 } else {
                 
                     alert("Can not add '" + cfg.xtype + "' to BorderLayout");
@@ -32318,6 +30106,12 @@ Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
          * @param {Roo.ContentPanel} panel The panel
          */
         "panelremoved" : true,
+        /**
+         * @event beforecollapse
+         * Fires when this region before collapse.
+         * @param {Roo.LayoutRegion} this
+         */
+        "beforecollapse" : true,
         /**
          * @event collapsed
          * Fires when this region is collapsed.
@@ -32585,7 +30379,7 @@ Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
  * @cfg {Boolean}   floatable       False to disable floating (defaults to true)
  * @cfg {Object}    margins         Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
  * @cfg {Object}    cmargins        Margins for the element when collapsed (defaults to: north/south {top: 2, left: 0, right:0, bottom: 2} or east/west {top: 0, left: 2, right:2, bottom: 0})
- * @cfg {String}    tabPosition     "top" or "bottom" (defaults to "bottom")
+ * @cfg {String}    tabPosition     (top|bottom) "top" or "bottom" (defaults to "bottom")
  * @cfg {String}    collapsedTitle  Optional string message to display in the collapsed block of a north or south region
  * @cfg {Boolean}   alwaysShowTabs  True to always display tabs even when there is only 1 panel (defaults to false)
  * @cfg {Boolean}   autoScroll      True to enable overflow scrolling (defaults to false)
@@ -32869,22 +30663,29 @@ Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
      * Collapses this region.
      * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
      */
-    collapse : function(skipAnim){
-        if(this.collapsed) return;
-        this.collapsed = true;
-        if(this.split){
-            this.split.el.hide();
+    collapse : function(skipAnim, skipCheck){
+        if(this.collapsed) {
+            return;
         }
-        if(this.config.animate && skipAnim !== true){
-            this.fireEvent("invalidated", this);
-            this.animateCollapse();
-        }else{
-            this.el.setLocation(-20000,-20000);
-            this.el.hide();
-            this.collapsedEl.show();
-            this.fireEvent("collapsed", this);
-            this.fireEvent("invalidated", this);
+        
+        if(skipCheck || this.fireEvent("beforecollapse", this) != false){
+            
+            this.collapsed = true;
+            if(this.split){
+                this.split.el.hide();
+            }
+            if(this.config.animate && skipAnim !== true){
+                this.fireEvent("invalidated", this);
+                this.animateCollapse();
+            }else{
+                this.el.setLocation(-20000,-20000);
+                this.el.hide();
+                this.collapsedEl.show();
+                this.fireEvent("collapsed", this);
+                this.fireEvent("invalidated", this);
+            }
         }
+        
     },
 
     animateCollapse : function(){
@@ -32897,8 +30698,12 @@ Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
      * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
      */
     expand : function(e, skipAnim){
-        if(e) e.stopPropagation();
-        if(!this.collapsed || this.el.hasActiveFx()) return;
+        if(e) {
+            e.stopPropagation();
+        }
+        if(!this.collapsed || this.el.hasActiveFx()) {
+            return;
+        }
         if(this.isSlid){
             this.afterSlideIn();
             skipAnim = true;
@@ -33009,8 +30814,10 @@ Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
      * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
      * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
      */
-    showPanel : function(panel){
-        if(panel = this.getPanel(panel)){
+    showPanel : function(panel)
+    {
+        panel = this.getPanel(panel);
+        if(panel){
             if(this.tabs){
                 var tab = this.tabs.getTab(panel.getEl().id);
                 if(tab.isHidden()){
@@ -33277,7 +31084,9 @@ Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
     beforeSlide: function(){
         if(Roo.isGecko){// firefox overflow auto bug workaround
             this.bodyEl.clip();
-            if(this.tabs) this.tabs.bodyEl.clip();
+            if(this.tabs) {
+                this.tabs.bodyEl.clip();
+            }
             if(this.activePanel){
                 this.activePanel.getEl().clip();
                 
@@ -33291,7 +31100,9 @@ Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
     afterSlide : function(){
         if(Roo.isGecko){// firefox overflow auto bug workaround
             this.bodyEl.unclip();
-            if(this.tabs) this.tabs.bodyEl.unclip();
+            if(this.tabs) {
+                this.tabs.bodyEl.unclip();
+            }
             if(this.activePanel){
                 this.activePanel.getEl().unclip();
                 if(this.activePanel.afterSlide){
@@ -33924,8 +31735,7 @@ Roo.ContentPanel = function(el, config, content){
          * @param {Roo.ContentPanel} this
          */
         "render" : true
-        
-        
+         
         
     });
     
@@ -34101,7 +31911,7 @@ panel.load({
         }
         if(this.footer){
             var te = this.footer.getEl();
-            Roo.log("footer:" + te.getHeight());
+            //Roo.log("footer:" + te.getHeight());
             
             height -= te.getHeight();
             te.setWidth(width);
@@ -34227,7 +32037,9 @@ layout.addxtype({
             this.form = new  Roo.form.Form(cfg);
             
             
-            if ( this.form.allItems.length) this.form.render(el.dom);
+            if ( this.form.allItems.length) {
+                this.form.render(el.dom);
+            }
             return this.form;
         }
         // should only have one of theses..
@@ -35172,12 +32984,12 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
         return this;
     },
 
-       /**
-        * Reconfigures the grid to use a different Store and Column Model.
-        * The View will be bound to the new objects and refreshed.
-        * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
-        * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
-        */
+    /**
+     * Reconfigures the grid to use a different Store and Column Model.
+     * The View will be bound to the new objects and refreshed.
+     * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
+     * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
+     */
     reconfigure : function(dataSource, colModel){
         if(this.loadMask){
             this.loadMask.destroy();
@@ -35189,7 +33001,41 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
         this.colModel = colModel;
         this.view.refresh(true);
     },
-
+    /**
+     * addColumns
+     * Add's a column, default at the end..
+     
+     * @param {int} position to add (default end)
+     * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel} 
+     */
+    addColumns : function(pos, ar)
+    {
+        
+        for (var i =0;i< ar.length;i++) {
+            var cfg = ar[i];
+            cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
+            this.cm.lookup[cfg.id] = cfg;
+        }
+        
+        
+        if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
+            pos = this.cm.config.length; //this.cm.config.push(cfg);
+        } 
+        pos = Math.max(0,pos);
+        ar.unshift(0);
+        ar.unshift(pos);
+        this.cm.config.splice.apply(this.cm.config, ar);
+        
+        
+        
+        this.view.generateRules(this.cm);
+        this.view.refresh(true);
+        
+    },
+    
+    
+    
+    
     // private
     onKeyDown : function(e){
         this.fireEvent("keydown", e);
@@ -35219,7 +33065,7 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
     // private
     processEvent : function(name, e){
         // does this fire select???
-        Roo.log('grid:processEvent '  + name);
+        //Roo.log('grid:processEvent '  + name);
         
         if (name != 'touchstart' ) {
             this.fireEvent(name, e);    
@@ -35229,7 +33075,9 @@ Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
         var v = this.view;
         var header = v.findHeaderIndex(t);
         if(header !== false){
-            this.fireEvent("header" + (name == 'touchstart' ? 'click' : name), this, header, e);
+            var ename = name == 'touchstart' ? 'click' : name;
+             
+            this.fireEvent("header" + ename, this, header, e);
         }else{
             var row = v.findRowIndex(t);
             var cell = v.findCellIndex(t);
@@ -35442,7 +33290,7 @@ Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
     hdClass : "x-grid-hd",
     splitClass : "x-grid-hd-split",
     
-       init: function(grid){
+    init: function(grid){
         this.grid = grid;
                var cid = this.grid.getGridEl().id;
         this.colSelector = "#" + cid + " ." + this.cellClass + "-";
@@ -35451,7 +33299,7 @@ Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
         this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
        },
        
-       getColumnRenderers : function(){
+    getColumnRenderers : function(){
        var renderers = [];
        var cm = this.grid.colModel;
         var colCount = cm.getColumnCount();
@@ -36223,8 +34071,8 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
             p.cellId = "x-grid-hd-0-" + i;
             p.splitId = "x-grid-csplit-0-" + i;
             p.id = cm.getColumnId(i);
-            p.title = cm.getColumnTooltip(i) || "";
             p.value = cm.getColumnHeader(i) || "";
+            p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</)  ? '' :  p.value  || "";
             p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
             if(!cm.isLocked(i)){
                 cb[cb.length] = ct.apply(p);
@@ -36384,7 +34232,9 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
         if(s){ // splitters not created yet
             var pos = 0, locked = true;
             for(var i = 0, len = cm.getColumnCount(); i < len; i++){
-                if(cm.isHidden(i)) continue;
+                if(cm.isHidden(i)) {
+                    continue;
+                }
                 var w = cm.getColumnWidth(i); // make sure it's a number
                 if(!cm.isLocked(i) && locked){
                     pos = 0;
@@ -36581,7 +34431,8 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
                 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
                 renderer : cm.getRenderer(i),
                 id : cm.getColumnId(i),
-                locked : cm.isLocked(i)
+                locked : cm.isLocked(i),
+                has_editor : cm.isCellEditable(i)
             };
         }
 
@@ -36613,9 +34464,14 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
                         p.id = c.id;
                         p.css = p.attr = "";
                         p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
-                        if(p.value == undefined || p.value === "") p.value = "&#160;";
-                        if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
-                            p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
+                        if(p.value == undefined || p.value === "") {
+                            p.value = "&#160;";
+                        }
+                        if(c.has_editor){
+                            p.css += ' x-grid-editable-cell';
+                        }
+                        if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
+                            p.css +=  ' x-grid-dirty-cell';
                         }
                         var markup = ct.apply(p);
                         if(!c.locked){
@@ -36641,7 +34497,7 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
                             record: r,
                             rowIndex : rowIndex,
                             rowClass : ''
-                        }
+                        };
                         this.grid.fireEvent('rowclass', this, rowcfg);
                         alt.push(rowcfg.rowClass);
                     }
@@ -36667,9 +34523,15 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
                         p.id = c.id;
                         p.css = p.attr = "";
                         p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
-                        if(p.value == undefined || p.value === "") p.value = "&#160;";
+                        if(p.value == undefined || p.value === "") {
+                            p.value = "&#160;";
+                        }
+                        //Roo.log(c);
+                         if(c.has_editor){
+                            p.css += ' x-grid-editable-cell';
+                        }
                         if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
-                            p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
+                            p.css += ' x-grid-dirty-cell' 
                         }
                         
                         var markup = ct.apply(p);
@@ -36696,10 +34558,11 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
                             record: r,
                             rowIndex : rowIndex,
                             rowClass : ''
-                        }
+                        };
                         this.grid.fireEvent('rowclass', this, rowcfg);
                         alt.push(rowcfg.rowClass);
                     }
+                    
                     rp.alt = alt.join(" ");
                     rp.cells = lcb.join("");
                     lbuf[lbuf.length] = rt.apply(rp);
@@ -36786,7 +34649,9 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
         };
         var renderer = cm.getRenderer(colIndex);
         var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
-        if(typeof val == "undefined" || val === "") val = "&#160;";
+        if(typeof val == "undefined" || val === "") {
+            val = "&#160;";
+        }
         cellText.innerHTML = val;
         cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
         this.syncRowHeights(rowIndex, rowIndex);
@@ -36951,7 +34816,17 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
     },
 
 
-    handleHeaderClick : function(g, index){
+    handleHeaderClick : function(g, index,e){
+        
+        Roo.log("header click");
+        
+        if (Roo.isTouch) {
+            // touch events on header are handled by context
+            this.handleHdCtx(g,index,e);
+            return;
+        }
+        
+        
         if(this.headersDisabled){
             return;
         }
@@ -37064,6 +34939,15 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
                     cm.setLocked(index, false);
                 }
             break;
+            case 'wider': // used to expand cols on touch..
+            case 'narrow':
+                var cw = cm.getColumnWidth(index);
+                cw += (item.id == 'wider' ? 1 : -1) * 50;
+                cw = Math.max(0, cw);
+                cw = Math.min(cw,4000);
+                cm.setColumnWidth(index, cw);
+                break;
+                
             default:
                 index = cm.getIndexById(item.id.substr(4));
                 if(index != -1){
@@ -37193,6 +35077,15 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
                     {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
                 );
             }
+            if (Roo.isTouch) {
+                 this.hmenu.add('-',
+                    {id:"wider", text: this.columnsWiderText},
+                    {id:"narrow", text: this.columnsNarrowText }
+                );
+                
+                 
+            }
+            
             if(this.grid.enableColumnHide !== false){
 
                 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
@@ -37325,6 +35218,11 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
         s.setSize(vw, vh);
 
         var bt = this.getBodyTable();
+        
+        if(cm.getLockedCount() == cm.config.length){
+            bt = this.getLockedTable();
+        }
+        
         var ltWidth = hasLock ?
                       Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
 
@@ -37395,7 +35293,10 @@ Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
     sortDescText : "Sort Descending",
     lockText : "Lock Column",
     unlockText : "Unlock Column",
-    columnsText : "Columns"
+    columnsText : "Columns",
+    columnsWiderText : "Wider",
+    columnsNarrowText : "Thinner"
 });
 
 
@@ -37736,7 +35637,8 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     /**
      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
      * given the cell's data value. See {@link #setRenderer}. If not specified, the
-     * default renderer uses the raw data value.
+     * default renderer returns the escaped data value. If an object is returned (bootstrap only)
+     * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
      */
        /**
      * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
@@ -37744,7 +35646,27 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     /**
      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
      */
-
+    /**
+     * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc).  Defaults to undefined.
+     */
+    /**
+     * @cfg {String} cursor (Optional)
+     */
+    /**
+     * @cfg {String} tooltip (Optional)
+     */
+    /**
+     * @cfg {Number} xs (Optional)
+     */
+    /**
+     * @cfg {Number} sm (Optional)
+     */
+    /**
+     * @cfg {Number} md (Optional)
+     */
+    /**
+     * @cfg {Number} lg (Optional)
+     */
     /**
      * Returns the id of the column at the specified index.
      * @param {Number} index The column index
@@ -37842,6 +35764,8 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
                 return i;
             }
         }
+        
+        return this.config.length;
     },
 
     /**
@@ -38019,7 +35943,7 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     /**
      * Returns true if the cell is editable.
      * @param {Number} colIndex The column index
-     * @param {Number} rowIndex The row index
+     * @param {Number} rowIndex The row index - this is nto actually used..?
      * @return {Boolean}
      */
     isCellEditable : function(colIndex, rowIndex){
@@ -38092,11 +36016,16 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     }
 });
 
-Roo.grid.ColumnModel.defaultRenderer = function(value){
+Roo.grid.ColumnModel.defaultRenderer = function(value)
+{
+    if(typeof value == "object") {
+        return value;
+    }
        if(typeof value == "string" && value.length < 1){
            return "&#160;";
        }
-       return value;
+    
+       return String.format("{0}", value);
 };
 
 // Alias for backwards compatibility
@@ -38283,6 +36212,7 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
         s.each(function(r){
             if((i = ds.indexOfId(r.id)) != -1){
                 v.onRowSelect(i);
+                s.add(ds.getAt(i)); // updating the selection relate data
             }else{
                 s.remove(r);
             }
@@ -38382,7 +36312,9 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
      * Clears all selections.
      */
     clearSelections : function(fast){
-        if(this.locked) return;
+        if(this.locked) {
+            return;
+        }
         if(fast !== true){
             var ds = this.grid.dataSource;
             var s = this.selections;
@@ -38401,7 +36333,9 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
      * Selects all rows.
      */
     selectAll : function(){
-        if(this.locked) return;
+        if(this.locked) {
+            return;
+        }
         this.selections.clear();
         for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
             this.selectRow(i, true);
@@ -38490,7 +36424,9 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
      * @param {Boolean} keepExisting (optional) True to retain existing selections
      */
     selectRange : function(startRow, endRow, keepExisting){
-        if(this.locked) return;
+        if(this.locked) {
+            return;
+        }
         if(!keepExisting){
             this.clearSelections();
         }
@@ -38511,7 +36447,9 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
      * @param {Number} endRow The index of the last row in the range
      */
     deselectRange : function(startRow, endRow, preventViewNotify){
-        if(this.locked) return;
+        if(this.locked) {
+            return;
+        }
         for(var i = startRow; i <= endRow; i++){
             this.deselectRow(i, preventViewNotify);
         }
@@ -38523,7 +36461,9 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
      * @param {Boolean} keepExisting (optional) True to keep existing selections
      */
     selectRow : function(index, keepExisting, preventViewNotify){
-        if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
+        if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
+            return;
+        }
         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
             if(!keepExisting || this.singleSelect){
                 this.clearSelections();
@@ -38544,7 +36484,9 @@ Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
      * @param {Number} row The index of the row to deselect
      */
     deselectRow : function(index, preventViewNotify){
-        if(this.locked) return;
+        if(this.locked) {
+            return;
+        }
         if(this.last == index){
             this.last = false;
         }
@@ -39011,441 +36953,1718 @@ Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
         this.startEditing(row, col);
     },
 
-    onEditComplete : function(ed, value, startValue){
-        this.editing = false;
-        this.activeEditor = null;
-        ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
-        var r = ed.record;
-        var field = this.colModel.getDataIndex(ed.col);
-        var e = {
-            grid: this,
-            record: r,
-            field: field,
-            originalValue: startValue,
-            value: value,
-            row: ed.row,
-            column: ed.col,
-            cancel:false,
-            editor: ed
-        };
-        var cell = Roo.get(this.view.getCell(ed.row,ed.col))
-        cell.show();
-          
-        if(String(value) !== String(startValue)){
-            
-            if(this.fireEvent("validateedit", e) !== false && !e.cancel){
-                r.set(field, e.value);
-                // if we are dealing with a combo box..
-                // then we also set the 'name' colum to be the displayField
-                if (ed.field.displayField && ed.field.name) {
-                    r.set(ed.field.name, ed.field.el.dom.value);
-                }
-                
-                delete e.cancel; //?? why!!!
-                this.fireEvent("afteredit", e);
-            }
-        } else {
-            this.fireEvent("afteredit", e); // always fire it!
+    onEditComplete : function(ed, value, startValue){
+        this.editing = false;
+        this.activeEditor = null;
+        ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
+        var r = ed.record;
+        var field = this.colModel.getDataIndex(ed.col);
+        var e = {
+            grid: this,
+            record: r,
+            field: field,
+            originalValue: startValue,
+            value: value,
+            row: ed.row,
+            column: ed.col,
+            cancel:false,
+            editor: ed
+        };
+        var cell = Roo.get(this.view.getCell(ed.row,ed.col));
+        cell.show();
+          
+        if(String(value) !== String(startValue)){
+            
+            if(this.fireEvent("validateedit", e) !== false && !e.cancel){
+                r.set(field, e.value);
+                // if we are dealing with a combo box..
+                // then we also set the 'name' colum to be the displayField
+                if (ed.field.displayField && ed.field.name) {
+                    r.set(ed.field.name, ed.field.el.dom.value);
+                }
+                
+                delete e.cancel; //?? why!!!
+                this.fireEvent("afteredit", e);
+            }
+        } else {
+            this.fireEvent("afteredit", e); // always fire it!
+        }
+        this.view.focusCell(ed.row, ed.col);
+    },
+
+    /**
+     * Starts editing the specified for the specified row/column
+     * @param {Number} rowIndex
+     * @param {Number} colIndex
+     */
+    startEditing : function(row, col){
+        this.stopEditing();
+        if(this.colModel.isCellEditable(col, row)){
+            this.view.ensureVisible(row, col, true);
+          
+            var r = this.dataSource.getAt(row);
+            var field = this.colModel.getDataIndex(col);
+            var cell = Roo.get(this.view.getCell(row,col));
+            var e = {
+                grid: this,
+                record: r,
+                field: field,
+                value: r.data[field],
+                row: row,
+                column: col,
+                cancel:false 
+            };
+            if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
+                this.editing = true;
+                var ed = this.colModel.getCellEditor(col, row);
+                
+                if (!ed) {
+                    return;
+                }
+                if(!ed.rendered){
+                    ed.render(ed.parentEl || document.body);
+                }
+                ed.field.reset();
+               
+                cell.hide();
+                
+                (function(){ // complex but required for focus issues in safari, ie and opera
+                    ed.row = row;
+                    ed.col = col;
+                    ed.record = r;
+                    ed.on("complete",   this.onEditComplete,        this,       {single: true});
+                    ed.on("specialkey", this.selModel.onEditorKey,  this.selModel);
+                    this.activeEditor = ed;
+                    var v = r.data[field];
+                    ed.startEdit(this.view.getCell(row, col), v);
+                    // combo's with 'displayField and name set
+                    if (ed.field.displayField && ed.field.name) {
+                        ed.field.el.dom.value = r.data[ed.field.name];
+                    }
+                    
+                    
+                }).defer(50, this);
+            }
+        }
+    },
+        
+    /**
+     * Stops any active editing
+     */
+    stopEditing : function(){
+        if(this.activeEditor){
+            this.activeEditor.completeEdit();
+        }
+        this.activeEditor = null;
+    },
+       
+        /**
+     * Called to get grid's drag proxy text, by default returns this.ddText.
+     * @return {String}
+     */
+    getDragDropText : function(){
+        var count = this.selModel.getSelectedCell() ? 1 : 0;
+        return String.format(this.ddText, count, count == 1 ? '' : 's');
+    }
+       
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+
+// private - not really -- you end up using it !
+// This is a support class used internally by the Grid components
+
+/**
+ * @class Roo.grid.GridEditor
+ * @extends Roo.Editor
+ * Class for creating and editable grid elements.
+ * @param {Object} config any settings (must include field)
+ */
+Roo.grid.GridEditor = function(field, config){
+    if (!config && field.field) {
+        config = field;
+        field = Roo.factory(config.field, Roo.form);
+    }
+    Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
+    field.monitorTab = false;
+};
+
+Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
+    
+    /**
+     * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
+     */
+    
+    alignment: "tl-tl",
+    autoSize: "width",
+    hideEl : false,
+    cls: "x-small-editor x-grid-editor",
+    shim:false,
+    shadow:"frame"
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+  
+
+  
+Roo.grid.PropertyRecord = Roo.data.Record.create([
+    {name:'name',type:'string'},  'value'
+]);
+
+
+Roo.grid.PropertyStore = function(grid, source){
+    this.grid = grid;
+    this.store = new Roo.data.Store({
+        recordType : Roo.grid.PropertyRecord
+    });
+    this.store.on('update', this.onUpdate,  this);
+    if(source){
+        this.setSource(source);
+    }
+    Roo.grid.PropertyStore.superclass.constructor.call(this);
+};
+
+
+
+Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
+    setSource : function(o){
+        this.source = o;
+        this.store.removeAll();
+        var data = [];
+        for(var k in o){
+            if(this.isEditableValue(o[k])){
+                data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
+            }
+        }
+        this.store.loadRecords({records: data}, {}, true);
+    },
+
+    onUpdate : function(ds, record, type){
+        if(type == Roo.data.Record.EDIT){
+            var v = record.data['value'];
+            var oldValue = record.modified['value'];
+            if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
+                this.source[record.id] = v;
+                record.commit();
+                this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
+            }else{
+                record.reject();
+            }
+        }
+    },
+
+    getProperty : function(row){
+       return this.store.getAt(row);
+    },
+
+    isEditableValue: function(val){
+        if(val && val instanceof Date){
+            return true;
+        }else if(typeof val == 'object' || typeof val == 'function'){
+            return false;
+        }
+        return true;
+    },
+
+    setValue : function(prop, value){
+        this.source[prop] = value;
+        this.store.getById(prop).set('value', value);
+    },
+
+    getSource : function(){
+        return this.source;
+    }
+});
+
+Roo.grid.PropertyColumnModel = function(grid, store){
+    this.grid = grid;
+    var g = Roo.grid;
+    g.PropertyColumnModel.superclass.constructor.call(this, [
+        {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
+        {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
+    ]);
+    this.store = store;
+    this.bselect = Roo.DomHelper.append(document.body, {
+        tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
+            {tag: 'option', value: 'true', html: 'true'},
+            {tag: 'option', value: 'false', html: 'false'}
+        ]
+    });
+    Roo.id(this.bselect);
+    var f = Roo.form;
+    this.editors = {
+        'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
+        'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
+        'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
+        'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
+        'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
+    };
+    this.renderCellDelegate = this.renderCell.createDelegate(this);
+    this.renderPropDelegate = this.renderProp.createDelegate(this);
+};
+
+Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
+    
+    
+    nameText : 'Name',
+    valueText : 'Value',
+    
+    dateFormat : 'm/j/Y',
+    
+    
+    renderDate : function(dateVal){
+        return dateVal.dateFormat(this.dateFormat);
+    },
+
+    renderBool : function(bVal){
+        return bVal ? 'true' : 'false';
+    },
+
+    isCellEditable : function(colIndex, rowIndex){
+        return colIndex == 1;
+    },
+
+    getRenderer : function(col){
+        return col == 1 ?
+            this.renderCellDelegate : this.renderPropDelegate;
+    },
+
+    renderProp : function(v){
+        return this.getPropertyName(v);
+    },
+
+    renderCell : function(val){
+        var rv = val;
+        if(val instanceof Date){
+            rv = this.renderDate(val);
+        }else if(typeof val == 'boolean'){
+            rv = this.renderBool(val);
+        }
+        return Roo.util.Format.htmlEncode(rv);
+    },
+
+    getPropertyName : function(name){
+        var pn = this.grid.propertyNames;
+        return pn && pn[name] ? pn[name] : name;
+    },
+
+    getCellEditor : function(colIndex, rowIndex){
+        var p = this.store.getProperty(rowIndex);
+        var n = p.data['name'], val = p.data['value'];
+        
+        if(typeof(this.grid.customEditors[n]) == 'string'){
+            return this.editors[this.grid.customEditors[n]];
+        }
+        if(typeof(this.grid.customEditors[n]) != 'undefined'){
+            return this.grid.customEditors[n];
+        }
+        if(val instanceof Date){
+            return this.editors['date'];
+        }else if(typeof val == 'number'){
+            return this.editors['number'];
+        }else if(typeof val == 'boolean'){
+            return this.editors['boolean'];
+        }else{
+            return this.editors['string'];
+        }
+    }
+});
+
+/**
+ * @class Roo.grid.PropertyGrid
+ * @extends Roo.grid.EditorGrid
+ * This class represents the  interface of a component based property grid control.
+ * <br><br>Usage:<pre><code>
+ var grid = new Roo.grid.PropertyGrid("my-container-id", {
+      
+ });
+ // set any options
+ grid.render();
+ * </code></pre>
+  
+ * @constructor
+ * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
+ * The container MUST have some type of size defined for the grid to fill. The container will be
+ * automatically set to position relative if it isn't already.
+ * @param {Object} config A config object that sets properties on this grid.
+ */
+Roo.grid.PropertyGrid = function(container, config){
+    config = config || {};
+    var store = new Roo.grid.PropertyStore(this);
+    this.store = store;
+    var cm = new Roo.grid.PropertyColumnModel(this, store);
+    store.store.sort('name', 'ASC');
+    Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
+        ds: store.store,
+        cm: cm,
+        enableColLock:false,
+        enableColumnMove:false,
+        stripeRows:false,
+        trackMouseOver: false,
+        clicksToEdit:1
+    }, config));
+    this.getGridEl().addClass('x-props-grid');
+    this.lastEditRow = null;
+    this.on('columnresize', this.onColumnResize, this);
+    this.addEvents({
+         /**
+            * @event beforepropertychange
+            * Fires before a property changes (return false to stop?)
+            * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
+            * @param {String} id Record Id
+            * @param {String} newval New Value
+         * @param {String} oldval Old Value
+            */
+        "beforepropertychange": true,
+        /**
+            * @event propertychange
+            * Fires after a property changes
+            * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
+            * @param {String} id Record Id
+            * @param {String} newval New Value
+         * @param {String} oldval Old Value
+            */
+        "propertychange": true
+    });
+    this.customEditors = this.customEditors || {};
+};
+Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
+    
+     /**
+     * @cfg {Object} customEditors map of colnames=> custom editors.
+     * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
+     * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
+     * false disables editing of the field.
+        */
+    
+      /**
+     * @cfg {Object} propertyNames map of property Names to their displayed value
+        */
+    
+    render : function(){
+        Roo.grid.PropertyGrid.superclass.render.call(this);
+        this.autoSize.defer(100, this);
+    },
+
+    autoSize : function(){
+        Roo.grid.PropertyGrid.superclass.autoSize.call(this);
+        if(this.view){
+            this.view.fitColumns();
         }
-        this.view.focusCell(ed.row, ed.col);
     },
 
-    /**
-     * Starts editing the specified for the specified row/column
-     * @param {Number} rowIndex
-     * @param {Number} colIndex
-     */
-    startEditing : function(row, col){
-        this.stopEditing();
-        if(this.colModel.isCellEditable(col, row)){
-            this.view.ensureVisible(row, col, true);
-          
-            var r = this.dataSource.getAt(row);
-            var field = this.colModel.getDataIndex(col);
-            var cell = Roo.get(this.view.getCell(row,col));
-            var e = {
-                grid: this,
-                record: r,
-                field: field,
-                value: r.data[field],
-                row: row,
-                column: col,
-                cancel:false 
-            };
-            if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
-                this.editing = true;
-                var ed = this.colModel.getCellEditor(col, row);
-                
-                if (!ed) {
-                    return;
-                }
-                if(!ed.rendered){
-                    ed.render(ed.parentEl || document.body);
-                }
-                ed.field.reset();
-               
-                cell.hide();
-                
-                (function(){ // complex but required for focus issues in safari, ie and opera
-                    ed.row = row;
-                    ed.col = col;
-                    ed.record = r;
-                    ed.on("complete",   this.onEditComplete,        this,       {single: true});
-                    ed.on("specialkey", this.selModel.onEditorKey,  this.selModel);
-                    this.activeEditor = ed;
-                    var v = r.data[field];
-                    ed.startEdit(this.view.getCell(row, col), v);
-                    // combo's with 'displayField and name set
-                    if (ed.field.displayField && ed.field.name) {
-                        ed.field.el.dom.value = r.data[ed.field.name];
-                    }
-                    
-                    
-                }).defer(50, this);
-            }
-        }
+    onColumnResize : function(){
+        this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
+        this.autoSize();
     },
-        
     /**
-     * Stops any active editing
+     * Sets the data for the Grid
+     * accepts a Key => Value object of all the elements avaiable.
+     * @param {Object} data  to appear in grid.
      */
-    stopEditing : function(){
-        if(this.activeEditor){
-            this.activeEditor.completeEdit();
-        }
-        this.activeEditor = null;
+    setSource : function(source){
+        this.store.setSource(source);
+        //this.autoSize();
     },
-       
-        /**
-     * Called to get grid's drag proxy text, by default returns this.ddText.
-     * @return {String}
+    /**
+     * Gets all the data from the grid.
+     * @return {Object} data  data stored in grid
      */
-    getDragDropText : function(){
-        var count = this.selModel.getSelectedCell() ? 1 : 0;
-        return String.format(this.ddText, count, count == 1 ? '' : 's');
+    getSource : function(){
+        return this.store.getSource();
     }
-       
 });/*
- * 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">
+  
+ * Licence LGPL
  */
-
-// private - not really -- you end up using it !
-// This is a support class used internally by the Grid components
-
 /**
- * @class Roo.grid.GridEditor
- * @extends Roo.Editor
- * Class for creating and editable grid elements.
- * @param {Object} config any settings (must include field)
+ * @class Roo.grid.Calendar
+ * @extends Roo.util.Grid
+ * This class extends the Grid to provide a calendar widget
+ * <br><br>Usage:<pre><code>
+ var grid = new Roo.grid.Calendar("my-container-id", {
+     ds: myDataStore,
+     cm: myColModel,
+     selModel: mySelectionModel,
+     autoSizeColumns: true,
+     monitorWindowResize: false,
+     trackMouseOver: true
+     eventstore : real data store..
+ });
+ // set any options
+ grid.render();
+  
+  * @constructor
+ * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
+ * The container MUST have some type of size defined for the grid to fill. The container will be
+ * automatically set to position relative if it isn't already.
+ * @param {Object} config A config object that sets properties on this grid.
  */
-Roo.grid.GridEditor = function(field, config){
-    if (!config && field.field) {
-        config = field;
-        field = Roo.factory(config.field, Roo.form);
+Roo.grid.Calendar = function(container, config){
+       // initialize the container
+       this.container = Roo.get(container);
+       this.container.update("");
+       this.container.setStyle("overflow", "hidden");
+    this.container.addClass('x-grid-container');
+
+    this.id = this.container.id;
+
+    Roo.apply(this, config);
+    // check and correct shorthanded configs
+    
+    var rows = [];
+    var d =1;
+    for (var r = 0;r < 6;r++) {
+        
+        rows[r]=[];
+        for (var c =0;c < 7;c++) {
+            rows[r][c]= '';
+        }
     }
-    Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
-    field.monitorTab = false;
-};
+    if (this.eventStore) {
+        this.eventStore= Roo.factory(this.eventStore, Roo.data);
+        this.eventStore.on('load',this.onLoad, this);
+        this.eventStore.on('beforeload',this.clearEvents, this);
+         
+    }
+    
+    this.dataSource = new Roo.data.Store({
+            proxy: new Roo.data.MemoryProxy(rows),
+            reader: new Roo.data.ArrayReader({}, [
+                   'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
+    });
 
-Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
+    this.dataSource.load();
+    this.ds = this.dataSource;
+    this.ds.xmodule = this.xmodule || false;
     
-    /**
-     * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
-     */
     
-    alignment: "tl-tl",
-    autoSize: "width",
-    hideEl : false,
-    cls: "x-small-editor x-grid-editor",
-    shim:false,
-    shadow:"frame"
-});/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-  
+    var cellRender = function(v,x,r)
+    {
+        return String.format(
+            '<div class="fc-day  fc-widget-content"><div>' +
+                '<div class="fc-event-container"></div>' +
+                '<div class="fc-day-number">{0}</div>'+
+                
+                '<div class="fc-day-content"><div style="position:relative"></div></div>' +
+            '</div></div>', v);
+    
+    }
+    
+    
+    this.colModel = new Roo.grid.ColumnModel( [
+        {
+            xtype: 'ColumnModel',
+            xns: Roo.grid,
+            dataIndex : 'weekday0',
+            header : 'Sunday',
+            renderer : cellRender
+        },
+        {
+            xtype: 'ColumnModel',
+            xns: Roo.grid,
+            dataIndex : 'weekday1',
+            header : 'Monday',
+            renderer : cellRender
+        },
+        {
+            xtype: 'ColumnModel',
+            xns: Roo.grid,
+            dataIndex : 'weekday2',
+            header : 'Tuesday',
+            renderer : cellRender
+        },
+        {
+            xtype: 'ColumnModel',
+            xns: Roo.grid,
+            dataIndex : 'weekday3',
+            header : 'Wednesday',
+            renderer : cellRender
+        },
+        {
+            xtype: 'ColumnModel',
+            xns: Roo.grid,
+            dataIndex : 'weekday4',
+            header : 'Thursday',
+            renderer : cellRender
+        },
+        {
+            xtype: 'ColumnModel',
+            xns: Roo.grid,
+            dataIndex : 'weekday5',
+            header : 'Friday',
+            renderer : cellRender
+        },
+        {
+            xtype: 'ColumnModel',
+            xns: Roo.grid,
+            dataIndex : 'weekday6',
+            header : 'Saturday',
+            renderer : cellRender
+        }
+    ]);
+    this.cm = this.colModel;
+    this.cm.xmodule = this.xmodule || false;
+        
+          
+    //this.selModel = new Roo.grid.CellSelectionModel();
+    //this.sm = this.selModel;
+    //this.selModel.init(this);
+    
+    
+    if(this.width){
+        this.container.setWidth(this.width);
+    }
 
-  
-Roo.grid.PropertyRecord = Roo.data.Record.create([
-    {name:'name',type:'string'},  'value'
-]);
+    if(this.height){
+        this.container.setHeight(this.height);
+    }
+    /** @private */
+       this.addEvents({
+        // raw events
+        /**
+         * @event click
+         * The raw click event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "click" : true,
+        /**
+         * @event dblclick
+         * The raw dblclick event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "dblclick" : true,
+        /**
+         * @event contextmenu
+         * The raw contextmenu event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "contextmenu" : true,
+        /**
+         * @event mousedown
+         * The raw mousedown event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "mousedown" : true,
+        /**
+         * @event mouseup
+         * The raw mouseup event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "mouseup" : true,
+        /**
+         * @event mouseover
+         * The raw mouseover event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "mouseover" : true,
+        /**
+         * @event mouseout
+         * The raw mouseout event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "mouseout" : true,
+        /**
+         * @event keypress
+         * The raw keypress event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "keypress" : true,
+        /**
+         * @event keydown
+         * The raw keydown event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "keydown" : true,
 
+        // custom events
 
-Roo.grid.PropertyStore = function(grid, source){
-    this.grid = grid;
-    this.store = new Roo.data.Store({
-        recordType : Roo.grid.PropertyRecord
+        /**
+         * @event cellclick
+         * Fires when a cell is clicked
+         * @param {Grid} this
+         * @param {Number} rowIndex
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "cellclick" : true,
+        /**
+         * @event celldblclick
+         * Fires when a cell is double clicked
+         * @param {Grid} this
+         * @param {Number} rowIndex
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "celldblclick" : true,
+        /**
+         * @event rowclick
+         * Fires when a row is clicked
+         * @param {Grid} this
+         * @param {Number} rowIndex
+         * @param {Roo.EventObject} e
+         */
+        "rowclick" : true,
+        /**
+         * @event rowdblclick
+         * Fires when a row is double clicked
+         * @param {Grid} this
+         * @param {Number} rowIndex
+         * @param {Roo.EventObject} e
+         */
+        "rowdblclick" : true,
+        /**
+         * @event headerclick
+         * Fires when a header is clicked
+         * @param {Grid} this
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "headerclick" : true,
+        /**
+         * @event headerdblclick
+         * Fires when a header cell is double clicked
+         * @param {Grid} this
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "headerdblclick" : true,
+        /**
+         * @event rowcontextmenu
+         * Fires when a row is right clicked
+         * @param {Grid} this
+         * @param {Number} rowIndex
+         * @param {Roo.EventObject} e
+         */
+        "rowcontextmenu" : true,
+        /**
+         * @event cellcontextmenu
+         * Fires when a cell is right clicked
+         * @param {Grid} this
+         * @param {Number} rowIndex
+         * @param {Number} cellIndex
+         * @param {Roo.EventObject} e
+         */
+         "cellcontextmenu" : true,
+        /**
+         * @event headercontextmenu
+         * Fires when a header is right clicked
+         * @param {Grid} this
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "headercontextmenu" : true,
+        /**
+         * @event bodyscroll
+         * Fires when the body element is scrolled
+         * @param {Number} scrollLeft
+         * @param {Number} scrollTop
+         */
+        "bodyscroll" : true,
+        /**
+         * @event columnresize
+         * Fires when the user resizes a column
+         * @param {Number} columnIndex
+         * @param {Number} newSize
+         */
+        "columnresize" : true,
+        /**
+         * @event columnmove
+         * Fires when the user moves a column
+         * @param {Number} oldIndex
+         * @param {Number} newIndex
+         */
+        "columnmove" : true,
+        /**
+         * @event startdrag
+         * Fires when row(s) start being dragged
+         * @param {Grid} this
+         * @param {Roo.GridDD} dd The drag drop object
+         * @param {event} e The raw browser event
+         */
+        "startdrag" : true,
+        /**
+         * @event enddrag
+         * Fires when a drag operation is complete
+         * @param {Grid} this
+         * @param {Roo.GridDD} dd The drag drop object
+         * @param {event} e The raw browser event
+         */
+        "enddrag" : true,
+        /**
+         * @event dragdrop
+         * Fires when dragged row(s) are dropped on a valid DD target
+         * @param {Grid} this
+         * @param {Roo.GridDD} dd The drag drop object
+         * @param {String} targetId The target drag drop object
+         * @param {event} e The raw browser event
+         */
+        "dragdrop" : true,
+        /**
+         * @event dragover
+         * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
+         * @param {Grid} this
+         * @param {Roo.GridDD} dd The drag drop object
+         * @param {String} targetId The target drag drop object
+         * @param {event} e The raw browser event
+         */
+        "dragover" : true,
+        /**
+         * @event dragenter
+         *  Fires when the dragged row(s) first cross another DD target while being dragged
+         * @param {Grid} this
+         * @param {Roo.GridDD} dd The drag drop object
+         * @param {String} targetId The target drag drop object
+         * @param {event} e The raw browser event
+         */
+        "dragenter" : true,
+        /**
+         * @event dragout
+         * Fires when the dragged row(s) leave another DD target while being dragged
+         * @param {Grid} this
+         * @param {Roo.GridDD} dd The drag drop object
+         * @param {String} targetId The target drag drop object
+         * @param {event} e The raw browser event
+         */
+        "dragout" : true,
+        /**
+         * @event rowclass
+         * Fires when a row is rendered, so you can change add a style to it.
+         * @param {GridView} gridview   The grid view
+         * @param {Object} rowcfg   contains record  rowIndex and rowClass - set rowClass to add a style.
+         */
+        'rowclass' : true,
+
+        /**
+         * @event render
+         * Fires when the grid is rendered
+         * @param {Grid} grid
+         */
+        'render' : true,
+            /**
+            * @event select
+            * Fires when a date is selected
+            * @param {DatePicker} this
+            * @param {Date} date The selected date
+            */
+        'select': true,
+        /**
+            * @event monthchange
+            * Fires when the displayed month changes 
+            * @param {DatePicker} this
+            * @param {Date} date The selected month
+            */
+        'monthchange': true,
+        /**
+            * @event evententer
+            * Fires when mouse over an event
+            * @param {Calendar} this
+            * @param {event} Event
+            */
+        'evententer': true,
+        /**
+            * @event eventleave
+            * Fires when the mouse leaves an
+            * @param {Calendar} this
+            * @param {event}
+            */
+        'eventleave': true,
+        /**
+            * @event eventclick
+            * Fires when the mouse click an
+            * @param {Calendar} this
+            * @param {event}
+            */
+        'eventclick': true,
+        /**
+            * @event eventrender
+            * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
+            * @param {Calendar} this
+            * @param {data} data to be modified
+            */
+        'eventrender': true
+        
     });
-    this.store.on('update', this.onUpdate,  this);
-    if(source){
-        this.setSource(source);
+
+    Roo.grid.Grid.superclass.constructor.call(this);
+    this.on('render', function() {
+        this.view.el.addClass('x-grid-cal'); 
+        
+        (function() { this.setDate(new Date()); }).defer(100,this); //default today..
+
+    },this);
+    
+    if (!Roo.grid.Calendar.style) {
+        Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
+            
+            
+            '.x-grid-cal .x-grid-col' :  {
+                height: 'auto !important',
+                'vertical-align': 'top'
+            },
+            '.x-grid-cal  .fc-event-hori' : {
+                height: '14px'
+            }
+             
+            
+        }, Roo.id());
     }
-    Roo.grid.PropertyStore.superclass.constructor.call(this);
-};
 
+    
+    
+};
+Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
+    /**
+     * @cfg {Store} eventStore The store that loads events.
+     */
+    eventStore : 25,
 
+     
+    activeDate : false,
+    startDay : 0,
+    autoWidth : true,
+    monitorWindowResize : false,
 
-Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
-    setSource : function(o){
-        this.source = o;
-        this.store.removeAll();
-        var data = [];
-        for(var k in o){
-            if(this.isEditableValue(o[k])){
-                data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
-            }
+    
+    resizeColumns : function() {
+        var col = (this.view.el.getWidth() / 7) - 3;
+        // loop through cols, and setWidth
+        for(var i =0 ; i < 7 ; i++){
+            this.cm.setColumnWidth(i, col);
         }
-        this.store.loadRecords({records: data}, {}, true);
     },
+     setDate :function(date) {
+        
+        Roo.log('setDate?');
+        
+        this.resizeColumns();
+        var vd = this.activeDate;
+        this.activeDate = date;
+//        if(vd && this.el){
+//            var t = date.getTime();
+//            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
+//                Roo.log('using add remove');
+//                
+//                this.fireEvent('monthchange', this, date);
+//                
+//                this.cells.removeClass("fc-state-highlight");
+//                this.cells.each(function(c){
+//                   if(c.dateValue == t){
+//                       c.addClass("fc-state-highlight");
+//                       setTimeout(function(){
+//                            try{c.dom.firstChild.focus();}catch(e){}
+//                       }, 50);
+//                       return false;
+//                   }
+//                   return true;
+//                });
+//                return;
+//            }
+//        }
+        
+        var days = date.getDaysInMonth();
+        
+        var firstOfMonth = date.getFirstDateOfMonth();
+        var startingPos = firstOfMonth.getDay()-this.startDay;
+        
+        if(startingPos < this.startDay){
+            startingPos += 7;
+        }
+        
+        var pm = date.add(Date.MONTH, -1);
+        var prevStart = pm.getDaysInMonth()-startingPos;
+//        
+        
+        
+        this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
+        
+        this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
+        //this.cells.addClassOnOver('fc-state-hover');
+        
+        var cells = this.cells.elements;
+        var textEls = this.textNodes;
+        
+        //Roo.each(cells, function(cell){
+        //    cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
+        //});
+        
+        days += startingPos;
 
-    onUpdate : function(ds, record, type){
-        if(type == Roo.data.Record.EDIT){
-            var v = record.data['value'];
-            var oldValue = record.modified['value'];
-            if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
-                this.source[record.id] = v;
-                record.commit();
-                this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
-            }else{
-                record.reject();
+        // convert everything to numbers so it's fast
+        var day = 86400000;
+        var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
+        //Roo.log(d);
+        //Roo.log(pm);
+        //Roo.log(prevStart);
+        
+        var today = new Date().clearTime().getTime();
+        var sel = date.clearTime().getTime();
+        var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
+        var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
+        var ddMatch = this.disabledDatesRE;
+        var ddText = this.disabledDatesText;
+        var ddays = this.disabledDays ? this.disabledDays.join("") : false;
+        var ddaysText = this.disabledDaysText;
+        var format = this.format;
+        
+        var setCellClass = function(cal, cell){
+            
+            //Roo.log('set Cell Class');
+            cell.title = "";
+            var t = d.getTime();
+            
+            //Roo.log(d);
+            
+            
+            cell.dateValue = t;
+            if(t == today){
+                cell.className += " fc-today";
+                cell.className += " fc-state-highlight";
+                cell.title = cal.todayText;
             }
-        }
-    },
+            if(t == sel){
+                // disable highlight in other month..
+                cell.className += " fc-state-highlight";
+                
+            }
+            // disabling
+            if(t < min) {
+                //cell.className = " fc-state-disabled";
+                cell.title = cal.minText;
+                return;
+            }
+            if(t > max) {
+                //cell.className = " fc-state-disabled";
+                cell.title = cal.maxText;
+                return;
+            }
+            if(ddays){
+                if(ddays.indexOf(d.getDay()) != -1){
+                    // cell.title = ddaysText;
+                   // cell.className = " fc-state-disabled";
+                }
+            }
+            if(ddMatch && format){
+                var fvalue = d.dateFormat(format);
+                if(ddMatch.test(fvalue)){
+                    cell.title = ddText.replace("%0", fvalue);
+                   cell.className = " fc-state-disabled";
+                }
+            }
+            
+            if (!cell.initialClassName) {
+                cell.initialClassName = cell.dom.className;
+            }
+            
+            cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
+        };
 
-    getProperty : function(row){
-       return this.store.getAt(row);
+        var i = 0;
+        
+        for(; i < startingPos; i++) {
+            cells[i].dayName =  (++prevStart);
+            Roo.log(textEls[i]);
+            d.setDate(d.getDate()+1);
+            
+            //cells[i].className = "fc-past fc-other-month";
+            setCellClass(this, cells[i]);
+        }
+        
+        var intDay = 0;
+        
+        for(; i < days; i++){
+            intDay = i - startingPos + 1;
+            cells[i].dayName =  (intDay);
+            d.setDate(d.getDate()+1);
+            
+            cells[i].className = ''; // "x-date-active";
+            setCellClass(this, cells[i]);
+        }
+        var extraDays = 0;
+        
+        for(; i < 42; i++) {
+            //textEls[i].innerHTML = (++extraDays);
+            
+            d.setDate(d.getDate()+1);
+            cells[i].dayName = (++extraDays);
+            cells[i].className = "fc-future fc-other-month";
+            setCellClass(this, cells[i]);
+        }
+        
+        //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
+        
+        var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
+        
+        // this will cause all the cells to mis
+        var rows= [];
+        var i =0;
+        for (var r = 0;r < 6;r++) {
+            for (var c =0;c < 7;c++) {
+                this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
+            }    
+        }
+        
+        this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
+        for(i=0;i<cells.length;i++) {
+            
+            this.cells.elements[i].dayName = cells[i].dayName ;
+            this.cells.elements[i].className = cells[i].className;
+            this.cells.elements[i].initialClassName = cells[i].initialClassName ;
+            this.cells.elements[i].title = cells[i].title ;
+            this.cells.elements[i].dateValue = cells[i].dateValue ;
+        }
+        
+        
+        
+        
+        //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
+        //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
+        
+        ////if(totalRows != 6){
+            //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
+           // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
+       // }
+        
+        this.fireEvent('monthchange', this, date);
+        
+        
     },
-
-    isEditableValue: function(val){
-        if(val && val instanceof Date){
-            return true;
-        }else if(typeof val == 'object' || typeof val == 'function'){
-            return false;
+ /**
+     * Returns the grid's SelectionModel.
+     * @return {SelectionModel}
+     */
+    getSelectionModel : function(){
+        if(!this.selModel){
+            this.selModel = new Roo.grid.CellSelectionModel();
         }
-        return true;
+        return this.selModel;
     },
 
-    setValue : function(prop, value){
-        this.source[prop] = value;
-        this.store.getById(prop).set('value', value);
+    load: function() {
+        this.eventStore.load()
+        
+        
+        
     },
-
-    getSource : function(){
-        return this.source;
-    }
-});
-
-Roo.grid.PropertyColumnModel = function(grid, store){
-    this.grid = grid;
-    var g = Roo.grid;
-    g.PropertyColumnModel.superclass.constructor.call(this, [
-        {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
-        {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
-    ]);
-    this.store = store;
-    this.bselect = Roo.DomHelper.append(document.body, {
-        tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
-            {tag: 'option', value: 'true', html: 'true'},
-            {tag: 'option', value: 'false', html: 'false'}
-        ]
-    });
-    Roo.id(this.bselect);
-    var f = Roo.form;
-    this.editors = {
-        'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
-        'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
-        'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
-        'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
-        'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
-    };
-    this.renderCellDelegate = this.renderCell.createDelegate(this);
-    this.renderPropDelegate = this.renderProp.createDelegate(this);
-};
-
-Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
-    
     
-    nameText : 'Name',
-    valueText : 'Value',
-    
-    dateFormat : 'm/j/Y',
-    
-    
-    renderDate : function(dateVal){
-        return dateVal.dateFormat(this.dateFormat);
-    },
-
-    renderBool : function(bVal){
-        return bVal ? 'true' : 'false';
-    },
-
-    isCellEditable : function(colIndex, rowIndex){
-        return colIndex == 1;
-    },
-
-    getRenderer : function(col){
-        return col == 1 ?
-            this.renderCellDelegate : this.renderPropDelegate;
+    findCell : function(dt) {
+        dt = dt.clearTime().getTime();
+        var ret = false;
+        this.cells.each(function(c){
+            //Roo.log("check " +c.dateValue + '?=' + dt);
+            if(c.dateValue == dt){
+                ret = c;
+                return false;
+            }
+            return true;
+        });
+        
+        return ret;
     },
-
-    renderProp : function(v){
-        return this.getPropertyName(v);
+    
+    findCells : function(rec) {
+        var s = rec.data.start_dt.clone().clearTime().getTime();
+       // Roo.log(s);
+        var e= rec.data.end_dt.clone().clearTime().getTime();
+       // Roo.log(e);
+        var ret = [];
+        this.cells.each(function(c){
+             ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
+            
+            if(c.dateValue > e){
+                return ;
+            }
+            if(c.dateValue < s){
+                return ;
+            }
+            ret.push(c);
+        });
+        
+        return ret;    
     },
-
-    renderCell : function(val){
-        var rv = val;
-        if(val instanceof Date){
-            rv = this.renderDate(val);
-        }else if(typeof val == 'boolean'){
-            rv = this.renderBool(val);
+    
+    findBestRow: function(cells)
+    {
+        var ret = 0;
+        
+        for (var i =0 ; i < cells.length;i++) {
+            ret  = Math.max(cells[i].rows || 0,ret);
         }
-        return Roo.util.Format.htmlEncode(rv);
-    },
-
-    getPropertyName : function(name){
-        var pn = this.grid.propertyNames;
-        return pn && pn[name] ? pn[name] : name;
+        return ret;
+        
     },
-
-    getCellEditor : function(colIndex, rowIndex){
-        var p = this.store.getProperty(rowIndex);
-        var n = p.data['name'], val = p.data['value'];
+    
+    
+    addItem : function(rec)
+    {
+        // look for vertical location slot in
+        var cells = this.findCells(rec);
         
-        if(typeof(this.grid.customEditors[n]) == 'string'){
-            return this.editors[this.grid.customEditors[n]];
+        rec.row = this.findBestRow(cells);
+        
+        // work out the location.
+        
+        var crow = false;
+        var rows = [];
+        for(var i =0; i < cells.length; i++) {
+            if (!crow) {
+                crow = {
+                    start : cells[i],
+                    end :  cells[i]
+                };
+                continue;
+            }
+            if (crow.start.getY() == cells[i].getY()) {
+                // on same row.
+                crow.end = cells[i];
+                continue;
+            }
+            // different row.
+            rows.push(crow);
+            crow = {
+                start: cells[i],
+                end : cells[i]
+            };
+            
         }
-        if(typeof(this.grid.customEditors[n]) != 'undefined'){
-            return this.grid.customEditors[n];
+        
+        rows.push(crow);
+        rec.els = [];
+        rec.rows = rows;
+        rec.cells = cells;
+        for (var i = 0; i < cells.length;i++) {
+            cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
+            
         }
-        if(val instanceof Date){
-            return this.editors['date'];
-        }else if(typeof val == 'number'){
-            return this.editors['number'];
-        }else if(typeof val == 'boolean'){
-            return this.editors['boolean'];
-        }else{
-            return this.editors['string'];
+        
+        
+    },
+    
+    clearEvents: function() {
+        
+        if (!this.eventStore.getCount()) {
+            return;
         }
-    }
-});
-
-/**
- * @class Roo.grid.PropertyGrid
- * @extends Roo.grid.EditorGrid
- * This class represents the  interface of a component based property grid control.
- * <br><br>Usage:<pre><code>
- var grid = new Roo.grid.PropertyGrid("my-container-id", {
-      
- });
- // set any options
- grid.render();
- * </code></pre>
-  
- * @constructor
- * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
- * The container MUST have some type of size defined for the grid to fill. The container will be
- * automatically set to position relative if it isn't already.
- * @param {Object} config A config object that sets properties on this grid.
- */
-Roo.grid.PropertyGrid = function(container, config){
-    config = config || {};
-    var store = new Roo.grid.PropertyStore(this);
-    this.store = store;
-    var cm = new Roo.grid.PropertyColumnModel(this, store);
-    store.store.sort('name', 'ASC');
-    Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
-        ds: store.store,
-        cm: cm,
-        enableColLock:false,
-        enableColumnMove:false,
-        stripeRows:false,
-        trackMouseOver: false,
-        clicksToEdit:1
-    }, config));
-    this.getGridEl().addClass('x-props-grid');
-    this.lastEditRow = null;
-    this.on('columnresize', this.onColumnResize, this);
-    this.addEvents({
-         /**
-            * @event beforepropertychange
-            * Fires before a property changes (return false to stop?)
-            * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
-            * @param {String} id Record Id
-            * @param {String} newval New Value
-         * @param {String} oldval Old Value
-            */
-        "beforepropertychange": true,
-        /**
-            * @event propertychange
-            * Fires after a property changes
-            * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
-            * @param {String} id Record Id
-            * @param {String} newval New Value
-         * @param {String} oldval Old Value
-            */
-        "propertychange": true
-    });
-    this.customEditors = this.customEditors || {};
-};
-Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
+        // reset number of rows in cells.
+        Roo.each(this.cells.elements, function(c){
+            c.rows = 0;
+        });
+        
+        this.eventStore.each(function(e) {
+            this.clearEvent(e);
+        },this);
+        
+    },
     
-     /**
-     * @cfg {Object} customEditors map of colnames=> custom editors.
-     * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
-     * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
-     * false disables editing of the field.
-        */
+    clearEvent : function(ev)
+    {
+        if (ev.els) {
+            Roo.each(ev.els, function(el) {
+                el.un('mouseenter' ,this.onEventEnter, this);
+                el.un('mouseleave' ,this.onEventLeave, this);
+                el.remove();
+            },this);
+            ev.els = [];
+        }
+    },
     
-      /**
-     * @cfg {Object} propertyNames map of property Names to their displayed value
-        */
     
-    render : function(){
-        Roo.grid.PropertyGrid.superclass.render.call(this);
-        this.autoSize.defer(100, this);
+    renderEvent : function(ev,ctr) {
+        if (!ctr) {
+             ctr = this.view.el.select('.fc-event-container',true).first();
+        }
+        
+         
+        this.clearEvent(ev);
+            //code
+       
+        
+        
+        ev.els = [];
+        var cells = ev.cells;
+        var rows = ev.rows;
+        this.fireEvent('eventrender', this, ev);
+        
+        for(var i =0; i < rows.length; i++) {
+            
+            cls = '';
+            if (i == 0) {
+                cls += ' fc-event-start';
+            }
+            if ((i+1) == rows.length) {
+                cls += ' fc-event-end';
+            }
+            
+            //Roo.log(ev.data);
+            // how many rows should it span..
+            var cg = this.eventTmpl.append(ctr,Roo.apply({
+                fccls : cls
+                
+            }, ev.data) , true);
+            
+            
+            cg.on('mouseenter' ,this.onEventEnter, this, ev);
+            cg.on('mouseleave' ,this.onEventLeave, this, ev);
+            cg.on('click', this.onEventClick, this, ev);
+            
+            ev.els.push(cg);
+            
+            var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
+            var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
+            //Roo.log(cg);
+             
+            cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);    
+            cg.setWidth(ebox.right - sbox.x -2);
+        }
     },
-
-    autoSize : function(){
-        Roo.grid.PropertyGrid.superclass.autoSize.call(this);
-        if(this.view){
-            this.view.fitColumns();
+    
+    renderEvents: function()
+    {   
+        // first make sure there is enough space..
+        
+        if (!this.eventTmpl) {
+            this.eventTmpl = new Roo.Template(
+                '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}"  style="position: absolute" unselectable="on">' +
+                    '<div class="fc-event-inner">' +
+                        '<span class="fc-event-time">{time}</span>' +
+                        '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
+                    '</div>' +
+                    '<div class="ui-resizable-heandle ui-resizable-e">&nbsp;&nbsp;&nbsp;</div>' +
+                '</div>'
+            );
+                
         }
+               
+        
+        
+        this.cells.each(function(c) {
+            //Roo.log(c.select('.fc-day-content div',true).first());
+            c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
+        });
+        
+        var ctr = this.view.el.select('.fc-event-container',true).first();
+        
+        var cls;
+        this.eventStore.each(function(ev){
+            
+            this.renderEvent(ev);
+             
+             
+        }, this);
+        this.view.layout();
+        
     },
-
-    onColumnResize : function(){
-        this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
-        this.autoSize();
+    
+    onEventEnter: function (e, el,event,d) {
+        this.fireEvent('evententer', this, el, event);
     },
-    /**
-     * Sets the data for the Grid
-     * accepts a Key => Value object of all the elements avaiable.
-     * @param {Object} data  to appear in grid.
-     */
-    setSource : function(source){
-        this.store.setSource(source);
-        //this.autoSize();
+    
+    onEventLeave: function (e, el,event,d) {
+        this.fireEvent('eventleave', this, el, event);
     },
-    /**
-     * Gets all the data from the grid.
-     * @return {Object} data  data stored in grid
-     */
-    getSource : function(){
-        return this.store.getSource();
+    
+    onEventClick: function (e, el,event,d) {
+        this.fireEvent('eventclick', this, el, event);
+    },
+    
+    onMonthChange: function () {
+        this.store.load();
+    },
+    
+    onLoad: function () {
+        
+        //Roo.log('calendar onload');
+//         
+        if(this.eventStore.getCount() > 0){
+            
+           
+            
+            this.eventStore.each(function(d){
+                
+                
+                // FIXME..
+                var add =   d.data;
+                if (typeof(add.end_dt) == 'undefined')  {
+                    Roo.log("Missing End time in calendar data: ");
+                    Roo.log(d);
+                    return;
+                }
+                if (typeof(add.start_dt) == 'undefined')  {
+                    Roo.log("Missing Start time in calendar data: ");
+                    Roo.log(d);
+                    return;
+                }
+                add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
+                add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
+                add.id = add.id || d.id;
+                add.title = add.title || '??';
+                
+                this.addItem(d);
+                
+             
+            },this);
+        }
+        
+        this.renderEvents();
     }
-});/*
+    
+
+});
+/*
+ grid : {
+                xtype: 'Grid',
+                xns: Roo.grid,
+                listeners : {
+                    render : function ()
+                    {
+                        _this.grid = this;
+                        
+                        if (!this.view.el.hasClass('course-timesheet')) {
+                            this.view.el.addClass('course-timesheet');
+                        }
+                        if (this.tsStyle) {
+                            this.ds.load({});
+                            return; 
+                        }
+                        Roo.log('width');
+                        Roo.log(_this.grid.view.el.getWidth());
+                        
+                        
+                        this.tsStyle =  Roo.util.CSS.createStyleSheet({
+                            '.course-timesheet .x-grid-row' : {
+                                height: '80px'
+                            },
+                            '.x-grid-row td' : {
+                                'vertical-align' : 0
+                            },
+                            '.course-edit-link' : {
+                                'color' : 'blue',
+                                'text-overflow' : 'ellipsis',
+                                'overflow' : 'hidden',
+                                'white-space' : 'nowrap',
+                                'cursor' : 'pointer'
+                            },
+                            '.sub-link' : {
+                                'color' : 'green'
+                            },
+                            '.de-act-sup-link' : {
+                                'color' : 'purple',
+                                'text-decoration' : 'line-through'
+                            },
+                            '.de-act-link' : {
+                                'color' : 'red',
+                                'text-decoration' : 'line-through'
+                            },
+                            '.course-timesheet .course-highlight' : {
+                                'border-top-style': 'dashed !important',
+                                'border-bottom-bottom': 'dashed !important'
+                            },
+                            '.course-timesheet .course-item' : {
+                                'font-family'   : 'tahoma, arial, helvetica',
+                                'font-size'     : '11px',
+                                'overflow'      : 'hidden',
+                                'padding-left'  : '10px',
+                                'padding-right' : '10px',
+                                'padding-top' : '10px' 
+                            }
+                            
+                        }, Roo.id());
+                                this.ds.load({});
+                    }
+                },
+                autoWidth : true,
+                monitorWindowResize : false,
+                cellrenderer : function(v,x,r)
+                {
+                    return v;
+                },
+                sm : {
+                    xtype: 'CellSelectionModel',
+                    xns: Roo.grid
+                },
+                dataSource : {
+                    xtype: 'Store',
+                    xns: Roo.data,
+                    listeners : {
+                        beforeload : function (_self, options)
+                        {
+                            options.params = options.params || {};
+                            options.params._month = _this.monthField.getValue();
+                            options.params.limit = 9999;
+                            options.params['sort'] = 'when_dt';    
+                            options.params['dir'] = 'ASC';    
+                            this.proxy.loadResponse = this.loadResponse;
+                            Roo.log("load?");
+                            //this.addColumns();
+                        },
+                        load : function (_self, records, options)
+                        {
+                            _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
+                                // if you click on the translation.. you can edit it...
+                                var el = Roo.get(this);
+                                var id = el.dom.getAttribute('data-id');
+                                var d = el.dom.getAttribute('data-date');
+                                var t = el.dom.getAttribute('data-time');
+                                //var id = this.child('span').dom.textContent;
+                                
+                                //Roo.log(this);
+                                Pman.Dialog.CourseCalendar.show({
+                                    id : id,
+                                    when_d : d,
+                                    when_t : t,
+                                    productitem_active : id ? 1 : 0
+                                }, function() {
+                                    _this.grid.ds.load({});
+                                });
+                           
+                           });
+                           
+                           _this.panel.fireEvent('resize', [ '', '' ]);
+                        }
+                    },
+                    loadResponse : function(o, success, response){
+                            // this is overridden on before load..
+                            
+                            Roo.log("our code?");      
+                            //Roo.log(success);
+                            //Roo.log(response)
+                            delete this.activeRequest;
+                            if(!success){
+                                this.fireEvent("loadexception", this, o, response);
+                                o.request.callback.call(o.request.scope, null, o.request.arg, false);
+                                return;
+                            }
+                            var result;
+                            try {
+                                result = o.reader.read(response);
+                            }catch(e){
+                                Roo.log("load exception?");
+                                this.fireEvent("loadexception", this, o, response, e);
+                                o.request.callback.call(o.request.scope, null, o.request.arg, false);
+                                return;
+                            }
+                            Roo.log("ready...");        
+                            // loop through result.records;
+                            // and set this.tdate[date] = [] << array of records..
+                            _this.tdata  = {};
+                            Roo.each(result.records, function(r){
+                                //Roo.log(r.data);
+                                if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
+                                    _this.tdata[r.data.when_dt.format('j')] = [];
+                                }
+                                _this.tdata[r.data.when_dt.format('j')].push(r.data);
+                            });
+                            
+                            //Roo.log(_this.tdata);
+                            
+                            result.records = [];
+                            result.totalRecords = 6;
+                    
+                            // let's generate some duumy records for the rows.
+                            //var st = _this.dateField.getValue();
+                            
+                            // work out monday..
+                            //st = st.add(Date.DAY, -1 * st.format('w'));
+                            
+                            var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
+                            
+                            var firstOfMonth = date.getFirstDayOfMonth();
+                            var days = date.getDaysInMonth();
+                            var d = 1;
+                            var firstAdded = false;
+                            for (var i = 0; i < result.totalRecords ; i++) {
+                                //var d= st.add(Date.DAY, i);
+                                var row = {};
+                                var added = 0;
+                                for(var w = 0 ; w < 7 ; w++){
+                                    if(!firstAdded && firstOfMonth != w){
+                                        continue;
+                                    }
+                                    if(d > days){
+                                        continue;
+                                    }
+                                    firstAdded = true;
+                                    var dd = (d > 0 && d < 10) ? "0"+d : d;
+                                    row['weekday'+w] = String.format(
+                                                    '<span style="font-size: 16px;"><b>{0}</b></span>'+
+                                                    '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
+                                                    d,
+                                                    date.format('Y-m-')+dd
+                                                );
+                                    added++;
+                                    if(typeof(_this.tdata[d]) != 'undefined'){
+                                        Roo.each(_this.tdata[d], function(r){
+                                            var is_sub = '';
+                                            var deactive = '';
+                                            var id = r.id;
+                                            var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
+                                            if(r.parent_id*1>0){
+                                                is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
+                                                id = r.parent_id;
+                                            }
+                                            if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
+                                                deactive = 'de-act-link';
+                                            }
+                                            
+                                            row['weekday'+w] += String.format(
+                                                    '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
+                                                    id, //0
+                                                    r.product_id_name, //1
+                                                    r.when_dt.format('h:ia'), //2
+                                                    is_sub, //3
+                                                    deactive, //4
+                                                    desc // 5
+                                            );
+                                        });
+                                    }
+                                    d++;
+                                }
+                                
+                                // only do this if something added..
+                                if(added > 0){ 
+                                    result.records.push(_this.grid.dataSource.reader.newRow(row));
+                                }
+                                
+                                
+                                // push it twice. (second one with an hour..
+                                
+                            }
+                            //Roo.log(result);
+                            this.fireEvent("load", this, o, o.request.arg);
+                            o.request.callback.call(o.request.scope, result, o.request.arg, true);
+                        },
+                    sortInfo : {field: 'when_dt', direction : 'ASC' },
+                    proxy : {
+                        xtype: 'HttpProxy',
+                        xns: Roo.data,
+                        method : 'GET',
+                        url : baseURL + '/Roo/Shop_course.php'
+                    },
+                    reader : {
+                        xtype: 'JsonReader',
+                        xns: Roo.data,
+                        id : 'id',
+                        fields : [
+                            {
+                                'name': 'id',
+                                'type': 'int'
+                            },
+                            {
+                                'name': 'when_dt',
+                                'type': 'string'
+                            },
+                            {
+                                'name': 'end_dt',
+                                'type': 'string'
+                            },
+                            {
+                                'name': 'parent_id',
+                                'type': 'int'
+                            },
+                            {
+                                'name': 'product_id',
+                                'type': 'int'
+                            },
+                            {
+                                'name': 'productitem_id',
+                                'type': 'int'
+                            },
+                            {
+                                'name': 'guid',
+                                'type': 'int'
+                            }
+                        ]
+                    }
+                },
+                toolbar : {
+                    xtype: 'Toolbar',
+                    xns: Roo,
+                    items : [
+                        {
+                            xtype: 'Button',
+                            xns: Roo.Toolbar,
+                            listeners : {
+                                click : function (_self, e)
+                                {
+                                    var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
+                                    sd.setMonth(sd.getMonth()-1);
+                                    _this.monthField.setValue(sd.format('Y-m-d'));
+                                    _this.grid.ds.load({});
+                                }
+                            },
+                            text : "Back"
+                        },
+                        {
+                            xtype: 'Separator',
+                            xns: Roo.Toolbar
+                        },
+                        {
+                            xtype: 'MonthField',
+                            xns: Roo.form,
+                            listeners : {
+                                render : function (_self)
+                                {
+                                    _this.monthField = _self;
+                                   // _this.monthField.set  today
+                                },
+                                select : function (combo, date)
+                                {
+                                    _this.grid.ds.load({});
+                                }
+                            },
+                            value : (function() { return new Date(); })()
+                        },
+                        {
+                            xtype: 'Separator',
+                            xns: Roo.Toolbar
+                        },
+                        {
+                            xtype: 'TextItem',
+                            xns: Roo.Toolbar,
+                            text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
+                        },
+                        {
+                            xtype: 'Fill',
+                            xns: Roo.Toolbar
+                        },
+                        {
+                            xtype: 'Button',
+                            xns: Roo.Toolbar,
+                            listeners : {
+                                click : function (_self, e)
+                                {
+                                    var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
+                                    sd.setMonth(sd.getMonth()+1);
+                                    _this.monthField.setValue(sd.format('Y-m-d'));
+                                    _this.grid.ds.load({});
+                                }
+                            },
+                            text : "Next"
+                        }
+                    ]
+                },
+                 
+            }
+        };
+        
+        *//*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -39539,20 +38758,18 @@ Roo.LoadMask.prototype = {
         }
         */
     
-        
-        
-        this.el.unmask(this.removeMask);
+        (function() { this.el.unmask(this.removeMask); }).defer(50, this);
     },
     // private
     onLoad : function()
     {
-        this.el.unmask(this.removeMask);
+        (function() { this.el.unmask(this.removeMask); }).defer(50, this);
     },
 
     // private
     onBeforeLoad : function(){
         if(!this.disabled){
-            this.el.mask(this.msg, this.msgCls);
+            (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
         }
     },