Roo/form/ComboBoxArray.js
[roojs1] / roojs-ui-debug.js
index fad5666..1d73780 100644 (file)
@@ -3040,6 +3040,8 @@ Roo.dd.ScrollManager = function(){
     var dragEl = null;
     var proc = {};
     
+    
+    
     var onStop = function(e){
         dragEl = null;
         clearProc();
@@ -3074,6 +3076,7 @@ Roo.dd.ScrollManager = function(){
     };
     
     var startProc = function(el, dir){
+         Roo.log('scroll startproc');
         clearProc();
         proc.el = el;
         proc.dir = dir;
@@ -3081,6 +3084,7 @@ Roo.dd.ScrollManager = function(){
     };
     
     var onFire = function(e, isDrop){
+       
         if(isDrop || !ddm.dragCurrent){ return; }
         var dds = Roo.dd.ScrollManager;
         if(!dragEl || dragEl != ddm.dragCurrent){
@@ -3137,6 +3141,7 @@ Roo.dd.ScrollManager = function(){
                 el = Roo.get(el);
                 els[el.id] = el;
             }
+            Roo.dd.ScrollManager.els = els;
         },
         
         /**
@@ -3940,6 +3945,7 @@ Roo.dd.DropTarget = function(el, config){
          * 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
@@ -6671,6 +6677,8 @@ Roo.data.Node = function(attributes){
         this.id = Roo.id(null, "ynode-");
         this.attributes.id = this.id;
     }
+     
+    
     /**
      * All child nodes of this node. @type Array
      */
@@ -10328,6 +10336,15 @@ Roo.extend(Roo.DatePicker, Roo.Component, {
      */
     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);
@@ -10349,8 +10366,9 @@ Roo.extend(Roo.DatePicker, Roo.Component, {
         }
     },
 
-    // private
+    // 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>',
@@ -16928,8 +16946,8 @@ Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
         }
         this.getSelectionModel().init(this);
         if (!this.root) {
-            console.log("ROOT not set in tree");
-            return;
+            Roo.log("ROOT not set in tree");
+            return this;
         }
         this.root.render();
         if(!this.rootVisible){
@@ -18512,6 +18530,11 @@ Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
     * to be loaded.
     */
     /**
+    * @cfg {String} requestMethod either GET or POST
+    * defaults to POST (due to BC)
+    * to be loaded.
+    */
+    /**
     * @cfg {Object} baseParams (optional) An object containing properties which
     * specify HTTP parameters to be passed to each request for child nodes.
     */
@@ -18924,6 +18947,7 @@ Roo.tree.TreeDropZone = function(tree, config){
 
 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
     ddGroup : "TreeDD",
+    scroll:  true,
     
     expandDelay : 1000,
     
@@ -18975,7 +18999,8 @@ Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
         return overEvent.cancel === false && result !== false;
     },
     
-    getDropPoint : function(e, n, dd){
+    getDropPoint : function(e, n, dd)
+    {
         var tn = n.node;
         if(tn.isRoot){
             return tn.allowChildren !== false ? "append" : false; // always append for root
@@ -19004,11 +19029,14 @@ Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
         }
     },
     
-    onNodeEnter : function(n, dd, e, data){
+    onNodeEnter : function(n, dd, e, data)
+    {
         this.cancelExpand();
     },
     
-    onNodeOver : function(n, dd, e, data){
+    onNodeOver : function(n, dd, e, data)
+    {
+       
         var pt = this.getDropPoint(e, n, dd);
         var node = n.node;
         
@@ -19045,6 +19073,7 @@ Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
     },
     
     onNodeOut : function(n, dd, e, data){
+        
         this.cancelExpand();
         this.removeDropIndicators(n);
     },
@@ -19143,7 +19172,8 @@ Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
             data.node.ui.highlight();
         }
         this.hideProxy();
-    }    
+    } 
+    
 });
 
 }
@@ -19167,11 +19197,12 @@ Roo.tree.TreeDragZone = function(tree, config){
 
 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
     ddGroup : "TreeDD",
-    
+   
     onBeforeDrag : function(data, e){
         var n = data.node;
         return n && n.draggable && !n.disabled;
     },
+     
     
     onInitDrag : function(e){
         var data = this.dragData;
@@ -19187,6 +19218,8 @@ Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
     
     onEndDrag : function(data, e){
         this.tree.fireEvent("enddrag", this.tree, data.node, e);
+        
+        
     },
     
     onValidDrop : function(dd, e, id){
@@ -21039,10 +21072,9 @@ Roo.menu.DateMenu = function(config){
      * @param {Date} date
      */
     this.relayEvents(di, ["select"]);
-
     this.on('beforeshow', function(){
         if(this.picker){
-            this.picker.hideMonthPicker(true);
+            this.picker.hideMonthPicker(false);
         }
     }, this);
 };
@@ -22660,7 +22692,7 @@ Roo.extend(Roo.form.DateField, Roo.form.TriggerField,  {
     
 
     /**
-     * @cfg {bool} useIso
+     * @cfg {Boolean} useIso
      * if enabled, then the date field will use a hidden field to store the 
      * real value as iso formated date. default (false)
      */ 
@@ -22683,7 +22715,7 @@ Roo.extend(Roo.form.DateField, Roo.form.TriggerField,  {
             this.el.dom.removeAttribute('name'); 
             this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
                     'before', true);
-            this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
+            this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
             // prevent input submission
             this.hiddenName = this.name;
         }
@@ -22696,6 +22728,7 @@ Roo.extend(Roo.form.DateField, Roo.form.TriggerField,  {
     {
         value = this.formatDate(value);
         if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
+            Roo.log('super failed');
             return false;
         }
         if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
@@ -22704,6 +22737,7 @@ Roo.extend(Roo.form.DateField, Roo.form.TriggerField,  {
         var svalue = value;
         value = this.parseDate(value);
         if(!value){
+            Roo.log('parse date failed' + svalue);
             this.markInvalid(String.format(this.invalidText, svalue, this.format));
             return false;
         }
@@ -22745,7 +22779,9 @@ Roo.extend(Roo.form.DateField, Roo.form.TriggerField,  {
      */
     getValue : function(){
         
-        return  this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
+        return  this.hiddenField ?
+                this.hiddenField.value :
+                this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
     },
 
     /**
@@ -22774,6 +22810,10 @@ dateField.setValue('2006-5-4');
             this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
         }
         Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
+        // make sure the value field is always stored as a date..
+        this.value = this.parseDate(date);
+        
+        
     },
 
     // private
@@ -22782,6 +22822,9 @@ dateField.setValue('2006-5-4');
             return value;
         }
         var v = Date.parseDate(value, this.format);
+         if (!v && this.useIso) {
+            v = Date.parseDate(value, 'Y-m-d');
+        }
         if(!v && this.altFormats){
             if(!this.altFormatsArray){
                 this.altFormatsArray = this.altFormats.split("|");
@@ -22802,6 +22845,7 @@ dateField.setValue('2006-5-4');
     // private
     menuListeners : {
         select: function(m, d){
+            
             this.setValue(d);
             this.fireEvent('select', this, d);
         },
@@ -22834,7 +22878,7 @@ dateField.setValue('2006-5-4');
             disabledDatesText : this.disabledDatesText,
             disabledDays : this.disabledDays,
             disabledDaysText : this.disabledDaysText,
-            format : this.format,
+            format : this.useIso ? 'Y-m-d' : this.format,
             minText : String.format(this.minText, this.formatDate(this.minValue)),
             maxText : String.format(this.maxText, this.formatDate(this.maxValue))
         });
@@ -22870,6 +22914,406 @@ dateField.setValue('2006-5-4');
  * <script type="text/javascript">
  */
  
+/**
+ * @class Roo.form.MonthField
+ * @extends Roo.form.TriggerField
+ * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
+* @constructor
+* Create a new MonthField
+* @param {Object} config
+ */
+Roo.form.MonthField = function(config){
+    
+    Roo.form.MonthField.superclass.constructor.call(this, config);
+    
+      this.addEvents({
+         
+        /**
+         * @event select
+         * Fires when a date is selected
+            * @param {Roo.form.MonthFieeld} combo This combo box
+            * @param {Date} date The date selected
+            */
+        'select' : true
+         
+    });
+    
+    
+    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 += "|";
+        }
+        this.ddMatch = new RegExp(re + ")");
+    }
+};
+
+Roo.extend(Roo.form.MonthField, Roo.form.TriggerField,  {
+    /**
+     * @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 Y",
+    /**
+     * @cfg {String} altFormats
+     * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
+     * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
+     */
+    altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
+    /**
+     * @cfg {Array} disabledDays
+     * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
+     */
+    disabledDays : [0,1,2,3,4,5,6],
+    /**
+     * @cfg {String} disabledDaysText
+     * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
+     */
+    disabledDaysText : "Disabled",
+    /**
+     * @cfg {Array} disabledDates
+     * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
+     * expression so they are very powerful. Some examples:
+     * <ul>
+     * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
+     * <li>["03/08", "09/16"] would disable those days for every year</li>
+     * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
+     * <li>["03/../2006"] would disable every day in March 2006</li>
+     * <li>["^03"] would disable every day in every March</li>
+     * </ul>
+     * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
+     * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
+     */
+    disabledDates : null,
+    /**
+     * @cfg {String} disabledDatesText
+     * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
+     */
+    disabledDatesText : "Disabled",
+    /**
+     * @cfg {Date/String} minValue
+     * The minimum allowed date. Can be either a Javascript date object or a string date in a
+     * valid format (defaults to null).
+     */
+    minValue : null,
+    /**
+     * @cfg {Date/String} maxValue
+     * The maximum allowed date. Can be either a Javascript date object or a string date in a
+     * valid format (defaults to null).
+     */
+    maxValue : null,
+    /**
+     * @cfg {String} minText
+     * The error text to display when the date in the cell is before minValue (defaults to
+     * 'The date in this field must be after {minValue}').
+     */
+    minText : "The date in this field must be equal to or after {0}",
+    /**
+     * @cfg {String} maxTextf
+     * The error text to display when the date in the cell is after maxValue (defaults to
+     * 'The date in this field must be before {maxValue}').
+     */
+    maxText : "The date in this field must be equal to or before {0}",
+    /**
+     * @cfg {String} invalidText
+     * The error text to display when the date in the field is invalid (defaults to
+     * '{value} is not a valid date - it must be in the format {format}').
+     */
+    invalidText : "{0} is not a valid date - it must be in the format {1}",
+    /**
+     * @cfg {String} triggerClass
+     * An additional CSS class used to style the trigger button.  The trigger will always get the
+     * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
+     * which displays a calendar icon).
+     */
+    triggerClass : 'x-form-date-trigger',
+    
+
+    /**
+     * @cfg {Boolean} useIso
+     * if enabled, then the date field will use a hidden field to store the 
+     * real value as iso formated date. default (true)
+     */ 
+    useIso : true,
+    /**
+     * @cfg {String/Object} autoCreate
+     * A DomHelper element spec, or true for a default element spec (defaults to
+     * {tag: "input", type: "text", size: "10", autocomplete: "off"})
+     */ 
+    // private
+    defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
+    
+    // private
+    hiddenField: false,
+    
+    hideMonthPicker : false,
+    
+    onRender : function(ct, position)
+    {
+        Roo.form.MonthField.superclass.onRender.call(this, ct, position);
+        if (this.useIso) {
+            this.el.dom.removeAttribute('name'); 
+            this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
+                    'before', true);
+            this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
+            // prevent input submission
+            this.hiddenName = this.name;
+        }
+            
+            
+    },
+    
+    // private
+    validateValue : function(value)
+    {
+        value = this.formatDate(value);
+        if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
+            return false;
+        }
+        if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
+             return true;
+        }
+        var svalue = value;
+        value = this.parseDate(value);
+        if(!value){
+            this.markInvalid(String.format(this.invalidText, svalue, this.format));
+            return false;
+        }
+        var time = value.getTime();
+        if(this.minValue && time < this.minValue.getTime()){
+            this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
+            return false;
+        }
+        if(this.maxValue && time > this.maxValue.getTime()){
+            this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
+            return false;
+        }
+        /*if(this.disabledDays){
+            var day = value.getDay();
+            for(var i = 0; i < this.disabledDays.length; i++) {
+               if(day === this.disabledDays[i]){
+                   this.markInvalid(this.disabledDaysText);
+                    return false;
+               }
+            }
+        }
+        */
+        var fvalue = this.formatDate(value);
+        /*if(this.ddMatch && this.ddMatch.test(fvalue)){
+            this.markInvalid(String.format(this.disabledDatesText, fvalue));
+            return false;
+        }
+        */
+        return true;
+    },
+
+    // private
+    // Provides logic to override the default TriggerField.validateBlur which just returns true
+    validateBlur : function(){
+        return !this.menu || !this.menu.isVisible();
+    },
+
+    /**
+     * Returns the current date value of the date field.
+     * @return {Date} The date value
+     */
+    getValue : function(){
+        
+        
+        
+        return  this.hiddenField ?
+                this.hiddenField.value :
+                this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
+    },
+
+    /**
+     * Sets the value of the date field.  You can pass a date object or any string that can be parsed into a valid
+     * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
+     * (the default format used is "m/d/y").
+     * <br />Usage:
+     * <pre><code>
+//All of these calls set the same date value (May 4, 2006)
+
+//Pass a date object:
+var dt = new Date('5/4/06');
+monthField.setValue(dt);
+
+//Pass a date string (default format):
+monthField.setValue('5/4/06');
+
+//Pass a date string (custom format):
+monthField.format = 'Y-m-d';
+monthField.setValue('2006-5-4');
+</code></pre>
+     * @param {String/Date} date The date or valid date string
+     */
+    setValue : function(date){
+        Roo.log('month setValue' + date);
+        // can only be first of month..
+        
+        var val = this.parseDate(date);
+        
+        if (this.hiddenField) {
+            this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
+        }
+        Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
+        this.value = this.parseDate(date);
+    },
+
+    // private
+    parseDate : function(value){
+        if(!value || value instanceof Date){
+            value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
+            return value;
+        }
+        var v = Date.parseDate(value, this.format);
+        if (!v && this.useIso) {
+            v = Date.parseDate(value, 'Y-m-d');
+        }
+        if (v) {
+            // 
+            v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
+        }
+        
+        
+        if(!v && this.altFormats){
+            if(!this.altFormatsArray){
+                this.altFormatsArray = this.altFormats.split("|");
+            }
+            for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
+                v = Date.parseDate(value, this.altFormatsArray[i]);
+            }
+        }
+        return v;
+    },
+
+    // private
+    formatDate : function(date, fmt){
+        return (!date || !(date instanceof Date)) ?
+               date : date.dateFormat(fmt || this.format);
+    },
+
+    // private
+    menuListeners : {
+        select: function(m, d){
+            this.setValue(d);
+            this.fireEvent('select', this, d);
+        },
+        show : function(){ // retain focus styling
+            this.onFocus();
+        },
+        hide : function(){
+            this.focus.defer(10, this);
+            var ml = this.menuListeners;
+            this.menu.un("select", ml.select,  this);
+            this.menu.un("show", ml.show,  this);
+            this.menu.un("hide", ml.hide,  this);
+        }
+    },
+    // private
+    // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
+    onTriggerClick : function(){
+        if(this.disabled){
+            return;
+        }
+        if(this.menu == null){
+            this.menu = new Roo.menu.DateMenu();
+           
+        }
+        
+        Roo.apply(this.menu.picker,  {
+            
+            showClear: this.allowBlank,
+            minDate : this.minValue,
+            maxDate : this.maxValue,
+            disabledDatesRE : this.ddMatch,
+            disabledDatesText : this.disabledDatesText,
+            
+            format : this.useIso ? 'Y-m-d' : this.format,
+            minText : String.format(this.minText, this.formatDate(this.minValue)),
+            maxText : String.format(this.maxText, this.formatDate(this.maxValue))
+            
+        });
+         this.menu.on(Roo.apply({}, this.menuListeners, {
+            scope:this
+        }));
+       
+        
+        var m = this.menu;
+        var p = m.picker;
+        
+        // hide month picker get's called when we called by 'before hide';
+        
+        var ignorehide = true;
+        p.hideMonthPicker  = function(disableAnim){
+            if (ignorehide) {
+                return;
+            }
+             if(this.monthPicker){
+                Roo.log("hideMonthPicker called");
+                if(disableAnim === true){
+                    this.monthPicker.hide();
+                }else{
+                    this.monthPicker.slideOut('t', {duration:.2});
+                    p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
+                    p.fireEvent("select", this, this.value);
+                    m.hide();
+                }
+            }
+        }
+        
+        Roo.log('picker set value');
+        Roo.log(this.getValue());
+        p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
+        m.show(this.el, 'tl-bl?');
+        ignorehide  = false;
+        // this will trigger hideMonthPicker..
+        
+        
+        // hidden the day picker
+        Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
+        
+        
+        
+      
+        
+        p.showMonthPicker.defer(100, p);
+    
+        
+       
+    },
+
+    beforeBlur : function(){
+        var v = this.parseDate(this.getRawValue());
+        if(v){
+            this.setValue(v);
+        }
+    }
+
+    /** @cfg {Boolean} grow @hide */
+    /** @cfg {Number} growMin @hide */
+    /** @cfg {Number} growMax @hide */
+    /**
+     * @hide
+     * @method autoSize
+     */
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
 
 /**
  * @class Roo.form.ComboBox
@@ -23591,6 +24035,9 @@ Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
         this.setValue(this.originalValue);
         this.clearInvalid();
         this.lastData = false;
+        if (this.view) {
+            this.view.clearSelections();
+        }
     },
     // private
     findRecord : function(prop, value){
@@ -24195,10 +24642,11 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
     
     reset : function()
     {
-        Roo.form.ComboBoxArray.superclass.reset.call(this); 
+        //Roo.form.ComboBoxArray.superclass.reset.call(this); 
         this.items.each(function(f) {
            f.remove(); 
         });
+        this.el.dom.value = '';
         if (this.hiddenEl) {
             this.hiddenEl.dom.value = '';
         }
@@ -24211,8 +24659,11 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
     setValue: function(v) // not a valid action - must use addItems..
     {
          
+        this.reset();
         
-        if (this.store.isLocal) {
+        
+        
+        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;
@@ -24229,9 +24680,14 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
                 
                 this.addItem(add);
             }, this) 
-            
-                
-            
+             
+        }
+        if (typeof(v) == 'object') {
+            // then let's assume it's an array of objects..
+            Roo.each(v, function(l) {
+                this.addItem(l);
+            }, this);
+             
         }
         
         
@@ -24242,9 +24698,17 @@ Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
         this.reset();
         this.el.dom.value = v[this.displayField];
         this.hiddenEl.dom.value = v[this.valueField];
+        if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
+            return;
+        }
+        var kv = v[this.valueField];
+        var dv = v[this.displayField];
+        kv = typeof(kv) != 'string' ? '' : kv;
+        dv = typeof(dv) != 'string' ? '' : dv;
+        
         
-        var keys = v[this.valueField].split(',');
-        var display = v[this.displayField].split(',');
+        var keys = kv.split(',');
+        var display = dv.split(',');
         for (var i = 0 ; i < keys.length; i++) {
             
             add = {};
@@ -25722,6 +26186,9 @@ Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
                 return;
             }
+            if (v.match(/^#/)) {
+                return;
+            }
             Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
             node.removeAttribute(n);
             
@@ -25761,14 +26228,15 @@ Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
             //console.log(a);
             if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
                 node.removeAttribute(a.name);
-                return;
+                continue;
             }
             if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
                 cleanAttr(a.name,a.value); // fixme..
-                return;
+                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..
@@ -25782,6 +26250,7 @@ Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
                 if (a.value.match(/body/)) {
                     node.className = '';
                 }
+                continue;
             }
             
             // style cleanup!?
@@ -26276,7 +26745,7 @@ Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
         
         if (this.btns) {
             for(var i =0; i< this.btns.length;i++) {
-                var b = this.btns[i];
+                var b = Roo.factory(this.btns[i],Roo.form);
                 b.cls =  'x-edit-none';
                 b.scope = editor;
                 tb.add(b);
@@ -28400,6 +28869,7 @@ Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
                 }
                 if (!rdata || !rdata.success) {
                     Roo.log(rdata);
+                    Roo.MessageBox.alert(Roo.encode(rdata));
                     return;
                 }
                 var data = rdata.data;
@@ -32724,7 +33194,17 @@ Roo.ContentPanel = function(el, config, content){
         this.toolbar = new Roo.Toolbar(this.toolbar);
     }
     
+    // xtype created footer. - not sure if will work as we normally have to render first..
+    if (this.footer && !this.footer.el && this.footer.xtype) {
+        if (!this.wrapEl) {
+            this.wrapEl = this.el.wrap();
+        }
     
+        this.footer.container = this.wrapEl.createChild();
+         
+        this.footer = Roo.factory(this.footer, Roo);
+        
+    }
     
     if(this.resizeEl){
         this.resizeEl = Roo.get(this.resizeEl, true);
@@ -32912,7 +33392,9 @@ panel.load({
         return this.wrapEl || this.el;
     },
     
-    adjustForComponents : function(width, height){
+    adjustForComponents : function(width, height)
+    {
+        Roo.log('adjustForComponents ');
         if(this.resizeEl != this.el){
             width -= this.el.getFrameWidth('lr');
             height -= this.el.getFrameWidth('tb');
@@ -32922,6 +33404,15 @@ panel.load({
             height -= te.getHeight();
             te.setWidth(width);
         }
+        if(this.footer){
+            var te = this.footer.getEl();
+            Roo.log("footer:" + te.getHeight());
+            
+            height -= te.getHeight();
+            te.setWidth(width);
+        }
+        
+        
         if(this.adjustments){
             width += this.adjustments[0];
             height += this.adjustments[1];
@@ -33030,7 +33521,13 @@ layout.addxtype({
     addxtype : function(cfg) {
         // add form..
         if (cfg.xtype.match(/^Form$/)) {
-            var el = this.el.createChild();
+            
+            var el;
+            //if (this.footer) {
+            //    el = this.footer.container.insertSibling(false, 'before');
+            //} else {
+                el = this.el.createChild();
+            //}
 
             this.form = new  Roo.form.Form(cfg);
             
@@ -33356,12 +33853,14 @@ Roo.TreePanel = function(config){
         //console.log('render tree');
         this.tree.render();
     });
+    // this should not be needed.. - it's actually the 'el' that resizes?
+    // actuall it breaks the containerScroll - dragging nodes auto scroll at top
     
-    this.on('resize',  function (cp, w, h) {
-            this.tree.innerCt.setWidth(w);
-            this.tree.innerCt.setHeight(h);
-            this.tree.innerCt.setStyle('overflow-y', 'auto');
-    });
+    //this.on('resize',  function (cp, w, h) {
+    //        this.tree.innerCt.setWidth(w);
+    //        this.tree.innerCt.setHeight(h);
+    //        //this.tree.innerCt.setStyle('overflow-y', 'auto');
+    //});
 
         
     
@@ -38761,7 +39260,11 @@ Roo.extend(Roo.XComponent, Roo.util.Observable, {
             }
         }
         
-               
+               if (!this.parent.el) {
+                       // probably an old style ctor, which has been disabled.
+                       return;
+                       
+               }
                // The 'tree' method is  '_tree now' 
             
         var tree = this._tree ? this._tree() : this.tree();
@@ -38778,7 +39281,12 @@ Roo.extend(Roo.XComponent, Roo.util.Observable, {
 });
 
 Roo.apply(Roo.XComponent, {
-    
+    /**
+     * @property  hideProgress
+     * true to disable the building progress bar.. usefull on single page renders.
+     * @type Boolean
+     */
+    hideProgress : false,
     /**
      * @property  buildCompleted
      * True when the builder has completed building the interface.
@@ -38833,23 +39341,24 @@ Roo.apply(Roo.XComponent, {
      */
     register : function(obj) {
                
-               Roo.XComponent.event.fireEvent('register', obj);
-               switch(typeof(obj.disabled) ) {
-                       
-                       case 'undefined':
-                               break;
-                       
-                       case 'function':
-                               if ( obj.disabled() ) {
-                                       return;
-                               }
-                               break;
-                       default:
-                               if (obj.disabled) {
-                                       return;
-                               }
-                               break;
-               }
+        Roo.XComponent.event.fireEvent('register', obj);
+        switch(typeof(obj.disabled) ) {
+                
+            case 'undefined':
+                break;
+            
+            case 'function':
+                if ( obj.disabled() ) {
+                        return;
+                }
+                break;
+            
+            default:
+                if (obj.disabled) {
+                        return;
+                }
+                break;
+        }
                
         this.modules.push(obj);
          
@@ -38903,6 +39412,8 @@ Roo.apply(Roo.XComponent, {
         var _t = this;
         Roo.each(this.modules , function (obj)
         {
+            Roo.XComponent.event.fireEvent('beforebuild', obj);
+            
             var opar = obj.parent;
             try { 
                 obj.parent = this.toObject(opar);
@@ -38912,9 +39423,9 @@ Roo.apply(Roo.XComponent, {
             }
             
             if (!obj.parent) {
-                               Roo.debug && Roo.log("GOT top level module");
-                               Roo.debug && Roo.log(obj);
-                               obj.modules = new Roo.util.MixedCollection(false, 
+                Roo.debug && Roo.log("GOT top level module");
+                Roo.debug && Roo.log(obj);
+                obj.modules = new Roo.util.MixedCollection(false, 
                     function(o) { return o.order + '' }
                 );
                 this.topModule = obj;
@@ -38933,7 +39444,9 @@ Roo.apply(Roo.XComponent, {
                     function(o) { return o.order + '' }
                 );
             }
-            
+            if (obj.parent.disabled) {
+                obj.disabled = true;
+            }
             obj.parent.modules.add(obj);
         }, this);
     },
@@ -38956,24 +39469,26 @@ Roo.apply(Roo.XComponent, {
         // make a flat list in order of modules to build.
         var mods = this.topModule ? [ this.topModule ] : [];
                
-               // elmodules (is a list of DOM based modules )
-        Roo.each(this.elmodules,function(e) { mods.push(e) });
+       // elmodules (is a list of DOM based modules )
+        Roo.each(this.elmodules, function(e) {
+            mods.push(e)
+        });
 
         
         // add modules to their parents..
         var addMod = function(m) {
-                       Roo.debug && Roo.log("build Order: add: " + m.name);
+           Roo.debug && Roo.log("build Order: add: " + m.name);
             
-            mods.push(m);
-            if (m.modules) {
-                               Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
-                m.modules.keySort('ASC',  cmp );
-                               Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
+        mods.push(m);
+        if (m.modules && !m.disabled) {
+            Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
+            m.modules.keySort('ASC',  cmp );
+            Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
 
-                m.modules.each(addMod);
-            } else {
-                               Roo.debug && Roo.log("build Order: no child modules");
-                       }
+            m.modules.each(addMod);
+        } else {
+            Roo.debug && Roo.log("build Order: no child modules");
+           }
             // not sure if this is used any more..
             if (m.finalize) {
                 m.finalize.name = m.name + " (clean up) ";
@@ -39011,23 +39526,27 @@ Roo.apply(Roo.XComponent, {
         
         var msg = "Building Interface...";
         // flash it up as modal - so we store the mask!?
-        Roo.MessageBox.show({ title: 'loading' });
-        Roo.MessageBox.show({
-           title: "Please wait...",
-           msg: msg,
-           width:450,
-           progress:true,
-           closable:false,
-           modal: false
-          
-        });
+        if (!this.hideProgress) {
+            Roo.MessageBox.show({ title: 'loading' });
+            Roo.MessageBox.show({
+               title: "Please wait...",
+               msg: msg,
+               width:450,
+               progress:true,
+               closable:false,
+               modal: false
+              
+            });
+        }
         var total = mods.length;
         
         var _this = this;
         var progressRun = function() {
             if (!mods.length) {
                 Roo.debug && Roo.log('hide?');
-                Roo.MessageBox.hide();
+                if (!this.hideProgress) {
+                    Roo.MessageBox.hide();
+                }
                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
                 
                 // THE END...
@@ -39049,7 +39568,9 @@ Roo.apply(Roo.XComponent, {
                     " of " + total + 
                     (m.name ? (' - ' + m.name) : '');
                        Roo.debug && Roo.log(msg);
-            Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
+            if (!this.hideProgress) { 
+                Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
+            }
             
          
             // is the module disabled?
@@ -39106,6 +39627,14 @@ Roo.XComponent.event = new Roo.util.Observable({
                         * 
                         */
                        'register' : true,
+            /**
+                        * @event beforebuild
+                        * Fires before each Component is built
+                        * can be used to apply permissions.
+                        * @param {Roo.XComponent} c the component being registerd.
+                        * 
+                        */
+                       'beforebuild' : true,
                        /**
                         * @event buildcomplete
                         * Fires on the top level element when all elements have been built