We can use .formData() of Body mixin to return a FormData representation of data at Chromium (Chrome) 60+ and Firefox 39+
Relevant specifications:
7.2 The Multipart Content-Type
Returning Values from Forms: multipart/form-data
Errata
Clarification of Body package data algorithm with bytes, FormData and multipart/form-data MIME type #392
Documenting de-facto handling of multipart/form-data form field file uploads #3040
Related
Multipart HTTP response
How to upload files in Web Workers when FormData is not defined
How to manually create multipart/form-data using JavaScript at client and at server to serve the multipart/form-data as a response?
You can create multipart/form-data manually with XMLHttpRequest like this example.
function multiPost(method, url, formHash){
var boundary = "nVenJ7H4puv"
var body = ""
for(var key in formHash){
body += "--" + boundary
+ "\r\nContent-Disposition: form-data; name=" + formHash[key].name
+ "\r\nContent-type: " + formHash[key].type
+ "\r\n\r\n" + formHash[key].value + "\r\n"
}
body += "--" + boundary + "--\r\n"
var xml = new XMLHttpRequest();
xml.open(method, url)
xml.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary)
xml.setRequestHeader("Content-Length", body.length)
xml.send(body)
}
You can write you own FormData polyfill, or just google it "FormData polyfill"))) And also you can use normal FormData at browsers Chrome, FireFox, Opera, Safari, IE(10+), Edge.
FormData polyfill is only useful for old IE, and for workers, but for workers you better should use this - https://gist.github.com/Rob--W/8b5adedd84c0d36aba64
wikipedia
standart formdata not of body
What you need to do? You want send formdata or recieve it at js?
You can try to use my polyfill, but I have not tested it.
sample:
var data = new RawFormData();
data.append("key","value")
data.append("key", new Blob("test"), "my file.txt");
data.getOutputDeferred().then(function(formData){
var xml = new XMLHttpRequest();
xml.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + data.getBoundry());
xml.setRequestHeader("Content-Length", formData.length);
xml.open(method, url);
xml.send(formData);
});
code:
/**
* #constructor
*/
RawFormData = function () {
this._promises = [];
this._boundry = this.makeBoundary();
};
/**
* #return {string}
*/
RawFormData.prototype.getBoundary = function () {
return this._boundry;
}
/**
* #return {string}
*/
RawFormData.prototype.makeBoundary = function () {
return 'MyBoundary' + window.btoa(Math.random().toString()).substr(0, 12);
};
/**
* #param {string} name
* #param {string|number|File|Blob|boolean|null|undefined} val
* #param {string=} filename
*/
RawFormData.prototype.append = function (name, val, filename) {
var prom = null;
if(val instanceof File || val instanceof Blob){
prom = this.readAsBinaryString(val).then(function(base64){
var contentType = val.type || 'application/octet-stream';
var result = '--' + this._boundry + '\r\n' +
'Content-Disposition: form-data; ' +
'name="' + name + '"; filename="' + this.encode_utf8(filename || "blob") + '"\r\n' +
'Content-Type: ' + contentType + '\r\n\r\n' +
base64 + '\r\n';
return result;
}.bind(this))
}else{
prom = new Promise(function(resolve){
return '--' + this._boundry + '\r\n' +
'Content-Disposition: form-data; ' +
'name="' + this.encode_utf8(name) + '"\r\n\r\n' +
this.encode_utf8(val) + '\r\n'
}.bind(this));
}
this._promises.push(prom);
return prom;
};
/**
* #return {File|Blob} blob
* #return {Promise<string>}
*/
RawFormData.prototype.readAsBinaryString = function (blob) {
var reader = new FileReader();
return new Promise(function(resolve,reject){
var binStringCallback = function (e) {
resolve(e.target.result);
};
var arrBufferCallback = function (e) {
var binary = "";
var bytes = new Uint8Array(e.target.result);
var length = bytes.byteLength;
for (var i = 0; i < length; i++) {
binary += String.fromCharCode(bytes[i]);
}
resolve(binary);
};
reader.onerror = reader.onabort = function () {
resolve(null);
};
if (typeof reader.readAsBinaryString != "undefined") {
reader.onload = binStringCallback;
reader.readAsBinaryString(blob);
} else {
reader.onload = arrBufferCallback;
reader.readAsArrayBuffer(blob);
}
});
};
RawFormData.prototype.encode_utf8 = function( s ){
return unescape( encodeURIComponent( s ) );
}
RawFormData.prototype.getOutputDeferred = function () {
return Promise.all(this._promises).then(function (rows) {
var output = '--' + this._boundry + '\r\n';
rows.forEach(function(row) {
output += row;
});
output += '--' + this._boundry + '\r\n';
return output;
}.bind(this));
};
Related
This is my first question on StackOverflow :)
I'm learning Javascript for a personal project and I get some troubles with asynchronous functions. Something is not clear to me yet with such functions :( .
I try to upload multifiles in an HTML form to prepare an XHR request. Below is my function that I trigger with a an AddEventListener on the submit button.
I found explications on MDN learning web development but since it was only for one file I custom it with a for loop on formCell[5].files (declared as global constant) which is where my files are.
The problem seems to be with the asynchronous behavior. Is an expert on stack have advice to me ? Is there a solution with promises for example ? The "If" with SetTimeOut to wait for loop execution don't seem to me very pretty.
I think I tried hundred solutions without success :)
Thanks a lot in advance,
Regards,
Romain
function sendData() {
/* Loading files */
var binnaryFiles = [null];
for (let i = 0; i < formCell[5].files.length; i++) {
let reader = new FileReader(); // FileReader API
reader.addEventListener("load", function () { // Asynchronous function (return result when read)
binnaryFiles[i] = reader.result;
});
// Read the file
reader.readAsBinaryString(formCell[5].files[i]);
}
if(binnaryFiles.length !== formCell[5].files.length) {
setTimeout( sendData, 10 );
return;
}
console.log("final" + binnaryFiles.length);
const XHR = new XMLHttpRequest();
const boundary = "blob"; // We need a separator to define each part of the request
let msg = "";
/* Loading files in the request */
for (let i = 0; i < formCell[5].files.length; i++) {
msg += "--" + boundary + "\r\n";
msg += 'content-disposition: form-data; '
+ 'name="' + formCell[5].name + '"; '
+ 'filename="' + formCell[5].files[i].name + '"\r\n';
msg += 'Content-Type: ' + formCell[5].files[i].type + '\r\n';
msg += '\r\n';
msg += binnaryFiles[i] + '\r\n';
}
/* Loading texts in the request */
for (let i = 0; i < formCell.length - 1; i++) {
msg += "--" + boundary + "\r\n";
msg += 'content-disposition: form-data; name="' + formCell[i].name + '"\r\n';
msg += '\r\n';
msg += formCell[i].value + "\r\n";
}
msg += "--" + boundary + "--";
XHR.addEventListener("load", function(event) {
alert( 'Yeah! Data sent and response loaded.' );
});
XHR.addEventListener("error", function(event) {
alert("Oops! Something went wrong.");
} );
XHR.open("POST", "http://localhost:3000/upload");
XHR.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
XHR.send(msg);
console.log(msg);
}
I think I finished by solving my problem using Promises :)
If anyone could confirm me that the code below is correct it could help me :)
Thanks,
Romain
function fileUpLoad(fileToUpload) {
return new Promise((resolve, reject) => {
const reader = new FileReader(); // FileReader API
reader.addEventListener("load", function () { // Asynchronous function (return result when read)
resolve(reader.result);
reject(reader.error);
});
// Read the file
reader.readAsBinaryString(fileToUpload);
});
}
/* Sending message */
function sendData(filesUploaded) {
let binnaryFiles = filesUploaded;
const XHR = new XMLHttpRequest();
const boundary = "blob"; // We need a separator to define each part of the request
let msg = "";
/* Loading files in the request */
for (let i = 0; i < binnaryFiles.length; i++) {
msg += "--" + boundary + "\r\n";
msg += 'content-disposition: form-data; '
+ 'name="' + formCell[5].name + '"; '
+ 'filename="' + formCell[5].files[i].name + '"\r\n';
msg += 'Content-Type: ' + formCell[5].files[i].type + '\r\n';
msg += '\r\n';
msg += binnaryFiles[i] + '\r\n';
}
/* Loading texts in the request */
for (let i = 0; i < formCell.length - 1; i++) {
msg += "--" + boundary + "\r\n";
msg += 'content-disposition: form-data; name="' + formCell[i].name + '"\r\n';
msg += '\r\n';
msg += formCell[i].value + "\r\n";
}
msg += "--" + boundary + "--";
XHR.addEventListener("load", function(event) {
alert( 'Yeah! Data sent and response loaded.' );
});
XHR.addEventListener("error", function(event) {
alert("Oops! Something went wrong.");
} );
XHR.open("POST", "http://localhost:3000/upload");
XHR.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
XHR.send(msg);
console.log(msg);
}
/* Validation on submit calling */
form.addEventListener("submit", function (evt) {
evt.preventDefault();
if (validationOnSubmit()) {
if (formCell[5].files.length > 0) {
let fileUploadingPromise = []
for (let i = 0; i < formCell[5].files.length; i++) {
fileUploadingPromise[i] = fileUpLoad(formCell[5].files[i]);
}
let binnaryFiles = [null];
Promise.all(fileUploadingPromise)
.then (resolve => {
for (let i = 0; i < formCell[5].files.length; i++) {
binnaryFiles[i] = resolve[i];
}
sendData(binnaryFiles)
})
.catch (reject => {
console.log(reject);
});
} else {
sendData(0);
}
}
});
I was trying to write simple javascript code to convert and upload files to Google Drive using Drive REST api(So that only converted document to google document format will be uploaded). I got succided in uploading docx/xlsx/pptx documents however when I am trying to macro enabled files such as .docm/.pptm/.xlsm I am getting error "Bad Request" shown in screenshot:Error while uploading .docm file
My JavaScript code looks like:
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<input type="file" id="fileToUpload"></input>
<button onclick="insertFile()">Pick File to Upload</button>
<script type="text/javascript">
var CLIENT_ID = 'CLIENT_ID_HERE';
var SCOPES = 'https://www.googleapis.com/auth/drive';
var FOLDER_ID = '';
/**
* Called when the client library is loaded to start the auth flow.
*/
function handleClientLoad() {
window.setTimeout(checkAuth, 1);
}
/**
* Check if the current user has authorized the application.
*/
function checkAuth() {
gapi.auth.authorize(
{'client_id': CLIENT_ID, 'scope': SCOPES},
handleAuthResult);
}
/**
* Called when authorization server replies.
*
* #param {Object} authResult Authorization result.
*/
function handleAuthResult(authResult) {
if (authResult && !authResult.error) {
console.log("Auth OK !!!");
}
}
function insertFile() {
fileData = document.getElementById("fileToUpload").files[0];
const boundary = '-------314159265358979323846';
const delimiter = "\r\n--" + boundary + "\r\n";
const close_delim = "\r\n--" + boundary + "--";
var reader = new FileReader();
reader.readAsBinaryString(fileData);
reader.onload = function(e) {
var contentType = fileData.type || 'application/octet-stream';
var metadata = {
'title': fileData.fileName,
'mimeType': contentType
};
var base64Data = btoa(reader.result);
var multipartRequestBody =
delimiter +
'Content-Type: application/json\r\n\r\n' +
JSON.stringify(metadata) +
delimiter +
'Content-Type: ' + contentType + '\r\n' +
'Content-Transfer-Encoding: base64\r\n' +
'\r\n' +
base64Data +
close_delim;
var request = gapi.client.request({
'path': '/upload/drive/v2/files',
'method': 'POST',
'params': {'convert': true},
'headers': {
'Content-Type': 'multipart/mixed; boundary="' + boundary + '"'
},
'body': multipartRequestBody});
request.execute((file) => {
console.log(file);
});
}
}
</script>
<script type="text/javascript" src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script>
EDIT:
Earlier I thought 'Google Drive does not support converting macro enabled files'. However when I tried to convert and upload the macro enabled files using python script I was able to do that . Python code:
http = httplib2.Http()
credentials.authorize(http)
drive_service = apiclient.discovery.build('drive', 'v2', http=http)
metadata = {'title': 'test_file.docm',
'mimeType' : 'application/vnd.ms-word.document.macroEnabled.12',}
res = drive_service.files().insert(convert='True',body=metadata,
media_body='test_file.docm', fields='mimeType,exportLinks').execute()
Am I missing anything in Javascript code?
here am trying to get reccurring events from calendar list for sharepoint Online app and there am using code as like
hostWebUrl = decodeURIComponent(manageQueryStringParameter('SPHostUrl'));
function GetListData() {
var webUrl = hostWebUrl;// = "http://server/sitewhereyourlistexists";
var listGuid = "{2000da75-8663-42d9-9999-ad855c54b4e0}"
// An XMLHttpRequest object is used to access the web service
var xhr = new XMLHttpRequest();
var url = webUrl + "/_vti_bin/Lists.asmx";
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xhr.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/sharepoint/soap/GetListItems");
// The message body consists of an XML document
// with SOAP elements corresponding to the GetListItems method parameters
// i.e. listName, query, and queryOptions
var data = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
"<soap:Body>" +
"<GetListItems xmlns=\"http://schemas.microsoft.com/sharepoint/soap/\">" +
"<listName>" + listGuid + "</listName>" +
"<query>" +
"<Query><Where>" +
"<DateRangesOverlap>" +
"<FieldRef Name=\"EventDate\"/>" +
"<FieldRef Name=\"EndDate\"/>" +
"<FieldRef Name=\"RecurrenceID\"/>" +
"<Value Type=\"DateTime\"><Today/></Value>" +
"</DateRangesOverlap>" +
"</Where></Query>" +
"</query>" +
"<queryOptions>" +
"<QueryOptions>" +
"<ExpandRecurrence>TRUE</ExpandRecurrence>" +
"</QueryOptions>" +
"</queryOptions>" +
"</GetListItems>" +
"</soap:Body>" +
"</soap:Envelope>";
// Here we define what code we want to run upon successfully getting the results
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
var doc = xhr.responseXML;
// grab all the "row" elements from the XML results
var rows = doc.getElementsByTagName("z:row");
var results = "Today's Schedule (" + rows.length + "):\n\n";
var events = {};
for (var i = 0, len = rows.length; i < len; i++) {
var id = rows[i].getAttribute("ows_FSObjType"); // prevent duplicates from appearing in results
if (!events[id]) {
events[id] = true;
var allDay = rows[i].getAttribute("ows_fAllDayEvent"),
title = rows[i].getAttribute("ows_Title"),
start = rows[i].getAttribute("ows_EventDate");
var index = start.indexOf(" ");
var date = start.substring(5, index) + "-" + start.substring(2, 4); // get the date in MM-dd-yyyy format
start = start.substring(index, index + 6); // get the start time in hh:mm format
var end = rows[i].getAttribute("ows_EndDate");
index = end.indexOf(" "); end = end.substring(index, index + 6); // get the end time in hh:mm format
results += date + " " + (allDay == "1" ? "All Day\t" : start + " to " + end) + " \t " + title + "\n";
}
}
alert(results);
} else {
alert("Error " + xhr.status);
}
}
};
// Finally, we actually kick off the query
xhr.send(data);
}
after calling this function in decument. ready section it is not retrieving any data but there is ine error which i can see in console of browser that is as below
You will click on the correct request in the left hand side panel, then select "Inspectors" in the right hand side top panel. Then choose between the different request and response options.
Ok I'm stuck, I want to create an event in facebook, using javascript facebook api, and I want to load an image on the event cover. I can not figure out how I can do it.
I create an image in a canvas and I can upload to facebook using an sendAsBinnary function
from: https://stackoverflow.com/a/5303242/945521
And this function
Facebook.prototype.postImageToFacebook = function(authToken, filename, mimeType, imageData, message){
try {
showMessage("Creating post...");
// this is the multipart/form-data boundary we'll use
var boundary = '----------RaNdOm_crAPP' + getBoundary();
// let's encode our image file, which is contained in the var
var formData = '--' + boundary + '\r\n';
formData += 'Content-Disposition: form-data; name="source"; filename="' + filename + '"\r\n';
formData += 'Content-Type: ' + mimeType + '\r\n\r\n';
for (var i = 0; i < imageData.length; ++i)
{
formData += String.fromCharCode(imageData[ i ] & 0xff);
}
formData += '\r\n';
formData += '--' + boundary + '\r\n';
formData += 'Content-Disposition: form-data; name="message"\r\n\r\n';
formData += message + '\r\n';
formData += '--' + boundary + '--\r\n';
//var xhr = new XMLHttpRequest();
var xhr = null;
if (window.XDomainRequest) {
xhr = new XDomainRequest();
}
else if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}
else {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
xhr.onload = function() {
window.alert("The photo was published successfully!!");
};
showMessage("Sending request...");
xhr.open("POST", "https://graph.facebook.com/me/photos?access_token=" + authToken, true);
if (xhr.setRequestHeader)
xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
xhr.sendAsBinary(formData);
} catch (ex) {
stopWaitingSpin();
debugLog(ex);
}
};
and with this
FB.api("/me/events", "POST", {
"name": name,
"start_time": start_time,
//"end_time":end_time,
"description": description,
"location": location,
//"location_id":location_id,
"privacy_type": privacy_type
},
function(response) {
if (response && !response.error) {
var event_id = response.id;
console.log(response);
}
});
I can create a event.
But what need to call to send the image to the cover on event???
Thank's to all
Actually its nowhere mentioned in the documentation yet, but to publish a cover photo on an event you need to call \POST /{event-id} with param cover_url:
{event-id} could be obtained as a result when you created an event.
FB.api("/{event-id}", "POST", {
cover_url: {image-url}
},
function(response) {
console.log(response); // you'll get the response as 'true' or 'false'
});
I'm trying to use javascript in order to set the contents of a file stored on Google Drive (for example, a .txt or .java file) to a specific String.
I know that the proper way to update a file stored on Google Drive is
function updateFile(fileId, fileMetadata, fileData, callback) {
const boundary = '-------314159265358979323846';
const delimiter = "\r\n--" + boundary + "\r\n";
const close_delim = "\r\n--" + boundary + "--";
//console.log("fileId: "+fileId+" fileData: "+fileData);
var reader = new FileReader();
reader.readAsBinaryString(fileData);
reader.onload = function(e) {
console.log("reader initialized");
var contentType = fileData.type || 'application/octet-stream';
// Updating the metadata is optional and you can instead use the value from drive.files.get.
var base64Data = btoa(reader.result);
var multipartRequestBody =
delimiter +
'Content-Type: application/json\r\n\r\n' +
JSON.stringify(fileMetadata) +
delimiter +
'Content-Type: ' + contentType + '\r\n' +
'Content-Transfer-Encoding: base64\r\n' +
'\r\n' +
base64Data +
close_delim;
var request = gapi.client.request({
'path': '/upload/drive/v2/files/' + fileId,
'method': 'PUT',
'params': {'uploadType': 'multipart', 'alt': 'json'},
'headers': {
'Content-Type': 'multipart/mixed; boundary="' + boundary + '"'
},
'body': multipartRequestBody});
if (!callback) {
callback = function(file) {
console.log(file)
};
}
request.execute(callback);
}
}
but this has not worked in setting the content to a specific String.
Never mind. I found the answer to my problem. Using the method updateFile from my question:
function save(fileId, content){
var contentArray = new Array(content.length);
for (var i = 0; i < contentArray.length; i++) {
contentArray[i] = content.charCodeAt(i);
}
var byteArray = new Uint8Array(contentArray);
var blob = new Blob([byteArray], {type: 'text/plain'});
var request = gapi.client.drive.files.get({'fileId': fileId});
request.execute(function(resp) {
updateFile(fileId,resp,blob,changesSaved);
// the callback^^^^^^
});
}