hobo_jquery 2.0.0.pre2 → 2.0.0.pre3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,503 +1,691 @@
1
1
  /*!
2
2
  * jQuery Form Plugin
3
- * version: 2.77 (23-MAY-2011)
3
+ * version: 3.17 (25-SEP-2012)
4
4
  * @requires jQuery v1.3.2 or later
5
5
  *
6
6
  * Examples and documentation at: http://malsup.com/jquery/form/
7
+ * Project repository: https://github.com/malsup/form
7
8
  * 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
9
+ * http://malsup.github.com/mit-license.txt
10
+ * http://malsup.github.com/gpl-license-v2.txt
10
11
  */
12
+ /*global ActiveXObject alert */
11
13
  ;(function($) {
14
+ "use strict";
12
15
 
13
16
  /*
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.
17
+ Usage Note:
18
+ -----------
19
+ Do not use both ajaxSubmit and ajaxForm on the same form. These
20
+ functions are mutually exclusive. Use ajaxSubmit if you want
21
+ to bind your own submit handler to the form. For example,
22
+
23
+ $(document).ready(function() {
24
+ $('#myForm').on('submit', function(e) {
25
+ e.preventDefault(); // <-- important
26
+ $(this).ajaxSubmit({
27
+ target: '#output'
28
+ });
29
+ });
30
+ });
31
+
32
+ Use ajaxForm when you want the plugin to manage all the event binding
33
+ for you. For example,
34
+
35
+ $(document).ready(function() {
36
+ $('#myForm').ajaxForm({
37
+ target: '#output'
38
+ });
39
+ });
40
+
41
+ You can also use ajaxForm with delegation (requires jQuery v1.7+), so the
42
+ form does not have to exist when you invoke ajaxForm:
43
+
44
+ $('#myForm').ajaxForm({
45
+ delegation: true,
46
+ target: '#output'
47
+ });
48
+
49
+ When using ajaxForm, the ajaxSubmit function will be invoked for you
50
+ at the appropriate time.
40
51
  */
41
52
 
53
+ /**
54
+ * Feature detection
55
+ */
56
+ var feature = {};
57
+ feature.fileapi = $("<input type='file'/>").get(0).files !== undefined;
58
+ feature.formdata = window.FormData !== undefined;
59
+
42
60
  /**
43
61
  * ajaxSubmit() provides a mechanism for immediately submitting
44
62
  * an HTML form using AJAX.
45
63
  */
46
64
  $.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');
65
+ /*jshint scripturl:true */
66
+
67
+ // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
68
+ if (!this.length) {
69
+ log('ajaxSubmit: skipping submit process - no element selected');
70
+ return this;
71
+ }
72
+
73
+ var method, action, url, $form = this;
74
+
75
+ if (typeof options == 'function') {
76
+ options = { success: options };
77
+ }
78
+
79
+ method = this.attr('method');
80
+ action = this.attr('action');
81
+ url = (typeof action === 'string') ? $.trim(action) : '';
82
+ url = url || window.location.href || '';
83
+ if (url) {
84
+ // clean url (don't include hash vaue)
85
+ url = (url.match(/^([^#]+)/)||[])[1];
86
+ }
87
+
88
+ options = $.extend(true, {
89
+ url: url,
90
+ success: $.ajaxSettings.success,
91
+ type: method || 'GET',
92
+ iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
93
+ }, options);
94
+
95
+ // hook for manipulating the form data before it is extracted;
96
+ // convenient for use with rich editors like tinyMCE or FCKEditor
97
+ var veto = {};
98
+ this.trigger('form-pre-serialize', [this, options, veto]);
99
+ if (veto.veto) {
100
+ log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
101
+ return this;
102
+ }
103
+
104
+ // provide opportunity to alter form data before it is serialized
105
+ if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
106
+ log('ajaxSubmit: submit aborted via beforeSerialize callback');
107
+ return this;
108
+ }
109
+
110
+ var traditional = options.traditional;
111
+ if ( traditional === undefined ) {
112
+ traditional = $.ajaxSettings.traditional;
113
+ }
114
+
115
+ var elements = [];
116
+ var qx, a = this.formToArray(options.semantic, elements);
117
+ if (options.data) {
118
+ options.extraData = options.data;
119
+ qx = $.param(options.data, traditional);
120
+ }
121
+
122
+ // give pre-submit callback an opportunity to abort the submit
123
+ if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
124
+ log('ajaxSubmit: submit aborted via beforeSubmit callback');
125
+ return this;
126
+ }
127
+
128
+ // fire vetoable 'validate' event
129
+ this.trigger('form-submit-validate', [a, this, options, veto]);
130
+ if (veto.veto) {
131
+ log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
132
+ return this;
133
+ }
134
+
135
+ var q = $.param(a, traditional);
136
+ if (qx) {
137
+ q = ( q ? (q + '&' + qx) : qx );
138
+ }
139
+ if (options.type.toUpperCase() == 'GET') {
140
+ options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
141
+ options.data = null; // data is null for 'get'
142
+ }
143
+ else {
144
+ options.data = q; // data is the query string for 'post'
145
+ }
146
+
147
+ var callbacks = [];
148
+ if (options.resetForm) {
149
+ callbacks.push(function() { $form.resetForm(); });
150
+ }
151
+ if (options.clearForm) {
152
+ callbacks.push(function() { $form.clearForm(options.includeHidden); });
153
+ }
154
+
155
+ // perform a load on the target only if dataType is not provided
156
+ if (!options.dataType && options.target) {
157
+ var oldSuccess = options.success || function(){};
158
+ callbacks.push(function(data) {
159
+ var fn = options.replaceTarget ? 'replaceWith' : 'html';
160
+ $(options.target)[fn](data).each(oldSuccess, arguments);
161
+ });
162
+ }
163
+ else if (options.success) {
164
+ callbacks.push(options.success);
165
+ }
166
+
167
+ options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
168
+ var context = options.context || this ; // jQuery 1.4+ supports scope context
169
+ for (var i=0, max=callbacks.length; i < max; i++) {
170
+ callbacks[i].apply(context, [data, status, xhr || $form, $form]);
171
+ }
172
+ };
173
+
174
+ // are there files to upload?
175
+ var fileInputs = $('input:file:enabled[value]', this); // [value] (issue #113)
176
+ var hasFileInputs = fileInputs.length > 0;
177
+ var mp = 'multipart/form-data';
178
+ var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
179
+
180
+ var fileAPI = feature.fileapi && feature.formdata;
181
+ log("fileAPI :" + fileAPI);
182
+ var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI;
183
+
184
+ // options.iframe allows user to force iframe mode
185
+ // 06-NOV-09: now defaulting to iframe mode if file input is detected
186
+ if (options.iframe !== false && (options.iframe || shouldUseFrame)) {
187
+ // hack to fix Safari hang (thanks to Tim Molendijk for this)
188
+ // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
189
+ if (options.closeKeepAlive) {
190
+ $.get(options.closeKeepAlive, function() {
191
+ fileUploadIframe(a);
192
+ });
193
+ }
194
+ else {
195
+ fileUploadIframe(a);
196
+ }
197
+ }
198
+ else if ((hasFileInputs || multipart) && fileAPI) {
199
+ options.jqxhr = fileUploadXhr(a);
200
+ }
201
+ else {
202
+ options.jqxhr = $.ajax(options);
203
+ }
204
+
205
+ // clear element array
206
+ for (var k=0; k < elements.length; k++)
207
+ elements[k] = null;
208
+
209
+ // fire 'notify' event
210
+ this.trigger('form-submit-notify', [this, options]);
211
+ return this;
212
+
213
+ // utility fn for deep serialization
214
+ function deepSerialize(extraData){
215
+ var serialized = $.param(extraData).split('&');
216
+ var len = serialized.length;
217
+ var result = {};
218
+ var i, part;
219
+ for (i=0; i < len; i++) {
220
+ part = serialized[i].split('=');
221
+ result[decodeURIComponent(part[0])] = decodeURIComponent(part[1]);
222
+ }
223
+ return result;
224
+ }
225
+
226
+ // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)
227
+ function fileUploadXhr(a) {
228
+ var formdata = new FormData();
229
+
230
+ for (var i=0; i < a.length; i++) {
231
+ formdata.append(a[i].name, a[i].value);
232
+ }
233
+
234
+ if (options.extraData) {
235
+ var serializedData = deepSerialize(options.extraData);
236
+ for (var p in serializedData)
237
+ if (serializedData.hasOwnProperty(p))
238
+ formdata.append(p, serializedData[p]);
239
+ }
240
+
241
+ options.data = null;
242
+
243
+ var s = $.extend(true, {}, $.ajaxSettings, options, {
244
+ contentType: false,
245
+ processData: false,
246
+ cache: false,
247
+ type: method || 'POST'
248
+ });
249
+
250
+ if (options.uploadProgress) {
251
+ // workaround because jqXHR does not expose upload property
252
+ s.xhr = function() {
253
+ var xhr = jQuery.ajaxSettings.xhr();
254
+ if (xhr.upload) {
255
+ xhr.upload.onprogress = function(event) {
256
+ var percent = 0;
257
+ var position = event.loaded || event.position; /*event.position is deprecated*/
258
+ var total = event.total;
259
+ if (event.lengthComputable) {
260
+ percent = Math.ceil(position / total * 100);
261
+ }
262
+ options.uploadProgress(event, position, total, percent);
263
+ };
264
+ }
265
+ return xhr;
266
+ };
267
+ }
268
+
269
+ s.data = null;
270
+ var beforeSend = s.beforeSend;
271
+ s.beforeSend = function(xhr, o) {
272
+ o.data = formdata;
273
+ if(beforeSend)
274
+ beforeSend.call(this, xhr, o);
275
+ };
276
+ return $.ajax(s);
277
+ }
278
+
279
+ // private function for handling file uploads (hat tip to YAHOO!)
280
+ function fileUploadIframe(a) {
281
+ var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
282
+ var useProp = !!$.fn.prop;
283
+
284
+ if ($(':input[name=submit],:input[id=submit]', form).length) {
285
+ // if there is an input with a name or id of 'submit' then we won't be
286
+ // able to invoke the submit fn on the form (at least not x-browser)
287
+ alert('Error: Form elements must not have name or id of "submit".');
288
+ return;
289
+ }
290
+
291
+ if (a) {
292
+ // ensure that every serialized input is still enabled
293
+ for (i=0; i < elements.length; i++) {
294
+ el = $(elements[i]);
295
+ if ( useProp )
296
+ el.prop('disabled', false);
297
+ else
298
+ el.removeAttr('disabled');
299
+ }
300
+ }
301
+
302
+ s = $.extend(true, {}, $.ajaxSettings, options);
303
+ s.context = s.context || s;
304
+ id = 'jqFormIO' + (new Date().getTime());
305
+ if (s.iframeTarget) {
306
+ $io = $(s.iframeTarget);
307
+ n = $io.attr('name');
308
+ if (!n)
309
+ $io.attr('name', id);
310
+ else
311
+ id = n;
312
+ }
313
+ else {
314
+ $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');
315
+ $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
316
+ }
317
+ io = $io[0];
318
+
319
+
320
+ xhr = { // mock object
321
+ aborted: 0,
322
+ responseText: null,
323
+ responseXML: null,
324
+ status: 0,
325
+ statusText: 'n/a',
326
+ getAllResponseHeaders: function() {},
327
+ getResponseHeader: function() {},
328
+ setRequestHeader: function() {},
329
+ abort: function(status) {
330
+ var e = (status === 'timeout' ? 'timeout' : 'aborted');
331
+ log('aborting upload... ' + e);
332
+ this.aborted = 1;
333
+ // #214
334
+ if (io.contentWindow.document.execCommand) {
335
+ try { // #214
336
+ io.contentWindow.document.execCommand('Stop');
337
+ } catch(ignore) {}
338
+ }
339
+ $io.attr('src', s.iframeSrc); // abort op in progress
340
+ xhr.error = e;
341
+ if (s.error)
342
+ s.error.call(s.context, xhr, e, status);
343
+ if (g)
344
+ $.event.trigger("ajaxError", [xhr, s, e]);
345
+ if (s.complete)
346
+ s.complete.call(s.context, xhr, e);
347
+ }
348
+ };
349
+
350
+ g = s.global;
351
+ // trigger ajax global events so that activity/block indicators work like normal
352
+ if (g && 0 === $.active++) {
353
+ $.event.trigger("ajaxStart");
354
+ }
355
+ if (g) {
356
+ $.event.trigger("ajaxSend", [xhr, s]);
357
+ }
358
+
359
+ if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
360
+ if (s.global) {
361
+ $.active--;
362
+ }
363
+ return;
364
+ }
365
+ if (xhr.aborted) {
366
+ return;
367
+ }
368
+
369
+ // add submitting element to data if we know it
370
+ sub = form.clk;
371
+ if (sub) {
372
+ n = sub.name;
373
+ if (n && !sub.disabled) {
374
+ s.extraData = s.extraData || {};
375
+ s.extraData[n] = sub.value;
376
+ if (sub.type == "image") {
377
+ s.extraData[n+'.x'] = form.clk_x;
378
+ s.extraData[n+'.y'] = form.clk_y;
379
+ }
380
+ }
381
+ }
382
+
383
+ var CLIENT_TIMEOUT_ABORT = 1;
384
+ var SERVER_ABORT = 2;
385
+
386
+ function getDoc(frame) {
387
+ var doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument ? frame.contentDocument : frame.document;
388
+ return doc;
389
+ }
390
+
391
+ // Rails CSRF hack (thanks to Yvan Barthelemy)
392
+ var csrf_token = $('meta[name=csrf-token]').attr('content');
393
+ var csrf_param = $('meta[name=csrf-param]').attr('content');
394
+ if (csrf_param && csrf_token) {
395
+ s.extraData = s.extraData || {};
396
+ s.extraData[csrf_param] = csrf_token;
397
+ }
398
+
399
+ // take a breath so that pending repaints get some cpu time before the upload starts
400
+ function doSubmit() {
401
+ // make sure form attrs are set
402
+ var t = $form.attr('target'), a = $form.attr('action');
403
+
404
+ // update form attrs in IE friendly way
405
+ form.setAttribute('target',id);
406
+ if (!method) {
407
+ form.setAttribute('method', 'POST');
408
+ }
409
+ if (a != s.url) {
410
+ form.setAttribute('action', s.url);
411
+ }
412
+
413
+ // ie borks in some cases when setting encoding
414
+ if (! s.skipEncodingOverride && (!method || /post/i.test(method))) {
415
+ $form.attr({
416
+ encoding: 'multipart/form-data',
417
+ enctype: 'multipart/form-data'
418
+ });
419
+ }
420
+
421
+ // support timout
422
+ if (s.timeout) {
423
+ timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);
424
+ }
425
+
426
+ // look for server aborts
427
+ function checkState() {
428
+ try {
429
+ var state = getDoc(io).readyState;
430
+ log('state = ' + state);
431
+ if (state && state.toLowerCase() == 'uninitialized')
432
+ setTimeout(checkState,50);
433
+ }
434
+ catch(e) {
435
+ log('Server abort: ' , e, ' (', e.name, ')');
436
+ cb(SERVER_ABORT);
437
+ if (timeoutHandle)
438
+ clearTimeout(timeoutHandle);
439
+ timeoutHandle = undefined;
440
+ }
441
+ }
442
+
443
+ // add "extra" data to form if provided in options
444
+ var extraInputs = [];
445
+ try {
446
+ if (s.extraData) {
447
+ for (var n in s.extraData) {
448
+ if (s.extraData.hasOwnProperty(n)) {
449
+ // if using the $.param format that allows for multiple values with the same name
450
+ if($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) {
451
+ extraInputs.push(
452
+ $('<input type="hidden" name="'+s.extraData[n].name+'">').attr('value',s.extraData[n].value)
453
+ .appendTo(form)[0]);
454
+ } else {
455
+ extraInputs.push(
456
+ $('<input type="hidden" name="'+n+'">').attr('value',s.extraData[n])
457
+ .appendTo(form)[0]);
458
+ }
459
+ }
460
+ }
461
+ }
462
+
463
+ if (!s.iframeTarget) {
464
+ // add iframe to doc and submit the form
465
+ $io.appendTo('body');
466
+ if (io.attachEvent)
467
+ io.attachEvent('onload', cb);
468
+ else
469
+ io.addEventListener('load', cb, false);
470
+ }
471
+ setTimeout(checkState,15);
472
+ form.submit();
473
+ }
474
+ finally {
475
+ // reset attrs and remove "extra" input elements
476
+ form.setAttribute('action',a);
477
+ if(t) {
478
+ form.setAttribute('target', t);
479
+ } else {
480
+ $form.removeAttr('target');
481
+ }
482
+ $(extraInputs).remove();
483
+ }
484
+ }
485
+
486
+ if (s.forceSync) {
487
+ doSubmit();
488
+ }
489
+ else {
490
+ setTimeout(doSubmit, 10); // this lets dom updates render
491
+ }
492
+
493
+ var data, doc, domCheckCount = 50, callbackProcessed;
494
+
495
+ function cb(e) {
496
+ if (xhr.aborted || callbackProcessed) {
497
+ return;
498
+ }
499
+ try {
500
+ doc = getDoc(io);
501
+ }
502
+ catch(ex) {
503
+ log('cannot access response document: ', ex);
504
+ e = SERVER_ABORT;
505
+ }
506
+ if (e === CLIENT_TIMEOUT_ABORT && xhr) {
507
+ xhr.abort('timeout');
508
+ return;
509
+ }
510
+ else if (e == SERVER_ABORT && xhr) {
511
+ xhr.abort('server abort');
512
+ return;
513
+ }
514
+
515
+ if (!doc || doc.location.href == s.iframeSrc) {
516
+ // response not received yet
517
+ if (!timedOut)
518
+ return;
519
+ }
520
+ if (io.detachEvent)
521
+ io.detachEvent('onload', cb);
522
+ else
523
+ io.removeEventListener('load', cb, false);
524
+
525
+ var status = 'success', errMsg;
526
+ try {
527
+ if (timedOut) {
528
+ throw 'timeout';
529
+ }
530
+
531
+ var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
532
+ log('isXml='+isXml);
533
+ if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) {
534
+ if (--domCheckCount) {
535
+ // in some browsers (Opera) the iframe DOM is not always traversable when
536
+ // the onload callback fires, so we loop a bit to accommodate
537
+ log('requeing onLoad callback, DOM not available');
538
+ setTimeout(cb, 250);
539
+ return;
540
+ }
541
+ // let this fall through because server response could be an empty document
542
+ //log('Could not access iframe DOM after mutiple tries.');
543
+ //throw 'DOMException: not available';
544
+ }
545
+
546
+ //log('response detected');
368
547
  var docRoot = doc.body ? doc.body : doc.documentElement;
369
548
  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
- };
549
+ xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
550
+ if (isXml)
551
+ s.dataType = 'xml';
552
+ xhr.getResponseHeader = function(header){
553
+ var headers = {'content-type': s.dataType};
554
+ return headers[header];
555
+ };
377
556
  // support for XHR 'status' & 'statusText' emulation :
378
557
  if (docRoot) {
379
558
  xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;
380
559
  xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;
381
560
  }
382
561
 
383
- var scr = /(json|script|text)/.test(s.dataType.toLowerCase());
384
- if (scr || s.textarea) {
385
- // see if user embedded response in textarea
386
- var ta = doc.getElementsByTagName('textarea')[0];
387
- if (ta) {
388
- xhr.responseText = ta.value;
562
+ var dt = (s.dataType || '').toLowerCase();
563
+ var scr = /(json|script|text)/.test(dt);
564
+ if (scr || s.textarea) {
565
+ // see if user embedded response in textarea
566
+ var ta = doc.getElementsByTagName('textarea')[0];
567
+ if (ta) {
568
+ xhr.responseText = ta.value;
389
569
  // support for XHR 'status' & 'statusText' emulation :
390
570
  xhr.status = Number( ta.getAttribute('status') ) || xhr.status;
391
571
  xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;
392
- }
393
- else if (scr) {
394
- // account for browsers injecting pre around json response
395
- var pre = doc.getElementsByTagName('pre')[0];
396
- var b = doc.getElementsByTagName('body')[0];
397
- if (pre) {
398
- xhr.responseText = pre.textContent ? pre.textContent : pre.innerHTML;
399
- }
400
- else if (b) {
401
- xhr.responseText = b.innerHTML;
402
- }
403
- }
404
- }
405
- else if (s.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
406
- xhr.responseXML = toXml(xhr.responseText);
407
- }
572
+ }
573
+ else if (scr) {
574
+ // account for browsers injecting pre around json response
575
+ var pre = doc.getElementsByTagName('pre')[0];
576
+ var b = doc.getElementsByTagName('body')[0];
577
+ if (pre) {
578
+ xhr.responseText = pre.textContent ? pre.textContent : pre.innerText;
579
+ }
580
+ else if (b) {
581
+ xhr.responseText = b.textContent ? b.textContent : b.innerText;
582
+ }
583
+ }
584
+ }
585
+ else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) {
586
+ xhr.responseXML = toXml(xhr.responseText);
587
+ }
408
588
 
409
589
  try {
410
- data = httpData(xhr, s.dataType, s);
590
+ data = httpData(xhr, dt, s);
411
591
  }
412
592
  catch (e) {
413
593
  status = 'parsererror';
414
594
  xhr.error = errMsg = (e || status);
415
595
  }
416
- }
417
- catch (e) {
418
- log('error caught',e);
419
- status = 'error';
596
+ }
597
+ catch (e) {
598
+ log('error caught: ',e);
599
+ status = 'error';
420
600
  xhr.error = errMsg = (e || status);
421
- }
601
+ }
422
602
 
423
- if (xhr.aborted) {
424
- log('upload aborted');
425
- status = null;
426
- }
603
+ if (xhr.aborted) {
604
+ log('upload aborted');
605
+ status = null;
606
+ }
427
607
 
428
608
  if (xhr.status) { // we've set xhr.status
429
609
  status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';
430
610
  }
431
611
 
432
- // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
433
- if (status === 'success') {
434
- s.success && s.success.call(s.context, data, 'success', xhr);
435
- g && $.event.trigger("ajaxSuccess", [xhr, s]);
436
- }
612
+ // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
613
+ if (status === 'success') {
614
+ if (s.success)
615
+ s.success.call(s.context, data, 'success', xhr);
616
+ if (g)
617
+ $.event.trigger("ajaxSuccess", [xhr, s]);
618
+ }
437
619
  else if (status) {
438
- if (errMsg == undefined)
439
- errMsg = xhr.statusText;
440
- s.error && s.error.call(s.context, xhr, status, errMsg);
441
- g && $.event.trigger("ajaxError", [xhr, s, errMsg]);
442
- }
443
-
444
- g && $.event.trigger("ajaxComplete", [xhr, s]);
445
-
446
- if (g && ! --$.active) {
447
- $.event.trigger("ajaxStop");
448
- }
449
-
450
- s.complete && s.complete.call(s.context, xhr, status);
451
-
452
- callbackProcessed = true;
453
- if (s.timeout)
454
- clearTimeout(timeoutHandle);
455
-
456
- // clean up
457
- setTimeout(function() {
458
- if (!s.iframeTarget)
459
- $io.remove();
460
- xhr.responseXML = null;
461
- }, 100);
462
- }
463
-
464
- var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
465
- if (window.ActiveXObject) {
466
- doc = new ActiveXObject('Microsoft.XMLDOM');
467
- doc.async = 'false';
468
- doc.loadXML(s);
469
- }
470
- else {
471
- doc = (new DOMParser()).parseFromString(s, 'text/xml');
472
- }
473
- return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
474
- };
475
- var parseJSON = $.parseJSON || function(s) {
476
- return window['eval']('(' + s + ')');
477
- };
478
-
479
- var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
480
-
481
- var ct = xhr.getResponseHeader('content-type') || '',
482
- xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
483
- data = xml ? xhr.responseXML : xhr.responseText;
484
-
485
- if (xml && data.documentElement.nodeName === 'parsererror') {
486
- $.error && $.error('parsererror');
487
- }
488
- if (s && s.dataFilter) {
489
- data = s.dataFilter(data, type);
490
- }
491
- if (typeof data === 'string') {
492
- if (type === 'json' || !type && ct.indexOf('json') >= 0) {
493
- data = parseJSON(data);
494
- } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
495
- $.globalEval(data);
496
- }
497
- }
498
- return data;
499
- };
500
- }
620
+ if (errMsg === undefined)
621
+ errMsg = xhr.statusText;
622
+ if (s.error)
623
+ s.error.call(s.context, xhr, status, errMsg);
624
+ if (g)
625
+ $.event.trigger("ajaxError", [xhr, s, errMsg]);
626
+ }
627
+
628
+ if (g)
629
+ $.event.trigger("ajaxComplete", [xhr, s]);
630
+
631
+ if (g && ! --$.active) {
632
+ $.event.trigger("ajaxStop");
633
+ }
634
+
635
+ if (s.complete)
636
+ s.complete.call(s.context, xhr, status);
637
+
638
+ callbackProcessed = true;
639
+ if (s.timeout)
640
+ clearTimeout(timeoutHandle);
641
+
642
+ // clean up
643
+ setTimeout(function() {
644
+ if (!s.iframeTarget)
645
+ $io.remove();
646
+ xhr.responseXML = null;
647
+ }, 100);
648
+ }
649
+
650
+ var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
651
+ if (window.ActiveXObject) {
652
+ doc = new ActiveXObject('Microsoft.XMLDOM');
653
+ doc.async = 'false';
654
+ doc.loadXML(s);
655
+ }
656
+ else {
657
+ doc = (new DOMParser()).parseFromString(s, 'text/xml');
658
+ }
659
+ return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
660
+ };
661
+ var parseJSON = $.parseJSON || function(s) {
662
+ /*jslint evil:true */
663
+ return window['eval']('(' + s + ')');
664
+ };
665
+
666
+ var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
667
+
668
+ var ct = xhr.getResponseHeader('content-type') || '',
669
+ xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
670
+ data = xml ? xhr.responseXML : xhr.responseText;
671
+
672
+ if (xml && data.documentElement.nodeName === 'parsererror') {
673
+ if ($.error)
674
+ $.error('parsererror');
675
+ }
676
+ if (s && s.dataFilter) {
677
+ data = s.dataFilter(data, type);
678
+ }
679
+ if (typeof data === 'string') {
680
+ if (type === 'json' || !type && ct.indexOf('json') >= 0) {
681
+ data = parseJSON(data);
682
+ } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
683
+ $.globalEval(data);
684
+ }
685
+ }
686
+ return data;
687
+ };
688
+ }
501
689
  };
502
690
 
503
691
  /**
@@ -506,9 +694,9 @@ $.fn.ajaxSubmit = function(options) {
506
694
  * The advantages of using this method instead of ajaxSubmit() are:
507
695
  *
508
696
  * 1: This method will include coordinates for <input type="image" /> elements (if the element
509
- * is used to submit the form).
697
+ * is used to submit the form).
510
698
  * 2. This method will include the submit element's name/value data (for the element that was
511
- * used to submit the form).
699
+ * used to submit the form).
512
700
  * 3. This method binds the submit() method to the form for you.
513
701
  *
514
702
  * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
@@ -516,60 +704,83 @@ $.fn.ajaxSubmit = function(options) {
516
704
  * the form itself.
517
705
  */
518
706
  $.fn.ajaxForm = function(options) {
519
- // in jQuery 1.3+ we can fix mistakes with the ready state
520
- if (this.length === 0) {
521
- var o = { s: this.selector, c: this.context };
522
- if (!$.isReady && o.s) {
523
- log('DOM not ready, queuing ajaxForm');
524
- $(function() {
525
- $(o.s,o.c).ajaxForm(options);
526
- });
527
- return this;
528
- }
529
- // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
530
- log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
531
- return this;
532
- }
533
-
534
- return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
535
- if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
536
- e.preventDefault();
537
- $(this).ajaxSubmit(options);
538
- }
539
- }).bind('click.form-plugin', function(e) {
540
- var target = e.target;
541
- var $el = $(target);
542
- if (!($el.is(":submit,input:image"))) {
543
- // is this a child element of the submit el? (ex: a span within a button)
544
- var t = $el.closest(':submit');
545
- if (t.length == 0) {
546
- return;
547
- }
548
- target = t[0];
549
- }
550
- var form = this;
551
- form.clk = target;
552
- if (target.type == 'image') {
553
- if (e.offsetX != undefined) {
554
- form.clk_x = e.offsetX;
555
- form.clk_y = e.offsetY;
556
- } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
557
- var offset = $el.offset();
558
- form.clk_x = e.pageX - offset.left;
559
- form.clk_y = e.pageY - offset.top;
560
- } else {
561
- form.clk_x = e.pageX - target.offsetLeft;
562
- form.clk_y = e.pageY - target.offsetTop;
563
- }
564
- }
565
- // clear form vars
566
- setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
567
- });
707
+ options = options || {};
708
+ options.delegation = options.delegation && $.isFunction($.fn.on);
709
+
710
+ // in jQuery 1.3+ we can fix mistakes with the ready state
711
+ if (!options.delegation && this.length === 0) {
712
+ var o = { s: this.selector, c: this.context };
713
+ if (!$.isReady && o.s) {
714
+ log('DOM not ready, queuing ajaxForm');
715
+ $(function() {
716
+ $(o.s,o.c).ajaxForm(options);
717
+ });
718
+ return this;
719
+ }
720
+ // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
721
+ log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
722
+ return this;
723
+ }
724
+
725
+ if ( options.delegation ) {
726
+ $(document)
727
+ .off('submit.form-plugin', this.selector, doAjaxSubmit)
728
+ .off('click.form-plugin', this.selector, captureSubmittingElement)
729
+ .on('submit.form-plugin', this.selector, options, doAjaxSubmit)
730
+ .on('click.form-plugin', this.selector, options, captureSubmittingElement);
731
+ return this;
732
+ }
733
+
734
+ return this.ajaxFormUnbind()
735
+ .bind('submit.form-plugin', options, doAjaxSubmit)
736
+ .bind('click.form-plugin', options, captureSubmittingElement);
568
737
  };
569
738
 
739
+ // private event handlers
740
+ function doAjaxSubmit(e) {
741
+ /*jshint validthis:true */
742
+ var options = e.data;
743
+ if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
744
+ e.preventDefault();
745
+ $(this).ajaxSubmit(options);
746
+ }
747
+ }
748
+
749
+ function captureSubmittingElement(e) {
750
+ /*jshint validthis:true */
751
+ var target = e.target;
752
+ var $el = $(target);
753
+ if (!($el.is(":submit,input:image"))) {
754
+ // is this a child element of the submit el? (ex: a span within a button)
755
+ var t = $el.closest(':submit');
756
+ if (t.length === 0) {
757
+ return;
758
+ }
759
+ target = t[0];
760
+ }
761
+ var form = this;
762
+ form.clk = target;
763
+ if (target.type == 'image') {
764
+ if (e.offsetX !== undefined) {
765
+ form.clk_x = e.offsetX;
766
+ form.clk_y = e.offsetY;
767
+ } else if (typeof $.fn.offset == 'function') {
768
+ var offset = $el.offset();
769
+ form.clk_x = e.pageX - offset.left;
770
+ form.clk_y = e.pageY - offset.top;
771
+ } else {
772
+ form.clk_x = e.pageX - target.offsetLeft;
773
+ form.clk_y = e.pageY - target.offsetTop;
774
+ }
775
+ }
776
+ // clear form vars
777
+ setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
778
+ }
779
+
780
+
570
781
  // ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
571
782
  $.fn.ajaxFormUnbind = function() {
572
- return this.unbind('submit.form-plugin click.form-plugin');
783
+ return this.unbind('submit.form-plugin click.form-plugin');
573
784
  };
574
785
 
575
786
  /**
@@ -583,56 +794,74 @@ $.fn.ajaxFormUnbind = function() {
583
794
  * It is this array that is passed to pre-submit callback functions provided to the
584
795
  * ajaxSubmit() and ajaxForm() methods.
585
796
  */
586
- $.fn.formToArray = function(semantic) {
587
- var a = [];
588
- if (this.length === 0) {
589
- return a;
590
- }
591
-
592
- var form = this[0];
593
- var els = semantic ? form.getElementsByTagName('*') : form.elements;
594
- if (!els) {
595
- return a;
596
- }
597
-
598
- var i,j,n,v,el,max,jmax;
599
- for(i=0, max=els.length; i < max; i++) {
600
- el = els[i];
601
- n = el.name;
602
- if (!n) {
603
- continue;
604
- }
605
-
606
- if (semantic && form.clk && el.type == "image") {
607
- // handle image inputs on the fly when semantic == true
608
- if(!el.disabled && form.clk == el) {
609
- a.push({name: n, value: $(el).val()});
610
- a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
611
- }
612
- continue;
613
- }
614
-
615
- v = $.fieldValue(el, true);
616
- if (v && v.constructor == Array) {
617
- for(j=0, jmax=v.length; j < jmax; j++) {
618
- a.push({name: n, value: v[j]});
619
- }
620
- }
621
- else if (v !== null && typeof v != 'undefined') {
622
- a.push({name: n, value: v});
623
- }
624
- }
625
-
626
- if (!semantic && form.clk) {
627
- // input type=='image' are not found in elements array! handle it here
628
- var $input = $(form.clk), input = $input[0];
629
- n = input.name;
630
- if (n && !input.disabled && input.type == 'image') {
631
- a.push({name: n, value: $input.val()});
632
- a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
633
- }
634
- }
635
- return a;
797
+ $.fn.formToArray = function(semantic, elements) {
798
+ var a = [];
799
+ if (this.length === 0) {
800
+ return a;
801
+ }
802
+
803
+ var form = this[0];
804
+ var els = semantic ? form.getElementsByTagName('*') : form.elements;
805
+ if (!els) {
806
+ return a;
807
+ }
808
+
809
+ var i,j,n,v,el,max,jmax;
810
+ for(i=0, max=els.length; i < max; i++) {
811
+ el = els[i];
812
+ n = el.name;
813
+ if (!n) {
814
+ continue;
815
+ }
816
+
817
+ if (semantic && form.clk && el.type == "image") {
818
+ // handle image inputs on the fly when semantic == true
819
+ if(!el.disabled && form.clk == el) {
820
+ a.push({name: n, value: $(el).val(), type: el.type });
821
+ a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
822
+ }
823
+ continue;
824
+ }
825
+
826
+ v = $.fieldValue(el, true);
827
+ if (v && v.constructor == Array) {
828
+ if (elements)
829
+ elements.push(el);
830
+ for(j=0, jmax=v.length; j < jmax; j++) {
831
+ a.push({name: n, value: v[j]});
832
+ }
833
+ }
834
+ else if (feature.fileapi && el.type == 'file' && !el.disabled) {
835
+ if (elements)
836
+ elements.push(el);
837
+ var files = el.files;
838
+ if (files.length) {
839
+ for (j=0; j < files.length; j++) {
840
+ a.push({name: n, value: files[j], type: el.type});
841
+ }
842
+ }
843
+ else {
844
+ // #180
845
+ a.push({ name: n, value: '', type: el.type });
846
+ }
847
+ }
848
+ else if (v !== null && typeof v != 'undefined') {
849
+ if (elements)
850
+ elements.push(el);
851
+ a.push({name: n, value: v, type: el.type, required: el.required});
852
+ }
853
+ }
854
+
855
+ if (!semantic && form.clk) {
856
+ // input type=='image' are not found in elements array! handle it here
857
+ var $input = $(form.clk), input = $input[0];
858
+ n = input.name;
859
+ if (n && !input.disabled && input.type == 'image') {
860
+ a.push({name: n, value: $input.val()});
861
+ a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
862
+ }
863
+ }
864
+ return a;
636
865
  };
637
866
 
638
867
  /**
@@ -640,8 +869,8 @@ $.fn.formToArray = function(semantic) {
640
869
  * in the format: name1=value1&amp;name2=value2
641
870
  */
642
871
  $.fn.formSerialize = function(semantic) {
643
- //hand off to jQuery.param for proper encoding
644
- return $.param(this.formToArray(semantic));
872
+ //hand off to jQuery.param for proper encoding
873
+ return $.param(this.formToArray(semantic));
645
874
  };
646
875
 
647
876
  /**
@@ -649,36 +878,36 @@ $.fn.formSerialize = function(semantic) {
649
878
  * This method will return a string in the format: name1=value1&amp;name2=value2
650
879
  */
651
880
  $.fn.fieldSerialize = function(successful) {
652
- var a = [];
653
- this.each(function() {
654
- var n = this.name;
655
- if (!n) {
656
- return;
657
- }
658
- var v = $.fieldValue(this, successful);
659
- if (v && v.constructor == Array) {
660
- for (var i=0,max=v.length; i < max; i++) {
661
- a.push({name: n, value: v[i]});
662
- }
663
- }
664
- else if (v !== null && typeof v != 'undefined') {
665
- a.push({name: this.name, value: v});
666
- }
667
- });
668
- //hand off to jQuery.param for proper encoding
669
- return $.param(a);
881
+ var a = [];
882
+ this.each(function() {
883
+ var n = this.name;
884
+ if (!n) {
885
+ return;
886
+ }
887
+ var v = $.fieldValue(this, successful);
888
+ if (v && v.constructor == Array) {
889
+ for (var i=0,max=v.length; i < max; i++) {
890
+ a.push({name: n, value: v[i]});
891
+ }
892
+ }
893
+ else if (v !== null && typeof v != 'undefined') {
894
+ a.push({name: this.name, value: v});
895
+ }
896
+ });
897
+ //hand off to jQuery.param for proper encoding
898
+ return $.param(a);
670
899
  };
671
900
 
672
901
  /**
673
902
  * Returns the value(s) of the element in the matched set. For example, consider the following form:
674
903
  *
675
904
  * <form><fieldset>
676
- * <input name="A" type="text" />
677
- * <input name="A" type="text" />
678
- * <input name="B" type="checkbox" value="B1" />
679
- * <input name="B" type="checkbox" value="B2"/>
680
- * <input name="C" type="radio" value="C1" />
681
- * <input name="C" type="radio" value="C2" />
905
+ * <input name="A" type="text" />
906
+ * <input name="A" type="text" />
907
+ * <input name="B" type="checkbox" value="B1" />
908
+ * <input name="B" type="checkbox" value="B2"/>
909
+ * <input name="C" type="radio" value="C1" />
910
+ * <input name="C" type="radio" value="C2" />
682
911
  * </fieldset></form>
683
912
  *
684
913
  * var v = $(':text').fieldValue();
@@ -705,60 +934,63 @@ $.fn.fieldSerialize = function(successful) {
705
934
  * for each element is returned.
706
935
  *
707
936
  * Note: This method *always* returns an array. If no valid value can be determined the
708
- * array will be empty, otherwise it will contain one or more values.
937
+ * array will be empty, otherwise it will contain one or more values.
709
938
  */
710
939
  $.fn.fieldValue = function(successful) {
711
- for (var val=[], i=0, max=this.length; i < max; i++) {
712
- var el = this[i];
713
- var v = $.fieldValue(el, successful);
714
- if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
715
- continue;
716
- }
717
- v.constructor == Array ? $.merge(val, v) : val.push(v);
718
- }
719
- return val;
940
+ for (var val=[], i=0, max=this.length; i < max; i++) {
941
+ var el = this[i];
942
+ var v = $.fieldValue(el, successful);
943
+ if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
944
+ continue;
945
+ }
946
+ if (v.constructor == Array)
947
+ $.merge(val, v);
948
+ else
949
+ val.push(v);
950
+ }
951
+ return val;
720
952
  };
721
953
 
722
954
  /**
723
955
  * Returns the value of the field element.
724
956
  */
725
957
  $.fieldValue = function(el, successful) {
726
- var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
727
- if (successful === undefined) {
728
- successful = true;
729
- }
730
-
731
- if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
732
- (t == 'checkbox' || t == 'radio') && !el.checked ||
733
- (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
734
- tag == 'select' && el.selectedIndex == -1)) {
735
- return null;
736
- }
737
-
738
- if (tag == 'select') {
739
- var index = el.selectedIndex;
740
- if (index < 0) {
741
- return null;
742
- }
743
- var a = [], ops = el.options;
744
- var one = (t == 'select-one');
745
- var max = (one ? index+1 : ops.length);
746
- for(var i=(one ? index : 0); i < max; i++) {
747
- var op = ops[i];
748
- if (op.selected) {
749
- var v = op.value;
750
- if (!v) { // extra pain for IE...
751
- v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
752
- }
753
- if (one) {
754
- return v;
755
- }
756
- a.push(v);
757
- }
758
- }
759
- return a;
760
- }
761
- return $(el).val();
958
+ var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
959
+ if (successful === undefined) {
960
+ successful = true;
961
+ }
962
+
963
+ if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
964
+ (t == 'checkbox' || t == 'radio') && !el.checked ||
965
+ (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
966
+ tag == 'select' && el.selectedIndex == -1)) {
967
+ return null;
968
+ }
969
+
970
+ if (tag == 'select') {
971
+ var index = el.selectedIndex;
972
+ if (index < 0) {
973
+ return null;
974
+ }
975
+ var a = [], ops = el.options;
976
+ var one = (t == 'select-one');
977
+ var max = (one ? index+1 : ops.length);
978
+ for(var i=(one ? index : 0); i < max; i++) {
979
+ var op = ops[i];
980
+ if (op.selected) {
981
+ var v = op.value;
982
+ if (!v) { // extra pain for IE...
983
+ v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
984
+ }
985
+ if (one) {
986
+ return v;
987
+ }
988
+ a.push(v);
989
+ }
990
+ }
991
+ return a;
992
+ }
993
+ return $(el).val();
762
994
  };
763
995
 
764
996
  /**
@@ -769,53 +1001,63 @@ $.fieldValue = function(el, successful) {
769
1001
  * - inputs of type submit, button, reset, and hidden will *not* be effected
770
1002
  * - button elements will *not* be effected
771
1003
  */
772
- $.fn.clearForm = function() {
773
- return this.each(function() {
774
- $('input,select,textarea', this).clearFields();
775
- });
1004
+ $.fn.clearForm = function(includeHidden) {
1005
+ return this.each(function() {
1006
+ $('input,select,textarea', this).clearFields(includeHidden);
1007
+ });
776
1008
  };
777
1009
 
778
1010
  /**
779
1011
  * Clears the selected form elements.
780
1012
  */
781
- $.fn.clearFields = $.fn.clearInputs = function() {
782
- return this.each(function() {
783
- var t = this.type, tag = this.tagName.toLowerCase();
784
- if (t == 'text' || t == 'password' || tag == 'textarea') {
785
- this.value = '';
786
- }
787
- else if (t == 'checkbox' || t == 'radio') {
788
- this.checked = false;
789
- }
790
- else if (tag == 'select') {
791
- this.selectedIndex = -1;
792
- }
793
- });
1013
+ $.fn.clearFields = $.fn.clearInputs = function(includeHidden) {
1014
+ var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
1015
+ return this.each(function() {
1016
+ var t = this.type, tag = this.tagName.toLowerCase();
1017
+ if (re.test(t) || tag == 'textarea') {
1018
+ this.value = '';
1019
+ }
1020
+ else if (t == 'checkbox' || t == 'radio') {
1021
+ this.checked = false;
1022
+ }
1023
+ else if (tag == 'select') {
1024
+ this.selectedIndex = -1;
1025
+ }
1026
+ else if (includeHidden) {
1027
+ // includeHidden can be the value true, or it can be a selector string
1028
+ // indicating a special test; for example:
1029
+ // $('#myForm').clearForm('.special:hidden')
1030
+ // the above would clean hidden inputs that have the class of 'special'
1031
+ if ( (includeHidden === true && /hidden/.test(t)) ||
1032
+ (typeof includeHidden == 'string' && $(this).is(includeHidden)) )
1033
+ this.value = '';
1034
+ }
1035
+ });
794
1036
  };
795
1037
 
796
1038
  /**
797
1039
  * Resets the form data. Causes all form elements to be reset to their original value.
798
1040
  */
799
1041
  $.fn.resetForm = function() {
800
- return this.each(function() {
801
- // guard against an input with the name of 'reset'
802
- // note that IE reports the reset function as an 'object'
803
- if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
804
- this.reset();
805
- }
806
- });
1042
+ return this.each(function() {
1043
+ // guard against an input with the name of 'reset'
1044
+ // note that IE reports the reset function as an 'object'
1045
+ if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
1046
+ this.reset();
1047
+ }
1048
+ });
807
1049
  };
808
1050
 
809
1051
  /**
810
1052
  * Enables or disables any matching elements.
811
1053
  */
812
1054
  $.fn.enable = function(b) {
813
- if (b === undefined) {
814
- b = true;
815
- }
816
- return this.each(function() {
817
- this.disabled = !b;
818
- });
1055
+ if (b === undefined) {
1056
+ b = true;
1057
+ }
1058
+ return this.each(function() {
1059
+ this.disabled = !b;
1060
+ });
819
1061
  };
820
1062
 
821
1063
  /**
@@ -823,37 +1065,39 @@ $.fn.enable = function(b) {
823
1065
  * selects/deselects and matching option elements.
824
1066
  */
825
1067
  $.fn.selected = function(select) {
826
- if (select === undefined) {
827
- select = true;
828
- }
829
- return this.each(function() {
830
- var t = this.type;
831
- if (t == 'checkbox' || t == 'radio') {
832
- this.checked = select;
833
- }
834
- else if (this.tagName.toLowerCase() == 'option') {
835
- var $sel = $(this).parent('select');
836
- if (select && $sel[0] && $sel[0].type == 'select-one') {
837
- // deselect all other options
838
- $sel.find('option').selected(false);
839
- }
840
- this.selected = select;
841
- }
842
- });
1068
+ if (select === undefined) {
1069
+ select = true;
1070
+ }
1071
+ return this.each(function() {
1072
+ var t = this.type;
1073
+ if (t == 'checkbox' || t == 'radio') {
1074
+ this.checked = select;
1075
+ }
1076
+ else if (this.tagName.toLowerCase() == 'option') {
1077
+ var $sel = $(this).parent('select');
1078
+ if (select && $sel[0] && $sel[0].type == 'select-one') {
1079
+ // deselect all other options
1080
+ $sel.find('option').selected(false);
1081
+ }
1082
+ this.selected = select;
1083
+ }
1084
+ });
843
1085
  };
844
1086
 
1087
+ // expose debug var
1088
+ $.fn.ajaxSubmit.debug = false;
1089
+
845
1090
  // helper fn for console logging
846
- // set $.fn.ajaxSubmit.debug to true to enable debug logging
847
1091
  function log() {
848
- if ($.fn.ajaxSubmit.debug) {
849
- var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
850
- if (window.console && window.console.log) {
851
- window.console.log(msg);
852
- }
853
- else if (window.opera && window.opera.postError) {
854
- window.opera.postError(msg);
855
- }
856
- }
857
- };
1092
+ if (!$.fn.ajaxSubmit.debug)
1093
+ return;
1094
+ var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
1095
+ if (window.console && window.console.log) {
1096
+ window.console.log(msg);
1097
+ }
1098
+ else if (window.opera && window.opera.postError) {
1099
+ window.opera.postError(msg);
1100
+ }
1101
+ }
858
1102
 
859
1103
  })(jQuery);