Javascript: Persist file upload between redirects - javascript

Since there were no answers to this question:
Resumable.js: Persist file uploading between redirects and browser restarts
I am working on a workaround to let users upload their files in a separate popup, while they browse other pages. This is how I am passing my file objects to the popup window:
index.html:
<ol id="chosenFilesList"></ol>
Select files
<br>
<br>
<br>
Upload
<script src="resumable.js"></script>
<script>
var fileArr = [];
function displaySelectedFiles() {
var fileList = '';
for (var i = 0; i < fileArr.length; i++)
if(fileArr[i])
fileList += '<li>' + fileArr[i].name + '</li><a style="cursor: pointer;" onclick="removeFile(' + fileArr[i] + ');">Remove</a>';
//localStorage.setItem('fileArr', fileArr);
document.getElementById('chosenFilesList').innerHTML = fileList;
}
var r = new Resumable({
target:'test.html'
});
r.assignBrowse(document.getElementById('browseButton'));
r.on('fileSuccess', function(file){
console.debug('fileSuccess',file);
});
r.on('fileProgress', function(file){
console.debug('fileProgress', file);
});
r.on('fileAdded', function(file, event){
//r.upload();
fileArr.push(file.file);
displaySelectedFiles();
console.debug('fileAdded', event);
});
r.on('filesAdded', function(array){
//r.upload();
displaySelectedFiles();
console.debug('filesAdded', array);
});
r.on('fileRetry', function(file){
console.debug(file);
});
r.on('fileError', function(file, message){
console.debug('fileError', file, message);
});
r.on('uploadStart', function(){
console.debug('uploadStart');
});
r.on('complete', function(){
console.debug('complete');
});
r.on('progress', function(){
console.debug('progress');
});
r.on('error', function(message, file){
console.debug('error', message, file);
});
r.on('pause', function(){
console.debug('pause');
});
r.on('cancel', function(){
console.debug('cancel');
});
var popupWindow;
var addFiles = function() {
for (var i = 0; i < fileArr.length; i++) {
if(fileArr[i])
popupWindow.r.addFile(fileArr[i]);
}
//popupWindow.startUpload();
window.location.reload();
setTimeout('popupWindow.focus()', 1);
};
document.getElementById('uploadButton').addEventListener('click', function(evt) {
popupWindow = window.windowPop('', 900, 500);
if(popupWindow.location.href.indexOf('test.html') === -1) {
popupWindow.location.href = 'test.html';
setTimeout(function(){
popupWindow.onload = addFiles;
addFiles();
}, 300);
} else {
addFiles();
}
});
function windowPop(url, width, height) {
var leftPosition, topPosition;
//Allow for borders.
leftPosition = (window.screen.width / 2) - ((width / 2) + 10);
//Allow for title and status bars.
topPosition = (window.screen.height / 2) - ((height / 2) + 50);
//Open the window.
return window.open(url, "Window2", "status=no,height=" + height + ",width=" + width + ",resizable=yes,left=" + leftPosition + ",top=" + topPosition + ",screenX=" + leftPosition + ",screenY=" + topPosition + ",toolbar=no,menubar=no,scrollbars=no,location=no,directories=no");
}
</script>
test.html:
<!DOCTYPE html>
<html>
<head>
<title>Resumable.js - Multiple simultaneous, stable and resumable uploads via the HTML5 File API</title>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div id="frame">
<h3>Demo</h3>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="resumable.js"></script>
<div class="resumable-error">
Your browser, unfortunately, is not supported by Resumable.js. The library requires support for the HTML5 File API along with file slicing.
</div>
<div class="resumable-drop" ondragenter="jQuery(this).addClass('resumable-dragover');" ondragend="jQuery(this).removeClass('resumable-dragover');" ondrop="jQuery(this).removeClass('resumable-dragover');">
Drop video files here to upload or <a class="resumable-browse"><u>select from your computer</u></a>
</div>
<div class="resumable-progress">
<table>
<tr>
<td width="100%"><div class="progress-container"><div class="progress-bar"></div></div></td>
<td class="progress-text" nowrap="nowrap"></td>
<td class="progress-pause" nowrap="nowrap">
<img src="resume.png" title="Resume upload" />
<img src="pause.png" title="Pause upload" />
</td>
</tr>
</table>
</div>
<ul class="resumable-list"></ul>
<script>
var r = new Resumable({
target:'/java-example/upload',
chunkSize:1*1024*1024,
simultaneousUploads:4,
testChunks: true,
throttleProgressCallbacks:1,
method: "octet"
});
// Resumable.js isn't supported, fall back on a different method
if(!r.support) {
$('.resumable-error').show();
} else {
// Show a place for dropping/selecting files
$('.resumable-drop').show();
r.assignDrop($('.resumable-drop')[0]);
r.assignBrowse($('.resumable-browse')[0]);
// Handle file add event
r.on('fileAdded', function(file){
// Show progress pabr
$('.resumable-progress, .resumable-list').show();
// Show pause, hide resume
$('.resumable-progress .progress-resume-link').hide();
$('.resumable-progress .progress-pause-link').show();
// Add the file to the list
$('.resumable-list').append('<li class="resumable-file-'+file.uniqueIdentifier+'">Uploading <span class="resumable-file-name"></span> <span class="resumable-file-progress"></span>');
$('.resumable-file-'+file.uniqueIdentifier+' .resumable-file-name').html(file.fileName);
// Actually start the upload
r.upload();
console.log(file);
});
r.on('pause', function(){
// Show resume, hide pause
$('.resumable-progress .progress-resume-link').show();
$('.resumable-progress .progress-pause-link').hide();
});
r.on('complete', function(){
// Hide pause/resume when the upload has completed
$('.resumable-progress .progress-resume-link, .resumable-progress .progress-pause-link').hide();
});
r.on('fileSuccess', function(file,message){
// Reflect that the file upload has completed
$('.resumable-file-'+file.uniqueIdentifier+' .resumable-file-progress').html('(completed)');
});
r.on('fileError', function(file, message){
// Reflect that the file upload has resulted in error
$('.resumable-file-'+file.uniqueIdentifier+' .resumable-file-progress').html('(file could not be uploaded: '+message+')');
});
r.on('fileProgress', function(file){
// Handle progress for both the file and the overall upload
$('.resumable-file-'+file.uniqueIdentifier+' .resumable-file-progress').html(Math.floor(file.progress()*100) + '%');
$('.progress-bar').css({width:Math.floor(r.progress()*100) + '%'});
});
}
</script>
</div>
</body>
</html>
I just added / modified https://github.com/23/resumable.js/tree/master/samples/java sample HTML files.
I am just getting all the file objects from file selectors and uploading them in a separate window using resumable.js (I don't think library is important here). It works flawlessly on Chrome and Firefox.
The problem with this approach is, in IE 11- (as far as I tested), the file uploading stops as soon as user is redirected to another page.
Can anybody please tell me how can I make it work in all browsers (hopefully, using pure javascript)?
Also, it will be a lot helpful, if I can just persist an upload between browser restarts as well.

Related

AngularJS toaster shows alert twice instead of one time on file upload

I'm using toaser to inform user that file was successfully uploaded. The problem is that toaster shows message twice.
Parts of my HTML code:
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular-resource.min.js"></script>
<script src="http://code.angularjs.org/1.4.8/angular-animate.min.js" ></script>
<script src="../common/toaster.js"></script>
<script src="../common/ng-file-upload.min.js"></script>
<script src="../common/ng-file-upload-shim.min.js"></script>
<script src="../common/angular-sanitize.min.js"></script>
<script src="messages.controller.js"></script>
<script src="../common/cookieGet.js"></script>
...
<table class="sendFile" ng-show="hiddenFriendId != null" style="overflow-y: auto; overflow-x: hidden; height:100px; width:100%;">
<tbody>
<tr>
<td style="vertical-align: top;">
<div
width = "100%"
ngf-select=""
ngf-drop=""
ng-model="files"
class="drop-box"
ngf-drag-over-class="{ accept:'dragover', reject:'dragover-err', delay:100}"
ngf-multiple="true" ngf-allow-dir="false"
ngf-max-size="10MB" ngf-max-files="10"
accept="image/*,application/pdf"
ngf-pattern="'image/*,application/pdf'">
Click here <b>OR</b> drag&drop pdfs or images
</div>
<div ngf-no-file-drop>File Drag/Drop is not supported for this browser</div>
<div ng-show="files.length>0">
<div ng-repeat="f in files">
<progressbar ng-show = "f.progressPercentage > 100">
<bar style="width:{{f.progressPercentage}}%;">
Upload: {{f.name | limitTo:50 }} {{f.$error}} {{f.$errorParam}} - {{ f.progressPercentage }}% completed
</bar>
</progressbar>
</div>
</div>
</td>
</tr>
</tbody>
</table>
And here is my JS part for file upload:
$scope.upload = function (files) {
var urlUploadFile = "http://localhost:8180/ChatRestNoSQLMaven/rest/MessageService/upload/";
var progressPercentage = 0;
if (files && files.length) {
for (var i=0; i < files.length; i++) {
var file = files[i];
if (!file.$error) {
Upload.upload({
url: urlUploadFile,
data: {
securityKey: securityKey,
friendId: $scope.hiddenFriendId,
file: file
}
}).then(function (resp) {
$timeout(function () {
});
}, function (response) {
if (response.status > 0) {
$scope.errorMsg = response.status + ': ' + response.data;
toaster.pop("error","Error","Unable to upload file. Please try again...");
}
}, function (evt) {
var loaded = evt.loaded;
var total = evt.total;
var number = 100.0 * (evt.loaded / evt.total);
if (number == 100){
toaster.pop("success","File uploaded","File " + file.name + " successfully uploaded");
}
file.progressPercentage = number.toFixed();
});
}
}
}
}
So, can anybody help me to avoid this problem and throw the toaser alert only once.
Thank you!
From the Javascript code section under https://github.com/danialfarid/ng-file-upload/blob/master/README.md#-usage, you can see that the THIRD callback in the Upload.upload().then(...) block is used to update the progress meter. It's not guaranteed to run just once.
You should, instead, try putting your toaster code in the FIRST callback where you have $timeout(...) currently to help isolate the issue.
Have you post the file cross domain?if you do,the browser will do twice request:first time is the OPTION request,seconde time is the real POST request.Check it in the Network of the devtools of the browser to make sure how many request the browser do.

JS FileReader: Read CSV from Local File & jquery-csv

I have a CSV file in the same directory as an html page, and I'd like to use FileReader to read the file contents into a jquery-csv's To Arrays function, but I can't seem to get it to work properly. I think I understand the asynchrony of this task, but have i depicted it correctly? Here, I'm trying to output the 2nd cell in the 2nd column. Thanks for any help.
<script type="text/javascript" src="https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1','packages':['timeline']}]}"></script>
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="jquery.csv-0.71.js"></script>
<script type="text/javascript">
var reader = new FileReader();
reader.onload = function(e) {
var text = e.target.result;
var data = $.csv.toArrays(text);
document.write(data[1][1]);
}
reader.readAsText('data.csv');
</script>
Here's a working demo provided by jquery-csv
<html>
<head>
<meta charset="utf-8" />
<title>Demo - CSV-to-Table</title>
</head>
<body>
<div id="inputs" class="clearfix">
<input type="file" id="files" name="files[]" multiple />
</div>
<hr />
<output id="list">
</output>
<hr />
<table id="contents" style="width:100%; height:400px;" border>
</table>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="http://evanplaice.github.io/jquery-csv/src/jquery.csv.min.js"></script>
<script>
$(document).ready(function() {
if(isAPIAvailable()) {
$('#files').bind('change', handleFileSelect);
}
});
function isAPIAvailable() {
// Check for the various File API support.
if (window.File && window.FileReader && window.FileList && window.Blob) {
// Great success! All the File APIs are supported.
return true;
} else {
// source: File API availability - http://caniuse.com/#feat=fileapi
// source: <output> availability - http://html5doctor.com/the-output-element/
document.writeln('The HTML5 APIs used in this form are only available in the following browsers:<br />');
// 6.0 File API & 13.0 <output>
document.writeln(' - Google Chrome: 13.0 or later<br />');
// 3.6 File API & 6.0 <output>
document.writeln(' - Mozilla Firefox: 6.0 or later<br />');
// 10.0 File API & 10.0 <output>
document.writeln(' - Internet Explorer: Not supported (partial support expected in 10.0)<br />');
// ? File API & 5.1 <output>
document.writeln(' - Safari: Not supported<br />');
// ? File API & 9.2 <output>
document.writeln(' - Opera: Not supported');
return false;
}
}
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
var file = files[0];
// read the file metadata
var output = ''
output += '<span style="font-weight:bold;">' + escape(file.name) + '</span><br />\n';
output += ' - FileType: ' + (file.type || 'n/a') + '<br />\n';
output += ' - FileSize: ' + file.size + ' bytes<br />\n';
output += ' - LastModified: ' + (file.lastModifiedDate ? file.lastModifiedDate.toLocaleDateString() : 'n/a') + '<br />\n';
// read the file contents
printTable(file);
// post the results
$('#list').append(output);
}
function printTable(file) {
var reader = new FileReader();
reader.readAsText(file);
reader.onload = function(event){
var csv = event.target.result;
var data = $.csv.toArrays(csv);
var html = '';
for(var row in data) {
html += '<tr>\r\n';
for(var item in data[row]) {
html += '<td>' + data[row][item] + '</td>\r\n';
}
html += '</tr>\r\n';
}
$('#contents').html(html);
};
reader.onerror = function(){ alert('Unable to read ' + file.fileName); };
}
</script>
</body>
</html>
Disclaimer: I'm the author of jquery-csv
It's not going to work.You have no permissions to read files with javascript from the browser. The only way to deal with it is to create an input[type=file] tag and add onChange event to it. For example:
document.getElementById('fileupload').addEventListener('change', function (e) {
var files = e.target.files;
//proceed your files here
reader.readAsText(files[0]);
}, false);

image upload and crop client side including on old browsers

I am looking for some sort of image uploader and cropper that works mainly client side before it saves to the server.
I have tried a few things but have the issue that most of it is html5 based and I can't seem to find some sort of flash based uploader for the older browsers.
I got slightly lost with the jquery file uploader which I know can be used in the older browsers and the still need to work on a cropping function (but that looks like it will be mostly server side which would be a last resort).
I have also used http://www.script-tutorials.com/html5-image-uploader-with-jcrop/ which sort of works it uploads but when I want to test the crop function it keeps opening up the upload.php file. I will put the code below here :
<!DOCTYPE html >
<html>
<head>
<title>test image uploader</title>
<!--Stylesheets-->
<link href="css/colorbox.css" rel="stylesheet"/>
<link href="css/jquery.Jcrop.min.css" rel="stylesheet"/>
<!-- scripts-->
<script src="js/jquery-1.9.1.min.js" type="text/javascript"></script>
<script src="js/jquery.min.js" type="text/javascript"></script>
<script src="js/jquery.Jcrop.min.js" type="text/javascript"></script>
<script src="js/script.js" type="text/javascript"></script>
</head>
<body >
<form id="upload_form" enctype="multipart/form-data" method="post" action="upload.php" onsubmit="return checkForm();">
<input type="hidden" id="x1" name="x1" />
<input type="hidden" id="y1" name="y1" />
<input type="hidden" id="x2" name="x2" />
<input type="hidden" id="y2" name="y2" />
<h2>Please select image file</h2>
<div>
<input type="file" name="image_file" id="image_file" onchange="fileSelectHandler();"/>
</div>
<div class="error"></div>
<div class="step2">
<h2>Please select a crop region</h2>
<img id="preview" />
<div class="info">
<label>File size</label><input type="text" id="filesize" name="filesize" />
<label>Type</label><input type="text" id="filetype" name="filetype" />
<label>Image dimension</label><input type="text" id="filedim" name="filedim" />
<label>W</label><input type="text" id="w" name="w" />
<label>H</label><input type="text" id="h" name="h" />
</div>
<input type="submit" value="Upload" />
</div>
</form>
</body>
<script type="text/javascript">
// convert bytes into friendly format
function bytesToSize(bytes) {
var sizes = ['Bytes', 'KB', 'MB'];
if (bytes == 0) return 'n/a';
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i];
};
// check for selected crop region
function checkForm() {
if (parseInt($('#w').val())) return true;
$('.error').html('Please select a crop region and then press Upload').show();
return false;
};
// update info by cropping (onChange and onSelect events handler)
function updateInfo(e) {
$('#x1').val(e.x);
$('#y1').val(e.y);
$('#x2').val(e.x2);
$('#y2').val(e.y2);
$('#w').val(e.w);
$('#h').val(e.h);
};
// clear info by cropping (onRelease event handler)
function clearInfo() {
$('.info #w').val('');
$('.info #h').val('');
};
function fileSelectHandler() {
// get selected file
var oFile = $('#image_file')[0].files[0];
// hide all errors
$('.error').hide();
// check for image type (jpg and png are allowed)
var rFilter = /^(image\/jpeg|image\/png)$/i;
if (!rFilter.test(oFile.type)) {
$('.error').html('Please select a valid image file (jpg and png are allowed)').show();
return;
}
// check for file size
if (oFile.size > 250 * 1024) {
$('.error').html('You have selected too big file, please select a one smaller image file').show();
return;
}
// preview element
var oImage = document.getElementById('preview');
// prepare HTML5 FileReader
var oReader = new FileReader();
oReader.onload = function (e) {
// e.target.result contains the DataURL which we can use as a source of the image
oImage.src = e.target.result;
oImage.onload = function () { // onload event handler
// display step 2
$('.step2').fadeIn(500);
// display some basic image info
var sResultFileSize = bytesToSize(oFile.size);
$('#filesize').val(sResultFileSize);
$('#filetype').val(oFile.type);
$('#filedim').val(oImage.naturalWidth + ' x ' + oImage.naturalHeight);
// Create variables (in this scope) to hold the Jcrop API and image size
var jcrop_api, boundx, boundy;
// destroy Jcrop if it is existed
if (typeof jcrop_api != 'undefined')
jcrop_api.destroy();
// initialize Jcrop
$('#preview').Jcrop({
minSize: [100, 100], // min crop size
boxWidth:600,
aspectRatio: 9/6, // keep aspect ratio 1:1
bgFade: true, // use fade effect
bgOpacity: .4, // fade opacity
onChange: updateInfo,
onSelect: updateInfo,
onRelease: clearInfo
}, function () {
// use the Jcrop API to get the real image size
var bounds = this.getBounds();
boundx = bounds[0];
boundy = bounds[1];
// Store the Jcrop API in the jcrop_api variable
jcrop_api = this;
});
};
};
// read selected file as DataURL
oReader.readAsDataURL(oFile);
}
</script>
</html>
here is the upload.php code :
<?php
/**
*
* HTML5 Image uploader with Jcrop
*
* Licensed under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright 2012, Script Tutorials
* http://www.script-tutorials.com/
*/
function uploadImageFile() { // Note: GD library is required for this function
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$iWidth = $iHeight = 200; // desired image result dimensions
$iJpgQuality = 90;
if ($_FILES) {
// if no errors and size less than 250kb
if (! $_FILES['image_file']['error'] && $_FILES['image_file']['size'] < 250 * 1024) {
if (is_uploaded_file($_FILES['image_file']['tmp_name'])) {
// new unique filename
$sTempFileName = 'cache/' . md5(time().rand());
// move uploaded file into cache folder
move_uploaded_file($_FILES['image_file']['tmp_name'], $sTempFileName);
// change file permission to 644
#chmod($sTempFileName, 0644);
if (file_exists($sTempFileName) && filesize($sTempFileName) > 0) {
$aSize = getimagesize($sTempFileName); // try to obtain image info
if (!$aSize) {
#unlink($sTempFileName);
return;
}
// check for image type
switch($aSize[2]) {
case IMAGETYPE_JPEG:
$sExt = '.jpg';
// create a new image from file
$vImg = #imagecreatefromjpeg($sTempFileName);
break;
/*case IMAGETYPE_GIF:
$sExt = '.gif';
// create a new image from file
$vImg = #imagecreatefromgif($sTempFileName);
break;*/
case IMAGETYPE_PNG:
$sExt = '.png';
// create a new image from file
$vImg = #imagecreatefrompng($sTempFileName);
break;
default:
#unlink($sTempFileName);
return;
}
// create a new true color image
$vDstImg = #imagecreatetruecolor( $iWidth, $iHeight );
// copy and resize part of an image with resampling
imagecopyresampled($vDstImg, $vImg, 0, 0, (int)$_POST['x1'], (int)$_POST['y1'], $iWidth, $iHeight, (int)$_POST['w'], (int)$_POST['h']);
// define a result image filename
$sResultFileName = $sTempFileName . $sExt;
// output image to file
imagejpeg($vDstImg, $sResultFileName, $iJpgQuality);
#unlink($sTempFileName);
return $sResultFileName;
}
}
}
}
}
}
$sImage = uploadImageFile();
echo '<img src="'.$sImage.'" />';
The other problem with it is I have no fall back option for the older browsers mainly IE8 and 9 because of it only being html5 based.
can anyone please help with any idea's please.

Resize and upload files without AJAX

Edit
It seems that this is most likely not possible because the canvas and the file input are not compatible data types.
The way to do something similar is to send an AJAX request using a "data url". I will look into that in more detail. Since I didn't want to use AJAX I'll try to fake the workflow to be more like a normal submit, i.e. with a refresh at the end.
End edit
I want to resize and upload a file without AJAX, as this is how it is currently being done (without a resized image - taken from a phone/tablet) and it works well in terms of workflow.
Hence after doing a resize I want to be able to make the resized "image" the value of a field, if this is possible.
I am using this library http://gokercebeci.com/dev/canvasresize to do the resizing for me.
I tried setting the data variable in the callback to be the file1 input's value i.e.
$("#file1").val(data);
But this threw an error. I have removed it in the code below, since I was pretty sure that wasn't the way to go about it.
I've copied the entire HTML/JS file below (the "Image Uploading" content was an example of using AJAX to upload the image, I have commented it out because I don't want to do that).
<!DOCTYPE html>
<html>
<head>
<title>Resize and Upload Images</title>
<script type="text/javascript" src="/public/javascripts/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="/public/javascripts/zepto.min.js"></script>
<script type="text/javascript" src="/public/javascripts/jquery.exif.js"></script>
<script type="text/javascript" src="/public/javascripts/jquery.canvasResize.js"></script>
<script type="text/javascript" src="/public/javascripts/binaryajax.js"></script>
<script type="text/javascript" src="/public/javascripts/canvasResize.js"></script>
<script type="text/javascript" src="/public/javascripts/exif.js"></script>
</head>
<body style="margin:48px;">
<div id="devcontainer">
<div id="area">
<h3>canvasResize</h3>
<div>
<form action="/upload" enctype="multipart/form-data" method="POST">
<input name="file1" type="file" id="file1"/>
<input name="file1" type="file"/>
<input name="data1" type="text"/>
<input name="data2" type="text"/>
</form>
<p><span></span></p>
<i></i>
</div>
<script>
$().ready(function() {
$('input[name=file1]').change(function(e) {
var file = e.target.files[0];
// RESET
$('#area p span').css('width', 0 + "%").html('');
$('#area img, #area canvas').remove();
$('#area i').html(JSON.stringify(e.target.files[0]).replace(/,/g, ", <br/>"));
// CANVAS RESIZING
canvasResize(file, {
width: 600,
height: 0,
crop: false,
quality: 80,
callback: function(data, width, height) {
// SHOW AS AN IMAGE
// =================================================
var img = new Image();
img.onload = function() {
$(this).css({
'margin': '10px auto',
'width': width,
'height': height
}).appendTo('#area div');
};
// /SHOW AS AN IMAGE
// =================================================
$(img).attr('src', data);
}
});
});
});
</script>
</div>
<div class="clearfix"></div>
</div>
</body>
</html>
<!--
// IMAGE UPLOADING
// =================================================
// Create a new formdata
var fd = new FormData();
// Add file data
var f = canvasResize('dataURLtoBlob', data);
f.name = file.name;
fd.append($('#area input').attr('name'), f);
var xhr = new XMLHttpRequest();
var loaded = Math.ceil((e.loaded / e.total) * 100);
$('#area p span').css({'width': loaded + "%"}).html(loaded + "%");
}
}, false);
// File uploaded
xhr.addEventListener("load", function(e)
{
var response = JSON.parse(e.target.responseText);
if (response.filename)
{
// Complete
$('#area p span').html('done');
$('#area b').html(response.filename);
$('<img>').attr({
'src': response.filename
}).appendTo($('#area div'));
}
}, false);
// Send data
xhr.send(fd);
}
-->
Create a callback function in the main window. Add an iFrame to the page that will handle file upload. Once your files have been uploaded call the call back function with the file names. Add the files to the canvas.

Dynamically uploading a file in background with JavaScript

I'm trying to upload files in the background. I am not able to use any frameworks so I have to do manually. The page already contains a form, and the file input fields are located within that form, so I can't embed a form in a form so I need to move the file input around.
The problem with the code I'm using is that it doesn't seem to actually submit, I don't see any network activity at all. Can anyone spot anything wrong here?
<form>
...
<input id="photo-file-input" type="file"/>
<button type="button" onClick="uploadBackground('photo-file-input');">Upload</button>
....
</form>
function uploadBackground(fileInputId)
{
var iframe = createIframe('TEST');
var form = createUploadForm('TEST', 'upload.php');
var fileInput = document.getElementById(fileInputId);
var fileInputParent = fileInput.parent;
//move file input into generated form
form.appendChild(fileInput);
form.submit();
iframe.onload = function()
{
alert('file was uploaded');
//put the file input back where it was
fileInputParent.appendChild(fileInput);
//clean up generated elements
iframe.parent.removeChild(iframe);
form.parent.removeChild(form);
}
}
function createUploadForm(target, action)
{
var form = document.createElement('form');
form.display = 'none';
form.target = target;
form.action = action;
form.method = 'POST';
form.enctype = 'multipart/form-data';
return form;
}
function createIframe(name)
{
var iframe;
try
{
iframe = document.createElement('<iframe name="' + name + '">');
}
catch (ex)
{
iframe = document.createElement('iframe');
iframe.name = name;
}
return iframe;
}
You can not copy a file input element and set/keep its value. It is for security reasons. There is no reason why you need to create a new form. Just append an iframe to the page, set the target of form to the iframe name and submit the original form.
I have looking for the same problem and I think, I have found an solution, which will work for Firefox and Chrome and may be on IE 10 and above ( here I need some morr testing )
The solution is a little bit ugly because I use a frameset. But this is the only solution I have found so far.
The use case is:
We have a website with an product catalog, the editor can upload videos for each product.
The upload of the video need a long time, so I have look for an solution, where after you have chosen a video an start the upload, you can navigate to an other product and upload an other file without to wait until the download of the first is complete.
The test is based on some other work:
https://stackoverflow.com/a/1186309/2248340
https://stackoverflow.com/a/105074/2248340
How it works:
If you press submit, all you form data will be placed in an object. in this object is also the selected file list.
This object will push in an array requests in the upload frame.
here runs the watchdog and look if there are new requests ( status = 0 )
If it found one a new upload is started.
Here is my test project to try it:
The frameset:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<frameset rows="*,100">
<frame id="start" name="start" src="start.html">
<frame id="upload" name="upload" src="frame.html">
</frameset>
<noframes>
<body>
please use this
</body>
</noframes>
</html>
start.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Start</title>
<script src="../js/jquery-1.11.3.min.js" ></script>
<script>
var files;
$.fn.serializeObject = function()
{
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name] !== undefined) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
};
var UploadRequest=function(f)
{
var o= {};
o['guid']=guid();
o['action']=$('form').attr('action');
o['files']=files;
o['values']=$('form').serializeObject();
o['status']=0;
return o;
}
function fileSelect( e){
files=e.target.files;
return false;
}
</script>
</head>
<body>
<form id="test" action="phpinfo.php">
<input name="test" >
<input type="hidden" name="h1" value="2">
<input type="file" name="uploadfile" onchange="fileSelect(event)">
<input type="submit" value="upload‚" >
</form>
<script>
var olddogcounter=localStorage['uploadwatchdog'];
var check=false;
function guid() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
}
$(function() {
$('#test').submit(function() {
var request=new UploadRequest();
parent.upload.requests.push(request);
return false;
});
});
</script>
<a href="test.html" >test</a>
</body>
</html>
and the upload frame:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>frame</title>
</head>
<body>
<h1>frame</h1>
<iframe id="response" width="100%" height="200"></iframe>
<script>
var requests=new Array();
var counter=0;
function watchdog()
{
for(var i=0; i<requests.length; i++)
{
var request=requests[i];
if(request.status==0)
{
alert("watchdog :"+dump(request));
request.status=1;
uploadFile(request);
}
}
}
function uploadFile(request)
{
var url = request.action;
var xhr = new XMLHttpRequest();
var fd = new FormData();
xhr.open("POST", url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
iframe=document.getElementById("response");
iframe.src="data:text/html;charset=utf-8," + escape(xhr.responseText);
}
};
if(request.files.length>1)
{
for(var i=0; i<request.files.length;i++)
{
var file=request.files[i];
fd.append("upload_file[]", file);
}
}
else
{
var file=request.files[0];
fd.append("upload_file",file );
}
for( var key in request.values)
{
fd.append(key,request.values[key] );
}
xhr.send(fd);
}
window.setInterval(watchdog,2000);
</script>
</body>
</html>
The solution is not complete, but I think is an good starting point.
ToDo:
- Show name of uploads in a list
- after upload remove request from array requests
- show progess bar for upload
- some error handling

Categories