/**
 * A method for submitting an HTML form using AJAX.
 *
 * This method mimics the functionality of the browser's native form submission.  Invoke it to
 * submit the form data.
 *
 * If a target id is provided, the text returned from the ajax call is loaded into the target element.
 * If a post-submit callback method is provided it is invoked when the the submit completes.
 * If neither a target or post-submit callback method are provided then the data returned (if any)
 * is evaluated in the global context.
 *
 * An optional pre-submit callback can be provided as a hook for running validation on the
 * form data.  If the pre-submit callback returns false the form will not be submitted.
 *
 * The action url and form method can also be provided to override the form defaults.  If not provided,
 * the form emement's 'action' and 'method' properties will be used.
 *
 * The semantic argument can be used to force form serialization in semantic order.  If your form must
 * be submitted with name/value pairs in semantic order then pass true for this arg, otherwise pass false
 * to avoid the overhead for this logic (which can be significant for very large forms).
 *
 * @example $("#form-id").ajaxSubmit(function(){
 *   alert("all done!");
 * });
 * @desc The form is submitted and a callback is fired, letting you know when it's done.
 *
 * @example $("#form-id").ajaxSubmit("#destination");
 * @desc The form is submitted and the resulting HTML contents are injected into the page, at your specified location.
 *
 * @example $("#form-id").ajaxSubmit();
 * @desc The form is submitted and the results returned from the server are
 * automatically executed (useful for having the server return more Javascript commands to execute).
 *
 * @example $("#form-id").submit(function() {
 *     $(this).ajaxSubmit("#destination");
 *     return false;
 * });
 * @desc Typical way of binding this method to a form.
 *
 * @name ajaxSubmit
 * @type jQuery
 * @param target   arg for the target id element to render
 * @param post_cb  callback after any results are returned
 * @param pre_cb   callback function before submission
 * @param url      url to invoke
 * @param mth      method to use, 'POST' or 'GET'
 * @param semantic true if serialization must maintain strict semantic ordering of elements (slower)
 * @return jQuery 
 * @see ajaxForm
 * @see load
 * @see $.ajax
 * @author jQuery Community
 */
jQuery.fn.ajaxSubmit = function(target, post_cb, pre_cb, url, mth, semantic) {
    var vars = this.serialize(semantic);
    
    // give 'pre' callback opportunity to abort the submit
    if (pre_cb && pre_cb.constructor == Function && pre_cb(vars) === false) return;

    var f = this[0];
    if (!url) {
        var a = f.getAttributeNode('action');
        if (a) url = a.nodeValue;
    }
    if (!mth) {
        var m = f.getAttributeNode('method');
        if (m) mth = m.nodeValue;
    }
    
    url = url || '';
    mth = mth || 'GET';
    
    // if no target or 'post' callback was provided then default to a callback
    // that evals the response
    var t = target || post_cb || function(r) {
            if (r.responseText) eval.call(window, r.responseText)
        };

    if (t && t.constructor == String)
        jQuery(t).load(url, vars, post_cb);
    else
        jQuery.ajax(mth, url, jQuery.param(vars), t);
    return this;
};

/**
 * Turn any HTML form into a form that submits using AJAX.
 *
 * The advantages of using this method, instead of the ajaxSubmit() method, are:
 *
 * 1: This method will include coordinates for <input type="image"/> elements.
 * 2. This method will include the submit element that was used to submit the form.
 * 3. This method binds the submit() method to the form for you.
 *
 * Note that for accurate x/y coordinates of image submit elements in ALL
 * browsers you need to also use the "dimensions" plugin.
 *
 * If a target id is provided, the text returned from the ajax call is loaded into the target element.
 * If a post-submit callback method is provided it is invoked when the the submit completes.
 * If neither a target or post-submit callback method are provided then the data returned (if any)
 * is evaluated in the global context.
 *
 * An optional pre-submit callback can be provided as a hook for running validation on the
 * form data.  If the pre-submit callback returns false the form will not be submitted.
 *
 * The semantic argument can be used to force form serialization in semantic order.  If your form must
 * be submitted with name/value pairs in semantic order then pass true for this arg, otherwise pass false
 * to avoid the overhead for this logic (which can be significant for very large forms).
 *
 * @example $('#form-id').ajaxForm();
 * @desc Just eval the results returned from the backend.
 *
 * @example $('#form-id').ajaxForm('#target-id');
 * @desc Render backend results directly to target ID (expects (x)HTML).
 *
 * @example $('#form-id').ajaxForm(post_callback);
 * @desc Submit to backend URL (form action) then call this function.
 *
 * @example $('#form-id').ajaxForm('#target-id', post_callback);
 * @desc Load target ID with backend results then call a function.
 *
 * @example $('#form-id').ajaxForm('#target-id', null, pre_callback);
 * @desc Call a browser function (for validation) and then (optionally) load server results to target ID.
 *
 * @example $('#form-id').ajaxForm('#target-id', post_callback, pre_callback);
 * @desc Call validation function first then load server results to target ID and then also call a browser function.
 *
 * @name ajaxForm
 * @param target   arg for the target id element to render
 * @param post_cb  callback after any results are returned
 * @param pre_cb   callback function before submission
 * @param semantic true if serialization must maintain strict semantic ordering of elements (slower)
 * @return jQuery
 * @type jQuery
 * @see serialize
 * @see ajaxSubmit
 * @author jQuery Community
 */
jQuery.fn.ajaxForm = function(target, post_cb, pre_cb, semantic) {
    return this.each(function() {
        jQuery("input[@type=submit],input[@type=image]", this).click(function(ev) {
            this.form.clk = this;
            
            if (ev.offsetX != undefined) {
                this.form.clk_x = ev.offsetX;
                this.form.clk_y = ev.offsetY;
            } else if (typeof jQuery.fn.offset == 'function') { 
                // use dimensions plugin if it's installed
                var offset = $(this).offset();
                this.form.clk_x = ev.pageX - offset.left;
                this.form.clk_y = ev.pageY - offset.top;
            } else {
                this.form.clk_x = ev.pageX - this.offsetLeft;
                this.form.clk_y = ev.pageY - this.offsetTop;
            }
        });
    }).submit(function(e) {
        jQuery(this).ajaxSubmit(target, post_cb, pre_cb, null, null, semantic);
        return false;
    });
};


/**
 * This function gathers form element variables into an array of objects
 * that can be passed to any AJAX function (such as $.post, $.ajax, or load).
 *
 * This function is primarily used by ajaxSubmit() but can
 * be used standalone as long as you don't need the x and y coordinates
 * associated with an <input type="image"/> elements.
 *
 * This method guarantees that posted data will be sent in the same 
 * semantic order as the elements reside on the form if the semantic
 * argument is true.  Use this only if you must as it takes longer to 
 * serialization the form in this manner.
 *
 * The semantic argument can be used to force form serialization in semantic order.  If your form must
 * be submitted with name/value pairs in semantic order then pass true for this arg, otherwise pass false
 * (or nothing) to avoid the overhead for this logic (which can be significant for very large forms).
 *
 * @example var vars = $("#myForm").serialize();
 * $.post( "myscript.cgi", vars );
 * @desc Collect all the data from a form and submit it to a server-side application.
 *
 * @name serialize
 * @param semantic true if serialization must maintain strict semantic ordering of elements (slower)
 * @type Array<Object>
 * @see ajaxForm
 * @see ajaxSubmit
 * @author jQuery Community
 */
jQuery.fn.serialize = function(semantic) {
    var a = [];
    var q = semantic ? '*:not(option)' : 'input,textarea,select,button';
    
    if (semantic)
        var ok = {input:1, textarea:1, select:1, button:1};
    
    jQuery(q, this).each(function() {
        if (semantic && !ok[this.nodeName.toLowerCase()])
            return;
            
        var n = this.name;
        var t = this.type;

        if ( !n || this.disabled || t == 'reset' ||
            (t == 'checkbox' || t == 'radio') && !this.checked ||
            (t == 'submit' || t == 'image' || t == 'button') && this.form.clk != this ||
            this.tagName.toLowerCase() == 'select' && this.selectedIndex == -1)
            return;

        if (t == 'image' && this.form.clk_x != undefined)
            return a.push(
                {name: n+'_x', value: this.form.clk_x},
                {name: n+'_y', value: this.form.clk_y}
            );

        if (t == 'select-multiple') {
            jQuery('option:selected', this).each( function() {
                a.push({name: n, value: this.value});
            });
            return;
        }

        a.push({name: n, value: this.value});
    });

    return a;
};

/**
 * helper method to serialize form data into a 'submittable' string;
 * this method will return a string in the format: name1=value1&name2=value2
 *
 * The semantic argument can be used to force form serialization in semantic order.  If your form must
 * be submitted with name/value pairs in semantic order then pass true for this arg, otherwise pass false
 * (or nothing) to avoid the overhead for this logic (which can be significant for very large forms).
 *
 * @example var data = $("#myForm").serialize();
 * $.ajax('POST', "myscript.cgi", data);
 * @desc Collect all the data from a form into a single string
 *
 * @name serializeToString
 * @param semantic true if serialization must maintain strict semantic ordering of elements (slower)
 * @type String
 * @see serialize
 * @author jQuery Community
 */
jQuery.fn.serializeToString = function(semantic) {
    return jQuery.param(this.serialize(semantic));
};
