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