Fix #5642 - Report designer - hebe
[roojs1] / Roo / form / BasicForm.js
index 06ddf74..a748bcb 100644 (file)
  * @param {Object} config Configuration options
  */
 Roo.form.BasicForm = function(el, config){
+    this.allItems = [];
+    this.childForms = [];
     Roo.apply(this, config);
     /*
      * The Roo.form.Field items in this form.
      * @type MixedCollection
      */
+     
+     
     this.items = new Roo.util.MixedCollection(false, function(o){
         return o.id || (o.id = Roo.id());
     });
@@ -78,10 +82,13 @@ Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
      * @cfg {Boolean} fileUpload
      * Set to true if this form is a file upload.
      */
+     
     /**
      * @cfg {Object} baseParams
      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
      */
+     /**
+     
     /**
      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
      */
@@ -95,20 +102,31 @@ Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
      * or setValues() data instead of when the form was first created.
      */
     trackResetOnLoad : false,
-
+    
+    
+    /**
+     * childForms - used for multi-tab forms
+     * @type {Array}
+     */
+    childForms : false,
     
     /**
-     * allFields - full list of fields.
+     * allItems - full list of fields.
      * @type {Array}
      */
-    allFields : false,
+    allItems : false,
     
     /**
      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
      * element by passing it or its id or mask the form itself by passing in true.
      * @type Mixed
      */
-    waitMsgTarget : undefined,
+    waitMsgTarget : false,
+    
+    /**
+     * @type Boolean
+     */
+    disableMask : false,
 
     // private
     initEl : function(el){
@@ -138,7 +156,7 @@ Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
     },
 
     /**
-     * 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(){
@@ -151,7 +169,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
@@ -231,23 +281,27 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
     // private
     beforeAction : function(action){
         var o = action.options;
-        if(o.waitMsg){
+        
+        if(!this.disableMask) {
             if(this.waitMsgTarget === true){
-                this.el.mask(o.waitMsg, 'x-mask-loading');
+                this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
             }else if(this.waitMsgTarget){
                 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
-                this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
-            }else{
-                Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
+                this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
+            }else {
+                Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
             }
         }
+        
+         
     },
 
     // private
     afterAction : function(action, success){
         this.activeAction = null;
         var o = action.options;
-        if(o.waitMsg){
+        
+        if(!this.disableMask) {
             if(this.waitMsgTarget === true){
                 this.el.unmask();
             }else if(this.waitMsgTarget){
@@ -257,16 +311,56 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
                 Roo.MessageBox.hide();
             }
         }
+        
         if(success){
             if(o.reset){
                 this.reset();
             }
             Roo.callback(o.success, o.scope, [this, action]);
             this.fireEvent('actioncomplete', this, action);
+            
         }else{
+            
+            // failure condition..
+            // we have a scenario where updates need confirming.
+            // eg. if a locking scenario exists..
+            // we look for { errors : { needs_confirm : true }} in the response.
+            if (
+                (typeof(action.result) != 'undefined')  &&
+                (typeof(action.result.errors) != 'undefined')  &&
+                (typeof(action.result.errors.needs_confirm) != 'undefined')
+           ){
+                var _t = this;
+                Roo.MessageBox.confirm(
+                    "Change requires confirmation",
+                    action.result.errorMsg,
+                    function(r) {
+                        if (r != 'yes') {
+                            return;
+                        }
+                        _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
+                    }
+                    
+                );
+                
+                
+                
+                return;
+            }
+            
             Roo.callback(o.failure, o.scope, [this, action]);
+            // show an error message if no failed handler is set..
+            if (!this.hasListener('actionfailed')) {
+                Roo.MessageBox.alert("Error",
+                    (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
+                        action.result.errorMsg :
+                        "Saving Failed, please check your entries or try again"
+                );
+            }
+            
             this.fireEvent('actionfailed', this, action);
         }
+        
     },
 
     /**
@@ -287,7 +381,38 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
         return field || null;
     },
 
-
+    /**
+     * Add a secondary form to this one, 
+     * Used to provide tabbed forms. One form is primary, with hidden values 
+     * which mirror the elements from the other forms.
+     * 
+     * @param {Roo.form.Form} form to add.
+     * 
+     */
+    addForm : function(form)
+    {
+       
+        if (this.childForms.indexOf(form) > -1) {
+            // already added..
+            return;
+        }
+        this.childForms.push(form);
+        var n = '';
+        Roo.each(form.allItems, function (fe) {
+            
+            n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
+            if (this.findField(n)) { // already added..
+                return;
+            }
+            var add = new Roo.form.Hidden({
+                name : n
+            });
+            add.render(this.el);
+            
+            this.add( add );
+        }, this);
+        
+    },
     /**
      * Mark fields in this form invalid in bulk.
      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
@@ -310,6 +435,10 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
                 }
             }
         }
+        Roo.each(this.childForms || [], function (f) {
+            f.markInvalid(errors);
+        });
+        
         return this;
     },
 
@@ -360,12 +489,14 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
                 }
             }
         }
-        if (this.childForms) {
-            Roo.each(this.childForms, function (f) {
-                f.setValues(values);
-            });
-        }
+        this.resetHasChanged();
         
+        
+        Roo.each(this.childForms || [], function (f) {
+            f.setValues(values);
+            f.resetHasChanged();
+        });
+                
         return this;
     },
 
@@ -377,8 +508,9 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
      */
     getValues : function(asString){
         if (this.childForms) {
+            // copy values from the child forms
             Roo.each(this.childForms, function (f) {
-                f.setValues(values);
+                this.setValues(f.getValues());
             }, this);
         }
         
@@ -390,6 +522,55 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
         }
         return Roo.urlDecode(fs);
     },
+    
+    /**
+     * Returns the fields in this form as an object with key/value pairs. 
+     * This differs from getValues as it calls getValue on each child item, rather than using dom data.
+     * @return {Object}
+     */
+    getFieldValues : function(with_hidden)
+    {
+        if (this.childForms) {
+            // copy values from the child forms
+            // should this call getFieldValues - probably not as we do not currently copy
+            // hidden fields when we generate..
+            Roo.each(this.childForms, function (f) {
+                this.setValues(f.getValues());
+            }, this);
+        }
+        
+        var ret = {};
+        this.items.each(function(f){
+            if (!f.getName()) {
+                return;
+            }
+            var v = f.getValue();
+            if (f.inputType =='radio') {
+                if (typeof(ret[f.getName()]) == 'undefined') {
+                    ret[f.getName()] = ''; // empty..
+                }
+                
+                if (!f.el.dom.checked) {
+                    return;
+                    
+                }
+                v = f.el.dom.value;
+                
+            }
+            
+            // not sure if this supported any more..
+            if ((typeof(v) == 'object') && f.getRawValue) {
+                v = f.getRawValue() ; // dates..
+            }
+            // combo boxes where name != hiddenName...
+            if (f.name != f.getName()) {
+                ret[f.name] = f.getRawValue();
+            }
+            ret[f.getName()] = v;
+        });
+        
+        return ret;
+    },
 
     /**
      * Clears all invalid messages in this form.
@@ -399,6 +580,12 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
         this.items.each(function(f){
            f.clearInvalid();
         });
+        
+        Roo.each(this.childForms || [], function (f) {
+            f.clearInvalid();
+        });
+        
+        
         return this;
     },
 
@@ -410,6 +597,12 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
         this.items.each(function(f){
             f.reset();
         });
+        
+        Roo.each(this.childForms || [], function (f) {
+            f.reset();
+        });
+        this.resetHasChanged();
+        
         return this;
     },