Holger Knublauch

Progress on DDR upload with JSON request

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