Index: jsf-api/src/main/resources/jsf.js =================================================================== --- jsf-api/src/main/resources/jsf.js (revision 12469) +++ jsf-api/src/main/resources/jsf.js (working copy) @@ -174,7 +174,7 @@ // function) but IE9 (at least) seems to render controls outside of // form. if (typeof context !== 'undefined' && context !== null && - context.form.enctype === "multipart/form-data") { + context.form.enctype === "multipart/form-data" && !isXHR2()) { returnVal = new FrameTransport(context); return returnVal; } @@ -1674,7 +1674,101 @@ }; }(); + function isXHR2() { + return !!XMLHttpRequest.prototype.overrideMimeType; + } + function encodeParameter(name, value) { + return encodeURIComponent(name) + '=' + encodeURIComponent(value); + } + + var DefaultQuery = function DefaultQuery(form) { + var queryString = ''; + + if (form) { + var viewState = jsf.getViewState(form); + if (queryString) { + queryString = queryString + '&' + viewState; + } else { + queryString = viewState; + } + } + + return { + addParameter: function addParameter(name, value) { + var parameter = encodeParameter(name, value); + if (queryString) { + queryString = queryString + '&' + parameter; + } else { + queryString = parameter; + } + }, + + sendGET: function sendGET(url, xhr, async) { + if (queryString.length > 0) { + url += ((url.indexOf("?") > -1) ? "&" : "?") + queryString; + } + xhr.open("GET", url, async); + xhr.send(); + }, + + sendPOST: function sendPOST(url, xhr, async) { + xhr.open("POST", url, async); + // note that we are including the charset=UTF-8 as part of the content type (even + // if encodeURIComponent encodes as UTF-8), because with some + // browsers it will not be set in the request. Some server implementations need to + // determine the character encoding from the request header content type. + xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded;charset=UTF-8'); + xhr.setRequestHeader('Faces-Request', 'partial/ajax'); + xhr.send(queryString); + } + } + }; + + var FormDataQuery = function FormDataQuery(form) { + var parameters = []; + + return { + addParameter: function addParameter(name, value) { + parameters.push({n: name, v: value}); + }, + + sendGET: function sendGET(url, xhr, async) { + var queryString = ''; + for (var i in parameters) { + var p = parameters[i]; + queryString += (queryString ? '&' : '') + encodeParameter(p.n, p.v); + } + + if (queryString.length > 0) { + url += ((url.indexOf("?") > -1) ? "&" : "?") + queryString; + } + xhr.open("GET", url, async); + xhr.send(); + }, + + sendPOST: function sendPOST(url, xhr, async) { + var formData = new FormData(form); + for (var i in parameters) { + var p = parameters[i]; + var name = p.n; + if (name) { + var value = p.v; + if (typeof p.v == 'File') { + formData.append(name, value, value.name); + } else { + formData.append(name, value); + } + } + } + xhr.open("POST", url, async); + xhr.setRequestHeader('Faces-Request', 'partial/ajax'); + xhr.send(formData); + } + } + }; + + /** * AjaxEngine handles Ajax implementation details. * @ignore @@ -1690,7 +1784,7 @@ req.xmlReq = null; // XMLHttpRequest Object req.async = true; // Default - Asynchronous req.parameters = {}; // Parameters For GET or POST - req.queryString = null; // Encoded Data For GET or POST + req.query = null; // Form Data For GET or POST req.method = null; // GET or POST req.status = null; // Response Status Code From Server req.fromQueue = false; // Indicates if the request was taken off the queue @@ -1729,6 +1823,25 @@ } }; + if (isXHR2()) { + req.xmlReq.upload.addEventListener('progress', function uploadProgress(event) { + if (event.lengthComputable) { + req.context.uploaded = event.loaded; + req.context.uploadTotal = event.total; + sendEvent(req.xmlReq, req.context, "upload-progress"); + } + }); + req.xmlReq.upload.addEventListener('load', function uploadCompleted(event) { + sendEvent(req.xmlReq, req.context, "upload-complete"); + }); + req.xmlReq.upload.addEventListener('abort', function uploadAborted(event) { + sendError(req.xmlReq, req.context, "upload-aborted"); + }); + req.xmlReq.upload.addEventListener('error', function uploadError(event) { + sendError(req.xmlReq, req.context, "upload-error"); + }); + } + /** * This function is called when the request/response interaction * is complete. If the return status code is successfull, @@ -1815,43 +1928,28 @@ if (req.generateUniqueUrl && req.method == "GET") { req.parameters["AjaxRequestUniqueId"] = new Date().getTime() + "" + req.requestIndex; } - var content = null; // For POST requests, to hold query string for (var i in req.parameters) { if (req.parameters.hasOwnProperty(i)) { - if (req.queryString.length > 0) { - req.queryString += "&"; - } - req.queryString += encodeURIComponent(i) + "=" + encodeURIComponent(req.parameters[i]); + req.query.addParameter(i, req.parameters[i]); } } - if (req.method === "GET") { - if (req.queryString.length > 0) { - req.url += ((req.url.indexOf("?") > -1) ? "&" : "?") + req.queryString; - } - } - req.xmlReq.open(req.method, req.url, req.async); - // note that we are including the charset=UTF-8 as part of the content type (even - // if encodeURIComponent encodes as UTF-8), because with some - // browsers it will not be set in the request. Some server implementations need to - // determine the character encoding from the request header content type. - if (req.method === "POST") { - if (typeof req.xmlReq.setRequestHeader !== 'undefined') { - req.xmlReq.setRequestHeader('Faces-Request', 'partial/ajax'); - req.xmlReq.setRequestHeader('Content-type', 'application/x-www-form-urlencoded;charset=UTF-8'); - } - content = req.queryString; - } // note that async == false is not a supported feature. We may change it in ways // that break existing programs at any time, with no warning. if(!req.async) { req.xmlReq.onreadystatechange = null; // no need for readystate change listening } + sendEvent(req.xmlReq, req.context, "begin"); - req.xmlReq.send(content); + if (req.method === "GET") { + req.query.sendGET(req.url, req.xmlReq, req.async); + } else if (req.method === "POST") { + req.query.sendPOST(req.url, req.xmlReq, req.async); + } + if(!req.async){ req.onComplete(); + } } - } }; return req; @@ -1953,6 +2051,10 @@ data.responseXML = request.responseXML; data.responseText = request.responseText; } + if (status === 'upload-progress') { + data.uploaded = context.uploaded; + data.uploadTotal = context.uploadTotal; + } if (context.onevent) { context.onevent.call(null, data); @@ -2371,7 +2473,7 @@ context.form = form; context.formid = form.id; - var viewState = jsf.getViewState(form); + var query = isXHR2() ? new FormDataQuery(form) : new DefaultQuery(form); // Set up additional arguments to be used in the request.. // Make sure "javax.faces.source" is set up. @@ -2470,7 +2572,7 @@ var sendRequest = function() { var ajaxEngine = new AjaxEngine(context); ajaxEngine.setupArguments(args); - ajaxEngine.queryString = viewState; + ajaxEngine.query = query; ajaxEngine.context.onevent = onevent; ajaxEngine.context.onerror = onerror; ajaxEngine.context.sourceid = element.id;