File drag and drop event in jquery - javascript

I'm trying to find a way of letting users drag and drop individual files into an area on my page that can then get submitted along with all my other form data.
In my research I've found multiple "drag and drop" upload scripts but they all do way, way too much. I want to handle the actual uploading myself and just provide a way for users to upload files without hitting the browse button.
Is there an event in jquery (or something similar) that I should be looking for?
Any help is much appreciated!

I came across this question while researching some AJAX file upload techniques.
I created a drag and drop upload script today (its still in proof of concept stage but heres the basic steps that I took.
$('drag-target-selector').on('drop', function(event) {
//stop the browser from opening the file
event.preventDefault();
//Now we need to get the files that were dropped
//The normal method would be to use event.dataTransfer.files
//but as jquery creates its own event object you ave to access
//the browser even through originalEvent. which looks like this
var files = event.originalEvent.dataTransfer.files;
//Use FormData to send the files
var formData = new FormData();
//append the files to the formData object
//if you are using multiple attribute you would loop through
//but for this example i will skip that
formData.append('files', files[0]);
}
now you can send formData to be processed by a php script or whatever else you want to use. I didn't use jquery in my script as there a lot of issues with it it seemed easier to use regular xhr. Here is that code
var xhr = new XMLHttpRequest();
xhr.open('POST', 'upload.php');
xhr.onload = function() {
console.log(xhr.responseText);
};
xhr.upload.onprogress = function(event) {
if (event.lengthComputable) {
var complete = (event.loaded / event.total * 100 | 0);
//updates a <progress> tag to show upload progress
$('progress').val(complete);
}
};
xhr.send(formData);

Related

How to get started adding fields in-browser that can be filled in on a PDF? (Like e-signature)

There are a million websites that offer e-signatures, usually by letting you draw a rectangle on a PDF (or file that is converted to a PDF) where the signature will be placed.
I assume that this is using the Canvas element and AJAX to send the location where the rectangle was drawn back to the server.
My nonprofit already uses a great open source document assembly tool called Docassemble. I'd like to leverage our existing form library to allow for direct integration with signatures. I actually already built a Docassemble app that does e-signing, but you need to manually place the fields in the file before uploading it. Placing the signature location in-browser would make it exponentially better. Having to pass it off to a third-party is probably more than we can pay for but also would be much less useful.
I'm not a novice programmer but I've never used the Canvas element. I really don't know where to start with this project. Any advice? Are there any libraries that would help? Docassemble is built on Python/Flask with Jquery but this seems mostly like a generic JavaScript question. I have seen so many cheap Docusign clones with this feature that I wonder if there's a library that I can't find with my Google-fu.
Have a look at https://github.com/szimek/signature_pad (live demo) which has no external deps.
The example in the docs/ directory implements a Save PNG button which downloads a PNG in the user's browser. I was able to modify these lines from the example to instead call my own upload function:
var dataURL = signaturePad.toDataURL();
// download(dataURL, "signature.png");
upload(dataURL)
This function makes the AJAX POST request:
function upload(data){
xhr = new XMLHttpRequest();
xhr.open('POST', '/submit');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = function() {
if (xhr.status === 200) {
alert('Data submitted: ' + xhr.responseText);
}
else if (xhr.status !== 200) {
alert('Request failed. Returned status of ' + xhr.status);
}
};
xhr.send(encodeURI('data=' + data));
Now in my /submit route request.form['data'] is an inline image which can then be stored in the database, or rendered directly in the src attribute of an <img> tag.

How to post blob and string with XMLHttpRequest javascript and PHP [duplicate]

I've seen many partial answers to this here and elsewhere, but I am very much a novice coder and am hoping for a thorough solution. I have been able to set up recording audio from a laptop mic in Chrome Canary (v. 29.x) and can, using recorder.js, relatively easily set up recording a .wav file and saving that locally, a la:
http://webaudiodemos.appspot.com/AudioRecorder/index.html
But I need to be able to save the file onto a Linux server I have running. It's the actual sending of the blob recorded data to the server and saving it out as a .wav file that's catching me up. I don't have the requisite PHP and/or AJAX knowledge about how to save the blob to a URL and to deal, as I have been given to understand, with binaries on Linux that make saving that .wav file challenging indeed. I'd greatly welcome any pointers in the right direction.
Client side JavaScript function to upload the WAV blob:
function upload(blob) {
var xhr=new XMLHttpRequest();
xhr.onload=function(e) {
if(this.readyState === 4) {
console.log("Server returned: ",e.target.responseText);
}
};
var fd=new FormData();
fd.append("that_random_filename.wav",blob);
xhr.open("POST","<url>",true);
xhr.send(fd);
}
PHP file upload_wav.php:
<?php
// get the temporary name that PHP gave to the uploaded file
$tmp_filename=$_FILES["that_random_filename.wav"]["tmp_name"];
// rename the temporary file (because PHP deletes the file as soon as it's done with it)
rename($tmp_filename,"/tmp/uploaded_audio.wav");
?>
after which you can play the file /tmp/uploaded_audio.wav.
But remember! /tmp/uploaded_audio.wav was created by the user www-data, and (by PHP default) is not readable by the user. To automate adding the appropriate permissions, append the line
chmod("/tmp/uploaded_audio.wav",0755);
to the end of the PHP (before the PHP end tag ?>).
Hope this helps.
Easiest way, if you just want to hack that code, is go in to recorderWorker.js, and hack the exportWAV() function to something like this:
function exportWAV(type){
var bufferL = mergeBuffers(recBuffersL, recLength);
var bufferR = mergeBuffers(recBuffersR, recLength);
var interleaved = interleave(bufferL, bufferR);
var dataview = encodeWAV(interleaved);
var audioBlob = new Blob([dataview], { type: type });
var xhr=new XMLHttpRequest();
xhr.onload=function(e) {
if(this.readyState === 4) {
console.log("Server returned: ",e.target.responseText);
}
};
var fd=new FormData();
fd.append("that_random_filename.wav",audioBlob);
xhr.open("POST","<url>",true);
xhr.send(fd);
}
Then that method will save to server from inside the worker thread, rather than pushing it back to the main thread. (The complex Worker-based mechanism in RecorderJS is because a large encode should be done off-thread.)
Really, ideally, you'd just use a MediaRecorder today, and let it do the encoding, but that's a whole 'nother ball of wax.

How to load a PDF into a blob so it can be uploaded?

I'm working on a testing framework that needs to pass files to the drop listener of a PLUpload instance. I need to create blob objects to pass inside a Data Transfer Object of the sort generated on a Drag / Drop event. I have it working fine for text files and image files. I would like to add support for PDF's, but it seems that I can't get the encoding right after retrieving the response. The response is coming back as text because I'm using Sahi to retrieve it in order to avoid Cross-Domain issues.
In short: the string I'm receiving is UTF-8 encoded and therefore the content looks like you opened a PDF with a text editor. I am wondering how to convert this back into the necessary format to create a blob, so that after the document gets uploaded everything looks okay.
What steps do I need to go through to convert the UTF-8 string into the proper blob object? (Yes, I am aware I could submit an XHR request and change the responseType property and (maybe) get closer, however due to complications with the way Sahi operates I'm not going to explain here why I would prefer not to go this route).
Also, I'm not familiar enough but I have a hunch maybe I lose data by retrieving it as a string? If that's the case I'll find another approach.
The existing code and the most recent approach I have tried is here:
var data = '%PDF-1.7%����115 0 obj<</Linearized 1/L ...'
var arr = [];
var utf8 = unescape(encodeURIComponent(data));
for (var i = 0; i < utf8.length; i++) {
arr.push(utf8.charCodeAt(i));
}
var file = new Blob(arr, {type: 'application/pdf'});
It looks like you were close. I just did this for a site which needed to read a PDF from another website and drop it into a fileuploader plugin. Here is what worked for me:
var url = "http://some-websites.com/Pdf/";
//You may not need this part if you have the PDF data locally already
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
//console.log(this.response, typeof this.response);
//now convert your Blob from the response into a File and give it a name
var fileOfBlob = new File([this.response], 'your_file.pdf');
// Now do something with the File
// for filuploader (blueimp), just use the add method
$('#fileupload').fileupload('add', {
files: [ fileOfBlob ],
fileInput: $(this)
});
}
}
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.send();
I found help on the XHR as blob here. Then this SO answer helped me with naming the File. You might be able to use the Blob by itself, but you won't be able to give it a name unless its passed into a File.

Parse a local file to an array using JavaScript

I am trying to read a local file and have each line as an index in an array using JavaScript. I have been searching for the past 20 minutes and either I'm stupid or there really isn't an answer that pertains to my problem (...but it's probably the former :P). I am really new to JavaScript so if you have an answer could you please comment the code just to I know what's going on?
Also, from the searching I've done on the internet some people said JavaScript can't read local file for security reasons so if that is correct is there another language I can use? I'm a bit familiar with PHP if that is an option, which I doubt it is.
EDIT
As per thg435's question, I'll explain what I am trying to accomplish.
My project is to analyze a BUNCH of water quality data that has been collected by the Ontario gov't (which I've done) and display it in some way. I have chosen to display it on a webpage using the Google Maps API. I currently have a file of chemicals that were found. Each line is a different chemical. I would like to read the file in an array then create an option menu displaying the chemicals in the array.
Also, the local file I would like to read will the be the same name and location all the time. I have seen people have boxes where the user clicks and chooses their file or to drag and drop but that's not what I'm looking for.
I don't think I explained this properly. I have a file in the same directory as my HTML and JavaScript files that contains words. Example:
Line 1: "Iron"
Line 2: "Aluminum"
Line 3: "Steel"
etc...
I would like to read the file and parse each line into a different index in an array. I don't want the user to be able to choose which file to read using the <input ... /> thing.
You're going to want to take a look at the FileReader API. This should allow you to read the text of a local file via readAsText(). This won't work in every browser but should work in all modern browser. You can see which browsers support it here.
Example:
<input id="file" type="file" />
var filesInput = document.getElementById("file");
filesInput.addEventListener("change", function (event) {
var files = event.target.files;
var file = files[0];
var reader = new FileReader();
reader.addEventListener("load", function (event) {
var textFile = event.target;
alert(textFile.result);
});
reader.readAsText(file);
});
It's not possible to invoke the FileReader API without user interaction. Consequently, your user would have to select whatever file to load in order for it to be read in pure JS. Since I'm assuming this will be up on a server, why not just put the list of chemicals also up on the server and GET the JSON encoded array of the results. Then you can decode them with Javascript.
You can access local files in 2 ways that I know of. The first way is making the user drag-and-drop the files onto the page, and using an <input type="file"> tag.
For the former, you would need to do the following:
addEventListener('dragover', function(e){e.preventDefault();});
addEventListener('drop', function(e) {
eventHandler.call(e.dataTransfer||e.clipboardData);
e.preventDefault();
});
For the latter, you'd need to add an event listener for the change event on the input:
document.getElementById('upload').addEventListener('change', eventHandler)
And for both, you'd need to have this as a basic callback function:
function eventHandler() {
var file = this.files[0]; //get the files
var reader = new FileReader(); //initiate reader
reader.onloadend = callbackFn; //set event handler
reader.readAsText(file); //initiate reading of files
if (this.id) { //only run if this is the input
var id = this.id;
this.outerHTML = this.outerHTML; //this resets the input
document.getElementById(id).addEventListener('change', eventHandler); //reattach event handler
}
function callbackFn(e) {
document.getElementById('output').value = e.target.result; //output it to a textarea
}
}
Here is a demo where the text contents (that what you see when opening it in notepad) of any file you drop in it, or any file you select from the input, is put in the textarea.
For more information, see https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications.

xhr2 file upload - accessing filenames with formData

I have an upload component to my application, which successfully uses the older form upload method in an iFrame. I have an Ajax poll that returns upload progress every 1000ms.
I am doing feature detection and allowing capable browsers to upload via xhr2. The theory is that I then have access to the progress on the client side; no need to poll, and the progress bar updates far more smoothly and elegantly! At the end of the batch upload, I need to redirect to a page showing a list of all the files uploaded.
You can upload files through xhr2 two ways: each file is its own upload, or you make a "formData" object containing all files. Each has benefits and drawbacks, and I think I'm trying to get the best of both worlds which may not be possible. The "best of both worlds" to me would meet these requirements:
Be able to display progress and filenames of individual files as they go
Be able to display a "total progress" bar as the package is sent
Capture the "package" of files on the server side and send back a redirect upon completion of the whole package.
Here's sample code for single-file transfer. I can meet criteria #1 easily, and could make code for criteria #2 with some effort. #3 is a bit more problematic as the client side simply sends a bunch of separate files as individual transfers.
function uploadFile(file) {
xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
//domNode.bar is a cached jQuery object
domNode.bar.css('width', (evt.loaded / evt.total) * 100 + "%");
console.log('my current filename is: ' + file.name;
}
else {
// No data to calculate on
}
}, false);
xhr.addEventListener("load", function() {
console.log("finished upload");
}, false);
xhr.open("post", remoteURL, true);
// Set appropriate headers
xhr.setRequestHeader("Content-Type", "application/octet-stream");
xhr.setRequestHeader("X-File-Name", file.name);
xhr.setRequestHeader("X-File-Size", file.size);
xhr.setRequestHeader("X-File-Type", file.type);
// Send the file
xhr.send(file);
}
}
Here's sample code for sending as formData. I cannot meet criteria #1 right now... at all. I can meet critera #2 and #3 fairly easily:
function uploadFile(form) {
xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", function(evt) {
if (evt.lengthComputable) {
console.log(evt);
domNode.bar.css('width', (evt.loaded / evt.total) * 100 + "%");
// no longer have access to the file object
}
else {
// No data to calculate on
}
}, false);
xhr.addEventListener("load", function() {
console.log(xhr);
}, false);
xhr.open("post", remoteURL, true);
// Set appropriate headers
xhr.setRequestHeader("Content-Type", "multipart/form-data");
// Send the form
xhr.send(form);
}
}
// just assume that I've used formData.append to build a valid form object,
// which I have; and that this is triggered by a click event or something
uploadFile(form);
I'm not completely without options, but before I move forward with implementation I just wanted to sanity check that I'm not missing anything. Here are the options as I see them:
Continue to use only the Ajax calls for progress. Less smooth which is counter to our design goal, but the benefit is that I don't need to use an iFrame for the upload since I have the xhr2 API. I also get the single redirect when the stream closes.
Iterate over the files and do some heavy lifting on the client side for the progress; in addition to individual file progress bars, I can create an algorithm to track total progress. At the same time, I send a file count to the server, and use this count to hold off on a redirect URL until the last file arrives, and then I can send it.
Any thoughts?
If you want to send all files in one request, FormData is your only option of the two. Either option allows you to cover points 1 & 2.
Since you asked about other APIs, I feel it is justified in mentioning the cross-browser upload tool I maintain: Fine Uploader. My library provides callbacks that will allow you to easily achieve goals #1 & #2. As far as #3 is concerned, Fine Uploader sends each file in a separate request. However, it is not hard to make use of Fine Uploader's API to present a "total progress" bar. I've done just that in a project that uses Fine Uploader. The library provides a bunch of callbacks and exposes a comprehensive API that should be useful to you, given the points you have specified.
Note that upload progress is not currently available in IE9 and older in Fine Uploader, but you should be able to make use of your method to display progress via ajax calls. Your method is one possible approach, but there is another possible option that is scheduled for further review in the future: use of Apache/nginx's UploadProgress module. See feature request #506.

Categories

Resources