~pexego/openobject-addons/6.1-pexego-sale_commission

« back to all changes in this revision

Viewing changes to django_pos/static/js/jquery.form.js

  • Committer: Santi Argueso (Pexego)
  • Date: 2013-02-06 17:03:36 UTC
  • mfrom: (10.1.6 pexego-addons_6.1)
  • Revision ID: santiago@pexego.es-20130206170336-ml430s6p9jknun0j
[MERGE]

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*!
 
2
 * jQuery Form Plugin
 
3
 * version: 2.77 (23-MAY-2011)
 
4
 * @requires jQuery v1.3.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
;(function($) {
 
12
 
 
13
/*
 
14
        Usage Note:
 
15
        -----------
 
16
        Do not use both ajaxSubmit and ajaxForm on the same form.  These
 
17
        functions are intended to be exclusive.  Use ajaxSubmit if you want
 
18
        to bind your own submit handler to the form.  For example,
 
19
 
 
20
        $(document).ready(function() {
 
21
                $('#myForm').bind('submit', function(e) {
 
22
                        e.preventDefault(); // <-- important
 
23
                        $(this).ajaxSubmit({
 
24
                                target: '#output'
 
25
                        });
 
26
                });
 
27
        });
 
28
 
 
29
        Use ajaxForm when you want the plugin to manage all the event binding
 
30
        for you.  For example,
 
31
 
 
32
        $(document).ready(function() {
 
33
                $('#myForm').ajaxForm({
 
34
                        target: '#output'
 
35
                });
 
36
        });
 
37
 
 
38
        When using ajaxForm, the ajaxSubmit function will be invoked for you
 
39
        at the appropriate time.
 
40
*/
 
41
 
 
42
/**
 
43
 * ajaxSubmit() provides a mechanism for immediately submitting
 
44
 * an HTML form using AJAX.
 
45
 */
 
46
$.fn.ajaxSubmit = function(options) {
 
47
        // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
 
48
        if (!this.length) {
 
49
                log('ajaxSubmit: skipping submit process - no element selected');
 
50
                return this;
 
51
        }
 
52
 
 
53
        if (typeof options == 'function') {
 
54
                options = { success: options };
 
55
        }
 
56
 
 
57
        var action = this.attr('action');
 
58
        var url = (typeof action === 'string') ? $.trim(action) : '';
 
59
        url = url || window.location.href || '';
 
60
        if (url) {
 
61
                // clean url (don't include hash vaue)
 
62
                url = (url.match(/^([^#]+)/)||[])[1];
 
63
        }
 
64
 
 
65
        options = $.extend(true, {
 
66
                url:  url,
 
67
                success: $.ajaxSettings.success,
 
68
                type: this[0].getAttribute('method') || 'GET', // IE7 massage (see issue 57)
 
69
                iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
 
70
        }, options);
 
71
 
 
72
        // hook for manipulating the form data before it is extracted;
 
73
        // convenient for use with rich editors like tinyMCE or FCKEditor
 
74
        var veto = {};
 
75
        this.trigger('form-pre-serialize', [this, options, veto]);
 
76
        if (veto.veto) {
 
77
                log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
 
78
                return this;
 
79
        }
 
80
 
 
81
        // provide opportunity to alter form data before it is serialized
 
82
        if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
 
83
                log('ajaxSubmit: submit aborted via beforeSerialize callback');
 
84
                return this;
 
85
        }
 
86
 
 
87
        var n,v,a = this.formToArray(options.semantic);
 
88
        if (options.data) {
 
89
                options.extraData = options.data;
 
90
                for (n in options.data) {
 
91
                        if(options.data[n] instanceof Array) {
 
92
                                for (var k in options.data[n]) {
 
93
                                        a.push( { name: n, value: options.data[n][k] } );
 
94
                                }
 
95
                        }
 
96
                        else {
 
97
                                v = options.data[n];
 
98
                                v = $.isFunction(v) ? v() : v; // if value is fn, invoke it
 
99
                                a.push( { name: n, value: v } );
 
100
                        }
 
101
                }
 
102
        }
 
103
 
 
104
        // give pre-submit callback an opportunity to abort the submit
 
105
        if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
 
106
                log('ajaxSubmit: submit aborted via beforeSubmit callback');
 
107
                return this;
 
108
        }
 
109
 
 
110
        // fire vetoable 'validate' event
 
111
        this.trigger('form-submit-validate', [a, this, options, veto]);
 
112
        if (veto.veto) {
 
113
                log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
 
114
                return this;
 
115
        }
 
116
 
 
117
        var q = $.param(a);
 
118
 
 
119
        if (options.type.toUpperCase() == 'GET') {
 
120
                options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
 
121
                options.data = null;  // data is null for 'get'
 
122
        }
 
123
        else {
 
124
                options.data = q; // data is the query string for 'post'
 
125
        }
 
126
 
 
127
        var $form = this, callbacks = [];
 
128
        if (options.resetForm) {
 
129
                callbacks.push(function() { $form.resetForm(); });
 
130
        }
 
131
        if (options.clearForm) {
 
132
                callbacks.push(function() { $form.clearForm(); });
 
133
        }
 
134
 
 
135
        // perform a load on the target only if dataType is not provided
 
136
        if (!options.dataType && options.target) {
 
137
                var oldSuccess = options.success || function(){};
 
138
                callbacks.push(function(data) {
 
139
                        var fn = options.replaceTarget ? 'replaceWith' : 'html';
 
140
                        $(options.target)[fn](data).each(oldSuccess, arguments);
 
141
                });
 
142
        }
 
143
        else if (options.success) {
 
144
                callbacks.push(options.success);
 
145
        }
 
146
 
 
147
        options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
 
148
                var context = options.context || options;   // jQuery 1.4+ supports scope context 
 
149
                for (var i=0, max=callbacks.length; i < max; i++) {
 
150
                        callbacks[i].apply(context, [data, status, xhr || $form, $form]);
 
151
                }
 
152
        };
 
153
 
 
154
        // are there files to upload?
 
155
        var fileInputs = $('input:file', this).length > 0;
 
156
        var mp = 'multipart/form-data';
 
157
        var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
 
158
 
 
159
        // options.iframe allows user to force iframe mode
 
160
        // 06-NOV-09: now defaulting to iframe mode if file input is detected
 
161
   if (options.iframe !== false && (fileInputs || options.iframe || multipart)) {
 
162
           // hack to fix Safari hang (thanks to Tim Molendijk for this)
 
163
           // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
 
164
           if (options.closeKeepAlive) {
 
165
                   $.get(options.closeKeepAlive, fileUpload);
 
166
                }
 
167
           else {
 
168
                   fileUpload();
 
169
                }
 
170
   }
 
171
   else {
 
172
                $.ajax(options);
 
173
   }
 
174
 
 
175
        // fire 'notify' event
 
176
        this.trigger('form-submit-notify', [this, options]);
 
177
        return this;
 
178
 
 
179
 
 
180
        // private function for handling file uploads (hat tip to YAHOO!)
 
181
        function fileUpload() {
 
182
                var form = $form[0], s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
 
183
 
 
184
                if ($(':input[name=submit],:input[id=submit]', form).length) {
 
185
                        // if there is an input with a name or id of 'submit' then we won't be
 
186
                        // able to invoke the submit fn on the form (at least not x-browser)
 
187
                        alert('Error: Form elements must not have name or id of "submit".');
 
188
                        return;
 
189
                }
 
190
                
 
191
                s = $.extend(true, {}, $.ajaxSettings, options);
 
192
                s.context = s.context || s;
 
193
                $io, id = 'jqFormIO' + (new Date().getTime());
 
194
                if (s.iframeTarget) {
 
195
                        $io = $(s.iframeTarget);
 
196
                        n = $io.attr('name');
 
197
                        if (n == null)
 
198
                                $io.attr('name', id);
 
199
                        else
 
200
                                id = n;
 
201
                }
 
202
                else {
 
203
                        $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');
 
204
                        $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
 
205
                }
 
206
                io = $io[0];
 
207
 
 
208
 
 
209
                xhr = { // mock object
 
210
                        aborted: 0,
 
211
                        responseText: null,
 
212
                        responseXML: null,
 
213
                        status: 0,
 
214
                        statusText: 'n/a',
 
215
                        getAllResponseHeaders: function() {},
 
216
                        getResponseHeader: function() {},
 
217
                        setRequestHeader: function() {},
 
218
                        abort: function(status) {
 
219
                                var e = (status === 'timeout' ? 'timeout' : 'aborted');
 
220
                                log('aborting upload... ' + e);
 
221
                                this.aborted = 1;
 
222
                                $io.attr('src', s.iframeSrc); // abort op in progress
 
223
                                xhr.error = e;
 
224
                                s.error && s.error.call(s.context, xhr, e, e);
 
225
                                g && $.event.trigger("ajaxError", [xhr, s, e]);
 
226
                                s.complete && s.complete.call(s.context, xhr, e);
 
227
                        }
 
228
                };
 
229
 
 
230
                g = s.global;
 
231
                // trigger ajax global events so that activity/block indicators work like normal
 
232
                if (g && ! $.active++) {
 
233
                        $.event.trigger("ajaxStart");
 
234
                }
 
235
                if (g) {
 
236
                        $.event.trigger("ajaxSend", [xhr, s]);
 
237
                }
 
238
 
 
239
                if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
 
240
                        if (s.global) {
 
241
                                $.active--;
 
242
                        }
 
243
                        return;
 
244
                }
 
245
                if (xhr.aborted) {
 
246
                        return;
 
247
                }
 
248
 
 
249
                // add submitting element to data if we know it
 
250
                sub = form.clk;
 
251
                if (sub) {
 
252
                        n = sub.name;
 
253
                        if (n && !sub.disabled) {
 
254
                                s.extraData = s.extraData || {};
 
255
                                s.extraData[n] = sub.value;
 
256
                                if (sub.type == "image") {
 
257
                                        s.extraData[n+'.x'] = form.clk_x;
 
258
                                        s.extraData[n+'.y'] = form.clk_y;
 
259
                                }
 
260
                        }
 
261
                }
 
262
 
 
263
                // take a breath so that pending repaints get some cpu time before the upload starts
 
264
                function doSubmit() {
 
265
                        // make sure form attrs are set
 
266
                        var t = $form.attr('target'), a = $form.attr('action');
 
267
 
 
268
                        // update form attrs in IE friendly way
 
269
                        form.setAttribute('target',id);
 
270
                        if (form.getAttribute('method') != 'POST') {
 
271
                                form.setAttribute('method', 'POST');
 
272
                        }
 
273
                        if (form.getAttribute('action') != s.url) {
 
274
                                form.setAttribute('action', s.url);
 
275
                        }
 
276
 
 
277
                        // ie borks in some cases when setting encoding
 
278
                        if (! s.skipEncodingOverride) {
 
279
                                $form.attr({
 
280
                                        encoding: 'multipart/form-data',
 
281
                                        enctype:  'multipart/form-data'
 
282
                                });
 
283
                        }
 
284
 
 
285
                        // support timout
 
286
                        if (s.timeout) {
 
287
                                timeoutHandle = setTimeout(function() { timedOut = true; cb(true); }, s.timeout);
 
288
                        }
 
289
 
 
290
                        // add "extra" data to form if provided in options
 
291
                        var extraInputs = [];
 
292
                        try {
 
293
                                if (s.extraData) {
 
294
                                        for (var n in s.extraData) {
 
295
                                                extraInputs.push(
 
296
                                                        $('<input type="hidden" name="'+n+'" value="'+s.extraData[n]+'" />')
 
297
                                                                .appendTo(form)[0]);
 
298
                                        }
 
299
                                }
 
300
 
 
301
                                if (!s.iframeTarget) {
 
302
                                        // add iframe to doc and submit the form
 
303
                                        $io.appendTo('body');
 
304
                        io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
 
305
                                }
 
306
                                form.submit();
 
307
                        }
 
308
                        finally {
 
309
                                // reset attrs and remove "extra" input elements
 
310
                                form.setAttribute('action',a);
 
311
                                if(t) {
 
312
                                        form.setAttribute('target', t);
 
313
                                } else {
 
314
                                        $form.removeAttr('target');
 
315
                                }
 
316
                                $(extraInputs).remove();
 
317
                        }
 
318
                }
 
319
 
 
320
                if (s.forceSync) {
 
321
                        doSubmit();
 
322
                }
 
323
                else {
 
324
                        setTimeout(doSubmit, 10); // this lets dom updates render
 
325
                }
 
326
 
 
327
                var data, doc, domCheckCount = 50, callbackProcessed;
 
328
 
 
329
                function cb(e) {
 
330
                        if (xhr.aborted || callbackProcessed) {
 
331
                                return;
 
332
                        }
 
333
                        if (e === true && xhr) {
 
334
                                xhr.abort('timeout');
 
335
                                return;
 
336
                        }
 
337
 
 
338
                        var doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
 
339
                        if (!doc || doc.location.href == s.iframeSrc) {
 
340
                                // response not received yet
 
341
                                if (!timedOut)
 
342
                                        return;
 
343
                        }
 
344
            io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
 
345
 
 
346
                        var status = 'success', errMsg;
 
347
                        try {
 
348
                                if (timedOut) {
 
349
                                        throw 'timeout';
 
350
                                }
 
351
 
 
352
                                var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
 
353
                                log('isXml='+isXml);
 
354
                                if (!isXml && window.opera && (doc.body == null || doc.body.innerHTML == '')) {
 
355
                                        if (--domCheckCount) {
 
356
                                                // in some browsers (Opera) the iframe DOM is not always traversable when
 
357
                                                // the onload callback fires, so we loop a bit to accommodate
 
358
                                                log('requeing onLoad callback, DOM not available');
 
359
                                                setTimeout(cb, 250);
 
360
                                                return;
 
361
                                        }
 
362
                                        // let this fall through because server response could be an empty document
 
363
                                        //log('Could not access iframe DOM after mutiple tries.');
 
364
                                        //throw 'DOMException: not available';
 
365
                                }
 
366
 
 
367
                                //log('response detected');
 
368
                var docRoot = doc.body ? doc.body : doc.documentElement;
 
369
                xhr.responseText = docRoot ? docRoot.innerHTML : null;
 
370
                                xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
 
371
                                if (isXml)
 
372
                                        s.dataType = 'xml';
 
373
                                xhr.getResponseHeader = function(header){
 
374
                                        var headers = {'content-type': s.dataType};
 
375
                                        return headers[header];
 
376
                                };
 
377
                // support for XHR 'status' & 'statusText' emulation :
 
378
                if (docRoot) {
 
379
                    xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;
 
380
                    xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;
 
381
                }
 
382
                                var scr = /(json|script|text)/.test(s.dataType.toLowerCase());
 
383
                                if (scr || s.textarea) {
 
384
                                        // see if user embedded response in textarea
 
385
                                        var ta = doc.getElementsByTagName('textarea')[0];
 
386
                                        if (ta) {
 
387
                                                xhr.responseText = ta.value;
 
388
                        // support for XHR 'status' & 'statusText' emulation :
 
389
                        xhr.status = Number( ta.getAttribute('status') ) || xhr.status;
 
390
                        xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;
 
391
                                        }
 
392
                                        else if (scr) {
 
393
                                                // account for browsers injecting pre around json response
 
394
                                                var pre = doc.getElementsByTagName('pre')[0];
 
395
                                                var b = doc.getElementsByTagName('body')[0];
 
396
                                                if (pre) {
 
397
                                                        xhr.responseText = pre.textContent ? pre.textContent : pre.innerHTML;
 
398
                                                }
 
399
                                                else if (b) {
 
400
                                                        xhr.responseText = b.innerHTML;
 
401
                                                }
 
402
                                        }
 
403
                                }
 
404
                                else if (s.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
 
405
                                        xhr.responseXML = toXml(xhr.responseText);
 
406
                                }
 
407
 
 
408
                try {
 
409
                    data = httpData(xhr, s.dataType, s);
 
410
                }
 
411
                catch (e) {
 
412
                    status = 'parsererror';
 
413
                    xhr.error = errMsg = (e || status);
 
414
                }
 
415
                        }
 
416
                        catch (e) {
 
417
                                log('error caught',e);
 
418
                                status = 'error';
 
419
                xhr.error = errMsg = (e || status);
 
420
                        }
 
421
 
 
422
                        if (xhr.aborted) {
 
423
                                log('upload aborted');
 
424
                                status = null;
 
425
                        }
 
426
            if (xhr.status) { // we've set xhr.status
 
427
                status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';
 
428
            }
 
429
 
 
430
                        // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
 
431
                        if (status === 'success') {
 
432
                                s.success && s.success.call(s.context, data, 'success', xhr);
 
433
                                g && $.event.trigger("ajaxSuccess", [xhr, s]);
 
434
                        }
 
435
            else if (status) {
 
436
                                if (errMsg == undefined)
 
437
                                        errMsg = xhr.statusText;
 
438
                                s.error && s.error.call(s.context, xhr, status, errMsg);
 
439
                                g && $.event.trigger("ajaxError", [xhr, s, errMsg]);
 
440
            }
 
441
 
 
442
                        g && $.event.trigger("ajaxComplete", [xhr, s]);
 
443
 
 
444
                        if (g && ! --$.active) {
 
445
                                $.event.trigger("ajaxStop");
 
446
                        }
 
447
 
 
448
                        s.complete && s.complete.call(s.context, xhr, status);
 
449
 
 
450
                        callbackProcessed = true;
 
451
                        if (s.timeout)
 
452
                                clearTimeout(timeoutHandle);
 
453
 
 
454
                        // clean up
 
455
                        setTimeout(function() {
 
456
                                if (!s.iframeTarget)
 
457
                                        $io.remove();
 
458
                                xhr.responseXML = null;
 
459
                        }, 100);
 
460
                }
 
461
 
 
462
                var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
 
463
                        if (window.ActiveXObject) {
 
464
                                doc = new ActiveXObject('Microsoft.XMLDOM');
 
465
                                doc.async = 'false';
 
466
                                doc.loadXML(s);
 
467
                        }
 
468
                        else {
 
469
                                doc = (new DOMParser()).parseFromString(s, 'text/xml');
 
470
                        }
 
471
                        return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
 
472
                };
 
473
                var parseJSON = $.parseJSON || function(s) {
 
474
                        return window['eval']('(' + s + ')');
 
475
                };
 
476
 
 
477
                var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
 
478
 
 
479
                        var ct = xhr.getResponseHeader('content-type') || '',
 
480
                                xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
 
481
                                data = xml ? xhr.responseXML : xhr.responseText;
 
482
 
 
483
                        if (xml && data.documentElement.nodeName === 'parsererror') {
 
484
                                $.error && $.error('parsererror');
 
485
                        }
 
486
                        if (s && s.dataFilter) {
 
487
                                data = s.dataFilter(data, type);
 
488
                        }
 
489
                        if (typeof data === 'string') {
 
490
                                if (type === 'json' || !type && ct.indexOf('json') >= 0) {
 
491
                                        data = parseJSON(data);
 
492
                                } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
 
493
                                        $.globalEval(data);
 
494
                                }
 
495
                        }
 
496
                        return data;
 
497
                };
 
498
        }
 
499
};
 
500
 
 
501
/**
 
502
 * ajaxForm() provides a mechanism for fully automating form submission.
 
503
 *
 
504
 * The advantages of using this method instead of ajaxSubmit() are:
 
505
 *
 
506
 * 1: This method will include coordinates for <input type="image" /> elements (if the element
 
507
 *      is used to submit the form).
 
508
 * 2. This method will include the submit element's name/value data (for the element that was
 
509
 *      used to submit the form).
 
510
 * 3. This method binds the submit() method to the form for you.
 
511
 *
 
512
 * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
 
513
 * passes the options argument along after properly binding events for submit elements and
 
514
 * the form itself.
 
515
 */
 
516
$.fn.ajaxForm = function(options) {
 
517
        // in jQuery 1.3+ we can fix mistakes with the ready state
 
518
        if (this.length === 0) {
 
519
                var o = { s: this.selector, c: this.context };
 
520
                if (!$.isReady && o.s) {
 
521
                        log('DOM not ready, queuing ajaxForm');
 
522
                        $(function() {
 
523
                                $(o.s,o.c).ajaxForm(options);
 
524
                        });
 
525
                        return this;
 
526
                }
 
527
                // is your DOM ready?  http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
 
528
                log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
 
529
                return this;
 
530
        }
 
531
 
 
532
        return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
 
533
                if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
 
534
                        e.preventDefault();
 
535
                        $(this).ajaxSubmit(options);
 
536
                }
 
537
        }).bind('click.form-plugin', function(e) {
 
538
                var target = e.target;
 
539
                var $el = $(target);
 
540
                if (!($el.is(":submit,input:image"))) {
 
541
                        // is this a child element of the submit el?  (ex: a span within a button)
 
542
                        var t = $el.closest(':submit');
 
543
                        if (t.length == 0) {
 
544
                                return;
 
545
                        }
 
546
                        target = t[0];
 
547
                }
 
548
                var form = this;
 
549
                form.clk = target;
 
550
                if (target.type == 'image') {
 
551
                        if (e.offsetX != undefined) {
 
552
                                form.clk_x = e.offsetX;
 
553
                                form.clk_y = e.offsetY;
 
554
                        } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
 
555
                                var offset = $el.offset();
 
556
                                form.clk_x = e.pageX - offset.left;
 
557
                                form.clk_y = e.pageY - offset.top;
 
558
                        } else {
 
559
                                form.clk_x = e.pageX - target.offsetLeft;
 
560
                                form.clk_y = e.pageY - target.offsetTop;
 
561
                        }
 
562
                }
 
563
                // clear form vars
 
564
                setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
 
565
        });
 
566
};
 
567
 
 
568
// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
 
569
$.fn.ajaxFormUnbind = function() {
 
570
        return this.unbind('submit.form-plugin click.form-plugin');
 
571
};
 
572
 
 
573
/**
 
574
 * formToArray() gathers form element data into an array of objects that can
 
575
 * be passed to any of the following ajax functions: $.get, $.post, or load.
 
576
 * Each object in the array has both a 'name' and 'value' property.  An example of
 
577
 * an array for a simple login form might be:
 
578
 *
 
579
 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
 
580
 *
 
581
 * It is this array that is passed to pre-submit callback functions provided to the
 
582
 * ajaxSubmit() and ajaxForm() methods.
 
583
 */
 
584
$.fn.formToArray = function(semantic) {
 
585
        var a = [];
 
586
        if (this.length === 0) {
 
587
                return a;
 
588
        }
 
589
 
 
590
        var form = this[0];
 
591
        var els = semantic ? form.getElementsByTagName('*') : form.elements;
 
592
        if (!els) {
 
593
                return a;
 
594
        }
 
595
 
 
596
        var i,j,n,v,el,max,jmax;
 
597
        for(i=0, max=els.length; i < max; i++) {
 
598
                el = els[i];
 
599
                n = el.name;
 
600
                if (!n) {
 
601
                        continue;
 
602
                }
 
603
 
 
604
                if (semantic && form.clk && el.type == "image") {
 
605
                        // handle image inputs on the fly when semantic == true
 
606
                        if(!el.disabled && form.clk == el) {
 
607
                                a.push({name: n, value: $(el).val()});
 
608
                                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
 
609
                        }
 
610
                        continue;
 
611
                }
 
612
 
 
613
                v = $.fieldValue(el, true);
 
614
                if (v && v.constructor == Array) {
 
615
                        for(j=0, jmax=v.length; j < jmax; j++) {
 
616
                                a.push({name: n, value: v[j]});
 
617
                        }
 
618
                }
 
619
                else if (v !== null && typeof v != 'undefined') {
 
620
                        a.push({name: n, value: v});
 
621
                }
 
622
        }
 
623
 
 
624
        if (!semantic && form.clk) {
 
625
                // input type=='image' are not found in elements array! handle it here
 
626
                var $input = $(form.clk), input = $input[0];
 
627
                n = input.name;
 
628
                if (n && !input.disabled && input.type == 'image') {
 
629
                        a.push({name: n, value: $input.val()});
 
630
                        a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
 
631
                }
 
632
        }
 
633
        return a;
 
634
};
 
635
 
 
636
/**
 
637
 * Serializes form data into a 'submittable' string. This method will return a string
 
638
 * in the format: name1=value1&amp;name2=value2
 
639
 */
 
640
$.fn.formSerialize = function(semantic) {
 
641
        //hand off to jQuery.param for proper encoding
 
642
        return $.param(this.formToArray(semantic));
 
643
};
 
644
 
 
645
/**
 
646
 * Serializes all field elements in the jQuery object into a query string.
 
647
 * This method will return a string in the format: name1=value1&amp;name2=value2
 
648
 */
 
649
$.fn.fieldSerialize = function(successful) {
 
650
        var a = [];
 
651
        this.each(function() {
 
652
                var n = this.name;
 
653
                if (!n) {
 
654
                        return;
 
655
                }
 
656
                var v = $.fieldValue(this, successful);
 
657
                if (v && v.constructor == Array) {
 
658
                        for (var i=0,max=v.length; i < max; i++) {
 
659
                                a.push({name: n, value: v[i]});
 
660
                        }
 
661
                }
 
662
                else if (v !== null && typeof v != 'undefined') {
 
663
                        a.push({name: this.name, value: v});
 
664
                }
 
665
        });
 
666
        //hand off to jQuery.param for proper encoding
 
667
        return $.param(a);
 
668
};
 
669
 
 
670
/**
 
671
 * Returns the value(s) of the element in the matched set.  For example, consider the following form:
 
672
 *
 
673
 *  <form><fieldset>
 
674
 *        <input name="A" type="text" />
 
675
 *        <input name="A" type="text" />
 
676
 *        <input name="B" type="checkbox" value="B1" />
 
677
 *        <input name="B" type="checkbox" value="B2"/>
 
678
 *        <input name="C" type="radio" value="C1" />
 
679
 *        <input name="C" type="radio" value="C2" />
 
680
 *  </fieldset></form>
 
681
 *
 
682
 *  var v = $(':text').fieldValue();
 
683
 *  // if no values are entered into the text inputs
 
684
 *  v == ['','']
 
685
 *  // if values entered into the text inputs are 'foo' and 'bar'
 
686
 *  v == ['foo','bar']
 
687
 *
 
688
 *  var v = $(':checkbox').fieldValue();
 
689
 *  // if neither checkbox is checked
 
690
 *  v === undefined
 
691
 *  // if both checkboxes are checked
 
692
 *  v == ['B1', 'B2']
 
693
 *
 
694
 *  var v = $(':radio').fieldValue();
 
695
 *  // if neither radio is checked
 
696
 *  v === undefined
 
697
 *  // if first radio is checked
 
698
 *  v == ['C1']
 
699
 *
 
700
 * The successful argument controls whether or not the field element must be 'successful'
 
701
 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
 
702
 * The default value of the successful argument is true.  If this value is false the value(s)
 
703
 * for each element is returned.
 
704
 *
 
705
 * Note: This method *always* returns an array.  If no valid value can be determined the
 
706
 *         array will be empty, otherwise it will contain one or more values.
 
707
 */
 
708
$.fn.fieldValue = function(successful) {
 
709
        for (var val=[], i=0, max=this.length; i < max; i++) {
 
710
                var el = this[i];
 
711
                var v = $.fieldValue(el, successful);
 
712
                if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
 
713
                        continue;
 
714
                }
 
715
                v.constructor == Array ? $.merge(val, v) : val.push(v);
 
716
        }
 
717
        return val;
 
718
};
 
719
 
 
720
/**
 
721
 * Returns the value of the field element.
 
722
 */
 
723
$.fieldValue = function(el, successful) {
 
724
        var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
 
725
        if (successful === undefined) {
 
726
                successful = true;
 
727
        }
 
728
 
 
729
        if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
 
730
                (t == 'checkbox' || t == 'radio') && !el.checked ||
 
731
                (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
 
732
                tag == 'select' && el.selectedIndex == -1)) {
 
733
                        return null;
 
734
        }
 
735
 
 
736
        if (tag == 'select') {
 
737
                var index = el.selectedIndex;
 
738
                if (index < 0) {
 
739
                        return null;
 
740
                }
 
741
                var a = [], ops = el.options;
 
742
                var one = (t == 'select-one');
 
743
                var max = (one ? index+1 : ops.length);
 
744
                for(var i=(one ? index : 0); i < max; i++) {
 
745
                        var op = ops[i];
 
746
                        if (op.selected) {
 
747
                                var v = op.value;
 
748
                                if (!v) { // extra pain for IE...
 
749
                                        v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
 
750
                                }
 
751
                                if (one) {
 
752
                                        return v;
 
753
                                }
 
754
                                a.push(v);
 
755
                        }
 
756
                }
 
757
                return a;
 
758
        }
 
759
        return $(el).val();
 
760
};
 
761
 
 
762
/**
 
763
 * Clears the form data.  Takes the following actions on the form's input fields:
 
764
 *  - input text fields will have their 'value' property set to the empty string
 
765
 *  - select elements will have their 'selectedIndex' property set to -1
 
766
 *  - checkbox and radio inputs will have their 'checked' property set to false
 
767
 *  - inputs of type submit, button, reset, and hidden will *not* be effected
 
768
 *  - button elements will *not* be effected
 
769
 */
 
770
$.fn.clearForm = function() {
 
771
        return this.each(function() {
 
772
                $('input,select,textarea', this).clearFields();
 
773
        });
 
774
};
 
775
 
 
776
/**
 
777
 * Clears the selected form elements.
 
778
 */
 
779
$.fn.clearFields = $.fn.clearInputs = function() {
 
780
        return this.each(function() {
 
781
                var t = this.type, tag = this.tagName.toLowerCase();
 
782
                if (t == 'text' || t == 'password' || tag == 'textarea') {
 
783
                        this.value = '';
 
784
                }
 
785
                else if (t == 'checkbox' || t == 'radio') {
 
786
                        this.checked = false;
 
787
                }
 
788
                else if (tag == 'select') {
 
789
                        this.selectedIndex = -1;
 
790
                }
 
791
        });
 
792
};
 
793
 
 
794
/**
 
795
 * Resets the form data.  Causes all form elements to be reset to their original value.
 
796
 */
 
797
$.fn.resetForm = function() {
 
798
        return this.each(function() {
 
799
                // guard against an input with the name of 'reset'
 
800
                // note that IE reports the reset function as an 'object'
 
801
                if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
 
802
                        this.reset();
 
803
                }
 
804
        });
 
805
};
 
806
 
 
807
/**
 
808
 * Enables or disables any matching elements.
 
809
 */
 
810
$.fn.enable = function(b) {
 
811
        if (b === undefined) {
 
812
                b = true;
 
813
        }
 
814
        return this.each(function() {
 
815
                this.disabled = !b;
 
816
        });
 
817
};
 
818
 
 
819
/**
 
820
 * Checks/unchecks any matching checkboxes or radio buttons and
 
821
 * selects/deselects and matching option elements.
 
822
 */
 
823
$.fn.selected = function(select) {
 
824
        if (select === undefined) {
 
825
                select = true;
 
826
        }
 
827
        return this.each(function() {
 
828
                var t = this.type;
 
829
                if (t == 'checkbox' || t == 'radio') {
 
830
                        this.checked = select;
 
831
                }
 
832
                else if (this.tagName.toLowerCase() == 'option') {
 
833
                        var $sel = $(this).parent('select');
 
834
                        if (select && $sel[0] && $sel[0].type == 'select-one') {
 
835
                                // deselect all other options
 
836
                                $sel.find('option').selected(false);
 
837
                        }
 
838
                        this.selected = select;
 
839
                }
 
840
        });
 
841
};
 
842
 
 
843
// helper fn for console logging
 
844
// set $.fn.ajaxSubmit.debug to true to enable debug logging
 
845
function log() {
 
846
        if ($.fn.ajaxSubmit.debug) {
 
847
                var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
 
848
                if (window.console && window.console.log) {
 
849
                        window.console.log(msg);
 
850
                }
 
851
                else if (window.opera && window.opera.postError) {
 
852
                        window.opera.postError(msg);
 
853
                }
 
854
        }
 
855
};
 
856
 
 
857
})(jQuery);