I have managed to setup code to write to and read from a text file.
The problem I've run into is when I try to read the file after writing it.
It returns a null value.
I am assuming this is due to the write not being complete when the read starts.
How do I make the read wait for the write.
MyFile Class
MyFile = function() {
};
MyFile.prototype.readFile = function(fileDir, fileName) {
window.resolveLocalFileSystemURL(fileDir, function(dir) {
dir.getFile(fileName, {create: true}, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onerror = function(evt) {
console.log("Reading " + file.name + " Failed");
};
reader.onloadstart = function(evt) {
console.log("Read " + file.name + " Starting");
};
reader.onload = function(evt) {
console.log("Read " + file.name + " Successful");
window.localStorage.setItem(file.name + "Read", evt.target.result);
console.log(evt.target.result);
};
reader.onloadend = function(evt) {
console.log("Read " + file.name + " Ending");
};
reader.readAsText(file);
}, fail);
}, fail);
}, fail);
var strText = window.localStorage.getItem(fileName + "Read");
console.log(strText);
window.localStorage.removeItem(fileName + "Read");
return strText;
};
MyFile.prototype.overWriteFile = function(fileDir, fileName, strText) {
window.resolveLocalFileSystemURL(fileDir, function(dir) {
dir.getFile(fileName, {create: true}, function(file) {
if (!file) {
return;
} else {
console.log("Overwrite File Name: " + file.name);
}
file.createWriter(function(fileWriter) {
fileWriter.onwriteend = function(evt) {
if (fileWriter.length === 0) {
//fileWriter has been reset, write file
fileWriter.write(strText);
} else {
//file has been overwritten with blob
//use callback or resolve promise
console.log("Write " + file.name + " Success");
console.log(strText);
}
};
fileWriter.truncate(0);
}, fail);
});
});
};
Calling Write and Read
var myf = new MyFile();
myf.overWriteFile("Directory", "test.txt","Test.txt Contents");
console.log(myf.readFile("Directory", "test.txt"));
If you dont mind jQuery you can try using a custom event that you fire when the file is done writing.
MyFile.prototype.overWriteFile = function(fileDir, fileName, strText) {
//added self var to be accessed from within createWriter finished section
var self = this
window.resolveLocalFileSystemURL(fileDir, function(dir) {
dir.getFile(fileName, {create: true}, function(file) {
if (!file) {
return;
} else {
console.log("Overwrite File Name: " + file.name);
}
file.createWriter(function(fileWriter) {
fileWriter.onwriteend = function(evt) {
if (fileWriter.length === 0) {
//fileWriter has been reset, write file
fileWriter.write(strText);
} else {
//file has been overwritten with blob
//use callback or resolve promise
//triggers the finishedMyFileWrite on the MyFile instance
jQuery(self).tigger('finishedMyFileWrite');
console.log("Write " + file.name + " Success");
console.log(strText);
}
};
fileWriter.truncate(0);
}, fail);
});
});
};
var myf = new MyFile();
jQuery(myf).on('finishedMyFileWrite', function finishedWrite(){
console.log(this.readFile("Directory", "test.txt"));
});
myf.overWriteFile("Directory", "test.txt","Test.txt Contents");
I added a self variable to allow the custom event to target the specific instance of MyFile, then I trigger an event called finishedMyFileWrite after the file has written. The myf object is set to listen for this callback before writing. I am not able to test this as I dont have a cordova emulator, but the theory should work.
Related
I am trying to get Strophe.js based XMPP file transfer to work. I can get logged in to work on my openfire server. I can send messages and receive messages fine but I am having trouble with file transfer.
HTML:
<form name='file_form' class="panel-body">
<input type="file" id="file" name="file[]" />
<input type='button' id='btnSendFile' value='sendFile' />
<output id="list"></output>
</form>
Javascript file:
// file
var sid = null;
var chunksize;
var data;
var file = null;
var aFileParts, mimeFile, fileName;
function sendFileClick() {
file =$("#file")[0].files[0];
sendFile(file);
readAll(file, function(data) {
log("handleFileSelect:");
log(" >data="+data);
log(" >data.len="+data.length);
});
}
function sendFile(file) {
var to = $('#to').get(0).value;
var filename = file.name;
var filesize = file.size;
var mime = file.type;
chunksize = filesize;
sid = connection._proto.sid;
log('sendFile: to=' + to);
// send a stream initiation
connection.si_filetransfer.send(to, sid, filename, filesize, mime, function(err) {
fileTransferHandler(file, err);
});
}
function fileTransferHandler(file, err) {
log("fileTransferHandler: err=" + err);
if (err) {
return console.log(err);
}
var to = $('#to').get(0).value;
chunksize = file.size;
chunksize = 20 * 1024;
// successfully initiated the transfer, now open the band
connection.ibb.open(to, sid, chunksize, function(err) {
log("ibb.open: err=" + err);
if (err) {
return console.log(err);
}
readChunks(file, function(data, seq) {
sendData(to, seq, data);
});
});
}
function readAll(file, cb) {
var reader = new FileReader();
// If we use onloadend, we need to check the readyState.
reader.onloadend = function(evt) {
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
cb(evt.target.result);
}
};
reader.readAsDataURL(file);
}
function readChunks(file, callback) {
var fileSize = file.size;
var chunkSize = 20 * 1024; // bytes
var offset = 0;
var block = null;
var seq = 0;
var foo = function(evt) {
if (evt.target.error === null) {
offset += chunkSize; //evt.target.result.length;
seq++;
callback(evt.target.result, seq); // callback for handling read chunk
} else {
console.log("Read error: " + evt.target.error);
return;
}
if (offset >= fileSize) {
console.log("Done reading file");
return;
}
block(offset, chunkSize, file);
}
block = function(_offset, length, _file) {
log("_block: length=" + length + ", _offset=" + _offset);
var r = new FileReader();
var blob = _file.slice(_offset, length + _offset);
r.onload = foo;
r.readAsDataURL(blob);
}
block(offset, chunkSize, file);
}
function sendData(to, seq, data) {
// stream is open, start sending chunks of data
connection.ibb.data(to, sid, seq, data, function(err) {
log("ibb.data: err=" + err);
if (err) {
return console.log(err);
}
// ... repeat calling data
// keep sending until you're ready you've reached the end of the file
connection.ibb.close(to, sid, function(err) {
log("ibb.close: err=" + err);
if (err) {
return console.log(err);
}
// done
});
});
}
$('#btnSendFile').bind('click', function() {
console.log('File clicked:');
sendFileClick();
});
Full code is based on:
Complete example of Strophe.js file transfer
http://plnkr.co/edit/fYpXo1mFRWPxrLlgr123 (source can be download here: has errors). I changed the sendFileClick function.
I am getting:
ibb.open: err=Error: feature-not-implemented? Why is this error I am getting?
I am new to cordova plugin and in all thing..
I have implemented coedova plugin to download file..
Cordova plugin
here is the code..
var app = {
fileName: "abc.txt", //<-- this one i want to do dynamic
uriString: "http://.....", //<-- this one i want to do dynamic
// Application Constructor
initialize: function() {
this.bindEvents();
},
downloadFile: function(uriString, targetFile) {
var lblProgress = document.getElementById('lblProgress');
var complete = function() {
lblProgress.innerHTML = 'Done';
};
var error = function (err) {
console.log('Error: ' + err);
lblProgress.innerHTML = 'Error: ' + err;
};
var progress = function(progress) {
lblProgress.innerHTML = (100 * progress.bytesReceived / progress.totalBytesToReceive) + '%';
};
try{
var downloader = new BackgroundTransfer.BackgroundDownloader();
// Create a new download operation.
var download = downloader.createDownload(uriString, targetFile);
// Start the download and persist the promise to be able to cancel the download.
app.downloadPromise = download.startAsync().then(complete, error, progress);
} catch(err) {
console.log('Error: ' + err);
}
},
// Bind Event Listeners
//
// Bind any events that are required on startup. Common events are:
// 'load', 'deviceready', 'offline', and 'online'.
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
document.getElementById('btnStart').addEventListener('click', this.startDownload);
document.getElementById('btnStop').addEventListener('click', this.stopDownload);
document.getElementById('btnFileInfo').addEventListener('click', this.getFileInfo);
},
// deviceready Event Handler
//
// The scope of 'this' is the event. In order to call the 'receivedEvent'
// function, we must explicity call 'app.receivedEvent(...);'
onDeviceReady: function() {
app.receivedEvent('deviceready');
app.startDownload();
},
startDownload: function () {
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem) {
fileSystem.root.getFile(app.fileName, { create: true }, function (newFile) {
app.downloadFile(app.uriString, newFile);
});
});
},
stopDownload: function () {
app.downloadPromise && app.downloadPromise.cancel();
},
getFileInfo: function () {
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {
fileSystem.root.getFile(app.fileName, { create: true }, function (fileEntry) {
fileEntry.file(function (meta) {
document.getElementById('lblFileInfo').innerHTML =
"Modified: " + meta.lastModifiedDate + "<br/>" +
"size: " + meta.size;
});
}, function(error) {
document.getElementById('lblFileInfo').innerHTML = "error: " + error;
});
});
},
// Update DOM on a Received Event
receivedEvent: function(id) {
var parentElement = document.getElementById(id);
var listeningElement = parentElement.querySelector('.listening');
var receivedElement = parentElement.querySelector('.received');
listeningElement.setAttribute('style', 'display:none;');
receivedElement.setAttribute('style', 'display:block;');
console.log('Received Event: ' + id);
}
};
this js file start downloading when page load or we click on start button..
I want to remove onpage load and only set when button click.. also how to set dynamic value of uristring and filename??.....
I'm trying to append text to a file.
I have followed tutorial of Html5rocks as suggested by plugins's github page.
I've sucessfully created a file and wrote to it. But when im trying to append text, i got a write success event but no text is added. I'm only able to change characters but no characted added to the end. It's not an async issue, i'm also trying live test with chrome's js console. Im also using fileWriter.seek(fileWriter.length) before trying to write at the end. (but seek(0) to write a the beginning)
there is the module i wrote :
'use strict';
function File_mgmt(name) {
var name = name;
var myfile = '';
var next_write = '';
var that = this;
var errorHandler = function (e) {
var msg = '';
switch (e.code) {
case FileError.QUOTA_EXCEEDED_ERR:
msg = 'QUOTA_EXCEEDED_ERR';
break;
case FileError.NOT_FOUND_ERR:
msg = 'NOT_FOUND_ERR';
break;
case FileError.SECURITY_ERR:
msg = 'SECURITY_ERR';
break;
case FileError.INVALID_MODIFICATION_ERR:
msg = 'INVALID_MODIFICATION_ERR';
break;
case FileError.INVALID_STATE_ERR:
msg = 'INVALID_STATE_ERR';
break;
default:
msg = 'Unknown Error';
break;
};
console.log('Error: ' + msg);
};
var init = function() {
console.log("init");
request(gotFS);
};
var gotFS = function() {
console.log("gotfs");
window.resolveLocalFileSystemURL(cordova.file.externalDataDirectory, function(dir) {
dir.getFile(name, {create:true}, function(file) {
myfile = file;
}, errorHandler);
});
};
this.write = function (data) {
myfile.createWriter(function(fileWriter) {
fileWriter.onwriteend = function(e) {
console.log('Write completed.');
};
fileWriter.onerror = function(e) {
console.log('Write failed: ' + e.toString());
};
// Create a new Blob and write it to log.txt.
fileWriter.seek(fileWriter.length);
fileWriter.write(data);
}, errorHandler);
};
this.reopen = function() {
window.resolveLocalFileSystemURL(cordova.file.externalDataDirectory, function(dir) {
dir.getFile(name, {create:false}, function(file) {
myfile = file;
}, errorHandler);
});
};
this.getfile = function() {
return myfile;
};
this.writeTextBlob = function(data) {
this.write(new Blob([data], {type: 'text/plain'}));
};
var request = function(success){
var fail = function() {console.log("failed to initialise system")};
window.requestFileSystem(LocalFileSystem.PERSISTENT, 1024*1024, success, fail);
};
var writer = function() {
myfile.createWriter(function(fileWriter) {
fileWriter.onwriteend = function(e) {
console.log('Write completed.');
};
fileWriter.onerror = function(e) {
console.log('Write failed: ' + e.toString());
};
// Create a new Blob and write it to log.txt.
fileWriter.seek(fileWriter.length);
fileWriter.write(next_write);
}, errorHandler);
};
this.testWrite = function(data) {
next_write = data;
request(writer);
};
init();
return this;
}
I'm using it with chrome console with
var f = new File_mgmt("test");
f.writeTextBlob("test1");
f.writeTextBlob("test2");
Edit
I've tried to pass by a window.requestFileSystem() to append but it still doesnt work, I've also updated my code.
now i'm doing
var f = new File_mgmt("test");
f.testWrite("test1");
f.testWrite("test2");
It's appearing than my file actually got new data. I had to unplugged then replugged usb cable to see the new data appened to my file.
May be it's a problem with Windows. I'll look if i got the same problem on linux.
Within my Cordova app, I am downloading arbitrary files like images or video files. This is done with the Cordova file-transfer plugin and the "Range" Header, because I need to download the files in parts.
My Problem is, that I want to merge back the several small "Byte"-Files back together into the original file they once where to use that file. Every time I'm trying to read the resulting parts as binaryString via the FileReader and write them together in a new file, that file ends up a lot larger than the parts of the original file altogther and the resulting file is unusable.
Any help is appreciated.
Here is my code until now (long and ugly):
document.addEventListener('deviceready', deviceready, false);
var App;
var finishedFileUrl = "";
var async = {
sequence: function(items, callback) {
var def = $.Deferred(),
deferrers = [$.Deferred()];
for(var i = 0; i < items.length; i++) {
(function (n) {
deferrers[n + 1] = $.Deferred();
deferrers[n].always(function() {
callback(items[n], deferrers[n + 1]);
});
})(i);
}
deferrers[items.length].always(function() {
def.resolve();
});
deferrers[0].resolve();
return def.promise();
}
}
var aSmallImageArray = [
'' // Put URL to JPG accessible with Range Header Request here
];
var aByteSizeImageArray = [];
function formatDownloadArray(fileSize) {
for(var j = 1000; j <= fileSize; j += 1000) {
aByteSizeImageArray.push(j);
}
aByteSizeImageArray.push(j);
}
function deviceready() {
console.log('dv ready');
function registerHandlers() {
App = new DownloadApp();
formatDownloadArray(XXXXX); // XXXXX should be size of JPG in bytes
document.getElementById("startDl").onclick = function() {
var that = this;
console.log("load button clicked");
var folderName = "testimagefolder";
// sequence call
async.sequence(aByteSizeImageArray, function(currentBytes, iter) {
var filePath = aSmallImageArray[0];
var fileName = aSmallImageArray[0].substr(52,99) + currentBytes;
console.log(filePath);
console.log(fileName);
console.log("Starting with: " + fileName);
var uri = encodeURI(filePath);
var folderName = "testimagefolder";
document.getElementById("statusPlace").innerHTML = "<br/>Loading: " + uri;
App.load(currentBytes, uri, folderName, fileName,
function progress (percentage) {
document.getElementById("statusPlace").innerHTML = "<br/>" + percentage + "%";
},
function success (entry) {
console.log("Entry: " + entry);
document.getElementById("statusPlace").innerHTML = "<br/>Image saved to: " + App.filedir;
console.log("DownloadApp.filedir: " + App.filedir);
iter.resolve();
},
function error () {
document.getElementById("statusPlace").innerHTML = "<br/>Failed load image: " + uri;
iter.resolve();
}
);
}).then(function afterAsync () {
console.log("ASYNC DONE");
var ohNoItFailed = function ohNoItFailed (exeperro) {
console.log(exeperro);
}
// now we merge the fileparts into one file to show it
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (FileSystem) {
FileSystem.root.getDirectory(folderName, {create: true, exclusive: false}, function itSuccessed (Directory) {
Directory.getFile(aSmallImageArray[0].substr(52,99), {create: true, exclusive: false}, function itSuccessedAgain (fileEntry) {
finishedFileUrl = fileEntry.toURL();
var directoryReader = Directory.createReader();
var allFiles = directoryReader.readEntries(function succesReadDir (fileEntries) {
async.sequence(fileEntries, function(currentFile, iterThis) {
currentFile.file(function (theActualFile) {
var myFileReader = new FileReader();
myFileReader.onload = function (content) {
console.log('FileReader onload event fired!');
console.log('File Content should be: ' + content.target.result);
fileEntry.createWriter(
function mergeImage (writer) {
writer.onwrite = function (evnt) {
console.log("Writing successful!");
iterThis.resolve();
}
writer.seek(writer.length);
writer.write(content.target.result);
}, ohNoItFailed);
};
myFileReader.readAsBinaryString(theActualFile);
}, ohNoItFailed);
}).then(function afterAsyncTwo () {
console.log("NOW THE IMAGE SHOULD BE TAKEN FROM THIS PATH: " + finishedFileUrl);
//window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (FileSystem) {
//FileSystem.root.getDirectory(folderName, {create: true, exclusive: false}, function itSuccessed (Directory) {
//Directory.getFile(aSmallImageArray[0].substr(52,99), {create: true, exclusive: false}, function itSuccessedAgain (fileEntry) {
//fileEntry.createWriter(
document.getElementById("image_here").src = finishedFileUrl;
});
}, ohNoItFailed);
}, ohNoItFailed);
}, ohNoItFailed);
}, ohNoItFailed);
});
};
}
registerHandlers();
}
var DownloadApp = function() {}
DownloadApp.prototype = {
filedir: "",
load: function(currentBytes, uri, folderName, fileName, progress, success, fail) {
var that = this;
that.progress = progress;
that.success = success;
that.fail = fail;
filePath = "";
that.getFilesystem(
function(fileSystem) {
console.log("GotFS");
that.getFolder(fileSystem, folderName, function(folder) {
filePath = folder.toURL() + fileName;
console.log("FILEPATH: " + filePath);
console.log("URI: " + uri);
that.transferFile(currentBytes, uri, filePath, progress, success, fail);
}, function(error) {
console.log("Failed to get folder: " + error.code);
typeof that.fail === 'function' && that.fail(error);
});
},
function(error) {
console.log("Failed to get filesystem: " + error.code);
typeof that.fail === 'function' && that.fail(error);
}
);
},
getFilesystem: function (success, fail) {
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, success, fail);
},
getFolder: function (fileSystem, folderName, success, fail) {
fileSystem.root.getDirectory(folderName, {create: true, exclusive: false}, success, fail)
},
transferFile: function (currentBytes, uri, filePath, progress, success, fail) {
var that = this;
that.progress = progress;
that.success = success;
that.fail = fail;
console.log("here we go");
console.log("filePath before Request: " + filePath);
var previousBytes = currentBytes - 1000;
var transfer = new FileTransfer();
transfer.onprogress = function(progressEvent) {
if (progressEvent.lengthComputable) {
var perc = Math.floor(progressEvent.loaded / progressEvent.total * 100);
typeof that.progress === 'function' && that.progress(perc); // progression on scale 0..100 (percentage) as number
} else {
}
};
transfer.download(
uri,
filePath,
function success (entry) {
console.log("File saved to: " + entry.toURL());
typeof that.success === 'function' && that.success(entry);
},
function errorProblem(error) {
console.log("An error has occurred: Code = " + error.code);
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("download error code " + error.code);
typeof that.fail === 'function' && that.fail(error);
},
true,
{
headers: {
"Range": "bytes=" + previousBytes + "-" + currentBytes
}
}
);
}
}
async code by stackoverflow-user: Paul Facklam
-> Thanks a lot!
you can build a blob from other blobs, like the ones you use FileReader on now. (File()s are Blobs)
// put three blobs into a fourth:
var b=new Blob([new Blob(["hello"]), new Blob([" "]), new Blob(["world"])]);
// verify the blob has the data we expect:
var fr=new FileReader();
fr.onload=function(){alert(this.result);};
fr.readAsBinaryString(b); // shows: "hello world"
the binaryString flavor is used here to show how these low-order strings stack up, but the actual new blob instance should have all the orig (arbitrary) bytes from the original blobs, even if they aren't composed of simple strings...
Using readAsArrayBuffer() instead of readAsBinaryString() did the trick!
So instead of:
myFileReader.readAsBinaryString(theActualFile);
I did:
myFileReader.readAsBinaryArray(theActualFile);
And the resulting image file is usable.
I'm trying to hack/personalize a html5/ajax/javascript plugin for drag&drop and upload a file
(the problem with this plugin is that it uploads the file directly after being dropped on the drop zone..) So i want to change this behaviour and control the moment in which the upload should happens
(the upload uses jquery-ajax) by externalizing the upload function
The main plugin's script is written in this page (the html5Upload.js) :
/*jslint unparam: true, browser: true, devel: true */
/*global define*/
define(function () {
'use strict';
var module = {},
noop = function () { },
console = window.console || { log: noop },
supportsFileApi;
function UploadManager(options) {
var self = this;
self.dropContainer = options.dropContainer;
self.inputField = options.inputField;
self.uploadsQueue = [];
self.activeUploads = 0;
self.data = options.data;
self.key = options.key;
self.maxSimultaneousUploads = options.maxSimultaneousUploads || -1;
self.onFileAdded = options.onFileAdded || noop;
self.uploadUrl = options.uploadUrl;
self.onFileAddedProxy = function (upload) {
console.log('Event: onFileAdded, file: ' + upload.fileName);
self.onFileAdded(upload);
};
self.initialize();
}
function FileUpload(file) {
var self = this;
self.file = file;
self.fileName = file.name;
self.fileSize = file.size;
self.uploadSize = file.size;
self.uploadedBytes = 0;
self.eventHandlers = {};
self.events = {
onProgress: function (fileSize, uploadedBytes) {
var progress = uploadedBytes / fileSize * 100;
console.log('Event: upload onProgress, progress = ' + progress + ', fileSize = ' + fileSize + ', uploadedBytes = ' + uploadedBytes);
(self.eventHandlers.onProgress || noop)(progress, fileSize, uploadedBytes);
},
onStart: function () {
console.log('Event: upload onStart');
(self.eventHandlers.onStart || noop)();
},
onCompleted: function (data) {
console.log('Event: upload onCompleted, data = ' + data);
file = null;
(self.eventHandlers.onCompleted || noop)(data);
}
};
}
FileUpload.prototype = {
on: function (eventHandlers) {
this.eventHandlers = eventHandlers;
}
};
UploadManager.prototype = {
initialize: function () {
console.log('Initializing upload manager');
var manager = this,
dropContainer = manager.dropContainer,
inputField = manager.inputField,
cancelEvent = function (e) {
e.preventDefault();
e.stopPropagation();
};
if (dropContainer) {
manager.on(dropContainer, 'dragover', cancelEvent);
manager.on(dropContainer, 'dragenter', cancelEvent);
manager.on(dropContainer, 'drop', function (e) {
cancelEvent(e);
manager.processFiles(e.dataTransfer.files);
});
}
if (inputField) {
manager.on(inputField, 'change', function () {
manager.processFiles(this.files);
});
}
},
processFiles: function (files) {
console.log('Processing files: ' + files.length);
var manager = this,
len = files.length,
file,
upload,
i;
for (i = 0; i < len; i += 1) {
file = files[i];
if (file.size === 0) {
alert('Files with files size zero cannot be uploaded or multiple file uploads are not supported by your browser');
break;
}
upload = new FileUpload(file);
manager.uploadFile(upload);
}
},
uploadFile: function (upload) {
var manager = this;
manager.onFileAdded(upload);
// Queue upload if maximum simultaneous uploads reached:
if (manager.activeUploads === manager.maxSimultaneousUploads) {
console.log('Queue upload: ' + upload.fileName);
manager.uploadsQueue.push(upload);
return;
}
manager.ajaxUpload(upload);
},
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This is the function i want to externalize to be called from outside this script
ajaxUpload: function (upload) {
var manager = this,
xhr,
formData,
fileName,
file = upload.file,
prop,
data = manager.data,
key = manager.key || 'file';
console.log('Beging upload: ' + upload.fileName);
manager.activeUploads += 1;
xhr = new window.XMLHttpRequest();
formData = new window.FormData();
fileName = file.name;
xhr.open('POST', manager.uploadUrl);
// Triggered when upload starts:
xhr.upload.onloadstart = function () {
// File size is not reported during start!
console.log('Upload started: ' + fileName);
upload.events.onStart();
};
// Triggered many times during upload:
xhr.upload.onprogress = function (event) {
if (!event.lengthComputable) {
return;
}
// Update file size because it might be bigger than reported by the fileSize:
upload.events.onProgress(event.total, event.loaded);
};
// Triggered when upload is completed:
xhr.onload = function (event) {
console.log('Upload completed: ' + fileName);
// Reduce number of active uploads:
manager.activeUploads -= 1;
upload.events.onCompleted(event.target.responseText);
// Check if there are any uploads left in a queue:
if (manager.uploadsQueue.length) {
manager.ajaxUpload(manager.uploadsQueue.shift());
}
};
// Triggered when upload fails:
xhr.onerror = function () {
console.log('Upload failed: ', upload.fileName);
};
// Append additional data if provided:
if (data) {
for (prop in data) {
if (data.hasOwnProperty(prop)) {
console.log('Adding data: ' + prop + ' = ' + data[prop]);
formData.append(prop, data[prop]);
}
}
}
// Append file data:
formData.append(key, file);
// Initiate upload:
xhr.send(formData);
},
on: function (element, eventName, handler) {
if (!element) {
return;
}
if (element.addEventListener) {
element.addEventListener(eventName, handler, false);
} else if (element.attachEvent) {
element.attachEvent('on' + eventName, handler);
} else {
element['on' + eventName] = handler;
}
}
};
module.fileApiSupported = function () {
if (typeof supportsFileApi !== 'boolean') {
var input = document.createElement("input");
input.setAttribute("type", "file");
supportsFileApi = !!input.files;
}
return supportsFileApi;
};
module.initialize = function (options) {
return new UploadManager(options);
};
return module;
});
i was thinking about to set the scope of all variables needed by that function to the global scope
and define it outside the prototype .. i'm not sure it will work as this function calls the manager to which it belongs itself..
honnestly, i'm not that expert to make this work , i hope your help guys
Simply set it to where it returns whatever it is you need in the global scope. For example,
Instead of:
return module;
Do:
return {
module: module,
fileUpload: FileUpload };
You could take the text define and replace it with var uploader = this will give you an object with all of the characteristics and methods including the one you are looking to extract. Now if this code is relying on some other externally defined object it might through some errors but a basic reading of the code doesn't appear to rely on anything. I would not change the scope of the variables or attempt to cut out one (or even a few) methods. JavaScript closures make removing arbitrary code much harder.
As i said, setting the variables's scope needed by the function to the global scope
var monmanager;
var monupload;
/////////////////////////////////////////////////////////////////////////////////////
/*jslint unparam: true, browser: true, devel: true */
/*global define*/
define(function () {
'use strict';
var module = {},
noop = function () { },
console = window.console || { log: noop },
supportsFileApi;
function UploadManager(options) {
var self = this;
self.dropContainer = options.dropContainer;
self.inputField = options.inputField;
self.uploadsQueue = [];
self.activeUploads = 0;
self.data = options.data;
self.key = options.key;
self.maxSimultaneousUploads = options.maxSimultaneousUploads || -1;
self.onFileAdded = options.onFileAdded || noop;
self.uploadUrl = options.uploadUrl;
self.onFileAddedProxy = function (upload) {
console.log('Event: onFileAdded, file: ' + upload.fileName);
self.onFileAdded(upload);
};
self.initialize();
}
function FileUpload(file) {
var self = this;
self.file = file;
self.fileName = file.name;
self.fileSize = file.size;
self.uploadSize = file.size;
self.uploadedBytes = 0;
self.eventHandlers = {};
self.events = {
onProgress: function (fileSize, uploadedBytes) {
var progress = uploadedBytes / fileSize * 100;
console.log('Event: upload onProgress, progress = ' + progress + ', fileSize = ' + fileSize + ', uploadedBytes = ' + uploadedBytes);
(self.eventHandlers.onProgress || noop)(progress, fileSize, uploadedBytes);
},
onStart: function () {
console.log('Event: upload onStart');
(self.eventHandlers.onStart || noop)();
},
onCompleted: function (data) {
console.log('Event: upload onCompleted, data = ' + data);
file = null;
(self.eventHandlers.onCompleted || noop)(data);
}
};
}
FileUpload.prototype = {
on: function (eventHandlers) {
this.eventHandlers = eventHandlers;
}
};
UploadManager.prototype = {
initialize: function () {
console.log('Initializing upload manager');
var manager = this,
dropContainer = manager.dropContainer,
inputField = manager.inputField,
cancelEvent = function (e) {
e.preventDefault();
e.stopPropagation();
};
if (dropContainer) {
manager.on(dropContainer, 'dragover', cancelEvent);
manager.on(dropContainer, 'dragenter', cancelEvent);
manager.on(dropContainer, 'drop', function (e) {
cancelEvent(e);
manager.processFiles(e.dataTransfer.files);
});
}
if (inputField) {
manager.on(inputField, 'change', function () {
manager.processFiles(this.files);
});
}
},
processFiles: function (files) {
console.log('Processing files: ' + files.length);
var manager = this,
len = files.length,
file,
upload,
i;
for (i = 0; i < len; i += 1) {
file = files[i];
if (file.size === 0) {
alert('Files with files size zero cannot be uploaded or multiple file uploads are not supported by your browser');
break;
}
upload = new FileUpload(file);
manager.uploadFile(upload);
}
},
uploadFile: function (upload) {
var manager = this;
//////////my modification////////////////-----------------------------------------<<<<<<<<<<<<<<<
monmanager = manager;
//////////////////////////-----------------------------------------<<<<<<<<<<<<<<<
manager.onFileAdded(upload);
// Queue upload if maximum simultaneous uploads reached:
if (manager.activeUploads === manager.maxSimultaneousUploads) {
console.log('Queue upload: ' + upload.fileName);
manager.uploadsQueue.push(upload);
return;
}
//////////my modification////////////////-----------------------------------------<<<<<<<<<<<<<<<
monupload = upload;
//////////////////////////-----------------------------------------<<<<<<<<<<<<<<<
// manager.ajaxUpload(upload);
},
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This is the function i want to externalize to be called from outside this script
ajaxUpload: function (upload) {
var manager = this,
xhr,
formData,
fileName,
file = upload.file,
prop,
data = manager.data,
key = manager.key || 'file';
console.log('Beging upload: ' + upload.fileName);
manager.activeUploads += 1;
xhr = new window.XMLHttpRequest();
formData = new window.FormData();
fileName = file.name;
xhr.open('POST', manager.uploadUrl);
// Triggered when upload starts:
xhr.upload.onloadstart = function () {
// File size is not reported during start!
console.log('Upload started: ' + fileName);
upload.events.onStart();
};
// Triggered many times during upload:
xhr.upload.onprogress = function (event) {
if (!event.lengthComputable) {
return;
}
// Update file size because it might be bigger than reported by the fileSize:
upload.events.onProgress(event.total, event.loaded);
};
// Triggered when upload is completed:
xhr.onload = function (event) {
console.log('Upload completed: ' + fileName);
// Reduce number of active uploads:
manager.activeUploads -= 1;
upload.events.onCompleted(event.target.responseText);
// Check if there are any uploads left in a queue:
if (manager.uploadsQueue.length) {
manager.ajaxUpload(manager.uploadsQueue.shift());
}
};
// Triggered when upload fails:
xhr.onerror = function () {
console.log('Upload failed: ', upload.fileName);
};
// Append additional data if provided:
if (data) {
for (prop in data) {
if (data.hasOwnProperty(prop)) {
console.log('Adding data: ' + prop + ' = ' + data[prop]);
formData.append(prop, data[prop]);
}
}
}
// Append file data:
formData.append(key, file);
// Initiate upload:
xhr.send(formData);
},
on: function (element, eventName, handler) {
if (!element) {
return;
}
if (element.addEventListener) {
element.addEventListener(eventName, handler, false);
} else if (element.attachEvent) {
element.attachEvent('on' + eventName, handler);
} else {
element['on' + eventName] = handler;
}
}
};
module.fileApiSupported = function () {
if (typeof supportsFileApi !== 'boolean') {
var input = document.createElement("input");
input.setAttribute("type", "file");
supportsFileApi = !!input.files;
}
return supportsFileApi;
};
module.initialize = function (options) {
return new UploadManager(options);
};
return module;
});
and then i could call the function from outside :
$("#testcontrol").click(function(){
console.log( "it's clicked !" );
monmanager.ajaxUpload(monupload);
});
now it's fine :)