From 44798e2ad08849bdc828c1dff76c116c4606749c Mon Sep 17 00:00:00 2001 From: Szymon Nowak Date: Mon, 3 Mar 2014 23:10:04 +0100 Subject: [PATCH 1/4] Initial version of saving file using Filesystem API --- app/index.html | 1 + .../app/controllers/index_controller.js | 13 +- app/scripts/app/lib/file.js | 115 ++++++++++++++++++ app/scripts/app/lib/webrtc.js | 104 +++++++++------- app/scripts/vendor/idb.filesystem.min.js | 16 +++ 5 files changed, 193 insertions(+), 56 deletions(-) create mode 100644 app/scripts/app/lib/file.js create mode 100644 app/scripts/vendor/idb.filesystem.min.js diff --git a/app/index.html b/app/index.html index 3c45f6e..fc6835b 100644 --- a/app/index.html +++ b/app/index.html @@ -51,6 +51,7 @@ + diff --git a/app/scripts/app/controllers/index_controller.js b/app/scripts/app/controllers/index_controller.js index 4e622c1..437d217 100644 --- a/app/scripts/app/controllers/index_controller.js +++ b/app/scripts/app/controllers/index_controller.js @@ -155,23 +155,12 @@ FileDrop.IndexController = Ember.ArrayController.extend({ console.log('Peer:\t Received file', data); var connection = data.connection, - peer = this.findBy('peer.id', connection.peer), - blob = data.blob, - info = peer.get('transfer.info'), - dataUrl; + peer = this.findBy('peer.id', connection.peer); // Stop listening for 'receiving' progress now that we have a file peer.get('peer.connection').removeAllListeners('receiving_progress'); peer.set('transfer.receiving_progress', 0); peer.set('transfer.info', null); - - // Save received file - dataUrl = window.URL.createObjectURL(blob); - var a = document.createElement('a'); - a.setAttribute('download', info.name); - a.setAttribute('href', dataUrl); - document.body.appendChild(a); - a.click(); }, // Based on http://net.ipcalf.com/ diff --git a/app/scripts/app/lib/file.js b/app/scripts/app/lib/file.js new file mode 100644 index 0000000..bbc0b4d --- /dev/null +++ b/app/scripts/app/lib/file.js @@ -0,0 +1,115 @@ +window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem; +window.URL = window.URL || window.webkitURL; + +FileDrop.File = function (options) { + var self = this; + + this.name = options.name; + this.size = options.size; + this.type = options.type; + + this._reset(); + + return new Promise(function (resolve, reject) { + window.requestFileSystem( + window.TEMPORARY, + options.size, + function (filesystem) { + self.filesystem = filesystem; + resolve(self); + }, + function (error) { + this.errorHandler(error); + reject(error); + } + ); + }); +}; + +FileDrop.File.prototype.append = function (data) { + var self = this, + options = { + create: this.create + }; + + return new Promise(function (resolve, reject) { + self.filesystem.root.getFile(self.name, options, function (fileEntry) { + if (self.create) { + self.fileEntry = fileEntry; + self.create = false; + } + + fileEntry.createWriter(function (writer) { + var blob = new Blob(data, {type: self.type}); + + // console.log('File: Appending ' + blob.size + ' bytes at ' + self.seek); + + writer.onwriteend = function () { + self.seek += blob.size; + resolve(fileEntry); + }; + + writer.onerror = function (error) { + this.errorHandler(error); + reject(error); + }; + + writer.seek(self.seek); + writer.write(blob); + }, function (error) { + this.errorHandler(error); + reject(error); + }); + }, function (error) { + this.errorHandler(error); + reject(error); + }); + }); +}; + +FileDrop.File.prototype.save = function () { + console.log('File: Saving file: ', this.fileEntry); + + var a = document.createElement('a'); + a.download = this.name; + a.href = this.fileEntry.toURL(); // TODO: Add Firefox version as well + document.body.appendChild(a); + a.click(); + + this._reset(); +}; + +FileDrop.File.prototype.errorHandler = function (error) { + var msg; + + switch (error.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.error('File error: ' + msg); +}; + +FileDrop.File.prototype._reset = function () { + this.create = true; + this.filesystem = null; + this.fileEntry = null; + this.seek = 0; +}; + diff --git a/app/scripts/app/lib/webrtc.js b/app/scripts/app/lib/webrtc.js index dc9d384..a860295 100644 --- a/app/scripts/app/lib/webrtc.js +++ b/app/scripts/app/lib/webrtc.js @@ -1,6 +1,3 @@ -window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem; -window.URL = window.URL || window.webkitURL; - // TODO: provide TURN server config // once it's possible to create rooms with custom names. FileDrop.WebRTC = function (options) { @@ -35,11 +32,10 @@ FileDrop.WebRTC = function (options) { // Listen for incoming connections this.conn.on('connection', this._onConnection.bind(this)); - this.conn.on('close', function (error) { + this.conn.on('close', function () { console.log('Peer:\t Connected to server closed.'); }); - this.conn.on('error', function (error) { console.log('Peer:\t Error while connecting to server: ', error); }); @@ -52,7 +48,7 @@ FileDrop.WebRTC = function (options) { }; }; -FileDrop.WebRTC.CHUNKS_PER_ACK = 32; +FileDrop.WebRTC.CHUNKS_PER_ACK = 64; FileDrop.WebRTC.prototype.connect = function (id) { var connection = this.conn.connect(id, { @@ -94,32 +90,38 @@ FileDrop.WebRTC.prototype._onConnection = function (connection) { }; FileDrop.WebRTC.prototype._onBinaryData = function (data, connection) { - var incoming = this.files.incoming[connection.peer], + var self = this, + incoming = this.files.incoming[connection.peer], + block = incoming.block, info = incoming.info, + receivedChunkNum = incoming.receivedChunkNum, chunksPerAck = FileDrop.WebRTC.CHUNKS_PER_ACK, - cache = incoming.cache, - receivedChunkNum, nextChunkNum, blob; - - cache.push(data); - - receivedChunkNum = cache.length - 1; - nextChunkNum = receivedChunkNum + 1; + nextChunkNum, lastChunkInFile, lastChunkInBlock; connection.emit('receiving_progress', receivedChunkNum / (info.chunksTotal - 1)); - console.log('Got chunk no ' + (receivedChunkNum + 1) + ' out of ' + info.chunksTotal); + // console.log('Got chunk no ' + (receivedChunkNum + 1) + ' out of ' + info.chunksTotal); - if (receivedChunkNum === info.chunksTotal - 1) { - // If all chunks were transmitted, create a blob - blob = new Blob(cache, {type : info.type}); + block.push(data); - $.publish('file.p2p.peer', { - blob: blob, - connection: connection + nextChunkNum = incoming.receivedChunkNum = receivedChunkNum + 1; + lastChunkInFile = receivedChunkNum === info.chunksTotal - 1; + lastChunkInBlock = receivedChunkNum > 0 && ((receivedChunkNum + 1) % chunksPerAck) === 0; + + if (lastChunkInFile || lastChunkInBlock) { + this.file.append(block).then(function () { + if (lastChunkInFile) { + self.file.save(); + + $.publish('file.p2p.peer', { + blob: self.file, + connection: connection + }); + } else { + // console.log('Requesting block starting at: ' + (nextChunkNum)); + incoming.block = []; + self._requestFileBlock(connection, nextChunkNum); + } }); - } else if (receivedChunkNum > 0 && (receivedChunkNum + 1) % chunksPerAck === 0) { - // If all chunks in a block were transmitted, request a new block - console.log('Requesting block starting at: ' + (receivedChunkNum + 1)); - this._requestFileBlock(connection, receivedChunkNum + 1); } }; @@ -161,7 +163,7 @@ FileDrop.WebRTC.prototype._onJSONData = function (data, connection) { case 'block_request': var file = this.files.outgoing[connection.peer].file; - console.log('Peer:\t Block request: ', data.payload); + // console.log('Peer:\t Block request: ', data.payload); this._sendBlock(connection, file, data.payload); break; @@ -190,25 +192,31 @@ FileDrop.WebRTC.prototype.sendFileInfo = function (connection, info) { }; FileDrop.WebRTC.prototype.sendFileResponse = function (connection, response) { - var message = { - type: 'response', - payload: response - }; + var self = this, + message = { + type: 'response', + payload: response + }; - // If recipient rejected the file, delete stored file info - if (!response) { + if (response) { + // If recipient accepted the file, request required space to store the file on HTML5 filesystem + var incoming = this.files.incoming[connection.peer], + info = incoming.info; + + new FileDrop.File({name: info.name, size: info.size, type: info.type}) + .then(function (file) { + self.file = file; + + incoming.block = []; + incoming.receivedChunkNum = 0; + + connection.send(JSON.stringify(message)); + }); + } else { + // Otherwise, delete stored file info delete this.files.incoming[connection.peer]; + connection.send(JSON.stringify(message)); } - - connection.send(JSON.stringify(message)); -}; - -FileDrop.WebRTC.prototype._requestFileBlock = function (connection, chunkNum) { - var message = { - type: 'block_request', - payload: chunkNum - }; - connection.send(JSON.stringify(message)); }; FileDrop.WebRTC.prototype.sendFile = function (connection, file) { @@ -222,6 +230,14 @@ FileDrop.WebRTC.prototype.sendFile = function (connection, file) { this._sendBlock(connection, file, 0); }; +FileDrop.WebRTC.prototype._requestFileBlock = function (connection, chunkNum) { + var message = { + type: 'block_request', + payload: chunkNum + }; + connection.send(JSON.stringify(message)); +}; + // FIXME: Figure out why 64th chunk is sent twice FileDrop.WebRTC.prototype._sendBlock = function (connection, file, beginChunkNum) { var info = this.files.outgoing[connection.peer].info, @@ -231,7 +247,7 @@ FileDrop.WebRTC.prototype._sendBlock = function (connection, file, beginChunkNum endChunkNum = beginChunkNum + chunksToSend - 1, chunkNum; - console.log('Send block: start: ' + beginChunkNum + ' end: ' + endChunkNum); + // console.log('Send block: start: ' + beginChunkNum + ' end: ' + endChunkNum); for (chunkNum = beginChunkNum; chunkNum < endChunkNum + 1; chunkNum++) { this._sendChunk(connection, file, chunkNum); @@ -255,7 +271,7 @@ FileDrop.WebRTC.prototype._sendChunk = function (connection, file, chunkNum) { connection.send(event.target.result); connection.emit('sending_progress', chunkNum / (info.chunksTotal - 1)); - console.log('Sent chunk no ' + (chunkNum + 1) + ' out of ' + info.chunksTotal); + // console.log('Sent chunk no ' + (chunkNum + 1) + ' out of ' + info.chunksTotal); } }; reader.readAsArrayBuffer(blob); diff --git a/app/scripts/vendor/idb.filesystem.min.js b/app/scripts/vendor/idb.filesystem.min.js new file mode 100644 index 0000000..0ec2fbf --- /dev/null +++ b/app/scripts/vendor/idb.filesystem.min.js @@ -0,0 +1,16 @@ +(function(f){function m(a){var c=a.code,b=a.name;Object.defineProperty(this,"code",{set:function(a){c=a},get:function(){return c}});Object.defineProperty(this,"name",{set:function(a){b=a},get:function(){return b}})}function q(a,c){var b=c;c[0]!=g&&(b=a,b=a!=g?b+(g+c):b+c);for(var b=b.split(g),d=0;dthis.length)c=this.length;0>c&&(c+=this.length);0>c&&(c=0)};this.truncate=function(a){b=b?af&&(f=0);b=new Blob([e,new Uint8Array(f),d,g],{type:b.type})}else b=new Blob([d],{type:d.type});a.file_.blob_=b;a.file_.lastModifiedDate=d.lastModifiedDate||null;h.put(a,function(){c+=d.size;if(this.onwriteend)this.onwriteend()}.bind(this),this.onerror)}}function y(a){var c=!1;this.readEntries=function(b,d){if(!b)throw Error("Expected successCallback argument.");c?b([]):h.getAllEntries(a.fullPath,function(a){c=!0;b(a)},d)}}function s(a,c){this.modificationTime_=a||null;this.size_=c|| +0}function o(){}function j(a){this.file_=null;Object.defineProperty(this,"isFile",{enumerable:!0,get:function(){return!0}});Object.defineProperty(this,"isDirectory",{enumerable:!0,get:function(){return!1}});if(a)this.file_=a.file_,this.name=a.name,this.fullPath=a.fullPath,this.filesystem=a.filesystem}function i(a){Object.defineProperty(this,"isFile",{enumerable:!0,get:function(){return!1}});Object.defineProperty(this,"isDirectory",{enumerable:!0,get:function(){return!0}});if(a)this.name=a.name,this.fullPath= +a.fullPath,this.filesystem=a.filesystem}function z(a){t=a==f.TEMPORARY?"Temporary":"Persistent";this.name=(location.protocol+location.host).replace(/:/g,"_")+":"+t;this.root=new i;this.root.fullPath=g;this.root.filesystem=this;this.root.name=""}function k(a){switch(a.target.errorCode){case 12:console.log("Error - Attempt to open db with a lower version than the current one.");break;default:console.log("errorCode: "+a.target.errorCode)}console.log(a,a.code,a.message)}if(!f.requestFileSystem&&!f.webkitRequestFileSystem){var u= +f.indexedDB||f.mozIndexedDB||f.msIndexedDB;if(u){f.TEMPORARY=0;f.PERSISTENT=1;if(void 0===f.FileError)window.FileError=function(){},FileError.prototype.prototype=Error.prototype;FileError.INVALID_MODIFICATION_ERR=9;FileError.NOT_FOUND_ERR=1;m.prototype=FileError.prototype;m.prototype.toString=Error.prototype.toString;var l=new m({code:FileError.INVALID_MODIFICATION_ERR,name:"INVALID_MODIFICATION_ERR"}),p=new m({code:1E3,name:"Not implemented"}),w=new m({code:FileError.NOT_FOUND_ERR,name:"Not found"}), +n=null,t="temporary",h={db:null},g="/",v=String.fromCharCode(g.charCodeAt(0)+1);r.prototype.constructor=r;s.prototype={get modificationTime(){return this.modificationTime_},get size(){return this.size_}};o.prototype={name:null,fullPath:null,filesystem:null,copyTo:function(){throw p;},getMetadata:function(a,c){if(!a)throw Error("Expected successCallback argument.");try{this.isFile?a(new s(this.file_.lastModifiedDate,this.file_.size)):c(new m({code:1001,name:"getMetadata() not implemented for DirectoryEntry"}))}catch(b){c&& +c(b)}},getParent:function(){throw p;},moveTo:function(){throw p;},remove:function(a,c){if(!a)throw Error("Expected successCallback argument.");h["delete"](this.fullPath,function(){a()},c)},toURL:function(){return"filesystem:"+(location.protocol+"//"+location.host)+g+t.toLowerCase()+this.fullPath}};j.prototype=new o;j.prototype.constructor=j;j.prototype.createWriter=function(a){a(new x(this))};j.prototype.file=function(a,c){if(!a)throw Error("Expected successCallback argument.");if(null==this.file_)if(c)c(w); +else throw w;else{var b=null==this.file_.blob_?this.file_:this.file_.blob_;b.lastModifiedDate=this.file_.lastModifiedDate;a(b)}};i.prototype=new o;i.prototype.constructor=i;i.prototype.createReader=function(){return new y(this)};i.prototype.getDirectory=function(a,c,b,d){a=q(this.fullPath,a);h.get(a,function(e){c||(c={});!0===c.create&&!0===c.exclusive&&e?d&&d(l):!0===c.create&&!e?(e=new i,e.name=a.split(g).pop(),e.fullPath=a,e.filesystem=n,h.put(e,b,d)):!0===c.create&&e?e.isDirectory?b(new i(e)): +d&&d(l):(!c.create||!1===c.create)&&!e?a==g?(e=new i,e.name="",e.fullPath=g,e.filesystem=n,b(e)):d&&d(l):(!c.create||!1===c.create)&&e&&e.isFile?d&&d(l):b(new i(e))},d)};i.prototype.getFile=function(a,c,b,d){a=q(this.fullPath,a);h.get(a,function(e){c||(c={});!0===c.create&&!0===c.exclusive&&e?d&&d(l):!0===c.create&&!e?(e=new j,e.name=a.split(g).pop(),e.fullPath=a,e.filesystem=n,e.file_=new r({size:0,name:e.name,lastModifiedDate:new Date}),h.put(e,b,d)):!0===c.create&&e?e.isFile?b(new j(e)):d&&d(l): +(!c.create||!1===c.create)&&!e?d&&d(l):(!c.create||!1===c.create)&&e&&e.isDirectory?d&&d(l):b(new j(e))},d)};i.prototype.removeRecursively=function(a,c){if(!a)throw Error("Expected successCallback argument.");this.remove(a,c)};h.open=function(a,c,b){var d=this,a=u.open(a.replace(":","_"));a.onerror=b||k;a.onupgradeneeded=function(a){d.db=a.target.result;d.db.onerror=k;d.db.objectStoreNames.contains("entries")||d.db.createObjectStore("entries")};a.onsuccess=function(a){d.db=a.target.result;d.db.onerror= +k;c(a)};a.onblocked=b||k};h.close=function(){this.db.close();this.db=null};h.drop=function(a,c){if(this.db){var b=u.deleteDatabase(this.db.name);b.onsuccess=function(b){a(b)};b.onerror=c||k;h.close()}};h.get=function(a,c,b){if(this.db){var d=this.db.transaction(["entries"],"readonly"),a=IDBKeyRange.bound(a,a+v,!1,!0),e=d.objectStore("entries").get(a);d.onabort=b||k;d.oncomplete=function(){c(e.result)}}};h.getAllEntries=function(a,c,b){if(this.db){var d=[],e=null;a!=g&&(e=IDBKeyRange.bound(a+g,a+v, +!1,!0));var f=this.db.transaction(["entries"],"readonly");f.onabort=b||k;f.oncomplete=function(){d=d.filter(function(b){var c=b.fullPath.split(g).length,d=a.split(g).length;if(a==g&&c Date: Tue, 4 Mar 2014 12:01:53 +0100 Subject: [PATCH 2/4] Add File#remove method. However, currently it's not used, as I don't know how to get notified when the file is completely saved to disk, so it can be safely removed. --- app/scripts/app/lib/file.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/app/scripts/app/lib/file.js b/app/scripts/app/lib/file.js index bbc0b4d..f5cefb6 100644 --- a/app/scripts/app/lib/file.js +++ b/app/scripts/app/lib/file.js @@ -76,7 +76,9 @@ FileDrop.File.prototype.save = function () { document.body.appendChild(a); a.click(); - this._reset(); + // TODO: figure out how to remove file once it's completely saved + // Remove file entry from filesystem + // this.remove().then(this._reset); }; FileDrop.File.prototype.errorHandler = function (error) { @@ -106,6 +108,25 @@ FileDrop.File.prototype.errorHandler = function (error) { console.error('File error: ' + msg); }; +FileDrop.File.prototype.remove = function () { + var self = this; + + return new Promise(function (resolve, reject) { + self.filesystem.root.getFile(self.name, {create: false}, function (fileEntry) { + fileEntry.remove(function () { + console.debug('File: Removed file: ' + self.name); + resolve(fileEntry); + }, function (error) { + this.errorHandler(error); + reject(error); + }); + }, function (error) { + this.errorHandler(error); + reject(error); + }); + }); +}; + FileDrop.File.prototype._reset = function () { this.create = true; this.filesystem = null; From 20a0c014207a2ccaba7c0ca647877ed1a30292f8 Mon Sep 17 00:00:00 2001 From: Szymon Nowak Date: Tue, 4 Mar 2014 22:17:29 +0100 Subject: [PATCH 3/4] Remove file from HTML5 filesystem after saving it to disk --- app/scripts/app/lib/file.js | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/app/scripts/app/lib/file.js b/app/scripts/app/lib/file.js index f5cefb6..ff7a7b1 100644 --- a/app/scripts/app/lib/file.js +++ b/app/scripts/app/lib/file.js @@ -68,17 +68,35 @@ FileDrop.File.prototype.append = function (data) { }; FileDrop.File.prototype.save = function () { + var self = this; + console.log('File: Saving file: ', this.fileEntry); var a = document.createElement('a'); a.download = this.name; - a.href = this.fileEntry.toURL(); // TODO: Add Firefox version as well - document.body.appendChild(a); - a.click(); - // TODO: figure out how to remove file once it's completely saved - // Remove file entry from filesystem - // this.remove().then(this._reset); + if (this._isWebKit()) { + a.href = this.fileEntry.toURL(); + finish(a); + } else { + this.fileEntry.file(function (file) { + a.href = window.URL.createObjectURL(file); + finish(a); + }); + } + + function finish(a) { + document.body.appendChild(a); + a.addEventListener('click', function () { + // Remove file entry from filesystem. + setTimeout(function () { + self.remove().then(self._reset); + }, 1); // Hack, but otherwise browser doesn't save the file at all. + + a.parentNode.removeChild(a); + }); + a.click(); + } }; FileDrop.File.prototype.errorHandler = function (error) { @@ -134,3 +152,7 @@ FileDrop.File.prototype._reset = function () { this.seek = 0; }; +FileDrop.File.prototype._isWebKit = function () { + return !!window.webkitRequestFileSystem; +}; + From a522621692ff04c54f1cb18d4129615b57417d0e Mon Sep 17 00:00:00 2001 From: Szymon Nowak Date: Wed, 5 Mar 2014 16:25:55 +0100 Subject: [PATCH 4/4] Clear filesystem on page load to remove any incomplete files --- app/index.html | 2 ++ app/scripts/app/lib/file.js | 37 +++++++++++++++++++++++++++------ app/scripts/initializer.js | 6 ++++++ app/scripts/vendor/filer.min.js | 16 ++++++++++++++ 4 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 app/scripts/initializer.js create mode 100644 app/scripts/vendor/filer.min.js diff --git a/app/index.html b/app/index.html index fc6835b..a380e86 100644 --- a/app/index.html +++ b/app/index.html @@ -43,6 +43,7 @@ + @@ -53,6 +54,7 @@ + diff --git a/app/scripts/app/lib/file.js b/app/scripts/app/lib/file.js index ff7a7b1..0eb72af 100644 --- a/app/scripts/app/lib/file.js +++ b/app/scripts/app/lib/file.js @@ -19,13 +19,38 @@ FileDrop.File = function (options) { resolve(self); }, function (error) { - this.errorHandler(error); + self.errorHandler(error); reject(error); } ); }); }; +FileDrop.File.removeAll = function () { + return new Promise(function (resolve, reject) { + var filer = new Filer(); + + filer.init({persistent: false}, function () { + filer.ls('/', function (entries) { + function rm(entry) { + if (entry) { + filer.rm(entry, function () { + rm(entries.pop()); + }); + } else { + resolve(); + } + } + + rm(entries.pop()); + }); + }, function (error) { + console.log(error); + reject(error); + }); + }); +}; + FileDrop.File.prototype.append = function (data) { var self = this, options = { @@ -50,18 +75,18 @@ FileDrop.File.prototype.append = function (data) { }; writer.onerror = function (error) { - this.errorHandler(error); + self.errorHandler(error); reject(error); }; writer.seek(self.seek); writer.write(blob); }, function (error) { - this.errorHandler(error); + self.errorHandler(error); reject(error); }); }, function (error) { - this.errorHandler(error); + self.errorHandler(error); reject(error); }); }); @@ -135,11 +160,11 @@ FileDrop.File.prototype.remove = function () { console.debug('File: Removed file: ' + self.name); resolve(fileEntry); }, function (error) { - this.errorHandler(error); + self.errorHandler(error); reject(error); }); }, function (error) { - this.errorHandler(error); + self.errorHandler(error); reject(error); }); }); diff --git a/app/scripts/initializer.js b/app/scripts/initializer.js new file mode 100644 index 0000000..9fffd48 --- /dev/null +++ b/app/scripts/initializer.js @@ -0,0 +1,6 @@ +// Clear HTML5 filesystem on page load +FileDrop.deferReadiness(); +FileDrop.File.removeAll().then(function () { + console.log("Cleared HTML5 filesystem"); + FileDrop.advanceReadiness(); +}); diff --git a/app/scripts/vendor/filer.min.js b/app/scripts/vendor/filer.min.js new file mode 100644 index 0000000..ca8b95e --- /dev/null +++ b/app/scripts/vendor/filer.min.js @@ -0,0 +1,16 @@ +var self=this;self.URL=self.URL||self.webkitURL;self.requestFileSystem=self.requestFileSystem||self.webkitRequestFileSystem;self.resolveLocalFileSystemURL=self.resolveLocalFileSystemURL||self.webkitResolveLocalFileSystemURL;navigator.temporaryStorage=navigator.temporaryStorage||navigator.webkitTemporaryStorage;navigator.persistentStorage=navigator.persistentStorage||navigator.webkitPersistentStorage;self.BlobBuilder=self.BlobBuilder||self.MozBlobBuilder||self.WebKitBlobBuilder; +if(void 0===self.FileError){var FileError=function(){};FileError.prototype.prototype=Error.prototype} +var Util={toArray:function(a){return Array.prototype.slice.call(a||[],0)},strToDataURL:function(a,b,c){return(void 0!=c?c:1)?"data:"+b+";base64,"+self.btoa(a):"data:"+b+","+a},strToObjectURL:function(a,b){for(var c=new Uint8Array(a.length),e=0;e