hobo_jquery 2.0.0.pre2 → 2.0.0.pre3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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);