/** * @private * The Entry class which is used to represent entries in a file system, * each of which may be a {@link Ext.space.filesystem.FileEntry} or a {@link Ext.space.filesystem.DirectoryEntry}. * * This is an abstract class. * @abstract */Ext.define('Ext.space.filesystem.Entry', { directory: false, path: 0, fileSystem: null, constructor: function(directory, path, fileSystem) { this.directory = directory; this.path = path; this.fileSystem = fileSystem; }, /** * Returns whether the entry is a file. * * @return {Boolean} * The entry is a file. */ isFile: function() { return !this.directory; }, /** * Returns whether the entry is a directory. * * @return {Boolean} * The entry is a directory. */ isDirectory: function() { return this.directory; }, /** * Returns the name of the entry, excluding the path leading to it. * * @return {String} * The entry name. */ getName: function() { var components = this.path.split('/'); for (var i = components.length - 1; i >= 0; --i) { if (components[i].length > 0) { return components[i]; } } return '/'; }, /** * Returns the full absolute path from the root to the entry. * * @return {String} * The entry full path. */ getFullPath: function() { return this.path; }, /** * Returns the file system on which the entry resides. * * @return {Ext.space.filesystem.FileSystem} * The entry file system. */ getFileSystem: function() { return this.fileSystem; }, /** * Moves the entry to a different location on the file system. * * @param {Object} config * The object which contains the following config options: * * @param {Ext.space.filesystem.DirectoryEntry} config.parent This is required. * The directory to which to move the entry. * * @param {String} config.newName This is optional. * The new name of the entry to move. Defaults to the entry's current name if unspecified. * * @param {Function} config.success This is optional. * The callback to be called when the entry has been successfully moved. * * @param {Ext.space.filesystem.Entry} config.success.entry * The entry for the new location. * * @param {Function} config.failure This is optional. * The callback to be called when an error occurred. * * @param {Object} config.failure.error * The occurred error. * * @param {Object} config.scope * The scope object */ moveTo: function(config) { if (config.parent == null) { throw new Error('Ext.space.filesystem.Entry#moveTo: You must specify a new `parent` of the entry.'); return null; } var me = this; Ext.space.Communicator.send({ command: 'FileSystem#moveTo', path: this.path, fileSystemId: this.fileSystem.id, parentPath: config.parent.path, newName: config.newName, copy: config.copy, callbacks: { success: function(path) { if (config.success) { var entry = me.directory ? new Ext.space.filesystem.DirectoryEntry(path, me.fileSystem) : new Ext.space.filesystem.FileEntry(path, me.fileSystem); config.success.call(config.scope || this, entry); } }, failure: function(error) { if (config.failure) { config.failure.call(config.scope || this, error); } } }, scope: config.scope || this }); }, /** * Works the same way as {@link Ext.space.filesystem.Entry#moveTo}, but copies the entry. */ copyTo: function(config) { this.moveTo(Ext.apply(config, { copy: true })); }, /** * Removes the entry from the file system. * * @param {Object} config * The object which contains the following config options: * * @param {Function} config.success This is optional. * The callback to be called when the entry has been successfully removed. * * @param {Function} config.failure This is optional. * The callback to be called when an error occurred. * * @param {Object} config.failure.error * The occurred error. * * @param {Object} config.scope * The scope object */ remove: function(config) { Ext.space.Communicator.send({ command: 'FileSystem#remove', path: this.path, fileSystemId: this.fileSystem.id, recursively: config.recursively, callbacks: { success: function() { if (config.success) { config.success.call(config.scope || this); } }, failure: function(error) { if (config.failure) { config.failure.call(config.scope || this, error); } } }, scope: config.scope || this }); }, /** * Looks up the parent directory containing the entry. * * @param {Object} config * The object which contains the following config options: * * @param {Function} config.success This is required. * The callback to be called when the parent directory has been successfully selected. * * @param {Ext.space.filesystem.DirectoryEntry} config.success.entry * The parent directory of the entry. * * @param {Function} config.failure This is optional. * The callback to be called when an error occurred. * * @param {Object} config.failure.error * The occurred error. * * @param {Object} config.scope * The scope object */ getParent: function(config) { if (!config.success) { throw new Error('Ext.space.filesystem.Entry#getParent: You must specify a `success` callback.'); return null; } var me = this; Ext.space.Communicator.send({ command: 'FileSystem#getParent', path: this.path, fileSystemId: this.fileSystem.id, callbacks: { success: function(path) { var entry = me.directory ? new Ext.space.filesystem.DirectoryEntry(path, me.fileSystem) : new Ext.space.filesystem.FileEntry(path, me.fileSystem); config.success.call(config.scope || this, entry); }, failure: function(error) { if (config.failure) { config.failure.call(config.scope || this, error); } } }, scope: config.scope || this }); }}); /** * @private * The DirectoryEntry class which is used to represent a directory on a file system. */Ext.define('Ext.space.filesystem.DirectoryEntry', { extend: Ext.space.filesystem.Entry, constructor: function(path, fileSystem) { Ext.space.filesystem.DirectoryEntry.superclass.constructor.apply(this, [true, path, fileSystem]); }, /** * Lists all the entries in the directory. * * @param {Object} config * The object which contains the following config options: * * @param {Function} config.success This is required. * The callback to be called when the entries has been successfully read. * * @param {Ext.space.filesystem.Entry[]} config.success.entries * The array of entries of the directory. * * @param {Function} config.failure This is optional. * The callback to be called when an error occurred. * * @param {Object} config.failure.error * The occurred error. * * @param {Object} config.scope * The scope object */ readEntries: function(config) { if (!config.success) { throw new Error('Ext.space.filesystem.DirectoryEntry#readEntries: You must specify a `success` callback.'); return null; } var me = this; Ext.space.Communicator.send({ command: 'FileSystem#readEntries', path: this.path, fileSystemId: this.fileSystem.id, callbacks: { success: function(entryInfos) { var entries = entryInfos.map(function(entryInfo) { return entryInfo.directory ? new Ext.space.filesystem.DirectoryEntry(entryInfo.path, me.fileSystem) : new Ext.space.filesystem.FileEntry(entryInfo.path, me.fileSystem); }); config.success.call(config.scope || this, entries); }, failure: function(error) { if (config.failure) { config.failure.call(config.scope || this, error); } } }, scope: config.scope || this }); }, /** * Creates or looks up a file. * * @param {Object} config * The object which contains the following config options: * * @param {String} config.path This is required. * The absolute path or relative path from the entry to the file to create or select. * * @param {Object} config.options This is optional. * The object which contains the following options: * * @param {Boolean} config.options.create This is optional. * Indicates whether to create a file, if path does not exist. * * @param {Boolean} config.options.exclusive This is optional. Used with 'create', by itself has no effect. * Indicates that method should fail, if path already exists. * * @param {Function} config.success This is optional. * The callback to be called when the file has been successfully created or selected. * * @param {Ext.space.filesystem.Entry} config.success.entry * The created or selected file. * * @param {Function} config.failure This is optional. * The callback to be called when an error occurred. * * @param {Object} config.failure.error * The occurred error. * * @param {Object} config.scope * The scope object */ getFile: function(config) { if (config.path == null) { throw new Error('Ext.space.filesystem.DirectoryEntry#getFile: You must specify a `path` of the file.'); return null; } if (config.options == null) { config.options = {}; } var me = this; Ext.space.Communicator.send({ command: 'FileSystem#getEntry', path: this.path, fileSystemId: this.fileSystem.id, newPath: config.path, directory: config.directory, create: config.options.create, exclusive: config.options.exclusive, callbacks: { success: function(path) { if (config.success) { var entry = config.directory ? new Ext.space.filesystem.DirectoryEntry(path, me.fileSystem) : new Ext.space.filesystem.FileEntry(path, me.fileSystem); config.success.call(config.scope || this, entry); } }, failure: function(error) { if (config.failure) { config.failure.call(config.scope || this, error); } } }, scope: config.scope || this }); }, /** * Works the same way as {@link Ext.space.filesystem.DirectoryEntry#getFile}, * but creates or looks up a directory. */ getDirectory: function(config) { this.getFile(Ext.apply(config, { directory: true })); }, /** * Works the same way as {@link Ext.space.filesystem.Entry#remove}, * but removes the directory and all of its contents, if any. */ removeRecursively: function(config) { this.remove(Ext.apply(config, { recursively: true })); }}); /** * @private * The FileEntry class which is used to represent a file on a file system. */Ext.define('Ext.space.filesystem.FileEntry', { extend: Ext.space.filesystem.Entry, offset: 0, constructor: function(path, fileSystem) { Ext.space.filesystem.FileEntry.superclass.constructor.apply(this, [false, path, fileSystem]); this.offset = 0; }, /** * Returns the byte offset into the file at which the next read/write will occur. * * @return {Number} * The file offset. */ getOffset: function() { return this.offset; }, /** * Sets the byte offset into the file at which the next read/write will occur. * * @param {Object} config * The object which contains the following config options: * * @param {Number} config.offset This is required. * The file offset to set. If negative, the offset back from the end of the file. * * @param {Function} config.success This is optional. * The callback to be called when the file offset has been successfully set. * * @param {Function} config.failure This is optional. * The callback to be called when an error occurred. * * @param {Object} config.failure.error * The occurred error. * * @param {Object} config.scope * The scope object */ seek: function(config) { if (config.offset == null) { throw new Error('Ext.space.filesystem.FileEntry#seek: You must specify an `offset` in the file.'); return null; } var me = this; Ext.space.Communicator.send({ command: 'FileSystem#seek', path: this.path, fileSystemId: this.fileSystem.id, offset: config.offset, callbacks: { success: function(offset) { me.offset = offset; if (config.success) { config.success.call(config.scope || this); } }, failure: function(error) { if (config.failure) { config.failure.call(config.scope || this, error); } } }, scope: config.scope || this }); }, /** * Reads the data from the file starting at the file offset. * * @param {Object} config * The object which contains the following config options: * * @param {Number} config.length This is optional. * The length of bytes to read from the file. Defaults to the file's current size if unspecified. * * @param {Function} config.success This is optional. * The callback to be called when the data has been successfully read. * * @param {Object} config.success.data * The read data. * * @param {Function} config.failure This is optional. * The callback to be called when an error occurred. * * @param {Object} config.failure.error * The occurred error. * * @param {Object} config.scope * The scope object */ read: function(config) { var me = this; Ext.space.Communicator.send({ command: 'FileSystem#read', path: this.path, fileSystemId: this.fileSystem.id, offset: this.offset, length: config.length, callbacks: { success: function(result) { me.offset = result.offset; if (config.success) { config.success.call(config.scope || this, result.data); } }, failure: function(error) { if (config.failure) { config.failure.call(config.scope || this, error); } } }, scope: config.scope || this }); }, /** * Writes the data to the file starting at the file offset. * * @param {Object} config * The object which contains the following config options: * * @param {Object} config.data This is required. * The data to write to the file. * * @param {Function} config.success This is optional. * The callback to be called when the data has been successfully written. * * @param {Function} config.failure This is optional. * The callback to be called when an error occurred. * * @param {Object} config.failure.error * The occurred error. * * @param {Object} config.scope * The scope object */ write: function(config) { if (config.data == null) { throw new Error('Ext.space.filesystem.FileEntry#write: You must specify a `data` for the file.'); return null; } var me = this; Ext.space.Communicator.send({ command: 'FileSystem#write', path: this.path, fileSystemId: this.fileSystem.id, offset: this.offset, data: config.data, callbacks: { success: function(offset) { me.offset = offset; if (config.success) { config.success.call(config.scope || this); } }, failure: function(error) { if (config.failure) { config.failure.call(config.scope || this, error); } } }, scope: config.scope || this }); }, /** * Truncates or extends the file to the specified size in bytes. * If the file is extended, the added bytes are null bytes. * * @param {Object} config * The object which contains the following config options: * * @param {Number} config.size This is required. * The new file size. * * @param {Function} config.success This is optional. * The callback to be called when the file size has been successfully changed. * * @param {Function} config.failure This is optional. * The callback to be called when an error occurred. * * @param {Object} config.failure.error * The occurred error. * * @param {Object} config.scope * The scope object */ truncate: function(config) { if (config.size == null) { throw new Error('Ext.space.filesystem.FileEntry#truncate: You must specify a `size` of the file.'); return null; } var me = this; Ext.space.Communicator.send({ command: 'FileSystem#truncate', path: this.path, fileSystemId: this.fileSystem.id, offset: this.offset, size: config.size, callbacks: { success: function(offset) { me.offset = offset; if (config.success) { config.success.call(config.scope || this); } }, failure: function(error) { if (config.failure) { config.failure.call(config.scope || this, error); } } }, scope: config.scope || this }); }}); /** * @private */Ext.define('Ext.space.filesystem.FileSystem', { id: 0, root: null, constructor: function(id) { this.id = id; this.root = new Ext.space.filesystem.DirectoryEntry('/', this); }, /** * Returns a {@link Ext.space.filesystem.DirectoryEntry} instance for the root of the file system. * * @return {Ext.space.filesystem.DirectoryEntry} * The file system root directory. */ getRoot: function() { return this.root; }}); /** * @private */Ext.define('Ext.space.FileSystem', { singleton: true, /** * Requests a {@link Ext.space.filesystem.FileSystem} instance. * * @param {Object} config * The object which contains the following config options: * * @param {Function} config.type This is optional. * The type of a file system to request. Specify "LOCKER" to request the File Locker. * * @param {Function} config.success This is required. * The callback to be called when the file system has been successfully created. * * @param {Ext.space.filesystem.FileSystem} config.success.fileSystem * The created file system. * * @param {Function} config.failure This is optional. * The callback to be called when an error occurred. * * @param {Object} config.failure.error * The occurred error. * * @param {Object} config.scope * The scope object */ requestFileSystem: function(config) { if (!config.success) { throw new Error('Ext.space.filesystem#requestFileSystem: You must specify a `success` callback.'); return null; } Ext.space.Communicator.send({ command: 'FileSystem#requestFileSystem', callbacks: { type: config.type, success: function(id) { var fileSystem = new Ext.space.filesystem.FileSystem(id); config.success.call(config.scope || this, fileSystem); }, failure: function(error) { if (config.failure) { config.failure.call(config.scope || this, error); } } }, scope: config.scope || this }); }});