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
Related
Using ionic,
I am trying to create an image blob from URI and have tried several codes but failed.
Here is where I implement the imagepicker in ionic:
$cordovaImagePicker.getPictures(options)
.then(function (results) {
console.log(results[0]);
var datablob = $scope.dataURItoBlob(results[0]);
technique 1 (create the blob):
$scope.dataURItoBlob = function(dataURI) {
var binary = atob(dataURI.split(',')[1]);
var array = [];
for (var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
return new Blob([new Uint8Array(array)], {
type: mimeString
});
}
technique 2 (create the blob):
$scope.dataURItoBlob = function(dataURI) {
var arr = dataURI.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {type:mime});
}
Both techniques does not work. Please help! thank you very much.
$cordovaImagePicker.getPictures(options)
.then(function (results) {
console.log(results[0]);
dataURItoBlob(results[0], function(url){
var datablob = url;
}, function(error){
console.error(error);
})
})
function dataURItoBlob(path, cb, error) {
resolveLocalFileSystemURL(path, function (fileEntry) {
fileEntry.file(function (file) {
var reader = new FileReader();
reader.onloadend = function () {
if (typeof cb === 'function') {
cb(this.result)
}
};
reader.readAsDataURL(file);
}, function (err) {
if (typeof error === 'function') {
error(err)
}
});
});
}
Needs to cordova-plugin-file
I am trying to upload an image to cloudinary using ionic cordova plugin. I can successfully post my image to cloudinary, but the response i received in xcode shows [object Object]. I would like to get the details of the response.
I tried printing the result using different ways such as iterating the keys of object, and nothing is been printed. is there a way for xcode to print out ionic console.log response? My code is as follow:
angular.module('starter.controllers', [])
.controller('DashCtrl', function($scope, $cordovaCamera, $cordovaGeolocation, $cordovaFileTransfer, $q, $base64, $translate) {
//$scope.$inject = ['$cordovaCamera','$cordovaGeolocation','$cordovaFileTransfer'];
$scope.imageURI = '';
$scope.log=function(){
console.log('hello~~~');
};
$scope.takePicture = function() {
console.log('taking pictures ....');
var uploadOptions = {
params : { 'upload_preset': "MY_PRESET"}
};
var options = {
quality: 50,
destinationType: Camera.DestinationType.FILE_URI,
sourceType: Camera.PictureSourceType.CAMERA,
encodingType: Camera.EncodingType.JPEG,
};
$cordovaCamera.getPicture(options).then(function(imageData) {
$scope.imageURI = imageData;
var ft = new FileTransfer();
function win (){
console.log('upload successful');
}
function fail(){
console.log('upload fail');
}
return $cordovaFileTransfer.upload("https://api.cloudinary.com/v1_1/MY_DOMAIN/image/upload", $scope.imageURI, uploadOptions);
})
.then(function(result){
console.log('result is~~~~~~ ', result);
console.log('print the result object '); // this shows nothing
var test1=JSON.parse(decodeURIComponent(result.response);
var test2=JSON.parse(decodeURIComponent(result);
console.log('test1 is ', test1); // didn't even print!!
console.log('test2 is ', test2); // didn't even print!!
for(var property in result[0]) {
console.log(property + "=" + obj[property]); // nothing here
}
for(var property in result[1]) {
console.log(property + "=" + obj[property]);// nothing here
}
for(var property in result) {
console.log(property + "=" + obj[property]);// nothing here
}
var url = result.secure_url || '';
var urlSmall;
if(result && result.eager[0]) { // this is not working
urlSmall = result.eager[0].secure_url || '';
console.log('url ~~~~~~~~ is ', urlSmall);
chat.sendMessage(roomId,'', 'default', urlSmall, function(result){
console.log('url is ', urlSmall);
console.log('message image url successfully updated to firebase');
})
}
// Do something with the results here.
$cordovaCamera.cleanup();
}, function(err){
// Do something with the error here
console.log('something is erroring')
$cordovaCamera.cleanup();
});
};
})
I'm uploading the big files using chunk method.If i make minimum number request to the server uploading is working fine.if make high number of request to the server Chrome browser has crashed with Aw Snap! error message.But other browsers are working fine with high number of request.
How to resolve this.Is there workaround?is it chromium bug?
Updated
Below function will slice the file then upload chunk to server .After all chunks uploaded. Merge Api will merge the chunk.
Code:
function readFile (file) {
var uploadBatchKey = this.guid;
var start = 0; //Start Index
var stop = file.size; //End Index
var chunksize = (document.getElementById('chunkSize').value * 1048576);
var index = this.chunkUploadIndex;
var reader = new FileReader();
var filecontent = null;
var waitingInterval = null;
var totalsegment = Math.ceil(stop / chunksize);
var isPreviousChunkUpload = true;
var match = ko.utils.arrayFirst(JSViewmodel.SelectedFiles(), function (item) {
return item.UploadManager == undefined ? false : (uploadBatchKey === item.UploadManager.guid);
});
match.UploadBatchKey(uploadBatchKey);
var handle = setInterval(function () {
if (isPreviousChunkUpload) {
if (!match.IsUploading()) {
clearInterval(handle);
}
else if (index > totalsegment) {
isPreviousChunkUpload = false;
var filename = match.IsRelativePath() ? file.webkitRelativePath : file.name;
console.log(file.size);
var batchData = { uploadBatchKey: uploadBatchKey, fileName: filename, fileSize: file.size };
$.ajax({
url: "/Home/MergeChunk",
type: 'POST',
async: false,
data: batchData,
success: function (result) {
debugger;
console.log(result);
if (result == "False")
match.IsFailed(true);
},
error: function (result) {
console.log(result);
debugger;
match.IsFailed(true);
}
});
match.IsUploading(false);
match.IsCompleted(true);
clearInterval(handle);
}
start = (index - 1) * chunksize;
stop = (index * chunksize) - 1;
reader.onloadend = function (evt) {
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
filecontent = evt.target.result;
var chunkContent = { chunkContent: window.btoa(filecontent), chunkIndex: index - 1, uploadBatchKey: uploadBatchKey };
console.log("onloadend" + chunkContent.chunkIndex);
$.ajax({
url: "/Home/Upload",
type: 'POST',
async: false,
data: chunkContent,
success: function (result) {
match.Percentage(Math.round((chunkContent.chunkIndex / totalsegment) * 100));
isPreviousChunkUpload = true;
}
});
}
};
var blob = file.slice(start, stop + 1);
reader.readAsBinaryString(blob);
isPreviousChunkUpload = false;
console.log("file slice:" + index);
index++;
match.UploadManager.chunkUploadIndex = index;
}
}, 500);
}
I need to upload attached resized images into a couchdb doc. Right now I'm not resizing images, only uploading them by using the following code:
function attachFile(event) {
event.preventDefault();
var form_data = {};
$("form.attach-file :file").each(function() {
form_data[this.name] = this.value;
});
if (!form_data._attachments || form_data._attachments.length == 0) {
alert("Please select a file to upload.");
return;
}
var id = $("#ant-show").data("doc")._id;
$(this).ajaxSubmit({
url: "db/" + $.couch.encodeDocId(id),
success: function(resp) {
$('#modal-attach').modal("hide");
helios_link(id);
}
});
}
The code I'm using to rezise images, but that doesn't work to upload them, is the following:
function attachFile(event) {
function isImage (str) {
return str.match(/(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg)((\?|#).*)?$)/i);
}
function resizeAndUpload(file, callback, progress)
{
var reader = new FileReader();
reader.onloadend = function() {
var tempImg = new Image();
tempImg.onload = function() {
var MAX_WIDTH = 500;
var MAX_HEIGHT = 500;
var tempW = tempImg.width;
var tempH = tempImg.height;
if (tempW > tempH) {
if (tempW > MAX_WIDTH) {
tempH *= MAX_WIDTH / tempW;
tempW = MAX_WIDTH;
}
} else {
if (tempH > MAX_HEIGHT) {
tempW *= MAX_HEIGHT / tempH;
tempH = MAX_HEIGHT;
}
}
var resizedCanvas = document.createElement('canvas');
resizedCanvas.width = tempW;
resizedCanvas.height = tempH;
var ctx = resizedCanvas.getContext("2d");
ctx.drawImage(this, 0, 0, tempW, tempH);
var dataURL = resizedCanvas.toDataURL("image/jpeg");
var file = dataURLtoBlob(dataURL);
var fd = $("#upload");
fd.append("_attachments", file);
var id = $("#ant-show").data("doc")._id;
console.log(fd);
fd.ajaxSubmit({
url: "db/" + $.couch.encodeDocId(id),
success: function(resp) {
$('#modal-attach').modal("hide");
helios_link(id);
}
});
};
tempImg.src = reader.result;
}
reader.readAsDataURL(file);
}
function dataURLtoBlob(dataURL) {
// Decodifica dataURL
var binary = atob(dataURL.split(',')[1]);
// Se transfiere a un array de 8-bit unsigned
var array = [];
var length = binary.length;
for(var i = 0; i < length; i++) {
array.push(binary.charCodeAt(i));
}
// Retorna el objeto Blob
return new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
}
function uploaded(response) {
// Código siguiente a la subida
}
function progressBar(percent) {
// Código durante la subida
}
event.preventDefault();
console.clear();
var files = document.getElementById('_attachments').files;
console.log(files);
resizeAndUpload(files[0], uploaded, progressBar);
}
Do anybody know how can I improve my code to make it work? I would like to have in fact two different solutions, one that helps me to improve my code and the second one, to get instructions on how to upload a URL BLOB as attachments into a couchdb document.
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