PageSourceSearch

https://www.j-live.tv/js/jquery-plugins/jquery.form.js

js j-live.tv collected 2026-10-07 10:17:42 UTC 21,272 bytes, 581 lines download raw bytes

1/*
2 * jQuery Form Plugin
3 * version: 2.10 (05/08/2008)
4 * @requires jQuery v1.2.2 or later
5 *
6 * Examples and documentation at: http://malsup.com/jquery/form/
7 * Dual licensed under the MIT and GPL licenses:
8 *   http://www.opensource.org/licenses/mit-license.php
9 *   http://www.gnu.org/licenses/gpl.html
10 *
11 * Revision: $Id$
12 */
13(function($) {
14
15/*
16    Usage Note:  
17    -----------
18    Do not use both ajaxSubmit and ajaxForm on the same form.  These
19    functions are intended to be exclusive.  Use ajaxSubmit if you want
20    to bind your own submit handler to the form.  For example,
21
22    $(document).ready(function() {
23        $('#myForm').bind('submit', function() {
24            $(this).ajaxSubmit({
25                target: '#output'
26            });
27            return false; // <-- important!
28        });
29    });
30
31    Use ajaxForm when you want the plugin to manage all the event binding
32    for you.  For example,
33
34    $(document).ready(function() {
35        $('#myForm').ajaxForm({
36            target: '#output'
37        });
38    });
39        
40    When using ajaxForm, the ajaxSubmit function will be invoked for you
41    at the appropriate time.  
42*/
43
44/**
45 * ajaxSubmit() provides a mechanism for immediately submitting 
46 * an HTML form using AJAX.
47 */
48$.fn.ajaxSubmit = function(options) {
49    // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
50    if (!this.length) {
51        log('ajaxSubmit: skipping submit process - no element selected');
52        return this;
53    }
54
55    if (typeof options == 'function')
56        options = { success: options };
57
58    options = $.extend({
59        url:  this.attr('action') || window.location.toString(),
60        type: this.attr('method') || 'GET'
61    }, options || {});
62
63    // hook for manipulating the form data before it is extracted;
64    // convenient for use with rich editors like tinyMCE or FCKEditor
65    var veto = {};
66    this.trigger('form-pre-serialize', [this, options, veto]);
67    if (veto.veto) {
68        log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
69        return this;
70   }
71
72    var a = this.formToArray(options.semantic);
73    if (options.data) {
74        options.extraData = options.data;
75        for (var n in options.data)
76            a.push( { name: n, value: options.data[n] } );
77    }
78
79    // give pre-submit callback an opportunity to abort the submit
80    if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
81        log('ajaxSubmit: submit aborted via beforeSubmit callback');
82        return this;
83    }    
84
85    // fire vetoable 'validate' event
86    this.trigger('form-submit-validate', [a, this, options, veto]);
87    if (veto.veto) {
88        log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
89        return this;
90    }    
91
92    var q = $.param(a);
93
94    if (options.type.toUpperCase() == 'GET') {
95        options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
96        options.data = null;  // data is null for 'get'
97    }
98    else
99        options.data = q; // data is the query string for 'post'
100
101    var $form = this, callbacks = [];
102    if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
103    if (options.clearForm) callbacks.push(function() { $form.clearForm(); });
104
105    // perform a load on the target only if dataType is not provided
106    if (!options.dataType && options.target) {
107        var oldSuccess = options.success || function(){};
108        callbacks.push(function(data) {
109            $(options.target).html(data).each(oldSuccess, arguments);
110        });
111    }
112    else if (options.success)
113        callbacks.push(options.success);
114
115    options.success = function(data, status) {
116        for (var i=0, max=callbacks.length; i < max; i++)
117            callbacks[i](data, status, $form);
118    };
119
120    // are there files to upload?
121    var files = $('input:file', this).fieldValue();
122    var found = false;
123    for (var j=0; j < files.length; j++)
124        if (files[j])
125            found = true;
126
127    // options.iframe allows user to force iframe mode
128   if (options.iframe || found) { 
129       // hack to fix Safari hang (thanks to Tim Molendijk for this)
130       // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
131       if ($.browser.safari && options.closeKeepAlive)
132           $.get(options.closeKeepAlive, fileUpload);
133       else
134           fileUpload();
135       }
136   else
137       $.ajax(options);
138
139    // fire 'notify' event
140    this.trigger('form-submit-notify', [this, options]);
141    return this;
142
143
144    // private function for handling file uploads (hat tip to YAHOO!)
145    function fileUpload() {
146        var form = $form[0];
147        var opts = $.extend({}, $.ajaxSettings, options);
148
149        var id = 'jqFormIO' + (new Date().getTime());
150        var $io = $('<iframe id="' + id + '" name="' + id + '" />');
151        var io = $io[0];
152
153        if ($.browser.msie || $.browser.opera) 
154            io.src = 'javascript:false;document.write("");';
155        $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
156
157        var xhr = { // mock object
158            responseText: null,
159            responseXML: null,
160            status: 0,
161            statusText: 'n/a',
162            getAllResponseHeaders: function() {},
163            getResponseHeader: function() {},
164            setRequestHeader: function() {}
165        };
166
167        var g = opts.global;
168        // trigger ajax global events so that activity/block indicators work like normal
169        if (g && ! $.active++) $.event.trigger("ajaxStart");
170        if (g) $.event.trigger("ajaxSend", [xhr, opts]);
171
172        var cbInvoked = 0;
173        var timedOut = 0;
174
175        // take a breath so that pending repaints get some cpu time before the upload starts
176        setTimeout(function() {
177            // make sure form attrs are set
178            var t = $form.attr('target'), a = $form.attr('action');
179            $form.attr({
180                target:   id,
181                encoding: 'multipart/form-data',
182                enctype:  'multipart/form-data',
183                method:   'POST',
184                action:   opts.url
185            });
186
187            // support timout
188            if (opts.timeout)
189                setTimeout(function() { timedOut = true; cb(); }, opts.timeout);
190
191            // add "extra" data to form if provided in options
192            var extraInputs = [];
193            try {
194                if (options.extraData)
195                    for (var n in options.extraData)
196                        extraInputs.push(
197                            $('<input type="hidden" name="'+n+'" value="'+options.extraData[n]+'" />')
198                                .appendTo(form)[0]);
199            
200                // add iframe to doc and submit the form
201                $io.appendTo('body');
202                io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
203                form.submit();
204            }
205            finally {
206                // reset attrs and remove "extra" input elements
207                $form.attr('action', a);
208                t ? $form.attr('target', t) : $form.removeAttr('target');
209                $(extraInputs).remove();
210            }
211        }, 10);
212
213        function cb() {
214            if (cbInvoked++) return;
215            
216            io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
217
218            var operaHack = 0;
219            var ok = true;
220            try {
221                if (timedOut) throw 'timeout';
222                // extract the server response from the iframe
223                var data, doc;
224
225                doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
226                
227                if (doc.body == null && !operaHack && $.browser.opera) {
228                    // In Opera 9.2.x the iframe DOM is not always traversable when
229                    // the onload callback fires so we give Opera 100ms to right itself
230                    operaHack = 1;
231                    cbInvoked--;
232                    setTimeout(cb, 100);
233                    return;
234                }
235                
236                xhr.responseText = doc.body ? doc.body.innerHTML : null;
237                xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
238                xhr.getResponseHeader = function(header){
239                    var headers = {'content-type': opts.dataType};
240                    return headers[header];
241                };
242
243                if (opts.dataType == 'json' || opts.dataType == 'script') {
244                    var ta = doc.getElementsByTagName('textarea')[0];
245                    xhr.responseText = ta ? ta.value : xhr.responseText;
246                }
247                else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
248                    xhr.responseXML = toXml(xhr.responseText);
249                }
250                data = $.httpData(xhr, opts.dataType);
251            }
252            catch(e){
253                ok = false;
254                $.handleError(opts, xhr, 'error', e);
255            }
256
257            // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
258            if (ok) {
259                opts.success(data, 'success');
260                if (g) $.event.trigger("ajaxSuccess", [xhr, opts]);
261            }
262            if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
263            if (g && ! --$.active) $.event.trigger("ajaxStop");
264            if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');
265
266            // clean up
267            setTimeout(function() {
268                $io.remove();
269                xhr.responseXML = null;
270            }, 100);
271        };
272
273        function toXml(s, doc) {
274            if (window.ActiveXObject) {
275                doc = new ActiveXObject('Microsoft.XMLDOM');
276                doc.async = 'false';
277                doc.loadXML(s);
278            }
279            else
280                doc = (new DOMParser()).parseFromString(s, 'text/xml');
281            return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
282        };
283    };
284};
285
286/**
287 * ajaxForm() provides a mechanism for fully automating form submission.
288 *
289 * The advantages of using this method instead of ajaxSubmit() are:
290 *
291 * 1: This method will include coordinates for <input type="image" /> elements (if the element
292 *    is used to submit the form).
293 * 2. This method will include the submit element's name/value data (for the element that was
294 *    used to submit the form).
295 * 3. This method binds the submit() method to the form for you.
296 *
297 * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
298 * passes the options argument along after properly binding events for submit elements and
299 * the form itself.
300 */ 
301$.fn.ajaxForm = function(options) {
302    return this.ajaxFormUnbind().bind('submit.form-plugin',function() {
303        $(this).ajaxSubmit(options);
304        return false;
305    }).each(function() {
306        // store options in hash
307        $(":submit,input:image", this).bind('click.form-plugin',function(e) {
308            var $form = this.form;
309            $form.clk = this;
310            if (this.type == 'image') {
311                if (e.offsetX != undefined) {
312                    $form.clk_x = e.offsetX;
313                    $form.clk_y = e.offsetY;
314                } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
315                    var offset = $(this).offset();
316                    $form.clk_x = e.pageX - offset.left;
317                    $form.clk_y = e.pageY - offset.top;
318                } else {
319                    $form.clk_x = e.pageX - this.offsetLeft;
320                    $form.clk_y = e.pageY - this.offsetTop;
321                }
322            }
323            // clear form vars
324            setTimeout(function() { $form.clk = $form.clk_x = $form.clk_y = null; }, 10);
325        });
326    });
327};
328
329// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
330$.fn.ajaxFormUnbind = function() {
331    this.unbind('submit.form-plugin');
332    return this.each(function() {
333        $(":submit,input:image", this).unbind('click.form-plugin');
334    });
335
336};
337
338/**
339 * formToArray() gathers form element data into an array of objects that can
340 * be passed to any of the following ajax functions: $.get, $.post, or load.
341 * Each object in the array has both a 'name' and 'value' property.  An example of
342 * an array for a simple login form might be:
343 *
344 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
345 *
346 * It is this array that is passed to pre-submit callback functions provided to the
347 * ajaxSubmit() and ajaxForm() methods.
348 */
349$.fn.formToArray = function(semantic) {
350    var a = [];
351    if (this.length == 0) return a;
352
353    var form = this[0];
354    var els = semantic ? form.getElementsByTagName('*') : form.elements;
355    if (!els) return a;
356    for(var i=0, max=els.length; i < max; i++) {
357        var el = els[i];
358        var n = el.name;
359        if (!n) continue;
360
361        if (semantic && form.clk && el.type == "image") {
362            // handle image inputs on the fly when semantic == true
363            if(!el.disabled && form.clk == el)
364                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
365            continue;
366        }
367
368        var v = $.fieldValue(el, true);
369        if (v && v.constructor == Array) {
370            for(var j=0, jmax=v.length; j < jmax; j++)
371                a.push({name: n, value: v[j]});
372        }
373        else if (v !== null && typeof v != 'undefined')
374            a.push({name: n, value: v});
375    }
376
377    if (!semantic && form.clk) {
378        // input type=='image' are not found in elements array! handle them here
379        var inputs = form.getElementsByTagName("input");
380        for(var i=0, max=inputs.length; i < max; i++) {
381            var input = inputs[i];
382            var n = input.name;
383            if(n && !input.disabled && input.type == "image" && form.clk == input)
384                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
385        }
386    }
387    return a;
388};
389
390/**
391 * Serializes form data into a 'submittable' string. This method will return a string
392 * in the format: name1=value1&amp;name2=value2
393 */
394$.fn.formSerialize = function(semantic) {
395    //hand off to jQuery.param for proper encoding
396    return $.param(this.formToArray(semantic));
397};
398
399/**
400 * Serializes all field elements in the jQuery object into a query string.
401 * This method will return a string in the format: name1=value1&amp;name2=value2
402 */
403$.fn.fieldSerialize = function(successful) {
404    var a = [];
405    this.each(function() {
406        var n = this.name;
407        if (!n) return;
408        var v = $.fieldValue(this, successful);
409        if (v && v.constructor == Array) {
410            for (var i=0,max=v.length; i < max; i++)
411                a.push({name: n, value: v[i]});
412        }
413        else if (v !== null && typeof v != 'undefined')
414            a.push({name: this.name, value: v});
415    });
416    //hand off to jQuery.param for proper encoding
417    return $.param(a);
418};
419
420/**
421 * Returns the value(s) of the element in the matched set.  For example, consider the following form:
422 *
423 *  <form><fieldset>
424 *      <input name="A" type="text" />
425 *      <input name="A" type="text" />
426 *      <input name="B" type="checkbox" value="B1" />
427 *      <input name="B" type="checkbox" value="B2"/>
428 *      <input name="C" type="radio" value="C1" />
429 *      <input name="C" type="radio" value="C2" />
430 *  </fieldset></form>
431 *
432 *  var v = $(':text').fieldValue();
433 *  // if no values are entered into the text inputs
434 *  v == ['','']
435 *  // if values entered into the text inputs are 'foo' and 'bar'
436 *  v == ['foo','bar']
437 *
438 *  var v = $(':checkbox').fieldValue();
439 *  // if neither checkbox is checked
440 *  v === undefined
441 *  // if both checkboxes are checked
442 *  v == ['B1', 'B2']
443 *
444 *  var v = $(':radio').fieldValue();
445 *  // if neither radio is checked
446 *  v === undefined
447 *  // if first radio is checked
448 *  v == ['C1']
449 *
450 * The successful argument controls whether or not the field element must be 'successful'
451 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
452 * The default value of the successful argument is true.  If this value is false the value(s)
453 * for each element is returned.
454 *
455 * Note: This method *always* returns an array.  If no valid value can be determined the
456 *       array will be empty, otherwise it will contain one or more values.
457 */
458$.fn.fieldValue = function(successful) {
459    for (var val=[], i=0, max=this.length; i < max; i++) {
460        var el = this[i];
461        var v = $.fieldValue(el, successful);
462        if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
463            continue;
464        v.constructor == Array ? $.merge(val, v) : val.push(v);
465    }
466    return val;
467};
468
469/**
470 * Returns the value of the field element.
471 */
472$.fieldValue = function(el, successful) {
473    var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
474    if (typeof successful == 'undefined') successful = true;
475
476    if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
477        (t == 'checkbox' || t == 'radio') && !el.checked ||
478        (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
479        tag == 'select' && el.selectedIndex == -1))
480            return null;
481
482    if (tag == 'select') {
483        var index = el.selectedIndex;
484        if (index < 0) return null;
485        var a = [], ops = el.options;
486        var one = (t == 'select-one');
487        var max = (one ? index+1 : ops.length);
488        for(var i=(one ? index : 0); i < max; i++) {
489            var op = ops[i];
490            if (op.selected) {
491                // extra pain for IE...
492                var v = $.browser.msie && !(op.attributes['value'].specified) ? op.text : op.value;
493                if (one) return v;
494                a.push(v);
495            }
496        }
497        return a;
498    }
499    return el.value;
500};
501
502/**
503 * Clears the form data.  Takes the following actions on the form's input fields:
504 *  - input text fields will have their 'value' property set to the empty string
505 *  - select elements will have their 'selectedIndex' property set to -1
506 *  - checkbox and radio inputs will have their 'checked' property set to false
507 *  - inputs of type submit, button, reset, and hidden will *not* be effected
508 *  - button elements will *not* be effected
509 */
510$.fn.clearForm = function() {
511    return this.each(function() {
512        $('input,select,textarea', this).clearFields();
513    });
514};
515
516/**
517 * Clears the selected form elements.
518 */
519$.fn.clearFields = $.fn.clearInputs = function() {
520    return this.each(function() {
521        var t = this.type, tag = this.tagName.toLowerCase();
522        if (t == 'text' || t == 'password' || tag == 'textarea')
523            this.value = '';
524        else if (t == 'checkbox' || t == 'radio')
525            this.checked = false;
526        else if (tag == 'select')
527            this.selectedIndex = -1;
528    });
529};
530
531/**
532 * Resets the form data.  Causes all form elements to be reset to their original value.
533 */
534$.fn.resetForm = function() {
535    return this.each(function() {
536        // guard against an input with the name of 'reset'
537        // note that IE reports the reset function as an 'object'
538        if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
539            this.reset();
540    });
541};
542
543/**
544 * Enables or disables any matching elements.
545 */
546$.fn.enable = function(b) { 
547    if (b == undefined) b = true;
548    return this.each(function() { 
549        this.disabled = !b 
550    });
551};
552
553/**
554 * Checks/unchecks any matching checkboxes or radio buttons and
555 * selects/deselects and matching option elements.
556 */
557$.fn.select = function(select) {
558    if (select == undefined) select = true;
559    return this.each(function() { 
560        var t = this.type;
561        if (t == 'checkbox' || t == 'radio')
562            this.checked = select;
563        else if (this.tagName.toLowerCase() == 'option') {
564            var $sel = $(this).parent('select');
565            if (select && $sel[0] && $sel[0].type == 'select-one') {
566                // deselect all other options
567                $sel.find('option').select(false);
568            }
569            this.selected = select;
570        }
571    });
572};
573
574// helper fn for console logging
575// set $.fn.ajaxSubmit.debug to true to enable debug logging
576function log() {
577    if ($.fn.ajaxSubmit.debug && window.console && window.console.log)
578        window.console.log('[jquery.form] ' + Array.prototype.join.call(arguments,''));
579};
580
581})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.