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.
Related
the following errors appear in console:
aes.js Failed to load resource: the server responded with a status of 404 (Not Found)
script.js Failed to load resource: the server responded with a status of 404 (Not Found)
aes.js Failed to load resource: the server responded with a status of 404 (Not Found)
script.js Failed to load resource: the server responded with a status of 404(Not Found)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>JavaScript File Encryption App</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="Docrypt_function.js"></script>
</head>
<body>
<a class="back"></a>
<div id="stage">
<div id="step1">
<div class="content">
<h1>What do you want to do?</h1>
<a class="button encrypt green">Encrypt a file</a>
<a class="button decrypt magenta">/Decrypt a file</a>
</div>
</div>
<div id="step2">
<div class="content if-encrypt">
<h1>Choose which file to encrypt</h1>
<h2>An encrypted copy of the file will be generated. No data is sent to our server.</h2>
<a class="button browse blue">Browse</a>
<input type="file" id="encrypt-input" />
</div>
<div class="content if-decrypt">
<h1>Choose which file to decrypt</h1>
<h2>Only files encrypted by this tool are accepted.</h2>
<a class="button browse blue">Browse</a>
<input type="file" id="decrypt-input" />
</div>
</div>
<div id="step3">
<div class="content if-encrypt">
<h1>Enter a pass phrase</h1>
<h2>This phrase will be used as an encryption key. Write it down or remember it; you won't be able to restore the file without it. </h2>
<input type="password" />
<input type="button" value="encrypt the file!" id="button proccess red"/>
</div>
<div class="content if-decrypt">
<h1>Enter the pass phrase</h1>
<h2>Enter the pass phrase that was used to encrypt this file. It is not possible to decrypt it without it.</h2>
<input type="password" />
<input type="button" value="dencrypt the file!" id="button proccess green"/>
</div>
</div>
<div id="step4">
<div class="content">
<h1>Your file is ready!</h1>
<input type="button" value="download your file" id="download button"/>
</div>
</div>
</div>
</body>
<script src="assets/js/aes.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="assets/js/script.js"></script>
</html>
Javascript code:
/**
* Created by Steven on 07-Feb-17.
*/
(function(){
var body = $('body'),
stage = $('#stage'),
back = $('a.back');
/* Step 1 */
$('#step1 .encrypt').click(function(){
body.attr('class', 'encrypt');
// Go to step 2
step(2);
});
$('#step1 .decrypt').click(function(){
body.attr('class', 'decrypt');
step(2);
});
/* Step 2 */
$('#step2 .button').click(function(){
// Trigger the file browser dialog
$(this).parent().find('input').click();
});
// Set up events for the file inputs
var file = null;
$('#step2').on('change', '#encrypt-input', function(e){
// Has a file been selected?
if(e.target.files.length!=1){
alert('Please select a file to encrypt!');
return false;
}
file = e.target.files[0];
if(file.size > 1024*1024){
alert('Please choose files smaller than 1mb, otherwise you may crash your browser. \nThis is a known issue.');
return;
}
step(3);
});
$('#step2').on('change', '#decrypt-input', function(e){
if(e.target.files.length!=1){
alert('Please select a file to decrypt!');
return false;
}
file = e.target.files[0];
step(3);
});
/* Step 3 */
$('a.button.process').click(function(){
var input = $(this).parent().find('input[type=password]'),
a = $('#step4 a.download'),
password = input.val();
input.val('');
if(password.length<5){
alert('Please choose a longer password!');
return;
}
// The HTML5 FileReader object will allow us to read the
// contents of the selected file.
var reader = new FileReader();
if(body.hasClass('encrypt')){
// Encrypt the file!
reader.onload = function(e){
// Use the CryptoJS library and the AES cypher to encrypt the
// contents of the file, held in e.target.result, with the password
var encrypted = CryptoJS.AES.encrypt(e.target.result, password);
// The download attribute will cause the contents of the href
// attribute to be downloaded when clicked. The download attribute
// also holds the name of the file that is offered for download.
a.attr('href', 'data:application/octet-stream,' + encrypted);
a.attr('download', file.name + '.encrypted');
step(4);
};
// This will encode the contents of the file into a data-uri.
// It will trigger the onload handler above, with the result
reader.readAsDataURL(file);
}
else {
// Decrypt it!
reader.onload = function(e){
var decrypted = CryptoJS.AES.decrypt(e.target.result, password)
.toString(CryptoJS.enc.Latin1);
if(!/^data:/.test(decrypted)){
alert("Invalid pass phrase or file! Please try again.");
return false;
}
a.attr('href', decrypted);
a.attr('download', file.name.replace('.encrypted',''));
step(4);
};
reader.readAsText(file);
}
});
/* The back button */
back.click(function(){
// Reinitialize the hidden file inputs,
// so that they don't hold the selection
// from last time
$('#step2 input[type=file]').replaceWith(function(){
return $(this).clone();
});
step(1);
});
// Helper function that moves the viewport to the correct step div
function step(i){
if(i == 1){
back.fadeOut();
}
else{
back.fadeIn();
}
// Move the #stage div. Changing the top property will trigger
// a css transition on the element. i-1 because we want the
// steps to start from 1:
stage.css('top',(-(i-1)*100)+'%');
}
/* //the encryption button
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('button proccess red').addEventListener('click',function (e) {
} )
})
//the decryption button
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('button proccess green').addEventListener('click',function (e) {
} )
})
//the download button
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('download button').addEventListener('click',function (e) {
} )
})
*/
});
You need to execute the code when the window loads: $(function() { instead of just (function() {
I am working on a small HTML file API application. This application can support users to drag, drop a file and read the file content. However, I found I either can make the drag, drop and read the file info part or using HTML upload feature to let users upload a file and read the file content.
Please see the example here: https://jsfiddle.net/tqcuor5g/
I just want the user can drop a file into a drop zone and the app can read its content and show in the text area.
My question is how can I make the application support drag, drop and read the file content at the same time? Thank you in advance!
Source code:
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
body
{
font-size:18pt;
}
#filedrop
{
width: 300px;
height: 200px;
color: Gray;
border: 10px dashed #9a9a9a;
}
</style>
<title>Reading a Text File</title>
<script type="text/javascript">
function init() {
var bHaveFileAPI = (window.File && window.FileReader);
if (!bHaveFileAPI) {
alert("This browser doesn't support the File API");
return;
}
document.getElementById("filedrop").addEventListener("drop", onFilesDropped);
document.getElementById("filedrop").addEventListener("dragover", onDragOver);
document.getElementById("fileElem").addEventListener("change", onFileChanged);
}
function onFileChanged(theEvt) {
var thefile = theEvt.target.files[0];
console.log(thefile);
// check to see if it is text
if (thefile.type != "text/plain") {
document.getElementById('filecontents').innerHTML = "No text file chosen";
return;
}
var reader = new FileReader();
reader.onload = function (evt) {
var resultText = evt.target.result;
document.getElementById('filecontents').innerHTML = resultText;
}
reader.readAsText(thefile);
}
function onDragOver(theEvt) {
theEvt.stopPropagation();
theEvt.preventDefault();
}
function onFilesDropped(theEvt) {
theEvt.stopPropagation();
theEvt.preventDefault();
var files = theEvt.target.files;
document.getElementById('filedata').innerHTML = "";
for (var i = 0; i <= files.length; i++) {
var fileInfo = "<p>File name: " + files[i].name + "; size: " + files[i].size + "; type: " + files[i].type + "</p>";
document.getElementById('filedata').innerHTML += fileInfo;
}
}
window.addEventListener("load", init);
</script>
</head>
<body>
<h1>Using Drag and Drop</h1>
<p>Drop files here: </p>
<div id="filedrop"></div>
<p>File Information: </p>
<div id="filedata"></div>
<h1>Reading File Data as Text</h1>
<form action="">
<label>Select a file: </label>
<input type="file" name="files" id="fileElem" />
</form>
<p>File contents: </p>
<textarea cols="80" rows="10" id="filecontents"></textarea>
</body>
</html>
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.
So I have a httpd server running which has links to a bunch of files. Lets say the user selects three files from a file list to download and they're located at:
mysite.com/file1
mysite.com/file2
mysite.com/file3
When they click the download button I want them to download these three files from the links above.
My download button looks something like:
var downloadButton = new Ext.Button({
text: "Download",
handler: function(){
//download the three files here
}
});
The best way to do this is to have your files zipped and link to that:
The other solution can be found here: How to make a link open multiple pages when clicked
Which states the following:
HTML:
Download
JS:
$('a.yourlink').click(function(e) {
e.preventDefault();
window.open('mysite.com/file1');
window.open('mysite.com/file2');
window.open('mysite.com/file3');
});
Having said this, I would still go with zipping the file, as this implementation requires JavaScript and can also sometimes be blocked as popups.
This was the method which worked best for me and didn't open up new tabs, but just downloaded the files/images I required:
var filesForDownload = [];
filesForDownload( { path: "/path/file1.txt", name: "file1.txt" } );
filesForDownload( { path: "/path/file2.jpg", name: "file2.jpg" } );
filesForDownload( { path: "/path/file3.png", name: "file3.png" } );
filesForDownload( { path: "/path/file4.txt", name: "file4.txt" } );
$jq('input.downloadAll').click( function( e )
{
e.preventDefault();
var temporaryDownloadLink = document.createElement("a");
temporaryDownloadLink.style.display = 'none';
document.body.appendChild( temporaryDownloadLink );
for( var n = 0; n < filesForDownload.length; n++ )
{
var download = filesForDownload[n];
temporaryDownloadLink.setAttribute( 'href', download.path );
temporaryDownloadLink.setAttribute( 'download', download.name );
temporaryDownloadLink.click();
}
document.body.removeChild( temporaryDownloadLink );
} );
I fond that executing click() event on a element inside a for loop for multiple files download works only for limited number of files (10 files in my case). The only reason that would explain this behavior that made sense to me, was speed/intervals of downloads executed by click() events.
I figure out that, if I slow down execution of click() event, then I will be able to downloads all files.
This is solution that worked for me.
var urls = [
'http://example.com/file1',
'http://example.com/file2',
'http://example.com/file3'
]
var interval = setInterval(download, 300, urls);
function download(urls) {
var url = urls.pop();
var a = document.createElement("a");
a.setAttribute('href', url);
a.setAttribute('download', '');
a.setAttribute('target', '_blank');
a.click();
if (urls.length == 0) {
clearInterval(interval);
}
}
I execute download event click() every 300ms. When there is no more files to download urls.length == 0 then, I execute clearInterval on interval function to stop downloads.
You can either:
Zip the selected files and return the one zipped file.
Open multiple pop-ups each prompting for a download.
Note - option one is objectively better.
Edit
Found an option three: https://stackoverflow.com/a/9425731/1803682
I've solved this a different way by using window.location. It works in Chrome, which fortunately is the only browser I had to support. Might be useful to someone. I'd initally used Dan's answer, which also needed the timeout I've used here or it only downloaded one file.
var linkArray = [];
linkArray.push("http://example.com/downloadablefile1");
linkArray.push("http://example.com/downloadablefile2");
linkArray.push("http://example.com/downloadablefile3");
function (linkArray) {
for (var i = 0; i < linkArray.length; i++) {
setTimeout(function (path) { window.location = path; }, 200 + i * 200, linkArray[i]);
}
};
<!DOCTYPE html>
<html ng-app='app'>
<head>
<title>
</title>
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="style.css">
</head>
<body ng-cloack>
<div class="container" ng-controller='FirstCtrl'>
<table class="table table-bordered table-downloads">
<thead>
<tr>
<th>Select</th>
<th>File name</th>
<th>Downloads</th>
</tr>
</thead>
<tbody>
<tr ng-repeat = 'tableData in tableDatas'>
<td>
<div class="checkbox">
<input type="checkbox" name="{{tableData.name}}" id="{{tableData.name}}" value="{{tableData.name}}" ng-model= 'tableData.checked' ng-change="selected()">
</div>
</td>
<td>{{tableData.fileName}}</td>
<td>
<a target="_self" id="download-{{tableData.name}}" ng-href="{{tableData.filePath}}" class="btn btn-success pull-right downloadable" download>download</a>
</td>
</tr>
</tbody>
</table>
<a class="btn btn-success pull-right" ng-click='downloadAll()'>download selected</a>
<p>{{selectedone}}</p>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="script.js"></script>
</body>
</html>
app.js
var app = angular.module('app', []);
app.controller('FirstCtrl', ['$scope','$http', '$filter', function($scope, $http, $filter){
$scope.tableDatas = [
{name: 'value1', fileName:'file1', filePath: 'data/file1.txt', selected: true},
{name: 'value2', fileName:'file2', filePath: 'data/file2.txt', selected: true},
{name: 'value3', fileName:'file3', filePath: 'data/file3.txt', selected: false},
{name: 'value4', fileName:'file4', filePath: 'data/file4.txt', selected: true},
{name: 'value5', fileName:'file5', filePath: 'data/file5.txt', selected: true},
{name: 'value6', fileName:'file6', filePath: 'data/file6.txt', selected: false},
];
$scope.application = [];
$scope.selected = function() {
$scope.application = $filter('filter')($scope.tableDatas, {
checked: true
});
}
$scope.downloadAll = function(){
$scope.selectedone = [];
angular.forEach($scope.application,function(val){
$scope.selectedone.push(val.name);
$scope.id = val.name;
angular.element('#'+val.name).closest('tr').find('.downloadable')[0].click();
});
}
}]);
plunker example: https://plnkr.co/edit/XynXRS7c742JPfCA3IpE?p=preview
This works in all browsers (IE11, Firefox, Microsoft Edge, Chrome and Chrome Mobile) My documents are in multiple select elements. The browsers seem to have issues when you try to do it too fast... So I used a timeout.
<select class="document">
<option val="word.docx">some word document</option>
</select>
//user clicks a download button to download all selected documents
$('#downloadDocumentsButton').click(function () {
var interval = 1000;
//select elements have class name of "document"
$('.document').each(function (index, element) {
var doc = $(element).val();
if (doc) {
setTimeout(function () {
window.location = doc;
}, interval * (index + 1));
}
});
});
This solution uses promises:
function downloadDocs(docs) {
docs[0].then(function (result) {
if (result.web) {
window.open(result.doc);
}
else {
window.location = result.doc;
}
if (docs.length > 1) {
setTimeout(function () { return downloadDocs(docs.slice(1)); }, 2000);
}
});
}
$('#downloadDocumentsButton').click(function () {
var files = [];
$('.document').each(function (index, element) {
var doc = $(element).val();
var ext = doc.split('.')[doc.split('.').length - 1];
if (doc && $.inArray(ext, docTypes) > -1) {
files.unshift(Promise.resolve({ doc: doc, web: false }));
}
else if (doc && ($.inArray(ext, webTypes) > -1 || ext.includes('?'))) {
files.push(Promise.resolve({ doc: doc, web: true }));
}
});
downloadDocs(files);
});
This is the easiest way I have found to download multiple files.
$('body').on('click','.download_btn',function(){
downloadFiles([
['File1.pdf', 'File1-link-here'],
['File2.pdf', 'File2-link-here'],
['File3.pdf', 'File3-link-here'],
['File4.pdf', 'File4-link-here']
]);
})
function downloadFiles(files){
if(files.length == 0){
return;
}
file = files.pop();
var Link = $('body').append('');
Link[0].click();
Link.remove();
downloadFiles(files);
}
This should be work for you.
Thank You.
you could go for the iframe
NOTE: though this is one of the few ways to download multiple files at once, without creating pop-up, this won't work with files that can be rendered in browser. check js comment
NOTE 2: some browsers may ask for permission to download multiple files from the same page
function download(){
const links = ["mysite.com/file1", "mysite.com/file2", "mysite.com/file3"]
// only works with files that don't render in browser
// ie: not video, not text, not photo
for(let i = 0; i < links.length; i++) {
var frame = document.createElement("iframe");
frame.src = links[i];
frame["download"] = 1
document.body.appendChild(frame);
}
}
iframe{
display: none;
}
<body>
<div onclick="download()">Download</div>
</body>
this solution works perfectly fine for me
var downloadButton = new Ext.Button({
text: "Download",
handler: function () {
/** #type {Array<string>} URLS */
const URLS = [
"mysite.com/file1 ",
"mysite.com/file2",
"mysite.com/file3",
];
for (let x = 0; x < URLS.length; x++) {
/** #type {string} URL */
const URL = URLS[x];
/** #type {HTMLLinkElement} LINK */
const LINK = document.createElement('a');
LINK.href = URL;
LINK.setAttribute('download', 'download');
document.body.appendChild(LINK);
LINK.click();
LINK.parentNode.removeChild(LINK);
window.URL.revokeObjectURL(URL);
}
}
});
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.