Created
January 11, 2016 19:28
-
-
Save youmad/aa6fc267ccd9550a8291 to your computer and use it in GitHub Desktop.
Send form with file as binary
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
var Utf8Encode = function (string) { | |
string = string.replace(/\r\n/g, "\n"); | |
var utftext = ""; | |
for (var n = 0; n < string.length; n++) { | |
var c = string.charCodeAt(n); | |
if (c < 128) { | |
utftext += String.fromCharCode(c); | |
} else if ((c > 127) && (c < 2048)) { | |
utftext += String.fromCharCode((c >> 6) | 192); | |
utftext += String.fromCharCode((c & 63) | 128); | |
} else { | |
utftext += String.fromCharCode((c >> 12) | 224); | |
utftext += String.fromCharCode(((c >> 6) & 63) | 128); | |
utftext += String.fromCharCode((c & 63) | 128); | |
} | |
} | |
return utftext; | |
} | |
/*\ | |
|*| :: XMLHttpRequest.prototype.sendAsBinary() Polyfill :: | |
|*| | |
|*| https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#sendAsBinary() | |
\*/ | |
if (!XMLHttpRequest.prototype.sendAsBinary) { | |
XMLHttpRequest.prototype.sendAsBinary = function (sData) { | |
var nBytes = sData.length, ui8Data = new Uint8Array(nBytes); | |
for (var nIdx = 0; nIdx < nBytes; nIdx++) { | |
ui8Data[nIdx] = sData.charCodeAt(nIdx) & 0xff; | |
} | |
/* send as ArrayBufferView...: */ | |
this.send(ui8Data); | |
/* ...or as ArrayBuffer (legacy)...: this.send(ui8Data.buffer); */ | |
}; | |
} | |
/*\ | |
|*| Немного изменёный вариант: | |
|*| 1. добавлен коллбэк. | |
|*| 2. имя поля и значение (кроме [type="file"]) кодируется в UTF-8. | |
|*| | |
|*| :: AJAX Form Submit Framework :: | |
|*| | |
|*| https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest | |
|*| | |
|*| This framework is released under the GNU Public License, version 3 or later. | |
|*| http://www.gnu.org/licenses/gpl-3.0-standalone.html | |
|*| | |
|*| Syntax: | |
|*| | |
|*| AJAXSubmit(HTMLFormElement, callback); | |
\*/ | |
var AJAXSubmit = (function () { | |
function submitData(oData) { | |
/* the AJAX request... */ | |
var oAjaxReq = new XMLHttpRequest(); | |
oAjaxReq.submittedData = oData; | |
oAjaxReq.onload = oData.callback; | |
if (oData.technique === 0) { | |
/* method is GET */ | |
oAjaxReq.open("get", oData.receiver.replace(/(?:\?.*)?$/, oData.segments.length > 0 ? "?" + oData.segments.join("&") : ""), true); | |
oAjaxReq.send(null); | |
} else { | |
/* method is POST */ | |
oAjaxReq.open("post", oData.receiver, true); | |
if (oData.technique === 3) { | |
/* enctype is multipart/form-data */ | |
var sBoundary = "---------------------------" + Date.now().toString(16); | |
oAjaxReq.setRequestHeader("Content-Type", "multipart\/form-data; boundary=" + sBoundary); | |
//Utf8Encode | |
oAjaxReq.sendAsBinary("--" + sBoundary + "\r\n" + oData.segments.join("--" + sBoundary + "\r\n") + "--" + sBoundary + "--\r\n"); | |
} else { | |
/* enctype is application/x-www-form-urlencoded or text/plain */ | |
oAjaxReq.setRequestHeader("Content-Type", oData.contentType); | |
oAjaxReq.send(oData.segments.join(oData.technique === 2 ? "\r\n" : "&")); | |
} | |
} | |
} | |
function processStatus(oData) { | |
if (oData.status > 0) { | |
return; | |
} | |
/* the form is now totally serialized! do something before sending it to the server... */ | |
/* doSomething(oData); */ | |
/* console.log("AJAXSubmit - The form is now serialized. Submitting..."); */ | |
submitData(oData); | |
} | |
function pushSegment(oFREvt) { | |
this.owner.segments[this.segmentIdx] += oFREvt.target.result + "\r\n"; | |
this.owner.status--; | |
processStatus(this.owner); | |
} | |
function plainEscape(sText) { | |
/* how should I treat a text/plain form encoding? what characters are not allowed? this is what I suppose...: */ | |
/* "4\3\7 - Einstein said E=mc2" ----> "4\\3\\7\ -\ Einstein\ said\ E\=mc2" */ | |
return sText.replace(/[\s\=\\]/g, "\\$&"); | |
} | |
function SubmitRequest(oTarget, callback) { | |
var nFile, sFieldType, oField, oSegmReq, oFile, bIsPost = oTarget.method.toLowerCase() === "post"; | |
/* console.log("AJAXSubmit - Serializing form..."); */ | |
this.contentType = bIsPost && oTarget.enctype ? oTarget.enctype : "application\/x-www-form-urlencoded"; | |
this.technique = bIsPost ? this.contentType === "multipart\/form-data" ? 3 : this.contentType === "text\/plain" ? 2 : 1 : 0; | |
this.receiver = oTarget.action.match(/\?/) ? oTarget.action + '&ajax=1' : oTarget.action + '?ajax=1'; | |
this.status = 0; | |
this.segments = []; | |
this.callback = callback; | |
var fFilter = this.technique === 2 ? plainEscape : escape; | |
for (var nItem = 0; nItem < oTarget.elements.length; nItem++) { | |
oField = oTarget.elements[nItem]; | |
if (!oField.hasAttribute("name")) { | |
continue; | |
} | |
var oFName = Utf8Encode(oField.name); | |
var oFValue = Utf8Encode(oField.value); | |
sFieldType = oField.nodeName.toUpperCase() === "INPUT" ? oField.getAttribute("type").toUpperCase() : "TEXT"; | |
if (sFieldType === "FILE" && oField.files.length > 0) { | |
if (this.technique === 3) { | |
/* enctype is multipart/form-data */ | |
for (nFile = 0; nFile < oField.files.length; nFile++) { | |
oFile = oField.files[nFile]; | |
oSegmReq = new FileReader(); | |
/* (custom properties:) */ | |
oSegmReq.segmentIdx = this.segments.length; | |
oSegmReq.owner = this; | |
/* (end of custom properties) */ | |
oSegmReq.onload = pushSegment; | |
this.segments.push("Content-Disposition: form-data; name=\"" + oFName + "\"; filename=\"" + oFName + "\"\r\nContent-Type: " + oFile.type + "\r\n\r\n"); | |
this.status++; | |
oSegmReq.readAsBinaryString(oFile); | |
} | |
} else { | |
/* enctype is application/x-www-form-urlencoded or text/plain or method is GET: files will not be sent! */ | |
for (nFile = 0; nFile < oField.files.length; this.segments.push(fFilter(oFName) + "=" + fFilter(oField.files[nFile++].name))) | |
; | |
} | |
} else if ((sFieldType !== "RADIO" && sFieldType !== "CHECKBOX") || oField.checked) { | |
/* field type is not FILE or is FILE but is empty */ | |
this.segments.push( | |
this.technique === 3 ? /* enctype is multipart/form-data */ | |
"Content-Disposition: form-data; name=\"" + oFName + "\"\r\n\r\n" + oFValue + "\r\n" | |
: /* enctype is application/x-www-form-urlencoded or text/plain or method is GET */ | |
fFilter(oFName) + "=" + fFilter(oFValue) | |
); | |
} | |
} | |
processStatus(this); | |
} | |
return function (oFormElement, callback) { | |
if (!oFormElement.action) { | |
return; | |
} | |
new SubmitRequest(oFormElement, callback); | |
}; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment