From 15d5673b85b06912150cc3fb7020e902fab98ea8 Mon Sep 17 00:00:00 2001 From: antoniobenedetti Date: Wed, 8 Jan 2014 15:42:27 +0100 Subject: [PATCH] jQuery Form 3.48.0-2013.12.28 The latest version of this plugin from https://github.com/malsup/form --- scripts/jquery.form.js | 429 +++++++++++++++++++++++++++++------------ 1 file changed, 302 insertions(+), 127 deletions(-) diff --git a/scripts/jquery.form.js b/scripts/jquery.form.js index 2731765..6fa4042 100644 --- a/scripts/jquery.form.js +++ b/scripts/jquery.form.js @@ -1,16 +1,28 @@ /*! * jQuery Form Plugin - * version: 3.15 (09-SEP-2012) - * @requires jQuery v1.3.2 or later - * + * version: 3.48.0-2013.12.28 + * Requires jQuery v1.5 or later + * Copyright (c) 2013 M. Alsup * Examples and documentation at: http://malsup.com/jquery/form/ * Project repository: https://github.com/malsup/form - * Dual licensed under the MIT and GPL licenses: - * http://malsup.github.com/mit-license.txt - * http://malsup.github.com/gpl-license-v2.txt + * Dual licensed under the MIT and GPL licenses. + * https://github.com/malsup/form#copyright-and-license */ -/*global ActiveXObject alert */ -;(function($) { +/*global ActiveXObject */ + +// AMD support +(function (factory) { + "use strict"; + if (typeof define === 'function' && define.amd) { + // using AMD; register as anon module + define(['jquery'], factory); + } else { + // no AMD; invoke directly + factory( (typeof(jQuery) != 'undefined') ? jQuery : window.Zepto ); + } +} + +(function($) { "use strict"; /* @@ -37,7 +49,7 @@ target: '#output' }); }); - + You can also use ajaxForm with delegation (requires jQuery v1.7+), so the form does not have to exist when you invoke ajaxForm: @@ -45,7 +57,7 @@ delegation: true, target: '#output' }); - + When using ajaxForm, the ajaxSubmit function will be invoked for you at the appropriate time. */ @@ -57,6 +69,23 @@ var feature = {}; feature.fileapi = $("").get(0).files !== undefined; feature.formdata = window.FormData !== undefined; +var hasProp = !!$.fn.prop; + +// attr2 uses prop when it can but checks the return type for +// an expected string. this accounts for the case where a form +// contains inputs with names like "action" or "method"; in those +// cases "prop" returns the element +$.fn.attr2 = function() { + if ( ! hasProp ) { + return this.attr.apply(this, arguments); + } + var val = this.prop.apply(this, arguments); + if ( ( val && val.jquery ) || typeof val === 'string' ) { + return val; + } + return this.attr.apply(this, arguments); +}; + /** * ajaxSubmit() provides a mechanism for immediately submitting * an HTML form using AJAX. @@ -69,15 +98,19 @@ $.fn.ajaxSubmit = function(options) { log('ajaxSubmit: skipping submit process - no element selected'); return this; } - + var method, action, url, $form = this; if (typeof options == 'function') { options = { success: options }; } + else if ( options === undefined ) { + options = {}; + } + + method = options.type || this.attr2('method'); + action = options.url || this.attr2('action'); - method = this.attr('method'); - action = this.attr('action'); url = (typeof action === 'string') ? $.trim(action) : ''; url = url || window.location.href || ''; if (url) { @@ -88,7 +121,7 @@ $.fn.ajaxSubmit = function(options) { options = $.extend(true, { url: url, success: $.ajaxSettings.success, - type: method || 'GET', + type: method || $.ajaxSettings.type, iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' }, options); @@ -111,7 +144,7 @@ $.fn.ajaxSubmit = function(options) { if ( traditional === undefined ) { traditional = $.ajaxSettings.traditional; } - + var elements = []; var qx, a = this.formToArray(options.semantic, elements); if (options.data) { @@ -135,7 +168,7 @@ $.fn.ajaxSubmit = function(options) { var q = $.param(a, traditional); if (qx) { q = ( q ? (q + '&' + qx) : qx ); - } + } if (options.type.toUpperCase() == 'GET') { options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; options.data = null; // data is null for 'get' @@ -165,14 +198,34 @@ $.fn.ajaxSubmit = function(options) { } options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg - var context = options.context || this ; // jQuery 1.4+ supports scope context + var context = options.context || this ; // jQuery 1.4+ supports scope context for (var i=0, max=callbacks.length; i < max; i++) { callbacks[i].apply(context, [data, status, xhr || $form, $form]); } }; + if (options.error) { + var oldError = options.error; + options.error = function(xhr, status, error) { + var context = options.context || this; + oldError.apply(context, [xhr, status, error, $form]); + }; + } + + if (options.complete) { + var oldComplete = options.complete; + options.complete = function(xhr, status) { + var context = options.context || this; + oldComplete.apply(context, [xhr, status, $form]); + }; + } + // are there files to upload? - var fileInputs = $('input:file:enabled[value]', this); // [value] (issue #113) + + // [value] (issue #113), also see comment: + // https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219 + var fileInputs = $('input[type=file]:enabled', this).filter(function() { return $(this).val() !== ''; }); + var hasFileInputs = fileInputs.length > 0; var mp = 'multipart/form-data'; var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); @@ -181,6 +234,8 @@ $.fn.ajaxSubmit = function(options) { log("fileAPI :" + fileAPI); var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI; + var jqxhr; + // options.iframe allows user to force iframe mode // 06-NOV-09: now defaulting to iframe mode if file input is detected if (options.iframe !== false && (options.iframe || shouldUseFrame)) { @@ -188,23 +243,26 @@ $.fn.ajaxSubmit = function(options) { // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d if (options.closeKeepAlive) { $.get(options.closeKeepAlive, function() { - fileUploadIframe(a); + jqxhr = fileUploadIframe(a); }); } - else { - fileUploadIframe(a); - } + else { + jqxhr = fileUploadIframe(a); + } } else if ((hasFileInputs || multipart) && fileAPI) { - fileUploadXhr(a); + jqxhr = fileUploadXhr(a); } else { - $.ajax(options); + jqxhr = $.ajax(options); } + $form.removeData('jqxhr').data('jqxhr', jqxhr); + // clear element array - for (var k=0; k < elements.length; k++) + for (var k=0; k < elements.length; k++) { elements[k] = null; + } // fire 'notify' event this.trigger('form-submit-notify', [this, options]); @@ -212,13 +270,16 @@ $.fn.ajaxSubmit = function(options) { // utility fn for deep serialization function deepSerialize(extraData){ - var serialized = $.param(extraData).split('&'); + var serialized = $.param(extraData, options.traditional).split('&'); var len = serialized.length; - var result = {}; + var result = []; var i, part; for (i=0; i < len; i++) { + // #252; undo param space replacement + serialized[i] = serialized[i].replace(/\+/g,' '); part = serialized[i].split('='); - result[decodeURIComponent(part[0])] = decodeURIComponent(part[1]); + // #278; use array instead of object storage, favoring array serializations + result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]); } return result; } @@ -233,9 +294,11 @@ $.fn.ajaxSubmit = function(options) { if (options.extraData) { var serializedData = deepSerialize(options.extraData); - for (var p in serializedData) - if (serializedData.hasOwnProperty(p)) - formdata.append(p, serializedData[p]); + for (i=0; i < serializedData.length; i++) { + if (serializedData[i]) { + formdata.append(serializedData[i][0], serializedData[i][1]); + } + } } options.data = null; @@ -244,15 +307,15 @@ $.fn.ajaxSubmit = function(options) { contentType: false, processData: false, cache: false, - type: 'POST' + type: method || 'POST' }); - + if (options.uploadProgress) { // workaround because jqXHR does not expose upload property s.xhr = function() { - var xhr = jQuery.ajaxSettings.xhr(); + var xhr = $.ajaxSettings.xhr(); if (xhr.upload) { - xhr.upload.onprogress = function(event) { + xhr.upload.addEventListener('progress', function(event) { var percent = 0; var position = event.loaded || event.position; /*event.position is deprecated*/ var total = event.total; @@ -260,42 +323,49 @@ $.fn.ajaxSubmit = function(options) { percent = Math.ceil(position / total * 100); } options.uploadProgress(event, position, total, percent); - }; + }, false); } return xhr; }; } s.data = null; - var beforeSend = s.beforeSend; - s.beforeSend = function(xhr, o) { + var beforeSend = s.beforeSend; + s.beforeSend = function(xhr, o) { + //Send FormData() provided by user + if (options.formData) { + o.data = options.formData; + } + else { o.data = formdata; - if(beforeSend) - beforeSend.call(this, xhr, o); + } + if(beforeSend) { + beforeSend.call(this, xhr, o); + } }; - $.ajax(s); + return $.ajax(s); } // private function for handling file uploads (hat tip to YAHOO!) function fileUploadIframe(a) { var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle; - var useProp = !!$.fn.prop; + var deferred = $.Deferred(); + + // #341 + deferred.abort = function(status) { + xhr.abort(status); + }; - if ($(':input[name=submit],:input[id=submit]', form).length) { - // if there is an input with a name or id of 'submit' then we won't be - // able to invoke the submit fn on the form (at least not x-browser) - alert('Error: Form elements must not have name or id of "submit".'); - return; - } - if (a) { // ensure that every serialized input is still enabled for (i=0; i < elements.length; i++) { el = $(elements[i]); - if ( useProp ) + if ( hasProp ) { el.prop('disabled', false); - else + } + else { el.removeAttr('disabled'); + } } } @@ -304,11 +374,13 @@ $.fn.ajaxSubmit = function(options) { id = 'jqFormIO' + (new Date().getTime()); if (s.iframeTarget) { $io = $(s.iframeTarget); - n = $io.attr('name'); - if (!n) - $io.attr('name', id); - else + n = $io.attr2('name'); + if (!n) { + $io.attr2('name', id); + } + else { id = n; + } } else { $io = $('