# BasicForm.js

    /**
     * @class Ext.form.BasicForm
     * @extends Ext.util.Observable
     * Supplies the functionality to do "actions" on forms and initialize Ext.form.Field types on existing markup.
     * @constructor
     * @param {String/HTMLElement/Ext.Element} el The form element or its id
     * @param {Object} config Configuration options
     */
    Ext.form.BasicForm = function(el, config){
        Ext.apply(this, config);
        /*
         * The Ext.form.Field items in this form.
         * @type MixedCollection
         */
        this.items = new Ext.util.MixedCollection(false, function(o){
            return o.id || (o.id = Ext.id());
        });
        this.addEvents({
            /**
             * @event beforeaction
             * Fires before any action is performed. Return false to cancel the action.
             * @param {Form} this
             * @param {Action} action The action to be performed
             */
            beforeaction: true,
            /**
             * @event actionfailed
             * Fires when an action fails.
             * @param {Form} this
             * @param {Action} action The action that failed
             */
            actionfailed : true,
            /**
             * @event actioncomplete
             * Fires when an action is completed.
             * @param {Form} this
             * @param {Action} action The action that completed
             */
            actioncomplete : true
        });
        if(el){
            this.initEl(el);
        }
        Ext.form.BasicForm.superclass.constructor.call(this);
    };

    Ext.extend(Ext.form.BasicForm, Ext.util.Observable, {
        /**
         * @cfg {String} method
         * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
         */
    // holder
    /***
         * @cfg {DataReader} reader
         * An Ext.data.DataReader (e.g. {@link Ext.data.XmlReader}) to be used to read data when executing "load" actions.
         * This is optional as there is built-in support for processing JSON.
         */
    // holder
    /***
         * @cfg {DataReader} errorReader
         * An Ext.data.DataReader (e.g. {@link Ext.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
         * This is completely optional as there is built-in support for processing JSON.
         */
    // holder
    /***
         * @cfg {String} url
         * The URL to use for form actions if one isn't supplied in the action options.
         */
    // holder
    /***
         * @cfg {Boolean} fileUpload
         * Set to true if this form is a file upload.
         */
    // holder
    /***
         * @cfg {Object} baseParams
         * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
         */
    // holder
    /***
         * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
         */
        timeout: 30,

        // private
        activeAction : null,

        /**
         * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
         * or setValues() data instead of when the form was first created.
         */
        trackResetOnLoad : false,

        /**
         * By default wait messages are displayed with Ext.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,

        // private
        initEl : function(el){
            this.el = Ext.get(el);
            this.id = this.el.id || Ext.id();
            this.el.on('submit', this.onSubmit, this);
            this.el.addClass('x-form');
        },

        // private
        onSubmit : function(e){
            e.stopEvent();
        },

        /**
         * Returns true if client-side validation on the form is successful.
         * @return Boolean
         */
        isValid : function(){
            var valid = true;
            this.items.each(function(f){
               if(!f.validate()){
                   valid = false;
               }
            });
            return valid;
        },

        /**
         * Returns true if any fields in this form have changed since their original load.
         * @return Boolean
         */
        isDirty : function(){
            var dirty = false;
            this.items.each(function(f){
               if(f.isDirty()){
                   dirty = true;
                   return false;
               }
            });
            return dirty;
        },

        /**
         * Performs a predefined action (submit or load) or custom actions you define on this form.
         * @param {String} actionName The name of the action type
         * @param {Object} options The options to pass to the action
         * @return {BasicForm} this
         */
        doAction : function(action, options){
            if(typeof action == 'string'){
                action = new Ext.form.Action.ACTION_TYPES[action](this, options);
            }
            if(this.fireEvent('beforeaction', this, action) !== false){
                this.beforeAction(action);
                action.run.defer(100, action);
            }
            return this;
        },

        /**
         * Shortcut to do a submit action.
         * @param {Object} options The options to pass to the action
         * @return {BasicForm} this
         */
        submit : function(options){
            this.doAction('submit', options);
            return this;
        },

        /**
         * Shortcut to do a load action.
         * @param {Object} options The options to pass to the action
         * @return {BasicForm} this
         */
        load : function(options){
            this.doAction('load', options);
            return this;
        },

        /**
         * Persists the values in this form into the passed Ext.data.Record object in a beginEdit/endEdit block.
         * @param {Record} record The record to edit
         * @return {BasicForm} this
         */
        updateRecord : function(record){
            record.beginEdit();
            var fs = record.fields;
            fs.each(function(f){
                var field = this.findField(f.name);
                if(field){
                    record.set(f.name, field.getValue());
                }
            }, this);
            record.endEdit();
            return this;
        },

        /**
         * Loads an Ext.data.Record into this form.
         * @param {Record} record The record to load
         * @return {BasicForm} this
         */
        loadRecord : function(record){
            this.setValues(record.data);
            return this;
        },

        // private
        beforeAction : function(action){
            var o = action.options;
            if(o.waitMsg){
                if(this.waitMsgTarget === true){
                    this.el.mask(o.waitMsg, 'x-mask-loading');
                }else if(this.waitMsgTarget){
                    this.waitMsgTarget = Ext.get(this.waitMsgTarget);
                    this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
                }else{
                    Ext.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
                }
            }
        },

        // private
        afterAction : function(action, success){
            this.activeAction = null;
            var o = action.options;
            if(o.waitMsg){
                if(this.waitMsgTarget === true){
                    this.el.unmask();
                }else if(this.waitMsgTarget){
                    this.waitMsgTarget.unmask();
                }else{
                    Ext.MessageBox.updateProgress(1);
                    Ext.MessageBox.hide();
                }
            }
            if(success){
                if(o.reset){
                    this.reset();
                }
                Ext.callback(o.success, o.scope, [this, action]);
                this.fireEvent('actioncomplete', this, action);
            }else{
                Ext.callback(o.failure, o.scope, [this, action]);
                this.fireEvent('actionfailed', this, action);
            }
        },

        /**
         * Find a Ext.form.Field in this form by id, dataIndex, name or hiddenName
         * @param {String} id The value to search for
         * @return Field
         */
        findField : function(id){
            var field = this.items.get(id);
            if(!field){
                this.items.each(function(f){
                    if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
                        field = f;
                        return false;
                    }
                });
            }
            return field || null;
        },

        /**
         * 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}
         * @return {BasicForm} this
         */
        markInvalid : function(errors){
            if(errors instanceof Array){
                for(var i = 0, len = errors.length; i < len; i++){
                    var fieldError = errors[i];
                    var f = this.findField(fieldError.id);
                    if(f){
                        f.markInvalid(fieldError.msg);
                    }
                }
            }else{
                var field, id;
                for(id in errors){
                    if(typeof errors[id] != 'function' && (field = this.findField(id))){
                        field.markInvalid(errors[id]);
                    }
                }
            }
            return this;
        },

        /**
         * Set values for fields in this form in bulk.
         * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
         * @return {BasicForm} this
         */
        setValues : function(values){
            if(values instanceof Array){ // array of objects
                for(var i = 0, len = values.length; i < len; i++){
                    var v = values[i];
                    var f = this.findField(v.id);
                    if(f){
                        f.setValue(v.value);
                        if(this.trackResetOnLoad){
                            f.originalValue = f.getValue();
                        }
                    }
                }
            }else{ // object hash
                var field, id;
                for(id in values){
                    if(typeof values[id] != 'function' && (field = this.findField(id))){
                        field.setValue(values[id]);
                        if(this.trackResetOnLoad){
                            field.originalValue = field.getValue();
                        }
                    }
                }
            }
            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.
         * @param {Boolean} asString
         * @return {Object}
         */
        getValues : function(asString){
            var fs = Ext.lib.Ajax.serializeForm(this.el.dom);
            if(asString === true){
                return fs;
            }
            return Ext.urlDecode(fs);
        },

        /**
         * Clears all invalid messages in this form.
         * @return {BasicForm} this
         */
        clearInvalid : function(){
            this.items.each(function(f){
               f.clearInvalid();
            });
            return this;
        },

        /**
         * Resets this form.
         * @return {BasicForm} this
         */
        reset : function(){
            this.items.each(function(f){
                f.reset();
            });
            return this;
        },

        /**
         * Add Ext.form components to this form.
         * @param {Field} field1
         * @param {Field} field2 (optional)
         * @param {Field} etc (optional)
         * @return {BasicForm} this
         */
        add : function(){
            this.items.addAll(Array.prototype.slice.call(arguments, 0));
            return this;
        },

        /**
         * Removes a field from the items collection (does NOT remove its markup).
         * @param {Field} field
         * @return {BasicForm} this
         */
        remove : function(field){
            this.items.remove(field);
            return this;
        },

        /**
         * Looks at the fields in this form, checks them for an id attribute,
         * and calls applyTo on the existing dom element with that id.
         * @return {BasicForm} this
         */
        render : function(){
            this.items.each(function(f){
                if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
                    f.applyTo(f.id);
                }
            });
            return this;
        },

        /**
         * Calls {@link Ext#apply} for all fields in this form with the passed object.
         * @param {Object} values
         * @return {BasicForm} this
         */
        applyToFields : function(o){
            this.items.each(function(f){
               Ext.apply(f, o);
            });
            return this;
        },

        /**
         * Calls {@link Ext#applyIf} for all field in this form with the passed object.
         * @param {Object} values
         * @return {BasicForm} this
         */
        applyIfToFields : function(o){
            this.items.each(function(f){
               Ext.applyIf(f, o);
            });
            return this;
        }
    });

    // back compat
    Ext.BasicForm = Ext.form.BasicForm;

Ext - Copyright © 2006-2007 Ext JS, LLC
All rights reserved.