Adding mapbox-gl branch
This commit is contained in:
@@ -0,0 +1,272 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Wrappers for HTML5 Entry objects. These are all in the same
|
||||
* file to avoid circular dependency issues.
|
||||
*
|
||||
* When adding or modifying functionality in this namespace, be sure to update
|
||||
* the mock counterparts in goog.testing.fs.
|
||||
*
|
||||
*/
|
||||
goog.provide('goog.fs.DirectoryEntry');
|
||||
goog.provide('goog.fs.DirectoryEntry.Behavior');
|
||||
goog.provide('goog.fs.Entry');
|
||||
goog.provide('goog.fs.FileEntry');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The interface for entries in the filesystem.
|
||||
* @interface
|
||||
*/
|
||||
goog.fs.Entry = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether or not this entry is a file.
|
||||
*/
|
||||
goog.fs.Entry.prototype.isFile = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether or not this entry is a directory.
|
||||
*/
|
||||
goog.fs.Entry.prototype.isDirectory = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} The name of this entry.
|
||||
*/
|
||||
goog.fs.Entry.prototype.getName = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} The full path to this entry.
|
||||
*/
|
||||
goog.fs.Entry.prototype.getFullPath = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!goog.fs.FileSystem} The filesystem backing this entry.
|
||||
*/
|
||||
goog.fs.Entry.prototype.getFileSystem = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the last modified date for this entry.
|
||||
*
|
||||
* @return {!goog.async.Deferred} The deferred Date for this entry. If an error
|
||||
* occurs, the errback is called with a {@link goog.fs.Error}.
|
||||
*/
|
||||
goog.fs.Entry.prototype.getLastModified = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the metadata for this entry.
|
||||
*
|
||||
* @return {!goog.async.Deferred} The deferred Metadata for this entry. If an
|
||||
* error occurs, the errback is called with a {@link goog.fs.Error}.
|
||||
*/
|
||||
goog.fs.Entry.prototype.getMetadata = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Move this entry to a new location.
|
||||
*
|
||||
* @param {!goog.fs.DirectoryEntry} parent The new parent directory.
|
||||
* @param {string=} opt_newName The new name of the entry. If omitted, the entry
|
||||
* retains its original name.
|
||||
* @return {!goog.async.Deferred} The deferred {@link goog.fs.FileEntry} or
|
||||
* {@link goog.fs.DirectoryEntry} for the new entry. If an error occurs, the
|
||||
* errback is called with a {@link goog.fs.Error}.
|
||||
*/
|
||||
goog.fs.Entry.prototype.moveTo = function(parent, opt_newName) {};
|
||||
|
||||
|
||||
/**
|
||||
* Copy this entry to a new location.
|
||||
*
|
||||
* @param {!goog.fs.DirectoryEntry} parent The new parent directory.
|
||||
* @param {string=} opt_newName The name of the new entry. If omitted, the new
|
||||
* entry has the same name as the original.
|
||||
* @return {!goog.async.Deferred} The deferred {@link goog.fs.FileEntry} or
|
||||
* {@link goog.fs.DirectoryEntry} for the new entry. If an error occurs, the
|
||||
* errback is called with a {@link goog.fs.Error}.
|
||||
*/
|
||||
goog.fs.Entry.prototype.copyTo = function(parent, opt_newName) {};
|
||||
|
||||
|
||||
/**
|
||||
* Wrap an HTML5 entry object in an appropriate subclass instance.
|
||||
*
|
||||
* @param {!Entry} entry The underlying Entry object.
|
||||
* @return {!goog.fs.Entry} The appropriate subclass wrapper.
|
||||
* @protected
|
||||
*/
|
||||
goog.fs.Entry.prototype.wrapEntry = function(entry) {};
|
||||
|
||||
|
||||
/**
|
||||
* Get the URL for this file.
|
||||
*
|
||||
* @param {string=} opt_mimeType The MIME type that will be served for the URL.
|
||||
* @return {string} The URL.
|
||||
*/
|
||||
goog.fs.Entry.prototype.toUrl = function(opt_mimeType) {};
|
||||
|
||||
|
||||
/**
|
||||
* Get the URI for this file.
|
||||
*
|
||||
* @deprecated Use {@link #toUrl} instead.
|
||||
* @param {string=} opt_mimeType The MIME type that will be served for the URI.
|
||||
* @return {string} The URI.
|
||||
*/
|
||||
goog.fs.Entry.prototype.toUri = function(opt_mimeType) {};
|
||||
|
||||
|
||||
/**
|
||||
* Remove this entry.
|
||||
*
|
||||
* @return {!goog.async.Deferred} A deferred object. If the removal succeeds,
|
||||
* the callback is called with true. If an error occurs, the errback is
|
||||
* called a {@link goog.fs.Error}.
|
||||
*/
|
||||
goog.fs.Entry.prototype.remove = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the parent directory.
|
||||
*
|
||||
* @return {!goog.async.Deferred} The deferred {@link goog.fs.DirectoryEntry}.
|
||||
* If an error occurs, the errback is called with a {@link goog.fs.Error}.
|
||||
*/
|
||||
goog.fs.Entry.prototype.getParent = function() {};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A directory in a local FileSystem.
|
||||
*
|
||||
* @interface
|
||||
* @extends {goog.fs.Entry}
|
||||
*/
|
||||
goog.fs.DirectoryEntry = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Behaviors for getting files and directories.
|
||||
* @enum {number}
|
||||
*/
|
||||
goog.fs.DirectoryEntry.Behavior = {
|
||||
/**
|
||||
* Get the file if it exists, error out if it doesn't.
|
||||
*/
|
||||
DEFAULT: 1,
|
||||
/**
|
||||
* Get the file if it exists, create it if it doesn't.
|
||||
*/
|
||||
CREATE: 2,
|
||||
/**
|
||||
* Error out if the file exists, create it if it doesn't.
|
||||
*/
|
||||
CREATE_EXCLUSIVE: 3
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get a file in the directory.
|
||||
*
|
||||
* @param {string} path The path to the file, relative to this directory.
|
||||
* @param {goog.fs.DirectoryEntry.Behavior=} opt_behavior The behavior for
|
||||
* handling an existing file, or the lack thereof.
|
||||
* @return {!goog.async.Deferred} The deferred {@link goog.fs.FileEntry}. If an
|
||||
* error occurs, the errback is called with a {@link goog.fs.Error}.
|
||||
*/
|
||||
goog.fs.DirectoryEntry.prototype.getFile = function(path, opt_behavior) {};
|
||||
|
||||
|
||||
/**
|
||||
* Get a directory within this directory.
|
||||
*
|
||||
* @param {string} path The path to the directory, relative to this directory.
|
||||
* @param {goog.fs.DirectoryEntry.Behavior=} opt_behavior The behavior for
|
||||
* handling an existing directory, or the lack thereof.
|
||||
* @return {!goog.async.Deferred} The deferred {@link goog.fs.DirectoryEntry}.
|
||||
* If an error occurs, the errback is called a {@link goog.fs.Error}.
|
||||
*/
|
||||
goog.fs.DirectoryEntry.prototype.getDirectory = function(path, opt_behavior) {};
|
||||
|
||||
|
||||
/**
|
||||
* Opens the directory for the specified path, creating the directory and any
|
||||
* intermediate directories as necessary.
|
||||
*
|
||||
* @param {string} path The directory path to create. May be absolute or
|
||||
* relative to the current directory. The parent directory ".." and current
|
||||
* directory "." are supported.
|
||||
* @return {!goog.async.Deferred} A deferred {@link goog.fs.DirectoryEntry} for
|
||||
* the requested path. If an error occurs, the errback is called with a
|
||||
* {@link goog.fs.Error}.
|
||||
*/
|
||||
goog.fs.DirectoryEntry.prototype.createPath = function(path) {};
|
||||
|
||||
|
||||
/**
|
||||
* Gets a list of all entries in this directory.
|
||||
*
|
||||
* @return {!goog.async.Deferred} The deferred list of {@link goog.fs.Entry}
|
||||
* results. If an error occurs, the errback is called with a
|
||||
* {@link goog.fs.Error}.
|
||||
*/
|
||||
goog.fs.DirectoryEntry.prototype.listDirectory = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Removes this directory and all its contents.
|
||||
*
|
||||
* @return {!goog.async.Deferred} A deferred object. If the removal succeeds,
|
||||
* the callback is called with true. If an error occurs, the errback is
|
||||
* called a {@link goog.fs.Error}.
|
||||
*/
|
||||
goog.fs.DirectoryEntry.prototype.removeRecursively = function() {};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A file in a local filesystem.
|
||||
*
|
||||
* @interface
|
||||
* @extends {goog.fs.Entry}
|
||||
*/
|
||||
goog.fs.FileEntry = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Create a writer for writing to the file.
|
||||
*
|
||||
* @return {!goog.async.Deferred<!goog.fs.FileWriter>} If an error occurs, the
|
||||
* errback is called with a {@link goog.fs.Error}.
|
||||
*/
|
||||
goog.fs.FileEntry.prototype.createWriter = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Get the file contents as a File blob.
|
||||
*
|
||||
* @return {!goog.async.Deferred<!File>} If an error occurs, the errback is
|
||||
* called with a {@link goog.fs.Error}.
|
||||
*/
|
||||
goog.fs.FileEntry.prototype.file = function() {};
|
||||
@@ -0,0 +1,405 @@
|
||||
// Copyright 2013 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Concrete implementations of the
|
||||
* goog.fs.DirectoryEntry, and goog.fs.FileEntry interfaces.
|
||||
*/
|
||||
goog.provide('goog.fs.DirectoryEntryImpl');
|
||||
goog.provide('goog.fs.EntryImpl');
|
||||
goog.provide('goog.fs.FileEntryImpl');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.async.Deferred');
|
||||
goog.require('goog.fs.DirectoryEntry');
|
||||
goog.require('goog.fs.Entry');
|
||||
goog.require('goog.fs.Error');
|
||||
goog.require('goog.fs.FileEntry');
|
||||
goog.require('goog.fs.FileWriter');
|
||||
goog.require('goog.functions');
|
||||
goog.require('goog.string');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Base class for concrete implementations of goog.fs.Entry.
|
||||
* @param {!goog.fs.FileSystem} fs The wrapped filesystem.
|
||||
* @param {!Entry} entry The underlying Entry object.
|
||||
* @constructor
|
||||
* @implements {goog.fs.Entry}
|
||||
*/
|
||||
goog.fs.EntryImpl = function(fs, entry) {
|
||||
/**
|
||||
* The wrapped filesystem.
|
||||
*
|
||||
* @type {!goog.fs.FileSystem}
|
||||
* @private
|
||||
*/
|
||||
this.fs_ = fs;
|
||||
|
||||
/**
|
||||
* The underlying Entry object.
|
||||
*
|
||||
* @type {!Entry}
|
||||
* @private
|
||||
*/
|
||||
this.entry_ = entry;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.EntryImpl.prototype.isFile = function() {
|
||||
return this.entry_.isFile;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.EntryImpl.prototype.isDirectory = function() {
|
||||
return this.entry_.isDirectory;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.EntryImpl.prototype.getName = function() {
|
||||
return this.entry_.name;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.EntryImpl.prototype.getFullPath = function() {
|
||||
return this.entry_.fullPath;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.EntryImpl.prototype.getFileSystem = function() {
|
||||
return this.fs_;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.EntryImpl.prototype.getLastModified = function() {
|
||||
return this.getMetadata().addCallback(function(metadata) {
|
||||
return metadata.modificationTime;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.EntryImpl.prototype.getMetadata = function() {
|
||||
var d = new goog.async.Deferred();
|
||||
|
||||
this.entry_.getMetadata(
|
||||
function(metadata) { d.callback(metadata); },
|
||||
goog.bind(function(err) {
|
||||
var msg = 'retrieving metadata for ' + this.getFullPath();
|
||||
d.errback(new goog.fs.Error(err, msg));
|
||||
}, this));
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.EntryImpl.prototype.moveTo = function(parent, opt_newName) {
|
||||
var d = new goog.async.Deferred();
|
||||
this.entry_.moveTo(
|
||||
parent.dir_, opt_newName,
|
||||
goog.bind(function(entry) { d.callback(this.wrapEntry(entry)); }, this),
|
||||
goog.bind(function(err) {
|
||||
var msg = 'moving ' + this.getFullPath() + ' into ' +
|
||||
parent.getFullPath() +
|
||||
(opt_newName ? ', renaming to ' + opt_newName : '');
|
||||
d.errback(new goog.fs.Error(err, msg));
|
||||
}, this));
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.EntryImpl.prototype.copyTo = function(parent, opt_newName) {
|
||||
var d = new goog.async.Deferred();
|
||||
this.entry_.copyTo(
|
||||
parent.dir_, opt_newName,
|
||||
goog.bind(function(entry) { d.callback(this.wrapEntry(entry)); }, this),
|
||||
goog.bind(function(err) {
|
||||
var msg = 'copying ' + this.getFullPath() + ' into ' +
|
||||
parent.getFullPath() +
|
||||
(opt_newName ? ', renaming to ' + opt_newName : '');
|
||||
d.errback(new goog.fs.Error(err, msg));
|
||||
}, this));
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.EntryImpl.prototype.wrapEntry = function(entry) {
|
||||
return entry.isFile ?
|
||||
new goog.fs.FileEntryImpl(this.fs_, /** @type {!FileEntry} */ (entry)) :
|
||||
new goog.fs.DirectoryEntryImpl(
|
||||
this.fs_, /** @type {!DirectoryEntry} */ (entry));
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.EntryImpl.prototype.toUrl = function(opt_mimeType) {
|
||||
return this.entry_.toURL(opt_mimeType);
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.EntryImpl.prototype.toUri = goog.fs.EntryImpl.prototype.toUrl;
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.EntryImpl.prototype.remove = function() {
|
||||
var d = new goog.async.Deferred();
|
||||
this.entry_.remove(
|
||||
goog.bind(d.callback, d, true /* result */),
|
||||
goog.bind(function(err) {
|
||||
var msg = 'removing ' + this.getFullPath();
|
||||
d.errback(new goog.fs.Error(err, msg));
|
||||
}, this));
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.EntryImpl.prototype.getParent = function() {
|
||||
var d = new goog.async.Deferred();
|
||||
this.entry_.getParent(
|
||||
goog.bind(function(parent) {
|
||||
d.callback(new goog.fs.DirectoryEntryImpl(this.fs_, parent));
|
||||
}, this),
|
||||
goog.bind(function(err) {
|
||||
var msg = 'getting parent of ' + this.getFullPath();
|
||||
d.errback(new goog.fs.Error(err, msg));
|
||||
}, this));
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A directory in a local FileSystem.
|
||||
*
|
||||
* This should not be instantiated directly. Instead, it should be accessed via
|
||||
* {@link goog.fs.FileSystem#getRoot} or
|
||||
* {@link goog.fs.DirectoryEntry#getDirectoryEntry}.
|
||||
*
|
||||
* @param {!goog.fs.FileSystem} fs The wrapped filesystem.
|
||||
* @param {!DirectoryEntry} dir The underlying DirectoryEntry object.
|
||||
* @constructor
|
||||
* @extends {goog.fs.EntryImpl}
|
||||
* @implements {goog.fs.DirectoryEntry}
|
||||
* @final
|
||||
*/
|
||||
goog.fs.DirectoryEntryImpl = function(fs, dir) {
|
||||
goog.fs.DirectoryEntryImpl.base(this, 'constructor', fs, dir);
|
||||
|
||||
/**
|
||||
* The underlying DirectoryEntry object.
|
||||
*
|
||||
* @type {!DirectoryEntry}
|
||||
* @private
|
||||
*/
|
||||
this.dir_ = dir;
|
||||
};
|
||||
goog.inherits(goog.fs.DirectoryEntryImpl, goog.fs.EntryImpl);
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.DirectoryEntryImpl.prototype.getFile = function(path, opt_behavior) {
|
||||
var d = new goog.async.Deferred();
|
||||
this.dir_.getFile(
|
||||
path, this.getOptions_(opt_behavior),
|
||||
goog.bind(function(entry) {
|
||||
d.callback(new goog.fs.FileEntryImpl(this.fs_, entry));
|
||||
}, this),
|
||||
goog.bind(function(err) {
|
||||
var msg = 'loading file ' + path + ' from ' + this.getFullPath();
|
||||
d.errback(new goog.fs.Error(err, msg));
|
||||
}, this));
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.DirectoryEntryImpl.prototype.getDirectory =
|
||||
function(path, opt_behavior) {
|
||||
var d = new goog.async.Deferred();
|
||||
this.dir_.getDirectory(
|
||||
path, this.getOptions_(opt_behavior),
|
||||
goog.bind(function(entry) {
|
||||
d.callback(new goog.fs.DirectoryEntryImpl(this.fs_, entry));
|
||||
}, this),
|
||||
goog.bind(function(err) {
|
||||
var msg = 'loading directory ' + path + ' from ' + this.getFullPath();
|
||||
d.errback(new goog.fs.Error(err, msg));
|
||||
}, this));
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.DirectoryEntryImpl.prototype.createPath = function(path) {
|
||||
// If the path begins at the root, reinvoke createPath on the root directory.
|
||||
if (goog.string.startsWith(path, '/')) {
|
||||
var root = this.getFileSystem().getRoot();
|
||||
if (this.getFullPath() != root.getFullPath()) {
|
||||
return root.createPath(path);
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out any empty path components caused by '//' or a leading slash.
|
||||
var parts = goog.array.filter(path.split('/'), goog.functions.identity);
|
||||
var existed = [];
|
||||
|
||||
/**
|
||||
* @param {goog.fs.DirectoryEntryImpl} dir
|
||||
* @return {!goog.async.Deferred}
|
||||
*/
|
||||
function getNextDirectory(dir) {
|
||||
if (!parts.length) {
|
||||
return goog.async.Deferred.succeed(dir);
|
||||
}
|
||||
|
||||
var def;
|
||||
var nextDir = parts.shift();
|
||||
|
||||
if (nextDir == '..') {
|
||||
def = dir.getParent();
|
||||
} else if (nextDir == '.') {
|
||||
def = goog.async.Deferred.succeed(dir);
|
||||
} else {
|
||||
def = dir.getDirectory(nextDir, goog.fs.DirectoryEntry.Behavior.CREATE);
|
||||
}
|
||||
return def.addCallback(getNextDirectory);
|
||||
}
|
||||
|
||||
return getNextDirectory(this);
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.DirectoryEntryImpl.prototype.listDirectory = function() {
|
||||
var d = new goog.async.Deferred();
|
||||
var reader = this.dir_.createReader();
|
||||
var results = [];
|
||||
|
||||
var errorCallback = goog.bind(function(err) {
|
||||
var msg = 'listing directory ' + this.getFullPath();
|
||||
d.errback(new goog.fs.Error(err, msg));
|
||||
}, this);
|
||||
|
||||
var successCallback = goog.bind(function(entries) {
|
||||
if (entries.length) {
|
||||
for (var i = 0, entry; entry = entries[i]; i++) {
|
||||
results.push(this.wrapEntry(entry));
|
||||
}
|
||||
reader.readEntries(successCallback, errorCallback);
|
||||
} else {
|
||||
d.callback(results);
|
||||
}
|
||||
}, this);
|
||||
|
||||
reader.readEntries(successCallback, errorCallback);
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.DirectoryEntryImpl.prototype.removeRecursively = function() {
|
||||
var d = new goog.async.Deferred();
|
||||
this.dir_.removeRecursively(
|
||||
goog.bind(d.callback, d, true /* result */),
|
||||
goog.bind(function(err) {
|
||||
var msg = 'removing ' + this.getFullPath() + ' recursively';
|
||||
d.errback(new goog.fs.Error(err, msg));
|
||||
}, this));
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts a value in the Behavior enum into an options object expected by the
|
||||
* File API.
|
||||
*
|
||||
* @param {goog.fs.DirectoryEntry.Behavior=} opt_behavior The behavior for
|
||||
* existing files.
|
||||
* @return {!Object<boolean>} The options object expected by the File API.
|
||||
* @private
|
||||
*/
|
||||
goog.fs.DirectoryEntryImpl.prototype.getOptions_ = function(opt_behavior) {
|
||||
if (opt_behavior == goog.fs.DirectoryEntry.Behavior.CREATE) {
|
||||
return {'create': true};
|
||||
} else if (opt_behavior == goog.fs.DirectoryEntry.Behavior.CREATE_EXCLUSIVE) {
|
||||
return {'create': true, 'exclusive': true};
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A file in a local filesystem.
|
||||
*
|
||||
* This should not be instantiated directly. Instead, it should be accessed via
|
||||
* {@link goog.fs.DirectoryEntry#getFile}.
|
||||
*
|
||||
* @param {!goog.fs.FileSystem} fs The wrapped filesystem.
|
||||
* @param {!FileEntry} file The underlying FileEntry object.
|
||||
* @constructor
|
||||
* @extends {goog.fs.EntryImpl}
|
||||
* @implements {goog.fs.FileEntry}
|
||||
* @final
|
||||
*/
|
||||
goog.fs.FileEntryImpl = function(fs, file) {
|
||||
goog.fs.FileEntryImpl.base(this, 'constructor', fs, file);
|
||||
|
||||
/**
|
||||
* The underlying FileEntry object.
|
||||
*
|
||||
* @type {!FileEntry}
|
||||
* @private
|
||||
*/
|
||||
this.file_ = file;
|
||||
};
|
||||
goog.inherits(goog.fs.FileEntryImpl, goog.fs.EntryImpl);
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.FileEntryImpl.prototype.createWriter = function() {
|
||||
var d = new goog.async.Deferred();
|
||||
this.file_.createWriter(
|
||||
function(w) { d.callback(new goog.fs.FileWriter(w)); },
|
||||
goog.bind(function(err) {
|
||||
var msg = 'creating writer for ' + this.getFullPath();
|
||||
d.errback(new goog.fs.Error(err, msg));
|
||||
}, this));
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.FileEntryImpl.prototype.file = function() {
|
||||
var d = new goog.async.Deferred();
|
||||
this.file_.file(
|
||||
function(f) { d.callback(f); },
|
||||
goog.bind(function(err) {
|
||||
var msg = 'getting file for ' + this.getFullPath();
|
||||
d.errback(new goog.fs.Error(err, msg));
|
||||
}, this));
|
||||
return d;
|
||||
};
|
||||
@@ -0,0 +1,181 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview A wrapper for the HTML5 FileError object.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.fs.Error');
|
||||
goog.provide('goog.fs.Error.ErrorCode');
|
||||
|
||||
goog.require('goog.debug.Error');
|
||||
goog.require('goog.object');
|
||||
goog.require('goog.string');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A filesystem error. Since the filesystem API is asynchronous, stack traces
|
||||
* are less useful for identifying where errors come from, so this includes a
|
||||
* large amount of metadata in the message.
|
||||
*
|
||||
* @param {!DOMError} error
|
||||
* @param {string} action The action being undertaken when the error was raised.
|
||||
* @constructor
|
||||
* @extends {goog.debug.Error}
|
||||
* @final
|
||||
*/
|
||||
goog.fs.Error = function(error, action) {
|
||||
/** @type {string} */
|
||||
this.name;
|
||||
|
||||
/**
|
||||
* @type {goog.fs.Error.ErrorCode}
|
||||
* @deprecated Use the 'name' or 'message' field instead.
|
||||
*/
|
||||
this.code;
|
||||
|
||||
if (goog.isDef(error.name)) {
|
||||
this.name = error.name;
|
||||
// TODO(user): Remove warning suppression after JSCompiler stops
|
||||
// firing a spurious warning here.
|
||||
/** @suppress {deprecated} */
|
||||
this.code = goog.fs.Error.getCodeFromName_(error.name);
|
||||
} else {
|
||||
this.code = error.code;
|
||||
this.name = goog.fs.Error.getNameFromCode_(error.code);
|
||||
}
|
||||
goog.fs.Error.base(this, 'constructor',
|
||||
goog.string.subs('%s %s', this.name, action));
|
||||
};
|
||||
goog.inherits(goog.fs.Error, goog.debug.Error);
|
||||
|
||||
|
||||
/**
|
||||
* Names of errors that may be thrown by the File API, the File System API, or
|
||||
* the File Writer API.
|
||||
*
|
||||
* @see http://dev.w3.org/2006/webapi/FileAPI/#ErrorAndException
|
||||
* @see http://www.w3.org/TR/file-system-api/#definitions
|
||||
* @see http://dev.w3.org/2009/dap/file-system/file-writer.html#definitions
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.fs.Error.ErrorName = {
|
||||
ABORT: 'AbortError',
|
||||
ENCODING: 'EncodingError',
|
||||
INVALID_MODIFICATION: 'InvalidModificationError',
|
||||
INVALID_STATE: 'InvalidStateError',
|
||||
NOT_FOUND: 'NotFoundError',
|
||||
NOT_READABLE: 'NotReadableError',
|
||||
NO_MODIFICATION_ALLOWED: 'NoModificationAllowedError',
|
||||
PATH_EXISTS: 'PathExistsError',
|
||||
QUOTA_EXCEEDED: 'QuotaExceededError',
|
||||
SECURITY: 'SecurityError',
|
||||
SYNTAX: 'SyntaxError',
|
||||
TYPE_MISMATCH: 'TypeMismatchError'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Error codes for file errors.
|
||||
* @see http://www.w3.org/TR/file-system-api/#idl-def-FileException
|
||||
*
|
||||
* @enum {number}
|
||||
* @deprecated Use the 'name' or 'message' attribute instead.
|
||||
*/
|
||||
goog.fs.Error.ErrorCode = {
|
||||
NOT_FOUND: 1,
|
||||
SECURITY: 2,
|
||||
ABORT: 3,
|
||||
NOT_READABLE: 4,
|
||||
ENCODING: 5,
|
||||
NO_MODIFICATION_ALLOWED: 6,
|
||||
INVALID_STATE: 7,
|
||||
SYNTAX: 8,
|
||||
INVALID_MODIFICATION: 9,
|
||||
QUOTA_EXCEEDED: 10,
|
||||
TYPE_MISMATCH: 11,
|
||||
PATH_EXISTS: 12
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.fs.Error.ErrorCode} code
|
||||
* @return {string} name
|
||||
* @private
|
||||
*/
|
||||
goog.fs.Error.getNameFromCode_ = function(code) {
|
||||
var name = goog.object.findKey(goog.fs.Error.NameToCodeMap_, function(c) {
|
||||
return code == c;
|
||||
});
|
||||
if (!goog.isDef(name)) {
|
||||
throw new Error('Invalid code: ' + code);
|
||||
}
|
||||
return name;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the code that corresponds to the given name.
|
||||
* @param {string} name
|
||||
* @return {goog.fs.Error.ErrorCode} code
|
||||
* @private
|
||||
*/
|
||||
goog.fs.Error.getCodeFromName_ = function(name) {
|
||||
return goog.fs.Error.NameToCodeMap_[name];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Mapping from error names to values from the ErrorCode enum.
|
||||
* @see http://www.w3.org/TR/file-system-api/#definitions.
|
||||
* @private {!Object<string, goog.fs.Error.ErrorCode>}
|
||||
*/
|
||||
goog.fs.Error.NameToCodeMap_ = goog.object.create(
|
||||
goog.fs.Error.ErrorName.ABORT,
|
||||
goog.fs.Error.ErrorCode.ABORT,
|
||||
|
||||
goog.fs.Error.ErrorName.ENCODING,
|
||||
goog.fs.Error.ErrorCode.ENCODING,
|
||||
|
||||
goog.fs.Error.ErrorName.INVALID_MODIFICATION,
|
||||
goog.fs.Error.ErrorCode.INVALID_MODIFICATION,
|
||||
|
||||
goog.fs.Error.ErrorName.INVALID_STATE,
|
||||
goog.fs.Error.ErrorCode.INVALID_STATE,
|
||||
|
||||
goog.fs.Error.ErrorName.NOT_FOUND,
|
||||
goog.fs.Error.ErrorCode.NOT_FOUND,
|
||||
|
||||
goog.fs.Error.ErrorName.NOT_READABLE,
|
||||
goog.fs.Error.ErrorCode.NOT_READABLE,
|
||||
|
||||
goog.fs.Error.ErrorName.NO_MODIFICATION_ALLOWED,
|
||||
goog.fs.Error.ErrorCode.NO_MODIFICATION_ALLOWED,
|
||||
|
||||
goog.fs.Error.ErrorName.PATH_EXISTS,
|
||||
goog.fs.Error.ErrorCode.PATH_EXISTS,
|
||||
|
||||
goog.fs.Error.ErrorName.QUOTA_EXCEEDED,
|
||||
goog.fs.Error.ErrorCode.QUOTA_EXCEEDED,
|
||||
|
||||
goog.fs.Error.ErrorName.SECURITY,
|
||||
goog.fs.Error.ErrorCode.SECURITY,
|
||||
|
||||
goog.fs.Error.ErrorName.SYNTAX,
|
||||
goog.fs.Error.ErrorCode.SYNTAX,
|
||||
|
||||
goog.fs.Error.ErrorName.TYPE_MISMATCH,
|
||||
goog.fs.Error.ErrorCode.TYPE_MISMATCH);
|
||||
@@ -0,0 +1,288 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview A wrapper for the HTML5 FileReader object.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.fs.FileReader');
|
||||
goog.provide('goog.fs.FileReader.EventType');
|
||||
goog.provide('goog.fs.FileReader.ReadyState');
|
||||
|
||||
goog.require('goog.async.Deferred');
|
||||
goog.require('goog.events.EventTarget');
|
||||
goog.require('goog.fs.Error');
|
||||
goog.require('goog.fs.ProgressEvent');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An object for monitoring the reading of files. This emits ProgressEvents of
|
||||
* the types listed in {@link goog.fs.FileReader.EventType}.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {goog.events.EventTarget}
|
||||
* @final
|
||||
*/
|
||||
goog.fs.FileReader = function() {
|
||||
goog.fs.FileReader.base(this, 'constructor');
|
||||
|
||||
/**
|
||||
* The underlying FileReader object.
|
||||
*
|
||||
* @type {!FileReader}
|
||||
* @private
|
||||
*/
|
||||
this.reader_ = new FileReader();
|
||||
|
||||
this.reader_.onloadstart = goog.bind(this.dispatchProgressEvent_, this);
|
||||
this.reader_.onprogress = goog.bind(this.dispatchProgressEvent_, this);
|
||||
this.reader_.onload = goog.bind(this.dispatchProgressEvent_, this);
|
||||
this.reader_.onabort = goog.bind(this.dispatchProgressEvent_, this);
|
||||
this.reader_.onerror = goog.bind(this.dispatchProgressEvent_, this);
|
||||
this.reader_.onloadend = goog.bind(this.dispatchProgressEvent_, this);
|
||||
};
|
||||
goog.inherits(goog.fs.FileReader, goog.events.EventTarget);
|
||||
|
||||
|
||||
/**
|
||||
* Possible states for a FileReader.
|
||||
*
|
||||
* @enum {number}
|
||||
*/
|
||||
goog.fs.FileReader.ReadyState = {
|
||||
/**
|
||||
* The object has been constructed, but there is no pending read.
|
||||
*/
|
||||
INIT: 0,
|
||||
/**
|
||||
* Data is being read.
|
||||
*/
|
||||
LOADING: 1,
|
||||
/**
|
||||
* The data has been read from the file, the read was aborted, or an error
|
||||
* occurred.
|
||||
*/
|
||||
DONE: 2
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Events emitted by a FileReader.
|
||||
*
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.fs.FileReader.EventType = {
|
||||
/**
|
||||
* Emitted when the reading begins. readyState will be LOADING.
|
||||
*/
|
||||
LOAD_START: 'loadstart',
|
||||
/**
|
||||
* Emitted when progress has been made in reading the file. readyState will be
|
||||
* LOADING.
|
||||
*/
|
||||
PROGRESS: 'progress',
|
||||
/**
|
||||
* Emitted when the data has been successfully read. readyState will be
|
||||
* LOADING.
|
||||
*/
|
||||
LOAD: 'load',
|
||||
/**
|
||||
* Emitted when the reading has been aborted. readyState will be LOADING.
|
||||
*/
|
||||
ABORT: 'abort',
|
||||
/**
|
||||
* Emitted when an error is encountered or the reading has been aborted.
|
||||
* readyState will be LOADING.
|
||||
*/
|
||||
ERROR: 'error',
|
||||
/**
|
||||
* Emitted when the reading is finished, whether successfully or not.
|
||||
* readyState will be DONE.
|
||||
*/
|
||||
LOAD_END: 'loadend'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Abort the reading of the file.
|
||||
*/
|
||||
goog.fs.FileReader.prototype.abort = function() {
|
||||
try {
|
||||
this.reader_.abort();
|
||||
} catch (e) {
|
||||
throw new goog.fs.Error(e, 'aborting read');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {goog.fs.FileReader.ReadyState} The current state of the FileReader.
|
||||
*/
|
||||
goog.fs.FileReader.prototype.getReadyState = function() {
|
||||
return /** @type {goog.fs.FileReader.ReadyState} */ (this.reader_.readyState);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {*} The result of the file read.
|
||||
*/
|
||||
goog.fs.FileReader.prototype.getResult = function() {
|
||||
return this.reader_.result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {goog.fs.Error} The error encountered while reading, if any.
|
||||
*/
|
||||
goog.fs.FileReader.prototype.getError = function() {
|
||||
return this.reader_.error &&
|
||||
new goog.fs.Error(this.reader_.error, 'reading file');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Wrap a progress event emitted by the underlying file reader and re-emit it.
|
||||
*
|
||||
* @param {!ProgressEvent} event The underlying event.
|
||||
* @private
|
||||
*/
|
||||
goog.fs.FileReader.prototype.dispatchProgressEvent_ = function(event) {
|
||||
this.dispatchEvent(new goog.fs.ProgressEvent(event, this));
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.FileReader.prototype.disposeInternal = function() {
|
||||
goog.fs.FileReader.base(this, 'disposeInternal');
|
||||
delete this.reader_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Starts reading a blob as a binary string.
|
||||
* @param {!Blob} blob The blob to read.
|
||||
*/
|
||||
goog.fs.FileReader.prototype.readAsBinaryString = function(blob) {
|
||||
this.reader_.readAsBinaryString(blob);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Reads a blob as a binary string.
|
||||
* @param {!Blob} blob The blob to read.
|
||||
* @return {!goog.async.Deferred} The deferred Blob contents as a binary string.
|
||||
* If an error occurs, the errback is called with a {@link goog.fs.Error}.
|
||||
*/
|
||||
goog.fs.FileReader.readAsBinaryString = function(blob) {
|
||||
var reader = new goog.fs.FileReader();
|
||||
var d = goog.fs.FileReader.createDeferred_(reader);
|
||||
reader.readAsBinaryString(blob);
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Starts reading a blob as an array buffer.
|
||||
* @param {!Blob} blob The blob to read.
|
||||
*/
|
||||
goog.fs.FileReader.prototype.readAsArrayBuffer = function(blob) {
|
||||
this.reader_.readAsArrayBuffer(blob);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Reads a blob as an array buffer.
|
||||
* @param {!Blob} blob The blob to read.
|
||||
* @return {!goog.async.Deferred} The deferred Blob contents as an array buffer.
|
||||
* If an error occurs, the errback is called with a {@link goog.fs.Error}.
|
||||
*/
|
||||
goog.fs.FileReader.readAsArrayBuffer = function(blob) {
|
||||
var reader = new goog.fs.FileReader();
|
||||
var d = goog.fs.FileReader.createDeferred_(reader);
|
||||
reader.readAsArrayBuffer(blob);
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Starts reading a blob as text.
|
||||
* @param {!Blob} blob The blob to read.
|
||||
* @param {string=} opt_encoding The name of the encoding to use.
|
||||
*/
|
||||
goog.fs.FileReader.prototype.readAsText = function(blob, opt_encoding) {
|
||||
this.reader_.readAsText(blob, opt_encoding);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Reads a blob as text.
|
||||
* @param {!Blob} blob The blob to read.
|
||||
* @param {string=} opt_encoding The name of the encoding to use.
|
||||
* @return {!goog.async.Deferred} The deferred Blob contents as text.
|
||||
* If an error occurs, the errback is called with a {@link goog.fs.Error}.
|
||||
*/
|
||||
goog.fs.FileReader.readAsText = function(blob, opt_encoding) {
|
||||
var reader = new goog.fs.FileReader();
|
||||
var d = goog.fs.FileReader.createDeferred_(reader);
|
||||
reader.readAsText(blob, opt_encoding);
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Starts reading a blob as a data URL.
|
||||
* @param {!Blob} blob The blob to read.
|
||||
*/
|
||||
goog.fs.FileReader.prototype.readAsDataUrl = function(blob) {
|
||||
this.reader_.readAsDataURL(blob);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Reads a blob as a data URL.
|
||||
* @param {!Blob} blob The blob to read.
|
||||
* @return {!goog.async.Deferred} The deferred Blob contents as a data URL.
|
||||
* If an error occurs, the errback is called with a {@link goog.fs.Error}.
|
||||
*/
|
||||
goog.fs.FileReader.readAsDataUrl = function(blob) {
|
||||
var reader = new goog.fs.FileReader();
|
||||
var d = goog.fs.FileReader.createDeferred_(reader);
|
||||
reader.readAsDataUrl(blob);
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new deferred object for the results of a read method.
|
||||
* @param {goog.fs.FileReader} reader The reader to create a deferred for.
|
||||
* @return {!goog.async.Deferred} The deferred results.
|
||||
* @private
|
||||
*/
|
||||
goog.fs.FileReader.createDeferred_ = function(reader) {
|
||||
var deferred = new goog.async.Deferred();
|
||||
reader.listen(goog.fs.FileReader.EventType.LOAD_END,
|
||||
goog.partial(function(d, r, e) {
|
||||
var result = r.getResult();
|
||||
var error = r.getError();
|
||||
if (result != null && !error) {
|
||||
d.callback(result);
|
||||
} else {
|
||||
d.errback(error);
|
||||
}
|
||||
r.dispose();
|
||||
}, deferred, reader));
|
||||
return deferred;
|
||||
};
|
||||
@@ -0,0 +1,166 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview A wrapper for the HTML5 FileSaver object.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.fs.FileSaver');
|
||||
goog.provide('goog.fs.FileSaver.EventType');
|
||||
goog.provide('goog.fs.FileSaver.ReadyState');
|
||||
|
||||
goog.require('goog.events.EventTarget');
|
||||
goog.require('goog.fs.Error');
|
||||
goog.require('goog.fs.ProgressEvent');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An object for monitoring the saving of files. This emits ProgressEvents of
|
||||
* the types listed in {@link goog.fs.FileSaver.EventType}.
|
||||
*
|
||||
* This should not be instantiated directly. Instead, its subclass
|
||||
* {@link goog.fs.FileWriter} should be accessed via
|
||||
* {@link goog.fs.FileEntry#createWriter}.
|
||||
*
|
||||
* @param {!FileSaver} fileSaver The underlying FileSaver object.
|
||||
* @constructor
|
||||
* @extends {goog.events.EventTarget}
|
||||
*/
|
||||
goog.fs.FileSaver = function(fileSaver) {
|
||||
goog.fs.FileSaver.base(this, 'constructor');
|
||||
|
||||
/**
|
||||
* The underlying FileSaver object.
|
||||
*
|
||||
* @type {!FileSaver}
|
||||
* @private
|
||||
*/
|
||||
this.saver_ = fileSaver;
|
||||
|
||||
this.saver_.onwritestart = goog.bind(this.dispatchProgressEvent_, this);
|
||||
this.saver_.onprogress = goog.bind(this.dispatchProgressEvent_, this);
|
||||
this.saver_.onwrite = goog.bind(this.dispatchProgressEvent_, this);
|
||||
this.saver_.onabort = goog.bind(this.dispatchProgressEvent_, this);
|
||||
this.saver_.onerror = goog.bind(this.dispatchProgressEvent_, this);
|
||||
this.saver_.onwriteend = goog.bind(this.dispatchProgressEvent_, this);
|
||||
};
|
||||
goog.inherits(goog.fs.FileSaver, goog.events.EventTarget);
|
||||
|
||||
|
||||
/**
|
||||
* Possible states for a FileSaver.
|
||||
*
|
||||
* @enum {number}
|
||||
*/
|
||||
goog.fs.FileSaver.ReadyState = {
|
||||
/**
|
||||
* The object has been constructed, but there is no pending write.
|
||||
*/
|
||||
INIT: 0,
|
||||
/**
|
||||
* Data is being written.
|
||||
*/
|
||||
WRITING: 1,
|
||||
/**
|
||||
* The data has been written to the file, the write was aborted, or an error
|
||||
* occurred.
|
||||
*/
|
||||
DONE: 2
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Events emitted by a FileSaver.
|
||||
*
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.fs.FileSaver.EventType = {
|
||||
/**
|
||||
* Emitted when the writing begins. readyState will be WRITING.
|
||||
*/
|
||||
WRITE_START: 'writestart',
|
||||
/**
|
||||
* Emitted when progress has been made in saving the file. readyState will be
|
||||
* WRITING.
|
||||
*/
|
||||
PROGRESS: 'progress',
|
||||
/**
|
||||
* Emitted when the data has been successfully written. readyState will be
|
||||
* WRITING.
|
||||
*/
|
||||
WRITE: 'write',
|
||||
/**
|
||||
* Emitted when the writing has been aborted. readyState will be WRITING.
|
||||
*/
|
||||
ABORT: 'abort',
|
||||
/**
|
||||
* Emitted when an error is encountered or the writing has been aborted.
|
||||
* readyState will be WRITING.
|
||||
*/
|
||||
ERROR: 'error',
|
||||
/**
|
||||
* Emitted when the writing is finished, whether successfully or not.
|
||||
* readyState will be DONE.
|
||||
*/
|
||||
WRITE_END: 'writeend'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Abort the writing of the file.
|
||||
*/
|
||||
goog.fs.FileSaver.prototype.abort = function() {
|
||||
try {
|
||||
this.saver_.abort();
|
||||
} catch (e) {
|
||||
throw new goog.fs.Error(e, 'aborting save');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {goog.fs.FileSaver.ReadyState} The current state of the FileSaver.
|
||||
*/
|
||||
goog.fs.FileSaver.prototype.getReadyState = function() {
|
||||
return /** @type {goog.fs.FileSaver.ReadyState} */ (this.saver_.readyState);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {goog.fs.Error} The error encountered while writing, if any.
|
||||
*/
|
||||
goog.fs.FileSaver.prototype.getError = function() {
|
||||
return this.saver_.error &&
|
||||
new goog.fs.Error(this.saver_.error, 'saving file');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Wrap a progress event emitted by the underlying file saver and re-emit it.
|
||||
*
|
||||
* @param {!ProgressEvent} event The underlying event.
|
||||
* @private
|
||||
*/
|
||||
goog.fs.FileSaver.prototype.dispatchProgressEvent_ = function(event) {
|
||||
this.dispatchEvent(new goog.fs.ProgressEvent(event, this));
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.FileSaver.prototype.disposeInternal = function() {
|
||||
delete this.saver_;
|
||||
goog.fs.FileSaver.base(this, 'disposeInternal');
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview A wrapper for the HTML5 FileSystem object.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.fs.FileSystem');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A local filesystem.
|
||||
*
|
||||
* @interface
|
||||
*/
|
||||
goog.fs.FileSystem = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} The name of the filesystem.
|
||||
*/
|
||||
goog.fs.FileSystem.prototype.getName = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!goog.fs.DirectoryEntry} The root directory of the filesystem.
|
||||
*/
|
||||
goog.fs.FileSystem.prototype.getRoot = function() {};
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright 2013 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Concrete implementation of the goog.fs.FileSystem interface
|
||||
* using an HTML FileSystem object.
|
||||
*/
|
||||
goog.provide('goog.fs.FileSystemImpl');
|
||||
|
||||
goog.require('goog.fs.DirectoryEntryImpl');
|
||||
goog.require('goog.fs.FileSystem');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A local filesystem.
|
||||
*
|
||||
* This shouldn't be instantiated directly. Instead, it should be accessed via
|
||||
* {@link goog.fs.getTemporary} or {@link goog.fs.getPersistent}.
|
||||
*
|
||||
* @param {!FileSystem} fs The underlying FileSystem object.
|
||||
* @constructor
|
||||
* @implements {goog.fs.FileSystem}
|
||||
* @final
|
||||
*/
|
||||
goog.fs.FileSystemImpl = function(fs) {
|
||||
/**
|
||||
* The underlying FileSystem object.
|
||||
*
|
||||
* @type {!FileSystem}
|
||||
* @private
|
||||
*/
|
||||
this.fs_ = fs;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.FileSystemImpl.prototype.getName = function() {
|
||||
return this.fs_.name;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.fs.FileSystemImpl.prototype.getRoot = function() {
|
||||
return new goog.fs.DirectoryEntryImpl(this, this.fs_.root);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!FileSystem} The underlying FileSystem object.
|
||||
*/
|
||||
goog.fs.FileSystemImpl.prototype.getBrowserFileSystem = function() {
|
||||
return this.fs_;
|
||||
};
|
||||
@@ -0,0 +1,111 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview A wrapper for the HTML5 FileWriter object.
|
||||
*
|
||||
* When adding or modifying functionality in this namespace, be sure to update
|
||||
* the mock counterparts in goog.testing.fs.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.fs.FileWriter');
|
||||
|
||||
goog.require('goog.fs.Error');
|
||||
goog.require('goog.fs.FileSaver');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An object for monitoring the saving of files, as well as other fine-grained
|
||||
* writing operations.
|
||||
*
|
||||
* This should not be instantiated directly. Instead, it should be accessed via
|
||||
* {@link goog.fs.FileEntry#createWriter}.
|
||||
*
|
||||
* @param {!FileWriter} writer The underlying FileWriter object.
|
||||
* @constructor
|
||||
* @extends {goog.fs.FileSaver}
|
||||
* @final
|
||||
*/
|
||||
goog.fs.FileWriter = function(writer) {
|
||||
goog.fs.FileWriter.base(this, 'constructor', writer);
|
||||
|
||||
/**
|
||||
* The underlying FileWriter object.
|
||||
*
|
||||
* @type {!FileWriter}
|
||||
* @private
|
||||
*/
|
||||
this.writer_ = writer;
|
||||
};
|
||||
goog.inherits(goog.fs.FileWriter, goog.fs.FileSaver);
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The byte offset at which the next write will occur.
|
||||
*/
|
||||
goog.fs.FileWriter.prototype.getPosition = function() {
|
||||
return this.writer_.position;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The length of the file.
|
||||
*/
|
||||
goog.fs.FileWriter.prototype.getLength = function() {
|
||||
return this.writer_.length;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Write data to the file.
|
||||
*
|
||||
* @param {!Blob} blob The data to write.
|
||||
*/
|
||||
goog.fs.FileWriter.prototype.write = function(blob) {
|
||||
try {
|
||||
this.writer_.write(blob);
|
||||
} catch (e) {
|
||||
throw new goog.fs.Error(e, 'writing file');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the file position at which the next write will occur.
|
||||
*
|
||||
* @param {number} offset An absolute byte offset into the file.
|
||||
*/
|
||||
goog.fs.FileWriter.prototype.seek = function(offset) {
|
||||
try {
|
||||
this.writer_.seek(offset);
|
||||
} catch (e) {
|
||||
throw new goog.fs.Error(e, 'seeking in file');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Changes the length of the file to that specified.
|
||||
*
|
||||
* @param {number} size The new size of the file, in bytes.
|
||||
*/
|
||||
goog.fs.FileWriter.prototype.truncate = function(size) {
|
||||
try {
|
||||
this.writer_.truncate(size);
|
||||
} catch (e) {
|
||||
throw new goog.fs.Error(e, 'truncating file');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,319 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Wrappers for the HTML5 File API. These wrappers closely mirror
|
||||
* the underlying APIs, but use Closure-style events and Deferred return values.
|
||||
* Their existence also makes it possible to mock the FileSystem API for testing
|
||||
* in browsers that don't support it natively.
|
||||
*
|
||||
* When adding public functions to anything under this namespace, be sure to add
|
||||
* its mock counterpart to goog.testing.fs.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.fs');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.async.Deferred');
|
||||
goog.require('goog.fs.Error');
|
||||
goog.require('goog.fs.FileReader');
|
||||
goog.require('goog.fs.FileSystemImpl');
|
||||
goog.require('goog.userAgent');
|
||||
|
||||
|
||||
/**
|
||||
* Get a wrapped FileSystem object.
|
||||
*
|
||||
* @param {goog.fs.FileSystemType_} type The type of the filesystem to get.
|
||||
* @param {number} size The size requested for the filesystem, in bytes.
|
||||
* @return {!goog.async.Deferred} The deferred {@link goog.fs.FileSystem}. If an
|
||||
* error occurs, the errback is called with a {@link goog.fs.Error}.
|
||||
* @private
|
||||
*/
|
||||
goog.fs.get_ = function(type, size) {
|
||||
var requestFileSystem = goog.global.requestFileSystem ||
|
||||
goog.global.webkitRequestFileSystem;
|
||||
|
||||
if (!goog.isFunction(requestFileSystem)) {
|
||||
return goog.async.Deferred.fail(new Error('File API unsupported'));
|
||||
}
|
||||
|
||||
var d = new goog.async.Deferred();
|
||||
requestFileSystem(type, size, function(fs) {
|
||||
d.callback(new goog.fs.FileSystemImpl(fs));
|
||||
}, function(err) {
|
||||
d.errback(new goog.fs.Error(err, 'requesting filesystem'));
|
||||
});
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The two types of filesystem.
|
||||
*
|
||||
* @enum {number}
|
||||
* @private
|
||||
*/
|
||||
goog.fs.FileSystemType_ = {
|
||||
/**
|
||||
* A temporary filesystem may be deleted by the user agent at its discretion.
|
||||
*/
|
||||
TEMPORARY: 0,
|
||||
/**
|
||||
* A persistent filesystem will never be deleted without the user's or
|
||||
* application's authorization.
|
||||
*/
|
||||
PERSISTENT: 1
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a temporary FileSystem object. A temporary filesystem may be deleted
|
||||
* by the user agent at its discretion.
|
||||
*
|
||||
* @param {number} size The size requested for the filesystem, in bytes.
|
||||
* @return {!goog.async.Deferred} The deferred {@link goog.fs.FileSystem}. If an
|
||||
* error occurs, the errback is called with a {@link goog.fs.Error}.
|
||||
*/
|
||||
goog.fs.getTemporary = function(size) {
|
||||
return goog.fs.get_(goog.fs.FileSystemType_.TEMPORARY, size);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a persistent FileSystem object. A persistent filesystem will never be
|
||||
* deleted without the user's or application's authorization.
|
||||
*
|
||||
* @param {number} size The size requested for the filesystem, in bytes.
|
||||
* @return {!goog.async.Deferred} The deferred {@link goog.fs.FileSystem}. If an
|
||||
* error occurs, the errback is called with a {@link goog.fs.Error}.
|
||||
*/
|
||||
goog.fs.getPersistent = function(size) {
|
||||
return goog.fs.get_(goog.fs.FileSystemType_.PERSISTENT, size);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a blob URL for a blob object.
|
||||
* Throws an error if the browser does not support Object Urls.
|
||||
*
|
||||
* @param {!Blob} blob The object for which to create the URL.
|
||||
* @return {string} The URL for the object.
|
||||
*/
|
||||
goog.fs.createObjectUrl = function(blob) {
|
||||
return goog.fs.getUrlObject_().createObjectURL(blob);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Revokes a URL created by {@link goog.fs.createObjectUrl}.
|
||||
* Throws an error if the browser does not support Object Urls.
|
||||
*
|
||||
* @param {string} url The URL to revoke.
|
||||
*/
|
||||
goog.fs.revokeObjectUrl = function(url) {
|
||||
goog.fs.getUrlObject_().revokeObjectURL(url);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {{createObjectURL: (function(!Blob): string),
|
||||
* revokeObjectURL: function(string): void}}
|
||||
*/
|
||||
goog.fs.UrlObject_;
|
||||
|
||||
|
||||
/**
|
||||
* Get the object that has the createObjectURL and revokeObjectURL functions for
|
||||
* this browser.
|
||||
*
|
||||
* @return {goog.fs.UrlObject_} The object for this browser.
|
||||
* @private
|
||||
*/
|
||||
goog.fs.getUrlObject_ = function() {
|
||||
var urlObject = goog.fs.findUrlObject_();
|
||||
if (urlObject != null) {
|
||||
return urlObject;
|
||||
} else {
|
||||
throw Error('This browser doesn\'t seem to support blob URLs');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Finds the object that has the createObjectURL and revokeObjectURL functions
|
||||
* for this browser.
|
||||
*
|
||||
* @return {?goog.fs.UrlObject_} The object for this browser or null if the
|
||||
* browser does not support Object Urls.
|
||||
* @private
|
||||
*/
|
||||
goog.fs.findUrlObject_ = function() {
|
||||
// This is what the spec says to do
|
||||
// http://dev.w3.org/2006/webapi/FileAPI/#dfn-createObjectURL
|
||||
if (goog.isDef(goog.global.URL) &&
|
||||
goog.isDef(goog.global.URL.createObjectURL)) {
|
||||
return /** @type {goog.fs.UrlObject_} */ (goog.global.URL);
|
||||
// This is what Chrome does (as of 10.0.648.6 dev)
|
||||
} else if (goog.isDef(goog.global.webkitURL) &&
|
||||
goog.isDef(goog.global.webkitURL.createObjectURL)) {
|
||||
return /** @type {goog.fs.UrlObject_} */ (goog.global.webkitURL);
|
||||
// This is what the spec used to say to do
|
||||
} else if (goog.isDef(goog.global.createObjectURL)) {
|
||||
return /** @type {goog.fs.UrlObject_} */ (goog.global);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether this browser supports Object Urls. If not, calls to
|
||||
* createObjectUrl and revokeObjectUrl will result in an error.
|
||||
*
|
||||
* @return {boolean} True if this browser supports Object Urls.
|
||||
*/
|
||||
goog.fs.browserSupportsObjectUrls = function() {
|
||||
return goog.fs.findUrlObject_() != null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Concatenates one or more values together and converts them to a Blob.
|
||||
*
|
||||
* @param {...(string|!Blob|!ArrayBuffer)} var_args The values that will make up
|
||||
* the resulting blob.
|
||||
* @return {!Blob} The blob.
|
||||
*/
|
||||
goog.fs.getBlob = function(var_args) {
|
||||
var BlobBuilder = goog.global.BlobBuilder || goog.global.WebKitBlobBuilder;
|
||||
|
||||
if (goog.isDef(BlobBuilder)) {
|
||||
var bb = new BlobBuilder();
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
bb.append(arguments[i]);
|
||||
}
|
||||
return bb.getBlob();
|
||||
} else {
|
||||
return goog.fs.getBlobWithProperties(goog.array.toArray(arguments));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a blob with the given properties.
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/API/Blob for more details.
|
||||
*
|
||||
* @param {Array<string|!Blob>} parts The values that will make up the
|
||||
* resulting blob.
|
||||
* @param {string=} opt_type The MIME type of the Blob.
|
||||
* @param {string=} opt_endings Specifies how strings containing newlines are to
|
||||
* be written out.
|
||||
* @return {!Blob} The blob.
|
||||
*/
|
||||
goog.fs.getBlobWithProperties = function(parts, opt_type, opt_endings) {
|
||||
var BlobBuilder = goog.global.BlobBuilder || goog.global.WebKitBlobBuilder;
|
||||
|
||||
if (goog.isDef(BlobBuilder)) {
|
||||
var bb = new BlobBuilder();
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
bb.append(parts[i], opt_endings);
|
||||
}
|
||||
return bb.getBlob(opt_type);
|
||||
} else if (goog.isDef(goog.global.Blob)) {
|
||||
var properties = {};
|
||||
if (opt_type) {
|
||||
properties['type'] = opt_type;
|
||||
}
|
||||
if (opt_endings) {
|
||||
properties['endings'] = opt_endings;
|
||||
}
|
||||
return new Blob(parts, properties);
|
||||
} else {
|
||||
throw Error('This browser doesn\'t seem to support creating Blobs');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts a Blob or a File into a string. This should only be used when the
|
||||
* blob is known to be small.
|
||||
*
|
||||
* @param {!Blob} blob The blob to convert.
|
||||
* @param {string=} opt_encoding The name of the encoding to use.
|
||||
* @return {!goog.async.Deferred} The deferred string. If an error occurrs, the
|
||||
* errback is called with a {@link goog.fs.Error}.
|
||||
* @deprecated Use {@link goog.fs.FileReader.readAsText} instead.
|
||||
*/
|
||||
goog.fs.blobToString = function(blob, opt_encoding) {
|
||||
return goog.fs.FileReader.readAsText(blob, opt_encoding);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Slices the blob. The returned blob contains data from the start byte
|
||||
* (inclusive) till the end byte (exclusive). Negative indices can be used
|
||||
* to count bytes from the end of the blob (-1 == blob.size - 1). Indices
|
||||
* are always clamped to blob range. If end is omitted, all the data till
|
||||
* the end of the blob is taken.
|
||||
*
|
||||
* @param {!Blob} blob The blob to be sliced.
|
||||
* @param {number} start Index of the starting byte.
|
||||
* @param {number=} opt_end Index of the ending byte.
|
||||
* @return {Blob} The blob slice or null if not supported.
|
||||
*/
|
||||
goog.fs.sliceBlob = function(blob, start, opt_end) {
|
||||
if (!goog.isDef(opt_end)) {
|
||||
opt_end = blob.size;
|
||||
}
|
||||
if (blob.webkitSlice) {
|
||||
// Natively accepts negative indices, clamping to the blob range and
|
||||
// range end is optional. See http://trac.webkit.org/changeset/83873
|
||||
return blob.webkitSlice(start, opt_end);
|
||||
} else if (blob.mozSlice) {
|
||||
// Natively accepts negative indices, clamping to the blob range and
|
||||
// range end is optional. See https://developer.mozilla.org/en/DOM/Blob
|
||||
// and http://hg.mozilla.org/mozilla-central/rev/dae833f4d934
|
||||
return blob.mozSlice(start, opt_end);
|
||||
} else if (blob.slice) {
|
||||
// Old versions of Firefox and Chrome use the original specification.
|
||||
// Negative indices are not accepted, only range end is clamped and
|
||||
// range end specification is obligatory.
|
||||
// See http://www.w3.org/TR/2009/WD-FileAPI-20091117/
|
||||
if ((goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('13.0')) ||
|
||||
(goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher('537.1'))) {
|
||||
if (start < 0) {
|
||||
start += blob.size;
|
||||
}
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
}
|
||||
if (opt_end < 0) {
|
||||
opt_end += blob.size;
|
||||
}
|
||||
if (opt_end < start) {
|
||||
opt_end = start;
|
||||
}
|
||||
return blob.slice(start, opt_end - start);
|
||||
}
|
||||
// IE and the latest versions of Firefox and Chrome use the new
|
||||
// specification. Natively accepts negative indices, clamping to the blob
|
||||
// range and range end is optional.
|
||||
// See http://dev.w3.org/2006/webapi/FileAPI/
|
||||
return blob.slice(start, opt_end);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<!--
|
||||
-->
|
||||
<head>
|
||||
<title>
|
||||
Closure Integration Tests - goog.fs
|
||||
</title>
|
||||
<script src="../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.fsTest');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="closureTestRunnerLog">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,842 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
goog.provide('goog.fsTest');
|
||||
goog.setTestOnly('goog.fsTest');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.async.Deferred');
|
||||
goog.require('goog.async.DeferredList');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.fs');
|
||||
goog.require('goog.fs.DirectoryEntry');
|
||||
goog.require('goog.fs.Error');
|
||||
goog.require('goog.fs.FileReader');
|
||||
goog.require('goog.fs.FileSaver');
|
||||
goog.require('goog.string');
|
||||
goog.require('goog.testing.AsyncTestCase');
|
||||
goog.require('goog.testing.PropertyReplacer');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
var TEST_DIR = 'goog-fs-test-dir';
|
||||
|
||||
var fsExists = goog.isDef(goog.global.requestFileSystem) ||
|
||||
goog.isDef(goog.global.webkitRequestFileSystem);
|
||||
var deferredFs = fsExists ? goog.fs.getTemporary() : null;
|
||||
var asyncTestCase = goog.testing.AsyncTestCase.createAndInstall();
|
||||
asyncTestCase.stepTimeout = 5000;
|
||||
var stubs = new goog.testing.PropertyReplacer();
|
||||
|
||||
function setUpPage() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadTestDir().addErrback(function(err) {
|
||||
var msg;
|
||||
if (err.code == goog.fs.Error.ErrorCode.QUOTA_EXCEEDED) {
|
||||
msg = err.message + '. If you\'re using Chrome, you probably need to ' +
|
||||
'pass --unlimited-quota-for-files on the command line.';
|
||||
} else if (err.code == goog.fs.Error.ErrorCode.SECURITY &&
|
||||
window.location.href.match(/^file:/)) {
|
||||
msg = err.message + '. file:// URLs can\'t access the filesystem API.';
|
||||
} else {
|
||||
msg = err.message;
|
||||
}
|
||||
var body = goog.dom.getDocument().body;
|
||||
goog.dom.insertSiblingBefore(
|
||||
goog.dom.createDom('h1', {}, msg), body.childNodes[0]);
|
||||
});
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadTestDir().
|
||||
addCallback(function(dir) { return dir.removeRecursively(); }).
|
||||
addBoth(continueTesting);
|
||||
asyncTestCase.waitForAsync('removing filesystem');
|
||||
}
|
||||
|
||||
function testUnavailableTemporaryFilesystem() {
|
||||
stubs.set(goog.global, 'requestFileSystem', null);
|
||||
stubs.set(goog.global, 'webkitRequestFileSystem', null);
|
||||
asyncTestCase.waitForAsync('testUnavailableTemporaryFilesystem');
|
||||
|
||||
goog.fs.getTemporary(1024).addErrback(function(e) {
|
||||
assertEquals('File API unsupported', e.message);
|
||||
continueTesting();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function testUnavailablePersistentFilesystem() {
|
||||
stubs.set(goog.global, 'requestFileSystem', null);
|
||||
stubs.set(goog.global, 'webkitRequestFileSystem', null);
|
||||
asyncTestCase.waitForAsync('testUnavailablePersistentFilesystem');
|
||||
|
||||
goog.fs.getPersistent(2048).addErrback(function(e) {
|
||||
assertEquals('File API unsupported', e.message);
|
||||
continueTesting();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function testIsFile() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadFile('test', goog.fs.DirectoryEntry.Behavior.CREATE).
|
||||
addCallback(function(fileEntry) {
|
||||
assertFalse(fileEntry.isDirectory());
|
||||
assertTrue(fileEntry.isFile());
|
||||
}).addBoth(continueTesting);
|
||||
asyncTestCase.waitForAsync('testIsFile');
|
||||
}
|
||||
|
||||
function testIsDirectory() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadDirectory('test', goog.fs.DirectoryEntry.Behavior.CREATE).
|
||||
addCallback(function(fileEntry) {
|
||||
assertTrue(fileEntry.isDirectory());
|
||||
assertFalse(fileEntry.isFile());
|
||||
}).addBoth(continueTesting);
|
||||
asyncTestCase.waitForAsync('testIsDirectory');
|
||||
}
|
||||
|
||||
function testReadFileUtf16() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
var str = 'test content';
|
||||
var buf = new ArrayBuffer(str.length * 2);
|
||||
var arr = new Uint16Array(buf);
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
arr[i] = str.charCodeAt(i);
|
||||
}
|
||||
|
||||
loadFile('test', goog.fs.DirectoryEntry.Behavior.CREATE).
|
||||
addCallback(goog.partial(writeToFile, arr.buffer)).
|
||||
addCallback(goog.partial(checkFileContentWithEncoding, str, 'UTF-16')).
|
||||
addBoth(continueTesting);
|
||||
asyncTestCase.waitForAsync('testReadFile');
|
||||
}
|
||||
|
||||
function testReadFileUtf8() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
var str = 'test content';
|
||||
var buf = new ArrayBuffer(str.length);
|
||||
var arr = new Uint8Array(buf);
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
arr[i] = str.charCodeAt(i) & 0xff;
|
||||
}
|
||||
|
||||
loadFile('test', goog.fs.DirectoryEntry.Behavior.CREATE).
|
||||
addCallback(goog.partial(writeToFile, arr.buffer)).
|
||||
addCallback(goog.partial(checkFileContentWithEncoding, str, 'UTF-8')).
|
||||
addBoth(continueTesting);
|
||||
asyncTestCase.waitForAsync('testReadFileUtf8');
|
||||
}
|
||||
|
||||
function testReadFileAsArrayBuffer() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
var str = 'test content';
|
||||
var buf = new ArrayBuffer(str.length);
|
||||
var arr = new Uint8Array(buf);
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
arr[i] = str.charCodeAt(i) & 0xff;
|
||||
}
|
||||
|
||||
loadFile('test', goog.fs.DirectoryEntry.Behavior.CREATE).
|
||||
addCallback(goog.partial(writeToFile, arr.buffer)).
|
||||
addCallback(goog.partial(checkFileContentAs, arr.buffer, 'ArrayBuffer',
|
||||
undefined)).
|
||||
addBoth(continueTesting);
|
||||
asyncTestCase.waitForAsync('testReadFileAsArrayBuffer');
|
||||
}
|
||||
|
||||
function testReadFileAsBinaryString() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
var str = 'test content';
|
||||
var buf = new ArrayBuffer(str.length);
|
||||
var arr = new Uint8Array(buf);
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
arr[i] = str.charCodeAt(i);
|
||||
}
|
||||
|
||||
loadFile('test', goog.fs.DirectoryEntry.Behavior.CREATE).
|
||||
addCallback(goog.partial(writeToFile, arr.buffer)).
|
||||
addCallback(goog.partial(checkFileContentAs, str, 'BinaryString',
|
||||
undefined)).
|
||||
addBoth(continueTesting);
|
||||
asyncTestCase.waitForAsync('testReadFileAsArrayBuffer');
|
||||
}
|
||||
|
||||
function testWriteFile() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadFile('test', goog.fs.DirectoryEntry.Behavior.CREATE).
|
||||
addCallback(goog.partial(writeToFile, 'test content')).
|
||||
addCallback(goog.partial(checkFileContent, 'test content')).
|
||||
addBoth(continueTesting);
|
||||
asyncTestCase.waitForAsync('testWriteFile');
|
||||
}
|
||||
|
||||
function testRemoveFile() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadFile('test', goog.fs.DirectoryEntry.Behavior.CREATE).
|
||||
addCallback(goog.partial(writeToFile, 'test content')).
|
||||
addCallback(function(file) { return file.remove(); }).
|
||||
addCallback(goog.partial(checkFileRemoved, 'test')).
|
||||
addBoth(continueTesting);
|
||||
asyncTestCase.waitForAsync('testRemoveFile');
|
||||
}
|
||||
|
||||
function testMoveFile() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
var deferredSubdir = loadDirectory(
|
||||
'subdir', goog.fs.DirectoryEntry.Behavior.CREATE);
|
||||
var deferredWrittenFile =
|
||||
loadFile('test', goog.fs.DirectoryEntry.Behavior.CREATE).
|
||||
addCallback(goog.partial(writeToFile, 'test content'));
|
||||
goog.async.DeferredList.gatherResults([deferredSubdir, deferredWrittenFile]).
|
||||
addCallback(splitArgs(function(dir, file) { return file.moveTo(dir); })).
|
||||
addCallback(goog.partial(checkFileContent, 'test content')).
|
||||
addCallback(goog.partial(checkFileRemoved, 'test')).
|
||||
addBoth(continueTesting);
|
||||
asyncTestCase.waitForAsync('testMoveFile');
|
||||
}
|
||||
|
||||
function testCopyFile() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
var deferredFile = loadFile('test', goog.fs.DirectoryEntry.Behavior.CREATE);
|
||||
var deferredSubdir = loadDirectory(
|
||||
'subdir', goog.fs.DirectoryEntry.Behavior.CREATE);
|
||||
var deferredWrittenFile = deferredFile.branch().
|
||||
addCallback(goog.partial(writeToFile, 'test content'));
|
||||
goog.async.DeferredList.gatherResults([deferredSubdir, deferredWrittenFile]).
|
||||
addCallback(splitArgs(function(dir, file) { return file.copyTo(dir); })).
|
||||
addCallback(goog.partial(checkFileContent, 'test content')).
|
||||
awaitDeferred(deferredFile).
|
||||
addCallback(goog.partial(checkFileContent, 'test content')).
|
||||
addBoth(continueTesting);
|
||||
asyncTestCase.waitForAsync('testMoveFile');
|
||||
}
|
||||
|
||||
function testAbortWrite() {
|
||||
// TODO(nicksantos): This test is broken in newer versions of chrome.
|
||||
// We don't know why yet.
|
||||
if (true) return;
|
||||
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
var deferredFile = loadFile('test', goog.fs.DirectoryEntry.Behavior.CREATE);
|
||||
deferredFile.branch().
|
||||
addCallback(goog.partial(startWrite, 'test content')).
|
||||
addCallback(function(writer) { writer.abort(); }).
|
||||
addCallback(
|
||||
goog.partial(waitForEvent, goog.fs.FileSaver.EventType.ABORT)).
|
||||
awaitDeferred(deferredFile).
|
||||
addCallback(goog.partial(checkFileContent, '')).
|
||||
addBoth(continueTesting);
|
||||
asyncTestCase.waitForAsync('testWriteFile');
|
||||
}
|
||||
|
||||
function testSeek() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
var deferredFile = loadFile('test', goog.fs.DirectoryEntry.Behavior.CREATE);
|
||||
deferredFile.branch().
|
||||
addCallback(goog.partial(writeToFile, 'test content')).
|
||||
addCallback(function(file) { return file.createWriter(); }).
|
||||
addCallback(
|
||||
goog.partial(checkReadyState, goog.fs.FileSaver.ReadyState.INIT)).
|
||||
addCallback(function(writer) {
|
||||
writer.seek(5);
|
||||
writer.write(goog.fs.getBlob('stuff and things'));
|
||||
}).
|
||||
addCallback(
|
||||
goog.partial(checkReadyState, goog.fs.FileSaver.ReadyState.WRITING)).
|
||||
addCallback(
|
||||
goog.partial(waitForEvent, goog.fs.FileSaver.EventType.WRITE)).
|
||||
awaitDeferred(deferredFile).
|
||||
addCallback(goog.partial(checkFileContent, 'test stuff and things')).
|
||||
addBoth(continueTesting);
|
||||
asyncTestCase.waitForAsync('testWriteFile');
|
||||
}
|
||||
|
||||
function testTruncate() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
var deferredFile = loadFile('test', goog.fs.DirectoryEntry.Behavior.CREATE);
|
||||
deferredFile.branch().
|
||||
addCallback(goog.partial(writeToFile, 'test content')).
|
||||
addCallback(function(file) { return file.createWriter(); }).
|
||||
addCallback(
|
||||
goog.partial(checkReadyState, goog.fs.FileSaver.ReadyState.INIT)).
|
||||
addCallback(function(writer) { writer.truncate(4); }).
|
||||
addCallback(
|
||||
goog.partial(checkReadyState, goog.fs.FileSaver.ReadyState.WRITING)).
|
||||
addCallback(
|
||||
goog.partial(waitForEvent, goog.fs.FileSaver.EventType.WRITE)).
|
||||
awaitDeferred(deferredFile).
|
||||
addCallback(goog.partial(checkFileContent, 'test')).
|
||||
addBoth(continueTesting);
|
||||
asyncTestCase.waitForAsync('testWriteFile');
|
||||
}
|
||||
|
||||
function testGetLastModified() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
var now = goog.now();
|
||||
loadFile('test', goog.fs.DirectoryEntry.Behavior.CREATE).
|
||||
addCallback(function(entry) {
|
||||
return entry.getLastModified();
|
||||
}).addCallback(function(date) {
|
||||
assertRoughlyEquals('Expected the last modified date to be within ' +
|
||||
'a few milliseconds of the test start time.',
|
||||
now, date.getTime(), 2000);
|
||||
}).addCallback(continueTesting);
|
||||
|
||||
asyncTestCase.waitForAsync('testGetLastModified');
|
||||
}
|
||||
|
||||
function testCreatePath() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadTestDir().
|
||||
addCallback(function(testDir) {
|
||||
return testDir.createPath('foo');
|
||||
}).
|
||||
addCallback(function(fooDir) {
|
||||
assertEquals('/goog-fs-test-dir/foo', fooDir.getFullPath());
|
||||
return fooDir.createPath('bar/baz/bat');
|
||||
}).
|
||||
addCallback(function(batDir) {
|
||||
assertEquals('/goog-fs-test-dir/foo/bar/baz/bat', batDir.getFullPath());
|
||||
}).
|
||||
addBoth(continueTesting);
|
||||
asyncTestCase.waitForAsync('testCreatePath');
|
||||
}
|
||||
|
||||
function testCreateAbsolutePath() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadTestDir().
|
||||
addCallback(function(testDir) {
|
||||
return testDir.createPath('/' + TEST_DIR + '/fee/fi/fo/fum');
|
||||
}).
|
||||
addCallback(function(absDir) {
|
||||
assertEquals('/goog-fs-test-dir/fee/fi/fo/fum', absDir.getFullPath());
|
||||
}).
|
||||
addBoth(continueTesting);
|
||||
asyncTestCase.waitForAsync('testCreateAbsolutePath');
|
||||
}
|
||||
|
||||
function testCreateRelativePath() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadTestDir().
|
||||
addCallback(function(dir) {
|
||||
return dir.createPath('../' + TEST_DIR + '/dir');
|
||||
}).
|
||||
addCallback(function(relDir) {
|
||||
assertEquals('/goog-fs-test-dir/dir', relDir.getFullPath());
|
||||
return relDir.createPath('.');
|
||||
}).
|
||||
addCallback(function(sameDir) {
|
||||
assertEquals('/goog-fs-test-dir/dir', sameDir.getFullPath());
|
||||
return sameDir.createPath('./././.');
|
||||
}).
|
||||
addCallback(function(reallySameDir) {
|
||||
assertEquals('/goog-fs-test-dir/dir', reallySameDir.getFullPath());
|
||||
return reallySameDir.createPath('./new/../..//dir/./new////.');
|
||||
}).
|
||||
addCallback(function(newDir) {
|
||||
assertEquals('/goog-fs-test-dir/dir/new', newDir.getFullPath());
|
||||
}).
|
||||
addBoth(continueTesting);
|
||||
asyncTestCase.waitForAsync('testCreateRelativePath');
|
||||
|
||||
}
|
||||
|
||||
function testCreateBadPath() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadTestDir().
|
||||
awaitDeferred(loadTestDir()).
|
||||
addCallback(function(dir) {
|
||||
// There is only one layer of parent directory from the test dir.
|
||||
return dir.createPath('../../../../' + TEST_DIR + '/baz/bat');
|
||||
}).
|
||||
addCallback(function(batDir) {
|
||||
assertEquals('The parent directory of the root directory should ' +
|
||||
'point back to the root directory.',
|
||||
'/goog-fs-test-dir/baz/bat', batDir.getFullPath());
|
||||
}).
|
||||
|
||||
awaitDeferred(loadTestDir()).
|
||||
addCallback(function(dir) {
|
||||
// An empty path should return the same as the input directory.
|
||||
return dir.createPath('');
|
||||
}).
|
||||
addCallback(function(testDir) {
|
||||
assertEquals('/goog-fs-test-dir', testDir.getFullPath());
|
||||
}).
|
||||
addBoth(continueTesting);
|
||||
asyncTestCase.waitForAsync('testCreateBadPath');
|
||||
}
|
||||
|
||||
function testGetAbsolutePaths() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadFile('foo', goog.fs.DirectoryEntry.Behavior.CREATE).
|
||||
awaitDeferred(loadTestDir()).
|
||||
addCallback(function(testDir) {
|
||||
return testDir.getDirectory('/');
|
||||
}).
|
||||
addCallback(function(root) {
|
||||
assertEquals('/', root.getFullPath());
|
||||
return root.getDirectory('/' + TEST_DIR);
|
||||
}).
|
||||
addCallback(function(testDir) {
|
||||
assertEquals('/goog-fs-test-dir', testDir.getFullPath());
|
||||
return testDir.getDirectory('//' + TEST_DIR + '////');
|
||||
}).
|
||||
addCallback(function(testDir) {
|
||||
assertEquals('/goog-fs-test-dir', testDir.getFullPath());
|
||||
return testDir.getDirectory('////');
|
||||
}).
|
||||
addCallback(function(testDir) {
|
||||
assertEquals('/', testDir.getFullPath());
|
||||
}).
|
||||
addBoth(continueTesting);
|
||||
asyncTestCase.waitForAsync('testGetAbsolutePaths');
|
||||
}
|
||||
|
||||
|
||||
function continueTesting(result) {
|
||||
asyncTestCase.continueTesting();
|
||||
if (result instanceof Error) {
|
||||
throw result;
|
||||
}
|
||||
}
|
||||
|
||||
function testListEmptyDirectory() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadTestDir().
|
||||
addCallback(function(dir) { return dir.listDirectory(); }).
|
||||
addCallback(function(entries) { assertArrayEquals([], entries); }).
|
||||
addCallback(continueTesting);
|
||||
asyncTestCase.waitForAsync('testListEmptyDirectory');
|
||||
}
|
||||
|
||||
|
||||
function testListDirectory() {
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
goog.async.Deferred.succeed().
|
||||
// Create the test directory and test entries.
|
||||
awaitDeferred(
|
||||
loadDirectory('testDir', goog.fs.DirectoryEntry.Behavior.CREATE)).
|
||||
awaitDeferred(
|
||||
loadFile('testFile', goog.fs.DirectoryEntry.Behavior.CREATE)).
|
||||
awaitDeferred(loadTestDir()).
|
||||
|
||||
// Verify the contents of the directory listing.
|
||||
addCallback(function(testDir) { return testDir.listDirectory(); }).
|
||||
addCallback(function(entries) {
|
||||
assertEquals(2, entries.length);
|
||||
|
||||
var dir = goog.array.find(entries, function(entry) {
|
||||
return entry.getName() == 'testDir';
|
||||
});
|
||||
assertNotNull(dir);
|
||||
assertTrue(dir.isDirectory());
|
||||
|
||||
var file = goog.array.find(entries, function(entry) {
|
||||
return entry.getName() == 'testFile';
|
||||
});
|
||||
assertNotNull(file);
|
||||
assertTrue(file.isFile());
|
||||
}).
|
||||
addCallback(continueTesting);
|
||||
|
||||
asyncTestCase.waitForAsync('testListDirectory');
|
||||
}
|
||||
|
||||
|
||||
function testListBigDirectory() {
|
||||
// TODO(nicksantos): This test is broken in newer versions of chrome.
|
||||
// We don't know why yet.
|
||||
if (true) return;
|
||||
|
||||
if (!fsExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
function getFileName(i) {
|
||||
return 'file' + goog.string.padNumber(i, String(count).length);
|
||||
}
|
||||
|
||||
// NOTE: This was intended to verify that the results from repeated
|
||||
// DirectoryReader.readEntries() callbacks are appropriately concatenated.
|
||||
// In current versions of Chrome (March 2011), all results are returned in the
|
||||
// first callback regardless of directory size. The count can be increased in
|
||||
// the future to test batched result lists once they are implemented.
|
||||
var count = 100;
|
||||
|
||||
var expectedNames = [];
|
||||
|
||||
var def = goog.async.Deferred.succeed();
|
||||
for (var i = 0; i < count; i++) {
|
||||
var name = getFileName(i);
|
||||
expectedNames.push(name);
|
||||
|
||||
def.awaitDeferred(
|
||||
loadFile(name, goog.fs.DirectoryEntry.Behavior.CREATE));
|
||||
}
|
||||
|
||||
def.awaitDeferred(loadTestDir()).
|
||||
addCallback(function(testDir) { return testDir.listDirectory(); }).
|
||||
addCallback(function(entries) {
|
||||
assertEquals(count, entries.length);
|
||||
|
||||
assertSameElements(expectedNames,
|
||||
goog.array.map(entries, function(entry) {
|
||||
return entry.getName();
|
||||
}));
|
||||
assertTrue(goog.array.every(entries, function(entry) {
|
||||
return entry.isFile();
|
||||
}));
|
||||
}).
|
||||
addCallback(continueTesting);
|
||||
|
||||
asyncTestCase.waitForAsync('testListBigDirectory');
|
||||
}
|
||||
|
||||
|
||||
function testSliceBlob() {
|
||||
// A mock blob object whose slice returns the parameters it was called with.
|
||||
var blob = {
|
||||
'size': 10,
|
||||
'slice': function(start, end) {
|
||||
return [start, end];
|
||||
}
|
||||
};
|
||||
|
||||
// Simulate Firefox 13 that implements the new slice.
|
||||
var tmpStubs = new goog.testing.PropertyReplacer();
|
||||
tmpStubs.set(goog.userAgent, 'GECKO', true);
|
||||
tmpStubs.set(goog.userAgent, 'WEBKIT', false);
|
||||
tmpStubs.set(goog.userAgent, 'IE', false);
|
||||
tmpStubs.set(goog.userAgent, 'VERSION', '13.0');
|
||||
tmpStubs.set(goog.userAgent, 'isVersionOrHigherCache_', {});
|
||||
|
||||
// Expect slice to be called with no change to parameters
|
||||
assertArrayEquals([2, 10], goog.fs.sliceBlob(blob, 2));
|
||||
assertArrayEquals([-2, 10], goog.fs.sliceBlob(blob, -2));
|
||||
assertArrayEquals([3, 6], goog.fs.sliceBlob(blob, 3, 6));
|
||||
assertArrayEquals([3, -6], goog.fs.sliceBlob(blob, 3, -6));
|
||||
|
||||
// Simulate IE 10 that implements the new slice.
|
||||
var tmpStubs = new goog.testing.PropertyReplacer();
|
||||
tmpStubs.set(goog.userAgent, 'GECKO', false);
|
||||
tmpStubs.set(goog.userAgent, 'WEBKIT', false);
|
||||
tmpStubs.set(goog.userAgent, 'IE', true);
|
||||
tmpStubs.set(goog.userAgent, 'VERSION', '10.0');
|
||||
tmpStubs.set(goog.userAgent, 'isVersionOrHigherCache_', {});
|
||||
|
||||
// Expect slice to be called with no change to parameters
|
||||
assertArrayEquals([2, 10], goog.fs.sliceBlob(blob, 2));
|
||||
assertArrayEquals([-2, 10], goog.fs.sliceBlob(blob, -2));
|
||||
assertArrayEquals([3, 6], goog.fs.sliceBlob(blob, 3, 6));
|
||||
assertArrayEquals([3, -6], goog.fs.sliceBlob(blob, 3, -6));
|
||||
|
||||
// Simulate Firefox 4 that implements the old slice.
|
||||
tmpStubs.set(goog.userAgent, 'GECKO', true);
|
||||
tmpStubs.set(goog.userAgent, 'WEBKIT', false);
|
||||
tmpStubs.set(goog.userAgent, 'IE', false);
|
||||
tmpStubs.set(goog.userAgent, 'VERSION', '2.0');
|
||||
tmpStubs.set(goog.userAgent, 'isVersionOrHigherCache_', {});
|
||||
|
||||
// Expect slice to be called with transformed parameters.
|
||||
assertArrayEquals([2, 8], goog.fs.sliceBlob(blob, 2));
|
||||
assertArrayEquals([8, 2], goog.fs.sliceBlob(blob, -2));
|
||||
assertArrayEquals([3, 3], goog.fs.sliceBlob(blob, 3, 6));
|
||||
assertArrayEquals([3, 1], goog.fs.sliceBlob(blob, 3, -6));
|
||||
|
||||
// Simulate Firefox 5 that implements mozSlice (new spec).
|
||||
delete blob.slice;
|
||||
blob.mozSlice = function(start, end) {
|
||||
return ['moz', start, end];
|
||||
};
|
||||
tmpStubs.set(goog.userAgent, 'GECKO', true);
|
||||
tmpStubs.set(goog.userAgent, 'WEBKIT', false);
|
||||
tmpStubs.set(goog.userAgent, 'IE', false);
|
||||
tmpStubs.set(goog.userAgent, 'VERSION', '5.0');
|
||||
tmpStubs.set(goog.userAgent, 'isVersionOrHigherCache_', {});
|
||||
|
||||
// Expect mozSlice to be called with no change to parameters.
|
||||
assertArrayEquals(['moz', 2, 10], goog.fs.sliceBlob(blob, 2));
|
||||
assertArrayEquals(['moz', -2, 10], goog.fs.sliceBlob(blob, -2));
|
||||
assertArrayEquals(['moz', 3, 6], goog.fs.sliceBlob(blob, 3, 6));
|
||||
assertArrayEquals(['moz', 3, -6], goog.fs.sliceBlob(blob, 3, -6));
|
||||
|
||||
// Simulate Chrome 20 that implements webkitSlice (new spec).
|
||||
delete blob.mozSlice;
|
||||
blob.webkitSlice = function(start, end) {
|
||||
return ['webkit', start, end];
|
||||
};
|
||||
tmpStubs.set(goog.userAgent, 'GECKO', false);
|
||||
tmpStubs.set(goog.userAgent, 'WEBKIT', true);
|
||||
tmpStubs.set(goog.userAgent, 'IE', false);
|
||||
tmpStubs.set(goog.userAgent, 'VERSION', '536.10');
|
||||
tmpStubs.set(goog.userAgent, 'isVersionOrHigherCache_', {});
|
||||
|
||||
// Expect webkitSlice to be called with no change to parameters.
|
||||
assertArrayEquals(['webkit', 2, 10], goog.fs.sliceBlob(blob, 2));
|
||||
assertArrayEquals(['webkit', -2, 10], goog.fs.sliceBlob(blob, -2));
|
||||
assertArrayEquals(['webkit', 3, 6], goog.fs.sliceBlob(blob, 3, 6));
|
||||
assertArrayEquals(['webkit', 3, -6], goog.fs.sliceBlob(blob, 3, -6));
|
||||
|
||||
tmpStubs.reset();
|
||||
}
|
||||
|
||||
|
||||
function testBrowserSupportsObjectUrls() {
|
||||
stubs.remove(goog.global, 'URL');
|
||||
stubs.remove(goog.global, 'webkitURL');
|
||||
stubs.remove(goog.global, 'createObjectURL');
|
||||
|
||||
assertFalse(goog.fs.browserSupportsObjectUrls());
|
||||
try {
|
||||
goog.fs.createObjectUrl();
|
||||
fail();
|
||||
} catch (e) {
|
||||
assertEquals('This browser doesn\'t seem to support blob URLs', e.message);
|
||||
}
|
||||
|
||||
var objectUrl = {};
|
||||
function createObjectURL() { return objectUrl; }
|
||||
stubs.set(goog.global, 'createObjectURL', createObjectURL);
|
||||
|
||||
assertTrue(goog.fs.browserSupportsObjectUrls());
|
||||
assertEquals(objectUrl, goog.fs.createObjectUrl());
|
||||
|
||||
stubs.reset();
|
||||
}
|
||||
|
||||
|
||||
function testGetBlobThrowsError() {
|
||||
stubs.remove(goog.global, 'BlobBuilder');
|
||||
stubs.remove(goog.global, 'WebKitBlobBuilder');
|
||||
stubs.remove(goog.global, 'Blob');
|
||||
|
||||
try {
|
||||
goog.fs.getBlob();
|
||||
fail();
|
||||
} catch (e) {
|
||||
assertEquals('This browser doesn\'t seem to support creating Blobs',
|
||||
e.message);
|
||||
}
|
||||
|
||||
stubs.reset();
|
||||
}
|
||||
|
||||
|
||||
function testGetBlobWithProperties() {
|
||||
// Skip test if browser doesn't support Blob API.
|
||||
if (typeof(goog.global.Blob) != 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
var blob = goog.fs.getBlobWithProperties(['test'], 'text/test', 'native');
|
||||
assertEquals('text/test', blob.type);
|
||||
}
|
||||
|
||||
|
||||
function testGetBlobWithPropertiesThrowsError() {
|
||||
stubs.remove(goog.global, 'BlobBuilder');
|
||||
stubs.remove(goog.global, 'WebKitBlobBuilder');
|
||||
stubs.remove(goog.global, 'Blob');
|
||||
|
||||
try {
|
||||
goog.fs.getBlobWithProperties();
|
||||
fail();
|
||||
} catch (e) {
|
||||
assertEquals('This browser doesn\'t seem to support creating Blobs',
|
||||
e.message);
|
||||
}
|
||||
|
||||
stubs.reset();
|
||||
}
|
||||
|
||||
|
||||
function testGetBlobWithPropertiesUsingBlobBuilder() {
|
||||
function BlobBuilder() {
|
||||
this.parts = [];
|
||||
this.append = function(value, endings) {
|
||||
this.parts.push({value: value, endings: endings});
|
||||
};
|
||||
this.getBlob = function(type) {
|
||||
return {type: type, builder: this};
|
||||
};
|
||||
}
|
||||
stubs.set(goog.global, 'BlobBuilder', BlobBuilder);
|
||||
|
||||
var blob = goog.fs.getBlobWithProperties(['test'], 'text/test', 'native');
|
||||
assertEquals('text/test', blob.type);
|
||||
assertEquals('test', blob.builder.parts[0].value);
|
||||
assertEquals('native', blob.builder.parts[0].endings);
|
||||
|
||||
stubs.reset();
|
||||
}
|
||||
|
||||
|
||||
function loadTestDir() {
|
||||
return deferredFs.branch().addCallback(function(fs) {
|
||||
return fs.getRoot().getDirectory(
|
||||
TEST_DIR, goog.fs.DirectoryEntry.Behavior.CREATE);
|
||||
});
|
||||
}
|
||||
|
||||
function loadFile(filename, behavior) {
|
||||
return loadTestDir().addCallback(function(dir) {
|
||||
return dir.getFile(filename, behavior);
|
||||
});
|
||||
}
|
||||
|
||||
function loadDirectory(filename, behavior) {
|
||||
return loadTestDir().addCallback(function(dir) {
|
||||
return dir.getDirectory(filename, behavior);
|
||||
});
|
||||
}
|
||||
|
||||
function startWrite(content, file) {
|
||||
return file.createWriter().
|
||||
addCallback(
|
||||
goog.partial(checkReadyState, goog.fs.FileSaver.ReadyState.INIT)).
|
||||
addCallback(function(writer) {
|
||||
writer.write(goog.fs.getBlob(content));
|
||||
return writer;
|
||||
}).
|
||||
addCallback(
|
||||
goog.partial(checkReadyState, goog.fs.FileSaver.ReadyState.WRITING));
|
||||
}
|
||||
|
||||
function waitForEvent(type, target) {
|
||||
var d = new goog.async.Deferred();
|
||||
goog.events.listenOnce(target, type, d.callback, false, d);
|
||||
return d;
|
||||
}
|
||||
|
||||
function writeToFile(content, file) {
|
||||
return startWrite(content, file).
|
||||
addCallback(
|
||||
goog.partial(waitForEvent, goog.fs.FileSaver.EventType.WRITE)).
|
||||
addCallback(function() { return file; });
|
||||
}
|
||||
|
||||
function checkFileContent(content, file) {
|
||||
return checkFileContentAs(content, 'Text', undefined, file);
|
||||
}
|
||||
|
||||
function checkFileContentWithEncoding(content, encoding, file) {
|
||||
checkFileContentAs(content, 'Text', encoding, file);
|
||||
}
|
||||
|
||||
function checkFileContentAs(content, filetype, encoding, file) {
|
||||
return file.file().
|
||||
addCallback(function(blob) {
|
||||
return goog.fs.FileReader['readAs' + filetype](blob, encoding);
|
||||
}).
|
||||
addCallback(goog.partial(checkEquals, content));
|
||||
}
|
||||
|
||||
function checkEquals(a, b) {
|
||||
if (a instanceof ArrayBuffer && b instanceof ArrayBuffer) {
|
||||
assertEquals(a.byteLength, b.byteLength);
|
||||
var viewA = new DataView(a);
|
||||
var viewB = new DataView(b);
|
||||
for (var i = 0; i < a.byteLength; i++) {
|
||||
assertEquals(viewA.getUint8(i), viewB.getUint8(i));
|
||||
}
|
||||
} else {
|
||||
assertEquals(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
function checkFileRemoved(filename) {
|
||||
return loadFile(filename).
|
||||
addCallback(goog.partial(fail, 'expected file to be removed')).
|
||||
addErrback(function(err) {
|
||||
assertEquals(err.code, goog.fs.Error.ErrorCode.NOT_FOUND);
|
||||
return true; // Go back to callback path
|
||||
});
|
||||
}
|
||||
|
||||
function checkReadyState(expectedState, writer) {
|
||||
assertEquals(expectedState, writer.getReadyState());
|
||||
}
|
||||
|
||||
function splitArgs(fn) {
|
||||
return function(args) { return fn(args[0], args[1]); };
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview A wrapper for the HTML5 File ProgressEvent objects.
|
||||
*
|
||||
*/
|
||||
goog.provide('goog.fs.ProgressEvent');
|
||||
|
||||
goog.require('goog.events.Event');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A wrapper for the progress events emitted by the File APIs.
|
||||
*
|
||||
* @param {!ProgressEvent} event The underlying event object.
|
||||
* @param {!Object} target The file access object emitting the event.
|
||||
* @extends {goog.events.Event}
|
||||
* @constructor
|
||||
* @final
|
||||
*/
|
||||
goog.fs.ProgressEvent = function(event, target) {
|
||||
goog.fs.ProgressEvent.base(this, 'constructor', event.type, target);
|
||||
|
||||
/**
|
||||
* The underlying event object.
|
||||
* @type {!ProgressEvent}
|
||||
* @private
|
||||
*/
|
||||
this.event_ = event;
|
||||
};
|
||||
goog.inherits(goog.fs.ProgressEvent, goog.events.Event);
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether or not the total size of the of the file being
|
||||
* saved is known.
|
||||
*/
|
||||
goog.fs.ProgressEvent.prototype.isLengthComputable = function() {
|
||||
return this.event_.lengthComputable;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The number of bytes saved so far.
|
||||
*/
|
||||
goog.fs.ProgressEvent.prototype.getLoaded = function() {
|
||||
return this.event_.loaded;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The total number of bytes in the file being saved.
|
||||
*/
|
||||
goog.fs.ProgressEvent.prototype.getTotal = function() {
|
||||
return this.event_.total;
|
||||
};
|
||||
Reference in New Issue
Block a user