file download with XMLHttpRequest - download

I am having a hard time implementing a simple file download script.
This is what I have so far, working ok :
Open an XMLHttpRequest
Get remote file as blob binary
Show download progress
My problem is :
creating a custom download directory
renaming downloaded file as original source name
downloaded file does not include its extension
Possibility to add the option to prompt a save as location before download ?
This is the snippet :
$('#DownloadBtn').click(function(e) {
e.preventDefault();
var urlFile = $(this).attr('href'); // remote file www.blabla.com/soft123.bin
var fileName = ''; // Get remote file name & extension ?
var progressBar = document.querySelector('progress');
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
function onError(e) {
console.log('Error', e);
}
var xhr = new XMLHttpRequest();
xhr.addEventListener("progress", updateProgress, false);
xhr.open('GET', urlFile, true);
xhr.responseType = 'blob';
var resourceDIRLOC = "Downloads";
xhr.onload = function(e) {
window.requestFileSystem(TEMPORARY, 10 * 1024 * 1024, function(fs) {
fs.root.getDirectory(fs.root.fullPath + '/' + resourceDIRLOC, {
create: true
}, function(dir) {
resourceDIR = dir;
fs.root.getFile(fileName, {
create: true
}, function(fileEntry) {
fileEntry.createWriter(function(writer) {
writer.onwrite = function(e) {};
writer.onerror = function(e) {};
var blob = new Blob([xhr.response], {
type: ' application/octet-stream'
});
writer.write(blob);
}, onError);
}, onError);
}, onError);
}, onError);
};
function updateProgress(e) {
if (e.lengthComputable) {
$(progressBar).show();
var i = (e.loaded / e.total) * 100;
progressBar.value = i;
if (i == 100) {
$(progressBar).hide();
}
}
}
xhr.send();
});
The downloaded file is located under FileSystem->000->t with 00 as name ( not soft123.bin )
I am not sure if it is possible to give the user an option to choose a download directory outside FileSystem? As defined above, target directory resourceDIRLOC = "Downloads" but the request is not creating this folder ? neither giving the file a name and extension
Any advise is appreciated
Thanks

Here is how you can keep track download progress and choose download directory in with Node-Webki. I was at first trying to download using an XMLHttpRequest in order to monitor download progress but I was having difficulties with the FileSystem API. This did the job just as I wanted, a simple file download with a progress bar. Hope it is helpful.
function download(file_url) {
var fs = require('fs');
var url = require('url');
var http = require('http');
var options = {
host: url.parse(file_url).host,
port: 80,
path: url.parse(file_url).pathname
};
var file_name = url.parse(file_url).pathname.split('/').pop();
var file = fs.createWriteStream('./' + file_name);
http.get(options, function(res) {
var fsize = res.headers['content-length'];
res.on('data', function(data) {
file.write(data);
progress(100 - (((fsize - file.bytesWritten) / fsize) * 100), $('#progressBar'));
}).on('end', function() {
file.end();
});
});
}
function progress(percent, $element) {
console.log("Download: " + parseInt(percent) + " %")
var progressBarWidth = percent * $element.width() / 100;
$element.find('div').css("width", progressBarWidth);
}
Answer found here

Related

Unable to download file with CasperJS

I am trying to download a file with CasperJS. If using browser, the download begins when user clicks a button and the response headers look like this:
I have tried these two methods with no luck:
1) https://stackoverflow.com/a/26334034
With this approach, the code block inside the if-statement is never executed. If I remove the condition, a bunch of resources are being saved, such as css files and so on. So the event listener is working, but for some reason not triggering when I use CasperJs click function to click the button that should start the download.
2) https://stackoverflow.com/a/30122021/692695
File.csv is saved but it's the web sites sourcecode, not the csv-file I get when I click the button on the website.
All of my code:
'use strict';
var utils = require('utils');
var casper = require('casper').create({
//verbose: true,
//logLevel: "debug",
clientScripts: ["node_modules/jquery/dist/jquery.min.js"]
});
function writeHtml(filename) {
var fs = require('fs');
var content = casper.getHTML();
fs.write(filename, content, 'w');
}
function getUrl() {
var url;
url = $('.tableofcontent_link:contains("Väestö työmarkkina-aseman, sukupuolen ja iän mukaan")').parent().attr('href');
return url;
}
casper.selectOptionByValue = function(selector, valueToMatch){
this.evaluate(function(selector, valueToMatch){
var select = document.querySelector(selector),
found = false;
Array.prototype.forEach.call(select.children, function(opt, i){
if (!found && opt.value.indexOf(valueToMatch) !== -1) {
select.selectedIndex = i;
found = true;
}
});
// dispatch change event in case there is some kind of validation
var evt = document.createEvent("UIEvents"); // or "HTMLEvents"
evt.initUIEvent("change", true, true);
select.dispatchEvent(evt);
}, selector, valueToMatch);
};
var link;
var url = 'http://pxnet2.stat.fi/PXWeb/pxweb/fi/StatFin/StatFin__tym__tyti/?table';
casper.start(url);
casper.userAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X)');
casper.then(function () {
this.echo("Now at: " + this.getCurrentUrl());
link = 'http://pxnet2.stat.fi' + casper.evaluate(getUrl);
});
casper.then(function () {
this.open(link);
});
casper.then(function() {
this.echo("Now at: " + this.getCurrentUrl());
// Select all data for each item
casper.click('#ctl00_ContentPlaceHolderMain_VariableSelector1_VariableSelector1_VariableSelectorValueSelectRepeater_ctl01_VariableValueSelect_VariableValueSelect_SelectAllButton');
casper.click('#ctl00_ContentPlaceHolderMain_VariableSelector1_VariableSelector1_VariableSelectorValueSelectRepeater_ctl02_VariableValueSelect_VariableValueSelect_SelectAllButton');
casper.click('#ctl00_ContentPlaceHolderMain_VariableSelector1_VariableSelector1_VariableSelectorValueSelectRepeater_ctl03_VariableValueSelect_VariableValueSelect_SelectAllButton');
casper.click('#ctl00_ContentPlaceHolderMain_VariableSelector1_VariableSelector1_VariableSelectorValueSelectRepeater_ctl04_VariableValueSelect_VariableValueSelect_SelectAllButton');
casper.click('#ctl00_ContentPlaceHolderMain_VariableSelector1_VariableSelector1_VariableSelectorValueSelectRepeater_ctl05_VariableValueSelect_VariableValueSelect_SelectAllButton');
});
casper.then(function() {
// casper.selectOptionByValue('#ctl00_ContentPlaceHolderMain_VariableSelector1_VariableSelector1_OutputFormats_OutputFormats_OutputFormatDropDownList',
// 'FileTypeExcelX');
// Select the format of the file from the select option list at the bottom
casper.selectOptionByValue('#ctl00_ContentPlaceHolderMain_VariableSelector1_VariableSelector1_OutputFormats_OutputFormats_OutputFormatDropDownList',
'FileTypeCsvWithHeadingAndSemiColon');
});
casper.then(function () {
// just for debugging
writeHtml('page1.html');
});
casper.then(function() {
//casper.click('#ctl00_ContentPlaceHolderMain_VariableSelector1_VariableSelector1_ButtonViewTable');
});
casper.then(function() {
// FIRST ATTEMPT TO LOAD THE DATA TO a file called file.csv
var formData = casper.evaluate(function(){
return $('form#aspnetForm').serialize();
});
//this.echo("Params: " + formData);
var targetFile = 'file.csv';
casper.download(link, targetFile, 'POST', formData);
});
casper.then(function () {
// just for debugging
writeHtml('page2.html');
});
// SECCOND ATTEMPT TO LOAD THE DATA TO a file called stats.csv
casper.on('resource.received', function (resource) {
if ((resource.url.indexOf('tyti_001') !== -1) ) {
this.echo(resource.url);
var file;
file = "stats.csv";
try {
this.echo("Attempting to download file " + file);
var fs = require('fs');
casper.download(resource.url, fs.workingDirectory + '/' + file);
} catch (e) {
this.echo(e);
}
}
});
casper.run(function () {
this.echo('End').exit();
});
And my package.json:
{
"scripts": {
"test": "dotest"
},
"pre-commit": ["test"],
"dependencies": {
"jquery": "^3.3.1"
},
"devDependencies": {
"pre-commit": "^1.2.2"
}
}
Explanation of the code:
First visit this page: http://pxnet2.stat.fi/PXWeb/pxweb/fi/StatFin/StatFin__tym__tyti/statfin_tyti_pxt_001.px/?rxid=bd4d5dc1-358d-407e-ae47-13266b79bfd0
There, dynamically pick a specified link and move there.
Select all data by clicking the V-shapen icon (look at the attached screenshot) and then select the format of the file.
I've faced this issue earlier with all versions except phantomjs 2.0.0. I also tried the solutions you shared from SO a year ago and they didn't work as well.
I'm going to assume you're using a phantomjs version other than 2.0.0.
Here's the link to download it
https://bitbucket.org/ariya/phantomjs/downloads/
With it, you will have access to onFileDownload method which you can override and use like below
casper.page.onFileDownload = function(status){
console.log('onFileDownload(' + status + ')');
return "newfile.csv";
};
onFileDownload will be called whenever a file is downloaded as a result of clicking a button (ajax) or as a result of sequential get/post requests.
All you have to do is, trigger the click on the button/link that will initiate download.
Note : My solution is assuming that everything else (site is not blocking phantomjs and your request headers/cookies are as expected)

SAPUI5 file upload download gets corrupted

Can someone help me.
I've implemented a file upload / download in UI5 that seems to work but when I download the file it gets corrupted and I can't open it.
For now I'm only testing with image files:
new sap.ui.unified.FileUploader({
buttonOnly: true,
buttonText: "Upload files",
icon: "sap-icon://upload",
change: function(oEvent) {
var oFileUploader = oEvent.getSource();
oItem = oFileUploader.getParent().getParent().getParent();
var sPath = oItem.getBindingContext().getPath();
var files = oEvent.getParameter("files");
var file = files[0];
if (file) {
var oNewFile = {
ID: that.count++,
SurveyAnswerID: oSA.ID,
FileName: oEvent.getParameter("newValue"),
FileBinary: null,
MimeType: "image/jpeg",
Mode: "POST"
};
var reader = new FileReader();
reader.onload = function(evt) {
var binaryString = evt.target.result;
oNewFile.FileBinary = binaryString;
};
reader.readAsBinaryString(file);
} else {
oNewFile.FileBinary = "";
oNewFile.FileName = "";
MessageToast.show("Something went wrong with the file upload.\n Please try again");
}
that._pushItemToFileUploadModel(oNewFile.ID, oNewFile);
that._getFileUploadModel().refresh();
}
})
Download code:
selectionChange: function(oEvent) {
var item = oEvent.getSource().getSelectedItem();
var model = that._getFileUploadModel();
if (item) {
var a = window.document.createElement('a');
a.href = window.URL.createObjectURL(new Blob([item.getDocumentId()], {
type: item.getMimeType()
}));
a.download = item.getFileName();
// Append anchor to body.
document.body.appendChild(a);
a.click();
// Remove anchor from body
document.body.removeChild(a);
}
try {
oEvent.getSource()._oList.removeSelections();
} catch (e) {
//DO nothing
}
},
What an I doing wrong here?
I solved my issue converting the file this way:
var u8_2 = new Uint8Array(atob(data).split("").map(function(c) {
return c.charCodeAt(0);
}));
var a = window.document.createElement('a');
a.href = window.URL.createObjectURL(new Blob([u8_2], {
type: item.getMimeType()
}));

winJS Copy deepFolder Tree to install win8.1 app content

I'm actualy working on a windows 8.1 app in js and html, the app contain a very large number of big files that i need to install and update many times. So i 've dev a fct to make update from usb device to local data app folder. It's working fine, but my fct is not build with promises and it's not easy to follow progress and completition...
So i'm working on a fully new fct, but it's not working ;o( can someone help me on the promise structure ?
My actual code :
app.copyTree = function (srcRootSorageFolder, destRootStorageFolder) {
console.log('copy tree Start...');
var fileToCopy = 0;
var fileCopied = 0;
var foldToCreate = 0;
var foldCreated = 0;
//-- init and wait promiseS ....
scanFolder(srcRootSorageFolder, destRootStorageFolder).then(
function () {
console.log('successfull copy !!');
console.log(fileCopied + ' fichier(s) copié(s) sur ' + fileToCopy);
console.log(foldCreated + ' dossier(s) créé(s) sur ' + foldToCreate);
},
function error(error) {
console.log('error copy' + error);
console.log(fileCopied + ' fichier(s) copié(s) sur ' + fileToCopy);
console.log(foldCreated + ' dossier(s) créé(s) sur ' + foldToCreate);
}
);
//--sub fct with promise to scan a folder and launch copy
function scanFolder(srcFoldStorage, destFoldStorage) {
console.log('scanFolder Start...');
var promises = [];
return new WinJS.Promise(function (complete, error) {
promises.push(
srcFoldStorage.getFilesAsync().then(function (filesList) {
fileToCopy += filesList.size;
copyFiles(filesList, destFoldStorage);
})
);
promises.push(
srcFoldStorage.getFoldersAsync().then(function (foldersList) {
foldToCreate += foldersList.size;
loopSubFolder(foldersList, destFoldStorage);
})
);
WinJS.Promise.join(promises).then(
function () {
complete();
},
error
);
});
}
//--sub fct with promise to copy all sub-folders in a folder to a destination
function loopSubFolder(foldersList, destStorFolder) {
console.log('loopSubFolder Start...');
var promises = [];
var collideOpt = Windows.Storage.CreationCollisionOption.openIfExists;
return new WinJS.Promise(function (complete, error) {
foldersList.forEach(function (reg) {
var foldName = reg.name;
promises.push(
destStorFolder.createFolderAsync(foldName, collideOpt).then(
function (newFoldStorage) {
foldCreated += 1;
scanFolder(reg, newFoldStorage);
})
);
});
WinJS.Promise.join(promises).then(
function () {
complete();
},
error
);
});
};
//--sub fct with promise to copy all file in a folder to a destination
function copyFiles(filesList, destStorFolder) {
console.log('copyFiles Start...');
var promises = [];
var collideOpt = Windows.Storage.CreationCollisionOption.replaceExisting;
return new WinJS.Promise(function (complete, error) {
filesList.forEach(function (reg) {
var fName = reg.name;
promises.push(
reg.copyAsync(destStorFolder, fName, collideOpt).then(fileCopied += 1)
);
});
WinJS.Promise.join(promises).then(
function () {
complete();
},
error
);
});
};
//--
};
Thanks for help
Mr
So, like promise and recursive are not really my friend...like god and evil... i've change my way to work and found a fully working and more simple solution.
I've decided to search file in my source folder, and after to look the number of file completed... I don't know why i'm not using this solution at the beginning...This way, i can make a kind of progress and be sure that all files are done.
If it can help another person with the same needs my code bellow :
app.copyFolder = function (srcRootSorageFolder, destRootStorageFolder) {
//srcRootSorageFolder & destRootStorageFolder need to be StorageFolder ( IAsyncOperation<StorageFolder>)
var totalFiles = 0; //total files to copy
var totalSize = 0; //total octects to copy
var doneCopies = 0; // files copy terminated
var doneSize = 0; // octets copied
//Prepare query to Search all files (deep search / recursive ) in the srcRootSorageFolder to follow progress
var queryOptions = new Windows.Storage.Search.QueryOptions();
queryOptions.folderDepth = Windows.Storage.Search.FolderDepth.deep;
var query = srcRootSorageFolder.createFileQueryWithOptions(queryOptions);
//--sub function to prepare progress (counting files and size)
function prepareProgress(files) {
var promises = [];
return new WinJS.Promise(function (complete, error) {
files.forEach(function (file) {
promises.push(
file.getBasicPropertiesAsync().then(function (props) {
totalFiles += 1;
totalSize += props.size;
})
)
});
WinJS.Promise.join(promises).then(
function () {
complete(files);
},
error
);
});
}
//--sub function to copy files
function copyFiles(files) {
var promises = [];
var folderCollideOpt = Windows.Storage.CreationCollisionOption.openIfExists;
var fileCollideOpt = Windows.Storage.CreationCollisionOption.replaceExisting;
return new WinJS.Promise(function (complete, error) {
files.forEach(function (file) {
var destPath = file.path.split(srcRootSorageFolder.path); // get the folder tree to create directory tree of the source folder in the dest folder
destPath = destPath[destPath.length - 1]; //keeping last element of the array
destPath = destPath.substring(1, destPath.lastIndexOf('\\')); //removing file name en 1st slash(\)
var fName = file.name;
promises.push(
destRootStorageFolder.createFolderAsync(destPath, folderCollideOpt).then(
function (destStorage) {
//dest folder ready, initialising ... start copying file
file.copyAsync(destStorage, fName, fileCollideOpt).then(
function (newFile) {
updateProgress(file,newFile);
});
}
)
)
});
WinJS.Promise.join(promises).then(
function () {
complete(files);
},
error
);
});
}
//--sub function to follow progress and defined if all copy are completed
function updateProgress(file,newFile) {
return new WinJS.Promise(function (complete, error) {
newfiles.getBasicPropertiesAsync().then(function (newProps) { console.log('ok (copy):' + newfiles.name + ':' + newProps.size); });
file.getBasicPropertiesAsync().then(function (props) {
doneCopies += 1;
doneSize += props.size;
console.log('ok (source):' + file.name + ':' + props.size);
//progress
var copiesProgress = Math.round((doneSize / totalSize) * 100 * 100) / 100; // copy percent with 2 decimals
console.log('progress: ' + copiesProgress + '%');
//completed action
if (doneCopies == totalFiles) {
console.log('Copy Done');
}
});
});
}
//--initialising process
query.getFilesAsync().then(prepareProgress).then(copyFiles).then(console.log('Copy Start....'));
};
I hope you like, and if you have comments to make it better, i'll like !
Thanks
Mr

How to upload a Cordova picture to a Laravel 4 project by using an API

I'm making a hybrid app with AngularJS and Cordova, using a Laravel 4 API & Backoffice.
I can make a picture with the application, but it does not upload. I don't really know how to upload the picture, and i don't really know how i can troubleshoot all of it.
I upload the image to the API-route i wrote, using the same upload-method as i use to do with the backoffice. This is what i have in the AngularJS-Controller, which uses Cordova to do the stuff.
var pictureSource; // picture source
var destinationType; // sets the format of returned value
pictureSource = navigator.camera.PictureSourceType;
destinationType = navigator.camera.DestinationType;
function clearCache() {
navigator.camera.cleanup();
}
var retries = 0;
function onPhotoDataSuccess(fileURI) {
var win = function (r) {
clearCache();
retries = 0;
alert('Done!');
}
var fail = function (error) {
if (retries == 0) {
retries ++
setTimeout(function() {
onPhotoDataSuccess(fileURI)
alert("kgoa ne keer opnief beginne");
}, 1000)
} else {
retries = 0;
clearCache();
alert('Ups. Something wrong happens!');
}
}
var options = new FileUploadOptions();
options.fileKey = "image";
options.fileName = fileURI.substr(fileURI.lastIndexOf('/') + 1);
options.mimeType = "image/jpeg";
options.params = {};
params.value1 = "test";
params.value2 = "param";
// if we need to send parameters to the server request
var ft = new FileTransfer();
ft.upload(fileURI, encodeURI("http://10.0.1.13/ClimbrBackoffice/public/api/routes/new/create"), win, fail, options);
}
// Called when a photo is successfully retrieved
//
function onPhotoURISuccess(imageURI) {
// Uncomment to view the image file URI
// console.log(imageURI);
// Get image handle
//
var largeImage = document.getElementById('largeImage');
// Unhide image elements
//
largeImage.style.display = 'block';
// Show the captured photo
// The inline CSS rules are used to resize the image
//
largeImage.src = imageURI;
}
// A button will call this function
//
$scope.capturePhoto = function(){
// Take picture using device camera and retrieve image as base64-encoded string
navigator.camera.getPicture(onPhotoDataSuccess, onFail, {
quality : 100,
destinationType : Camera.DestinationType.FILE_URI,
sourceType : Camera.PictureSourceType.CAMERA,
allowEdit : true,
encodingType: Camera.EncodingType.JPEG,
targetWidth: 250,
targetHeight: 400,
saveToPhotoAlbum: true,
correctOrientation: true
});
}
// A button will call this function
//
$scope.getPhoto = function(source) {
// Retrieve image file location from specified source
navigator.camera.getPicture(onPhotoURISuccess, onFail, { quality: 100,
destinationType: destinationType.FILE_URI,
sourceType: source });
}
I searched the web for good tutorials or explanations, but they drove me crazy.
Can someone please help me out?
Thanks!
Thomas
Your Angular controller should have the following function
$scope.upload = function() {
var options = {
fileKey: "file",
fileName: "image.png",
chunkedMode: false,
mimeType: "image/png"
};
$cordovaFileTransfer.upload("http://yourdomain.com/image_handler", "/android_asset/www/img/ionic.png", options).then(function(result) {
console.log("SUCCESS: " + JSON.stringify(result.response));
$scope.showAlert('Done', 'File Uploaded');
}, function(err) {
console.log("ERROR: " + JSON.stringify(err));
$scope.showAlert('Error', err);
}, function (progress) {
// constant progress updates
});}
And on your server, Laravel function could simply handle the image as:
public function getImageFromDevice(){
$destinationPath = 'uploads/';
$newImageName='MyImage.jpg';
Input::file('file')->move($destinationPath,$newImageName);
}
Do not forget to inject $cordovaFileTransfer in your controller.
That's it, this is a simple example you can extend it.
Credits to: Phonegap + Laravel 4 How to upload file

embed webgl in powerpoint or render animated gif from webgl

anyone got an idea how to embed a webgl animation into powerpoint. any tools that can be used on server side to capture an animated gif?
I did not make it work to embed webgl html directly in a powerpoint.
You can create images of webgl by calling toDataURL() as in
var canvas = document.createElement("canvas");
var gl = canvas.getContext("experimental-webgl");
function render() {
gl.clearColor(Math.random(), Math.random(), Math.random(), 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// takes a 'screenshot' of the canvas.
var image = canvas.toDataURL();
requestAnimationFrame(render);
}
render();
To make an animation you could send each of those screenshots to a server
...
var image = canvas.toDataURL();
var req = new XMLHTTPRequest();
req.open("POST", "http://localhost:8080", true);
var data = {
cmd: 'screenshot',
dataURL: image,
};
req.setRequestHeader("Content-type", "application/json");
req.send(JSON.stringify(data));
Here's a node.js server that will save the screenshots as .png files. You could then load them into some program to turn them into a gif.
var port = 8080
var screenshotCount = 0;
var http = require('http'),
url = require('url'),
fs = require('fs'),
util = require('util'),
path = require('path'),
querystring = require('querystring');
function postHandler(request, callback) {
var query_ = { };
var content_ = '';
request.addListener('data', function(chunk) {
content_ += chunk;
});
request.addListener('end', function() {
query_ = JSON.parse(content_);
callback(query_);
});
}
function sendJSONResponse(res, object) {
res.writeHead(200, {'Content-Type': 'application/json'});
res.write(JSON.stringify(object), 'utf8');
res.end();
}
function startsWith(str, start) {
return (str.length >= start.length &&
str.substr(0, start.length) == start);
}
function saveScreenshotFromDataURL(dataURL) {
var EXPECTED_HEADER = "data:image/png;base64,";
if (startsWith(dataURL, EXPECTED_HEADER)) {
var filename = "screenshot-" + (screenshotCount++) + ".png";
fs.writeFile(
filename,
dataURL.substr(
EXPECTED_HEADER.length,
dataURL.length - EXPECTED_HEADER.length),
'base64');
util.print("Saved Screenshot: " + filename + "\n");
}
}
server = http.createServer(function(req, res) {
// your normal server code
if (req.method == "POST") {
postHandler(req, function(query) {
switch (query.cmd) {
case 'screenshot':
saveScreenshotFromDataURL(query.dataURL);
sendJSONResponse(res, { ok: true });
break;
default:
util.print("err: unknown post: " + query + "\n");
break;
}
});
}
}),
server.listen(port);
Note that server only saves screenshots, it doesn't serve files (for brevity). So you'll need to either add that functionality or serve the files from another server.

Resources