Subversion-Projekte lars-tiefland.webhosting

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

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