define([ "util/manos" ], function(M) { /* The File object provides storage backed by the local HDD via the chrome.fileSystem API. */ var noop = function() {}; var File = function(entry) { this.entry = entry || null; this.onWrite = noop; }; File.prototype = { open: function(mode, c) { var self = this; mode = mode || "open"; //mode is "open" or "save" var modes = { "open": "openWritableFile", "save": "saveFile" }; chrome.fileSystem.chooseEntry({ type: modes[mode] }, function(entry) { //cancelling acts like an error, but isn't. if (!entry) return c(chrome.runtime.lastError); self.entry = entry; c(null, self); }); }, read: function(c) { var self = this; if (!self.entry) { console.error(self); c("File not opened"); } var reader = new FileReader(); reader.onload = function() { c(null, reader.result); }; reader.onerror = function(err) { console.error("File read error!"); c(err); }; self.entry.file(function(f) { reader.readAsText(f); }); }, write: function(data, c) { var self = this; c = c || function() {}; if (!self.entry) { //guard against cases where we accidentally write before opening return self.open("save").then(function() { return self.write(data, c); }); } M.chain( //check permissions function(next) { chrome.fileSystem.isWritableEntry(self.entry, next); }, //if read-only, try to open as writable function(ok, next) { if (!ok) { return chrome.fileSystem.getWritableEntry(self.entry, function(entry) { if (entry) { self.entry = entry; next(); } else { c("Couldn't open file as writable"); } }); } next(); }, //write file function() { self.entry.createWriter(function(writer) { writer.onerror = function(err) { console.error(err); c(err); } writer.onwriteend = function() { //after truncation, actually write the file writer.onwriteend = function() { c(); self.onWrite(); } var blob = new Blob([data]); writer.write(blob); }; writer.truncate(0); }); } ); }, stat: function(c) { var self = this; if (self.entry) { return self.entry.file(function(f) { c(null, f); }); } c("No file entry"); }, retain: function() { return chrome.fileSystem.retainEntry(this.entry); }, restore: function(id, c) { var self = this; chrome.fileSystem.isRestorable(id, function(is) { if (is) { chrome.fileSystem.restoreEntry(id, function(entry) { if (!entry) return c("restoreEntry() failed for " + id); self.entry = entry; c(); }); } else { c("isRestorable() returned false for " + id); } }); }, getPath: function(c) { var self = this; if (!self.entry) return fail("No backing entry, cannot get path"); chrome.fileSystem.getDisplayPath(self.entry, function(path) { c(null, path); }); } }; return File; });