diff options
author | Pierre Schmitz <pierre@archlinux.de> | 2012-05-03 13:01:35 +0200 |
---|---|---|
committer | Pierre Schmitz <pierre@archlinux.de> | 2012-05-03 13:01:35 +0200 |
commit | d9022f63880ce039446fba8364f68e656b7bf4cb (patch) | |
tree | 16b40fbf17bf7c9ee6f4ead25b16dd192378050a /resources/jquery/jquery.form.js | |
parent | 27cf83d177256813e2e802241085fce5dd0f3fb9 (diff) |
Update to MediaWiki 1.19.0
Diffstat (limited to 'resources/jquery/jquery.form.js')
-rw-r--r-- | resources/jquery/jquery.form.js | 310 |
1 files changed, 215 insertions, 95 deletions
diff --git a/resources/jquery/jquery.form.js b/resources/jquery/jquery.form.js index 53c078f9..fdcdd15a 100644 --- a/resources/jquery/jquery.form.js +++ b/resources/jquery/jquery.form.js @@ -1,6 +1,6 @@ /*! * jQuery Form Plugin - * version: 2.52 (07-DEC-2010) + * version: 2.84 (12-AUG-2011) * @requires jQuery v1.3.2 or later * * Examples and documentation at: http://malsup.com/jquery/form/ @@ -8,7 +8,7 @@ * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html */ -(function($) { +;(function($) { /* Usage Note: @@ -49,22 +49,26 @@ $.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 }; } - var action = this.attr('action'); - var url = (typeof action === 'string') ? $.trim(action) : ''; + method = this.attr('method'); + action = this.attr('action'); + url = (typeof action === 'string') ? $.trim(action) : ''; + url = url || window.location.href || ''; if (url) { // clean url (don't include hash vaue) url = (url.match(/^([^#]+)/)||[])[1]; } - url = url || window.location.href || ''; options = $.extend(true, { url: url, - type: this.attr('method') || 'GET', + success: $.ajaxSettings.success, + type: method || 'GET', iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' }, options); @@ -87,7 +91,7 @@ $.fn.ajaxSubmit = function(options) { if (options.data) { options.extraData = options.data; for (n in options.data) { - if(options.data[n] instanceof Array) { + if( $.isArray(options.data[n]) ) { for (var k in options.data[n]) { a.push( { name: n, value: options.data[n][k] } ); } @@ -123,7 +127,7 @@ $.fn.ajaxSubmit = function(options) { options.data = q; // data is the query string for 'post' } - var $form = this, callbacks = []; + var callbacks = []; if (options.resetForm) { callbacks.push(function() { $form.resetForm(); }); } @@ -161,14 +165,20 @@ $.fn.ajaxSubmit = function(options) { // hack to fix Safari hang (thanks to Tim Molendijk for this) // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d if (options.closeKeepAlive) { - $.get(options.closeKeepAlive, fileUpload); + $.get(options.closeKeepAlive, function() { fileUpload(a); }); } else { - fileUpload(); + fileUpload(a); } } else { - $.ajax(options); + // IE7 massage (see issue 57) + if ($.browser.msie && method == 'get') { + var ieMeth = $form[0].getAttribute('method'); + if (typeof ieMeth === 'string') + options.type = ieMeth; + } + $.ajax(options); } // fire 'notify' event @@ -177,8 +187,17 @@ $.fn.ajaxSubmit = function(options) { // private function for handling file uploads (hat tip to YAHOO!) - function fileUpload() { - var form = $form[0]; + function fileUpload(a) { + var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle; + var useProp = !!$.fn.prop; + + if (a) { + // ensure that every serialized input is still enabled + for (i=0; i < a.length; i++) { + el = $(form[a[i].name]); + el[ useProp ? 'prop' : 'attr' ]('disabled', false); + } + } 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 @@ -187,23 +206,25 @@ $.fn.ajaxSubmit = function(options) { return; } - var s = $.extend(true, {}, $.ajaxSettings, options); + s = $.extend(true, {}, $.ajaxSettings, options); s.context = s.context || s; - var id = 'jqFormIO' + (new Date().getTime()), fn = '_'+id; - window[fn] = function() { - var f = $io.data('form-plugin-onload'); - if (f) { - f(); - window[fn] = undefined; - try { delete window[fn]; } catch(e){} - } - }; - var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ s.iframeSrc +'" onload="window[\'_\'+this.id]()" />'); - var io = $io[0]; + id = 'jqFormIO' + (new Date().getTime()); + if (s.iframeTarget) { + $io = $(s.iframeTarget); + n = $io.attr('name'); + if (n == null) + $io.attr('name', id); + else + id = n; + } + else { + $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />'); + $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' }); + } + io = $io[0]; - $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' }); - var xhr = { // mock object + xhr = { // mock object aborted: 0, responseText: null, responseXML: null, @@ -212,13 +233,19 @@ $.fn.ajaxSubmit = function(options) { getAllResponseHeaders: function() {}, getResponseHeader: function() {}, setRequestHeader: function() {}, - abort: function() { + abort: function(status) { + var e = (status === 'timeout' ? 'timeout' : 'aborted'); + log('aborting upload... ' + e); this.aborted = 1; $io.attr('src', s.iframeSrc); // abort op in progress + xhr.error = e; + s.error && s.error.call(s.context, xhr, e, status); + g && $.event.trigger("ajaxError", [xhr, s, e]); + s.complete && s.complete.call(s.context, xhr, e); } }; - var g = s.global; + g = s.global; // trigger ajax global events so that activity/block indicators work like normal if (g && ! $.active++) { $.event.trigger("ajaxStart"); @@ -228,7 +255,7 @@ $.fn.ajaxSubmit = function(options) { } if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) { - if (s.global) { + if (s.global) { $.active--; } return; @@ -237,13 +264,10 @@ $.fn.ajaxSubmit = function(options) { return; } - var cbInvoked = false; - var timedOut = 0; - // add submitting element to data if we know it - var sub = form.clk; + sub = form.clk; if (sub) { - var n = sub.name; + n = sub.name; if (n && !sub.disabled) { s.extraData = s.extraData || {}; s.extraData[n] = sub.value; @@ -253,7 +277,15 @@ $.fn.ajaxSubmit = function(options) { } } } + + var CLIENT_TIMEOUT_ABORT = 1; + var SERVER_ABORT = 2; + function getDoc(frame) { + var doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument ? frame.contentDocument : frame.document; + return doc; + } + // take a breath so that pending repaints get some cpu time before the upload starts function doSubmit() { // make sure form attrs are set @@ -261,15 +293,15 @@ $.fn.ajaxSubmit = function(options) { // update form attrs in IE friendly way form.setAttribute('target',id); - if (form.getAttribute('method') != 'POST') { + if (!method) { form.setAttribute('method', 'POST'); } - if (form.getAttribute('action') != s.url) { + if (a != s.url) { form.setAttribute('action', s.url); } // ie borks in some cases when setting encoding - if (! s.skipEncodingOverride) { + if (! s.skipEncodingOverride && (!method || /post/i.test(method))) { $form.attr({ encoding: 'multipart/form-data', enctype: 'multipart/form-data' @@ -278,7 +310,23 @@ $.fn.ajaxSubmit = function(options) { // support timout if (s.timeout) { - setTimeout(function() { timedOut = true; cb(); }, s.timeout); + timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout); + } + + // look for server aborts + function checkState() { + try { + var state = getDoc(io).readyState; + log('state = ' + state); + if (state.toLowerCase() == 'uninitialized') + setTimeout(checkState,50); + } + catch(e) { + log('Server abort: ' , e, ' (', e.name, ')'); + cb(SERVER_ABORT); + timeoutHandle && clearTimeout(timeoutHandle); + timeoutHandle = undefined; + } } // add "extra" data to form if provided in options @@ -287,14 +335,17 @@ $.fn.ajaxSubmit = function(options) { if (s.extraData) { for (var n in s.extraData) { extraInputs.push( - $('<input type="hidden" name="'+n+'" value="'+s.extraData[n]+'" />') + $('<input type="hidden" name="'+n+'" />').attr('value',s.extraData[n]) .appendTo(form)[0]); } } - // add iframe to doc and submit the form - $io.appendTo('body'); - $io.data('form-plugin-onload', cb); + if (!s.iframeTarget) { + // add iframe to doc and submit the form + $io.appendTo('body'); + io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false); + } + setTimeout(checkState,15); form.submit(); } finally { @@ -315,24 +366,42 @@ $.fn.ajaxSubmit = function(options) { else { setTimeout(doSubmit, 10); // this lets dom updates render } - - var data, doc, domCheckCount = 50; - function cb() { - if (cbInvoked) { + var data, doc, domCheckCount = 50, callbackProcessed; + + function cb(e) { + if (xhr.aborted || callbackProcessed) { + return; + } + try { + doc = getDoc(io); + } + catch(ex) { + log('cannot access response document: ', ex); + e = SERVER_ABORT; + } + if (e === CLIENT_TIMEOUT_ABORT && xhr) { + xhr.abort('timeout'); + return; + } + else if (e == SERVER_ABORT && xhr) { + xhr.abort('server abort'); return; } - $io.removeData('form-plugin-onload'); - - var ok = true; + if (!doc || doc.location.href == s.iframeSrc) { + // response not received yet + if (!timedOut) + return; + } + io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false); + + var status = 'success', errMsg; try { if (timedOut) { throw 'timeout'; } - // extract the server response from the iframe - doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document; - + var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc); log('isXml='+isXml); if (!isXml && window.opera && (doc.body == null || doc.body.innerHTML == '')) { @@ -349,76 +418,104 @@ $.fn.ajaxSubmit = function(options) { } //log('response detected'); - cbInvoked = true; - xhr.responseText = doc.documentElement ? doc.documentElement.innerHTML : null; + var docRoot = doc.body ? doc.body : doc.documentElement; + xhr.responseText = docRoot ? docRoot.innerHTML : null; xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc; + if (isXml) + s.dataType = 'xml'; xhr.getResponseHeader = function(header){ var headers = {'content-type': s.dataType}; return headers[header]; }; - - var scr = /(json|script)/.test(s.dataType); + // support for XHR 'status' & 'statusText' emulation : + if (docRoot) { + xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status; + xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText; + } + + var dt = s.dataType || ''; + var scr = /(json|script|text)/.test(dt.toLowerCase()); if (scr || s.textarea) { // see if user embedded response in textarea var ta = doc.getElementsByTagName('textarea')[0]; if (ta) { xhr.responseText = ta.value; + // support for XHR 'status' & 'statusText' emulation : + xhr.status = Number( ta.getAttribute('status') ) || xhr.status; + xhr.statusText = ta.getAttribute('statusText') || xhr.statusText; } else if (scr) { // account for browsers injecting pre around json response var pre = doc.getElementsByTagName('pre')[0]; var b = doc.getElementsByTagName('body')[0]; if (pre) { - xhr.responseText = pre.textContent; + xhr.responseText = pre.textContent ? pre.textContent : pre.innerHTML; } else if (b) { xhr.responseText = b.innerHTML; } - } + } } else if (s.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) { xhr.responseXML = toXml(xhr.responseText); } - data = $.httpData(xhr, s.dataType); + + try { + data = httpData(xhr, s.dataType, s); + } + catch (e) { + status = 'parsererror'; + xhr.error = errMsg = (e || status); + } } - catch(e){ - log('error caught:',e); - ok = false; - xhr.error = e; - $.handleError(s, xhr, 'error', e); + catch (e) { + log('error caught: ',e); + status = 'error'; + xhr.error = errMsg = (e || status); } - + if (xhr.aborted) { log('upload aborted'); - ok = false; + status = null; } + if (xhr.status) { // we've set xhr.status + status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error'; + } + // ordering of these callbacks/triggers is odd, but that's how $.ajax does it - if (ok) { - s.success.call(s.context, data, 'success', xhr); - if (g) { - $.event.trigger("ajaxSuccess", [xhr, s]); - } - } - if (g) { - $.event.trigger("ajaxComplete", [xhr, s]); + if (status === 'success') { + s.success && s.success.call(s.context, data, 'success', xhr); + g && $.event.trigger("ajaxSuccess", [xhr, s]); } + else if (status) { + if (errMsg == undefined) + errMsg = xhr.statusText; + s.error && s.error.call(s.context, xhr, status, errMsg); + g && $.event.trigger("ajaxError", [xhr, s, errMsg]); + } + + g && $.event.trigger("ajaxComplete", [xhr, s]); + if (g && ! --$.active) { $.event.trigger("ajaxStop"); } - if (s.complete) { - s.complete.call(s.context, xhr, ok ? 'success' : 'error'); - } + + s.complete && s.complete.call(s.context, xhr, status); + + callbackProcessed = true; + if (s.timeout) + clearTimeout(timeoutHandle); // clean up setTimeout(function() { - $io.removeData('form-plugin-onload'); - $io.remove(); + if (!s.iframeTarget) + $io.remove(); xhr.responseXML = null; }, 100); } - function toXml(s, doc) { + var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+) if (window.ActiveXObject) { doc = new ActiveXObject('Microsoft.XMLDOM'); doc.async = 'false'; @@ -427,8 +524,33 @@ $.fn.ajaxSubmit = function(options) { else { doc = (new DOMParser()).parseFromString(s, 'text/xml'); } - return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null; - } + return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null; + }; + var parseJSON = $.parseJSON || function(s) { + return window['eval']('(' + s + ')'); + }; + + var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4 + + var ct = xhr.getResponseHeader('content-type') || '', + xml = type === 'xml' || !type && ct.indexOf('xml') >= 0, + data = xml ? xhr.responseXML : xhr.responseText; + + if (xml && data.documentElement.nodeName === 'parsererror') { + $.error && $.error('parsererror'); + } + if (s && s.dataFilter) { + data = s.dataFilter(data, type); + } + if (typeof data === 'string') { + if (type === 'json' || !type && ct.indexOf('json') >= 0) { + data = parseJSON(data); + } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) { + $.globalEval(data); + } + } + return data; + }; } }; @@ -462,7 +584,7 @@ $.fn.ajaxForm = function(options) { log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)')); return this; } - + return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) { if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed e.preventDefault(); @@ -526,7 +648,7 @@ $.fn.formToArray = function(semantic) { if (!els) { return a; } - + var i,j,n,v,el,max,jmax; for(i=0, max=els.length; i < max; i++) { el = els[i]; @@ -711,9 +833,10 @@ $.fn.clearForm = function() { * Clears the selected form elements. */ $.fn.clearFields = $.fn.clearInputs = function() { + var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list return this.each(function() { var t = this.type, tag = this.tagName.toLowerCase(); - if (t == 'text' || t == 'password' || tag == 'textarea') { + if (re.test(t) || tag == 'textarea') { this.value = ''; } else if (t == 'checkbox' || t == 'radio') { @@ -775,16 +898,13 @@ $.fn.selected = function(select) { }; // helper fn for console logging -// set $.fn.ajaxSubmit.debug to true to enable debug logging function log() { - if ($.fn.ajaxSubmit.debug) { - var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,''); - if (window.console && window.console.log) { - window.console.log(msg); - } - else if (window.opera && window.opera.postError) { - window.opera.postError(msg); - } + var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,''); + if (window.console && window.console.log) { + window.console.log(msg); + } + else if (window.opera && window.opera.postError) { + window.opera.postError(msg); } }; |