/** * @private */ Ext.define('Ext.device.filesystem.HTML5', { extend: 'Ext.device.filesystem.Abstract', /** * {@link Ext.device.filesystem.FileSystem}インスタンスをリクエストします。 * * var me = this; * var fs = Ext.create("Ext.device.FileSystem", {}); * fs.requestFileSystem({ * type: window.PERSISTENT, * size: 1024 * 1024, * success: function(fileSystem) { * me.fs = fileSystem; * }, * failure: function(err) { * console.log("FileSystem Failure: " + err.code); * } * }); * * @param {Object} config * オブジェクトには次のコンフィグオプションがあります。 * * @param {Number} config.type * window.TEMPORARY (0)またはwindow.PERSISTENT (1) * * @param {Number} config.size * アプリケーションに必要なストレージ容量です(単位はバイト)。 * * @param {Function} config.success 必須。ファイルシステムの作成に成功したときに呼び出されるコールバックです。 * * @param {Ext.device.filesystem.FileSystem} config.success.fileSystem * 作成したファイルシステムです。 * * @param {Function} config.failure オプション。エラーが発生したときに呼び出されるコールバックです。 * * @param {Object} config.failure.error * 発生したエラーです。 * * @param {Object} config.scope * スコープオブジェクトです。 */ requestFileSystem: function(config) { if (!config.success) { Ext.Logger.error('Ext.device.filesystem#requestFileSystem: You must specify a `success` callback.'); return null; } var me = this; var successCallback = function(fs) { var fileSystem = Ext.create('Ext.device.filesystem.FileSystem', fs); config.success.call(config.scope || me, fileSystem); }; window.requestFileSystem( config.type, config.size, successCallback, config.failure || Ext.emptyFn ); } }, function() { /** * ファイルシステムの表現に使用するFileSystemクラスです。 */ Ext.define('Ext.device.filesystem.FileSystem', { fs: null, root: null, constructor: function(fs) { this.fs = fs; this.root = Ext.create('Ext.device.filesystem.DirectoryEntry', '/', this); }, /** * ファイルシステムのルートに{@link Ext.device.filesystem.DirectoryEntry}インスタンスを返します。 * * @return {Ext.device.filesystem.DirectoryEntry} ファイルシステムのルートディレクトリです。 */ getRoot: function() { return this.root; } }, function() { /** * ファイルシステムのエントリの表現に使用するエントリクラスです。それぞれが{@link Ext.device.filesystem.FileEntry}または{@link Ext.device.filesystem.DirectoryEntry}です。 * * これは抽象クラスです。 * @abstract */ Ext.define('Ext.device.filesystem.Entry', { directory: false, path: 0, fileSystem: null, entry: null, constructor: function(directory, path, fileSystem) { this.directory = directory; this.path = path; this.fileSystem = fileSystem; }, /** * エントリがファイルであるかどうかを返します。 * * @return {Boolean} エントリはファイルです。 */ isFile: function() { return !this.directory; }, /** * エントリがディレクトリであるかどうかを返します。 * * @return {Boolean} エントリはディレクトリです。 */ isDirectory: function() { return this.directory; }, /** * パス部分を除いたエントリ名を返します。 * * @return {String} エントリ名です。 */ 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 '/'; }, /** * ルートからエントリまでの完全な絶対パスを返します。 * * @return {String} エントリの完全パスです。 */ getFullPath: function() { return this.path; }, /** * エントリがあるファイルシステムを返します。 * * @return {Ext.device.filesystem.FileSystem} エントリがあるファイルシステムです。 */ getFileSystem: function() { return this.fileSystem; }, getEntry: function() { return null; }, /** * エントリをファイルシステム内の別の場所に移動します。 * * @param {Object} config * オブジェクトには次のコンフィグオプションがあります。 * * @param {Ext.device.filesystem.DirectoryEntry} config.parent 必須。エントリの移動先となるディレクトリです。 * * @param {String} config.newName オプション。移動するエントリの新しい名前です。指定しない場合、デフォルト値であるエントリの現在の名前になります。 * * @param {Function} config.success オプション。エントリの移動に成功したときに呼び出されるコールバックです。 * * @param {Ext.device.filesystem.Entry} config.success.entry * 新しい場所のエントリです。 * * @param {Function} config.failure オプション。エラーが発生したときに呼び出されるコールバックです。 * * @param {Object} config.failure.error * 発生したエラーです。 * * @param {Object} config.scope * スコープオブジェクトです。 */ moveTo: function(config) { if (config.parent == null) { Ext.Logger.error('Ext.device.filesystem.Entry#moveTo: You must specify a new `parent` of the entry.'); return null; } var me = this; this.getEntry( { options: config.options || {}, success: function(sourceEntry) { config.parent.getEntry( { options: config.options || {}, success: function(destinationEntry) { if (config.copy) { sourceEntry.copyTo(destinationEntry, config.newName, function(entry) { config.success.call( config.scope || me, entry.isDirectory ? Ext.create('Ext.device.filesystem.DirectoryEntry', entry.fullPath, me.fileSystem) : Ext.create('Ext.device.filesystem.FileEntry', entry.fullPath, me.fileSystem) ); }, config.failure); } else { sourceEntry.moveTo(destinationEntry, config.newName, function(entry) { config.success.call( config.scope || me, entry.isDirectory ? Ext.create('Ext.device.filesystem.DirectoryEntry', entry.fullPath, me.fileSystem) : Ext.create('Ext.device.filesystem.FileEntry', entry.fullPath, me.fileSystem) ); }, config.failure); } }, failure: config.failure } ); }, failure: config.failure } ); }, /** * {@link Ext.device.filesystem.Entry#moveTo}と同じように機能しますが、エントリをコピーします。 */ copyTo: function(config) { this.moveTo(Ext.apply(config, { copy: true })); }, /** * ファイルシステムからエントリを削除します。 * * @param {Object} config * オブジェクトには次のコンフィグオプションがあります。 * * @param {Boolean} config.recursively オプション。任意のディレクトリとそのコンテンツすべてを削除します。 * * @param {Function} config.success オプション。エントリの削除に成功したときに呼び出されるコールバックです。 * * @param {Function} config.failure オプション。エラーが発生したときに呼び出されるコールバックです。 * * @param {Object} config.failure.error * 発生したエラーです。 * * @param {Object} config.scope * スコープオブジェクトです。 */ remove: function(config) { this.getEntry( { success: function(entry) { if (config.recursively && this.directory) { entry.removeRecursively(config.success, config.failure) } else { entry.remove(config.success, config.failure) } }, failure: config.failure } ) }, /** * そのエントリを保持する親ディレクトリを検索します。 * * @param {Object} config * オブジェクトには次のコンフィグオプションがあります。 * * @param {Function} config.success 必須。親ディレクトリの選択に成功したときに呼び出されるコールバックです。 * * @param {Ext.device.filesystem.DirectoryEntry} config.success.entry * エントリの親ディレクトリです。 * * @param {Function} config.failure オプション。エラーが発生したときに呼び出されるコールバックです。 * * @param {Object} config.failure.error * 発生したエラーです。 * * @param {Object} config.scope * スコープオブジェクトです。 */ getParent: function(config) { if (!config.success) { Ext.Logger.error('Ext.device.filesystem.Entry#getParent: You must specify a `success` callback.'); return null; } var me = this; this.getEntry( { options: config.options || {}, success: function(entry) { entry.getParent( function(parentEntry) { config.success.call( config.scope || me, parentEntry.isDirectory ? Ext.create('Ext.device.filesystem.DirectoryEntry', parentEntry.fullPath, me.fileSystem) : Ext.create('Ext.device.filesystem.FileEntry', parentEntry.fullPath, me.fileSystem) ) }, config.failure ) }, failure: config.failure } ) } }); /** * ファイルシステムのディレクトリの表現に使用するDirectoryEntryクラスです。 */ Ext.define('Ext.device.filesystem.DirectoryEntry', { extend: 'Ext.device.filesystem.Entry', cachedDirectory: null, constructor: function(path, fileSystem) { this.callParent([true, path, fileSystem]); }, /** * ローカルのファイルシステムのディレクトリをリクエストします。 * * @param {Object} config * * @param {Object} config.options * ファイル作成オプションです({create:true、exclusive:false})。 * * @param {Boolean} config.options.create * ディレクトリがない場合に作成するかどうかを示します。 * * @param {Boolean} config.options.exclusive * 作成オプションと共に使用する場合は、ディレクトリが既に存在する場合に作成処理によってエラーが発生したかどうかのみを示します。 * * @param {Function} config.success * ディレクトリが正常に返されたときに呼び出される関数です。 * * @param {Ext.device.filesystem.DirectoryEntry} config.success.directory * DirectoryEntryオブジェクトです。 * * @param {Function} config.failure * ディレクトリリクエストがエラーとなった場合に呼び出される関数です。 * * @param {FileError} config.failure.error */ getEntry: function(config) { var me = this; var callback = config.success; if ((config.options && config.options.create) && this.path) { var folders = this.path.split("/"); if (folders[0] == '.' || folders[0] == '') { folders = folders.slice(1); } var recursiveCreation = function(dirEntry) { if (folders.length) { dirEntry.getDirectory(folders.shift(), config.options, recursiveCreation, config.failure); } else { callback(dirEntry); } }; recursiveCreation(this.fileSystem.fs.root); } else { this.fileSystem.fs.root.getDirectory(this.path, config.options, function(directory) { config.success.call(config.scope || me, directory); }, config.failure ); } }, /** * ディレクトリ内のエントリをすべてリストします。 * * @param {Object} config * オブジェクトには次のコンフィグオプションがあります。 * * @param {Function} config.success 必須。エントリの読み取りに成功したときに呼び出されるコールバックです。 * * @param {Ext.device.filesystem.Entry[]} config.success.entries * ディレクトリのエントリの配列です。 * * @param {Function} config.failure オプション。エラーが発生したときに呼び出されるコールバックです。 * * @param {Object} config.failure.error * 発生したエラーです。 * * @param {Object} config.scope * スコープオブジェクトです。 */ readEntries: function(config) { if (!config.success) { Ext.Logger.error('Ext.device.filesystem.DirectoryEntry#readEntries: You must specify a `success` callback.'); return null; } var me = this; this.getEntry( { success: function(dirEntry) { var directoryReader = dirEntry.createReader(); directoryReader.readEntries( function(entryInfos) { var entries = [], i = 0, len = entryInfos.length; for (; i < len; i++) { entryInfo = entryInfos[i]; entries[i] = entryInfo.isDirectory ? Ext.create('Ext.device.filesystem.DirectoryEntry', entryInfo.fullPath, me.fileSystem) : Ext.create('Ext.device.filesystem.FileEntry', entryInfo.fullPath, me.fileSystem); } config.success.call(config.scope || this, entries); }, function(error) { if (config.failure) { config.failure.call(config.scope || this, error); } } ); }, failure: config.failure } ); }, /** * ファイルを作成または検索します。 * * @param {Object} config * オブジェクトには次のコンフィグオプションがあります。 * * @param {String} config.path 必須。エントリから作成または選択するファイルまでの絶対パスまたは相対パスです。 * * @param {Object} config.options オプション。オブジェクトには次のオプションがあります。 * * @param {Boolean} config.options.create オプション。パスがない場合にファイルを作成するかどうかを示します。 * * @param {Boolean} config.options.exclusive オプション。'create'の場合に使用します。単体では効力を持ちません。パスが存在する場合、メソッドの処理を失敗とするかどうかを示します。 * * @param {Function} config.success オプション。ファイルの作成または選択に成功したときに呼び出されるコールバックです。 * * @param {Ext.device.filesystem.Entry} config.success.entry * 作成または選択したファイルです。 * * @param {Function} config.failure オプション。エラーが発生したときに呼び出されるコールバックです。 * * @param {Object} config.failure.error * 発生したエラーです。 * * @param {Object} config.scope * スコープオブジェクトです。 */ getFile: function(config) { if (config.path == null) { Ext.Logger.error('Ext.device.filesystem.DirectoryEntry#getFile: You must specify a `path` of the file.'); return null; } var me = this; var fullPath = this.path + config.path; var fileEntry = Ext.create('Ext.device.filesystem.FileEntry', fullPath, this.fileSystem); fileEntry.getEntry( { success: function() { config.success.call(config.scope || me, fileEntry); }, options: config.options || {}, failure: config.failure } ) }, /** * {@link Ext.device.filesystem.DirectoryEntry#getFile}と同じように機能しますが、ディレクトリを作成または検索します。 */ getDirectory: function(config) { if (config.path == null) { Ext.Logger.error('Ext.device.filesystem.DirectoryEntry#getFile: You must specify a `path` of the file.'); return null; } var me = this; var fullPath = this.path + config.path; var directoryEntry = Ext.create('Ext.device.filesystem.DirectoryEntry', fullPath, this.fileSystem); directoryEntry.getEntry( { success: function() { config.success.call(config.scope || me, directoryEntry); }, options: config.options || {}, failure: config.failure } ) }, /** * {@link Ext.device.filesystem.Entry#remove}と同じように機能しますが、対象のディレクトリがある場合にそのディレクトリとコンテンツすべてを削除します。 */ removeRecursively: function(config) { this.remove(Ext.apply(config, { recursively: true })); } }); /** * ファイルシステムのファイルの表現に使用するFileEntryクラスです。 */ Ext.define('Ext.device.filesystem.FileEntry', { extend: 'Ext.device.filesystem.Entry', length: 0, offset: 0, constructor: function(path, fileSystem) { this.callParent([false, path, fileSystem]); this.offset = 0; this.length = 0; }, /** * ローカルのファイルシステムのファイルハンドルをリクエストします。 * * @param {Object} config * * @param {String} config.file * Filenameにはオプションでパスが文字フォーマット'/tmp/debug.txt'またはファイルオブジェクトとして含まれまれます。 * * @param {Object} config.options * ファイル作成オプションです({create:true、exclusive:false})。 * * @param {Boolean} config.options.create * ファイルがない場合に作成するかどうかを示します。 * * @param {Boolean} config.options.exclusive * 作成オプションと共に使用する場合は、ファイルが既に存在する場合に作成処理によってエラーが発生したかどうかのみを示します。 * * @param {Function} config.success * ファイルシステムが正常に返されたときに呼び出される関数です。 * * @param {FileSystem} config.success.entry * * @param {Function} config.failure * ファイルシステムリクエストがエラーとなった場合に呼び出される関数です。 * * @param {FileError} config.failure.error * */ getEntry: function(config) { var me = this; var originalConfig = Ext.applyIf({}, config); if (this.fileSystem) { var failure = function(evt) { if ((config.options && config.options.create) && Ext.isString(this.path)) { var folders = this.path.split("/"); if (folders[0] == '.' || folders[0] == '') { folders = folders.slice(1); } if (folders.length > 1 && !config.recursive === true) { folders.pop(); var dirEntry = Ext.create('Ext.device.filesystem.DirectoryEntry', folders.join("/"), me.fileSystem); dirEntry.getEntry( { options: config.options, success: function() { originalConfig.recursive = true; me.getEntry(originalConfig); }, failure: config.failure } ); } else { if (config.failure) { config.failure.call(config.scope || me, evt); } } } else { if (config.failure) { config.failure.call(config.scope || me, evt); } } }; this.fileSystem.fs.root.getFile(this.path, config.options || null, function(fileEntry) { fileEntry.file( function(file) { me.length = file.size; originalConfig.success.call(config.scope || me, fileEntry); }, function(error) { failure.call(config.scope || me, error); } ); }, function(error) { failure.call(config.scope || me, error); } ); } else { config.failure({code: -1, message: "FileSystem not Initialized"}); } }, /** * 次の読み取りや書き込みを開始するファイルのオフセットをバイト単位で返します。 * * @return {Number} ファイルのオフセット。 */ getOffset: function() { return this.offset; }, /** * 次の読み取りや書き込みを開始するファイルのオフセットをバイト単位で設定します。 * * @param {Object} config * オブジェクトには次のコンフィグオプションがあります。 * * @param {Number} config.offset 必須。設定するファイルのオフセットです。負の値の場合、ファイルの末尾から後方へオフセットします。 * * @param {Function} config.success オプション。ファイルのオフセットの設定に成功したときに呼び出されるコールバックです。 * * @param {Function} config.failure オプション。エラーが発生したときに呼び出されるコールバックです。 * * @param {Object} config.failure.error * 発生したエラーです。 * * @param {Object} config.scope * スコープオブジェクトです。 */ seek: function(config) { if (config.offset == null) { Ext.Logger.error('Ext.device.filesystem.FileEntry#seek: You must specify an `offset` in the file.'); return null; } this.offset = config.offset || 0; if (config.success) { config.success.call(config.scope || this); } }, /** * ファイルのオフセット位置からファイルデータの読み取りを開始します。 * * @param {Object} config * オブジェクトには次のコンフィグオプションがあります。 * * @param {Number} config.length オプション。ファイルを読み取る長さをバイト単位で指定します。指定しない場合、デフォルト値であるファイルの現在のサイズになります。 * * @param {String} config.encoding * テキストとして読み取る場合にのみ使用するオプションのエンコードタイプです。 * * @param {String} config.type * 読み取りに使用するタイプです。オプションは"text" (デフォルト値)、"dataURL"、"binaryString"、"arrayBuffer"です。 * * @param {Object} config.reader * ファイルリーダーに適用するオプションのコンフィグパラメータです。 * * @param {Function} config.reader.onloadstart * @param {Function} config.reader.onloadprogress * @param {Function} config.reader.onload * @param {Function} config.reader.onabort * @param {Function} config.reader.onerror * @param {Function} config.reader.onloadend * * @param {Function} config.success オプション。データの読み取りに成功したときに呼び出されるコールバックです。 * * @param {Object} config.success.data * 読み取ったデータです。 * * @param {Function} config.failure オプション。エラーが発生したときに呼び出されるコールバックです。 * * @param {Object} config.failure.error * 発生したエラーです。 * * @param {Object} config.scope * スコープオブジェクトです。 */ read: function(config) { var me = this; this.getEntry( { success: function(fileEntry) { fileEntry.file( function(file) { if (Ext.isNumber(config.length)) { if (Ext.isFunction(file.slice)) { file = file.slice(me.offset, config.length); } else { if (config.failure) { config.failure.call(config.scope || me, {code: -2, message: "File missing slice functionality"}); } return; } } var reader = new FileReader(); reader.onloadend = function(evt) { config.success.call(config.scope || me, evt.target.result); }; reader.onerror = function(error) { config.failure.call(config.scope || me, error); }; if (config.reader) { reader = Ext.applyIf(reader, config.reader); } config.encoding = config.encoding || "UTF8"; switch (config.type) { default: case "text": reader.readAsText(file, config.encoding); break; case "dataURL": reader.readAsDataURL(file); break; case "binaryString": reader.readAsBinaryString(file); break; case "arrayBuffer": reader.readAsArrayBuffer(file); break; } }, function(error) { config.failure.call(config.scope || me, error) } ); }, failure: function(error) { config.failure.call(config.scope || me, error) } } ) }, /** * ファイルのオフセット位置からファイルへのデータ書き込みを開始します。 * * @param {Object} config * オブジェクトには次のコンフィグオプションがあります。 * * @param {Object} config.data 必須。ファイルに書き込むデータです。 * * @param {Boolean} config.append オプション。ファイルの末尾に追加します。 * * @param {Object} config.writer * ファイルリーダーに適用するオプションのコンフィグパラメータです。 * * @param {Function} config.writer.onwritestart * @param {Function} config.writer.onprogress * @param {Function} config.writer.onwrite * @param {Function} config.writer.onabort * @param {Function} config.writer.onerror * @param {Function} config.writer.onwriteend * * @param {Function} config.success オプション。データの書き込みに成功したときに呼び出されるコールバックです。 * * @param {Function} config.failure オプション。エラーが発生したときに呼び出されるコールバックです。 * * @param {Object} config.failure.error * 発生したエラーです。 * * @param {Object} config.scope * スコープオブジェクトです。 */ write: function(config) { if (config.data == null) { Ext.Logger.error('Ext.device.filesystem.FileEntry#write: You must specify `data` to write into the file.'); return null; } var me = this; this.getEntry( { options: config.options || {}, success: function(fileEntry) { fileEntry.createWriter( function(writer) { writer.onwriteend = function(evt) { me.length = evt.target.length; config.success.call(config.scope || me, evt.result); }; writer.onerror = function(error) { config.failure.call(config.scope || me, error); }; if (config.writer) { writer = Ext.applyIf(writer, config.writer); } if (me.offset) { writer.seek(me.offset); } else if (config.append) { writer.seek(me.length); } me.writeData (writer, config.data); }, function(error) { config.failure.call(config.scope || me, error) } ) }, failure: function(error) { config.failure.call(config.scope || me, error) } } ) }, writeData: function(writer, data) { writer.write(new Blob([data])); }, /** * バイト単位で指定したサイズになるようにファイルを小さくまたは大きくします。ファイルを大きくする場合、nullバイトが追加されます。 * * @param {Object} config * オブジェクトには次のコンフィグオプションがあります。 * * @param {Number} config.size 必須。新しいファイルサイズです。 * * @param {Function} config.success オプション。ファイルサイズの変更に成功したときに呼び出されるコールバックです。 * * @param {Function} config.failure オプション。エラーが発生したときに呼び出されるコールバックです。 * * @param {Object} config.failure.error * 発生したエラーです。 * * @param {Object} config.scope * スコープオブジェクトです。 */ truncate: function(config) { if (config.size == null) { Ext.Logger.error('Ext.device.filesystem.FileEntry#write: You must specify a `size` of the file.'); return null; } var me = this; //noinspection JSValidateTypes this.getEntry( { success: function(fileEntry) { fileEntry.createWriter( function(writer) { writer.truncate(config.size); config.success.call(config.scope || me, me); }, function(error) { config.failure.call(config.scope || me, error) } ) }, failure: function(error) { config.failure.call(config.scope || me, error) } } ) } }); }); });