Home | History | Annotate | Download | only in front_end
      1 /*
      2  * Copyright (C) 2012 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 /**
     32  * @constructor
     33  * @extends {WebInspector.Object}
     34  */
     35 WebInspector.FileSystemModel = function()
     36 {
     37     WebInspector.Object.call(this);
     38 
     39     this._fileSystemsForOrigin = {};
     40 
     41     WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.SecurityOriginAdded, this._securityOriginAdded, this);
     42     WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.SecurityOriginRemoved, this._securityOriginRemoved, this);
     43 
     44     FileSystemAgent.enable();
     45 
     46     this._reset();
     47 }
     48 
     49 WebInspector.FileSystemModel.prototype = {
     50     _reset: function()
     51     {
     52         for (var securityOrigin in this._fileSystemsForOrigin)
     53             this._removeOrigin(securityOrigin);
     54         var securityOrigins = WebInspector.resourceTreeModel.securityOrigins();
     55         for (var i = 0; i < securityOrigins.length; ++i)
     56             this._addOrigin(securityOrigins[i]);
     57     },
     58 
     59     /**
     60      * @param {WebInspector.Event} event
     61      */
     62     _securityOriginAdded: function(event)
     63     {
     64         var securityOrigin = /** @type {string} */ (event.data);
     65         this._addOrigin(securityOrigin);
     66     },
     67 
     68     /**
     69      * @param {WebInspector.Event} event
     70      */
     71     _securityOriginRemoved: function(event)
     72     {
     73         var securityOrigin = /** @type {string} */ (event.data);
     74         this._removeOrigin(securityOrigin);
     75     },
     76 
     77     /**
     78      * @param {string} securityOrigin
     79      */
     80     _addOrigin: function(securityOrigin)
     81     {
     82         this._fileSystemsForOrigin[securityOrigin] = {};
     83 
     84         var types = ["persistent", "temporary"];
     85         for (var i = 0; i < types.length; ++i)
     86             this._requestFileSystemRoot(securityOrigin, types[i], this._fileSystemRootReceived.bind(this, securityOrigin, types[i], this._fileSystemsForOrigin[securityOrigin]));
     87     },
     88 
     89     /**
     90      * @param {string} securityOrigin
     91      */
     92     _removeOrigin: function(securityOrigin)
     93     {
     94         for (var type in this._fileSystemsForOrigin[securityOrigin]) {
     95             var fileSystem = this._fileSystemsForOrigin[securityOrigin][type];
     96             delete this._fileSystemsForOrigin[securityOrigin][type];
     97             this._fileSystemRemoved(fileSystem);
     98         }
     99         delete this._fileSystemsForOrigin[securityOrigin];
    100     },
    101 
    102     /**
    103      * @param {string} origin
    104      * @param {string} type
    105      * @param {function(number, FileSystemAgent.Entry=)} callback
    106      */
    107     _requestFileSystemRoot: function(origin, type, callback)
    108     {
    109         /**
    110          * @param {?Protocol.Error} error
    111          * @param {number} errorCode
    112          * @param {FileSystemAgent.Entry=} backendRootEntry
    113          */
    114         function innerCallback(error, errorCode, backendRootEntry)
    115         {
    116             if (error) {
    117                 callback(FileError.SECURITY_ERR);
    118                 return;
    119             }
    120 
    121             callback(errorCode, backendRootEntry);
    122         }
    123 
    124         FileSystemAgent.requestFileSystemRoot(origin, type, innerCallback.bind(this));
    125     },
    126 
    127     /**
    128      * @param {WebInspector.FileSystemModel.FileSystem} fileSystem
    129      */
    130     _fileSystemAdded: function(fileSystem)
    131     {
    132         this.dispatchEventToListeners(WebInspector.FileSystemModel.EventTypes.FileSystemAdded, fileSystem);
    133     },
    134 
    135     /**
    136      * @param {WebInspector.FileSystemModel.FileSystem} fileSystem
    137      */
    138     _fileSystemRemoved: function(fileSystem)
    139     {
    140         this.dispatchEventToListeners(WebInspector.FileSystemModel.EventTypes.FileSystemRemoved, fileSystem);
    141     },
    142 
    143     refreshFileSystemList: function()
    144     {
    145         this._reset();
    146     },
    147 
    148     /**
    149      * @param {string} origin
    150      * @param {string} type
    151      * @param {Object.<WebInspector.FileSystemModel.FileSystem>} store
    152      * @param {number} errorCode
    153      * @param {FileSystemAgent.Entry=} backendRootEntry
    154      */
    155     _fileSystemRootReceived: function(origin, type, store, errorCode, backendRootEntry)
    156     {
    157         if (!errorCode && backendRootEntry && this._fileSystemsForOrigin[origin] === store) {
    158             var fileSystem = new WebInspector.FileSystemModel.FileSystem(this, origin, type, backendRootEntry);
    159             store[type] = fileSystem;
    160             this._fileSystemAdded(fileSystem);
    161         }
    162     },
    163 
    164     /**
    165      * @param {WebInspector.FileSystemModel.Directory} directory
    166      * @param {function(number, Array.<WebInspector.FileSystemModel.Entry>=)} callback
    167      */
    168     requestDirectoryContent: function(directory, callback)
    169     {
    170         this._requestDirectoryContent(directory.url, this._directoryContentReceived.bind(this, directory, callback));
    171     },
    172 
    173     /**
    174      * @param {string} url
    175      * @param {function(number, Array.<FileSystemAgent.Entry>=)} callback
    176      */
    177     _requestDirectoryContent: function(url, callback)
    178     {
    179         /**
    180          * @param {?Protocol.Error} error
    181          * @param {number} errorCode
    182          * @param {Array.<FileSystemAgent.Entry>=} backendEntries
    183          */
    184         function innerCallback(error, errorCode, backendEntries)
    185         {
    186             if (error) {
    187                 callback(FileError.SECURITY_ERR);
    188                 return;
    189             }
    190 
    191             if (errorCode !== 0) {
    192                 callback(errorCode, null);
    193                 return;
    194             }
    195 
    196             callback(errorCode, backendEntries);
    197         }
    198 
    199         FileSystemAgent.requestDirectoryContent(url, innerCallback.bind(this));
    200     },
    201 
    202     /**
    203      * @param {WebInspector.FileSystemModel.Directory} parentDirectory
    204      * @param {function(number, Array.<WebInspector.FileSystemModel.Entry>=)} callback
    205      * @param {number} errorCode
    206      * @param {Array.<FileSystemAgent.Entry>=} backendEntries
    207      */
    208     _directoryContentReceived: function(parentDirectory, callback, errorCode, backendEntries)
    209     {
    210         var entries = [];
    211         for (var i = 0; i < backendEntries.length; ++i) {
    212             if (backendEntries[i].isDirectory)
    213                 entries.push(new WebInspector.FileSystemModel.Directory(this, parentDirectory.fileSystem, backendEntries[i]));
    214             else
    215                 entries.push(new WebInspector.FileSystemModel.File(this, parentDirectory.fileSystem, backendEntries[i]));
    216         }
    217 
    218         callback(errorCode, entries);
    219     },
    220 
    221     /**
    222      * @param {WebInspector.FileSystemModel.Entry} entry
    223      * @param {function(number, FileSystemAgent.Metadata=)} callback
    224      */
    225     requestMetadata: function(entry, callback)
    226     {
    227         /**
    228          * @param {?Protocol.Error} error
    229          * @param {number} errorCode
    230          * @param {FileSystemAgent.Metadata=} metadata
    231          */
    232         function innerCallback(error, errorCode, metadata)
    233         {
    234             if (error) {
    235                 callback(FileError.SECURITY_ERR);
    236                 return;
    237             }
    238 
    239             callback(errorCode, metadata);
    240         }
    241 
    242         FileSystemAgent.requestMetadata(entry.url, innerCallback.bind(this));
    243     },
    244 
    245     /**
    246      * @param {WebInspector.FileSystemModel.File} file
    247      * @param {boolean} readAsText
    248      * @param {number=} start
    249      * @param {number=} end
    250      * @param {string=} charset
    251      * @param {function(number, string=, string=)=} callback
    252      */
    253     requestFileContent: function(file, readAsText, start, end, charset, callback)
    254     {
    255         this._requestFileContent(file.url, readAsText, start, end, charset, callback);
    256     },
    257 
    258     /**
    259      * @param {string} url
    260      * @param {boolean} readAsText
    261      * @param {number=} start
    262      * @param {number=} end
    263      * @param {string=} charset
    264      * @param {function(number, string=, string=)=} callback
    265      */
    266     _requestFileContent: function(url, readAsText, start, end, charset, callback)
    267     {
    268         /**
    269          * @param {?Protocol.Error} error
    270          * @param {number} errorCode
    271          * @param {string=} content
    272          * @param {string=} charset
    273          */
    274         function innerCallback(error, errorCode, content, charset)
    275         {
    276             if (error) {
    277                 if (callback)
    278                     callback(FileError.SECURITY_ERR);
    279                 return;
    280             }
    281 
    282             if (callback)
    283                 callback(errorCode, content, charset);
    284         }
    285 
    286         FileSystemAgent.requestFileContent(url, readAsText, start, end, charset, innerCallback.bind(this));
    287     },
    288     /**
    289      * @param {WebInspector.FileSystemModel.Entry} entry
    290      * @param {function(number)=} callback
    291      */
    292     deleteEntry: function(entry, callback)
    293     {
    294         var fileSystemModel = this;
    295         if (entry === entry.fileSystem.root)
    296             this._deleteEntry(entry.url, hookFileSystemDeletion);
    297         else
    298             this._deleteEntry(entry.url, callback);
    299 
    300         function hookFileSystemDeletion(errorCode)
    301         {
    302             callback(errorCode);
    303             if (!errorCode)
    304                 fileSystemModel._removeFileSystem(entry.fileSystem);
    305         }
    306     },
    307 
    308     /**
    309      * @param {string} url
    310      * @param {function(number)=} callback
    311      */
    312     _deleteEntry: function(url, callback)
    313     {
    314         /**
    315          * @param {?Protocol.Error} error
    316          * @param {number} errorCode
    317          */
    318         function innerCallback(error, errorCode)
    319         {
    320             if (error) {
    321                 if (callback)
    322                     callback(FileError.SECURITY_ERR);
    323                 return;
    324             }
    325 
    326             if (callback)
    327                 callback(errorCode);
    328         }
    329 
    330         FileSystemAgent.deleteEntry(url, innerCallback.bind(this));
    331     },
    332 
    333     /**
    334      * @param {WebInspector.FileSystemModel.FileSystem} fileSystem
    335      */
    336     _removeFileSystem: function(fileSystem)
    337     {
    338         var origin = fileSystem.origin;
    339         var type = fileSystem.type;
    340         if (this._fileSystemsForOrigin[origin] && this._fileSystemsForOrigin[origin][type]) {
    341             delete this._fileSystemsForOrigin[origin][type];
    342             this._fileSystemRemoved(fileSystem);
    343 
    344             if (Object.isEmpty(this._fileSystemsForOrigin[origin]))
    345                 delete this._fileSystemsForOrigin[origin];
    346         }
    347     },
    348 
    349     __proto__: WebInspector.Object.prototype
    350 }
    351 
    352 
    353 WebInspector.FileSystemModel.EventTypes = {
    354     FileSystemAdded: "FileSystemAdded",
    355     FileSystemRemoved: "FileSystemRemoved"
    356 }
    357 
    358 /**
    359  * @constructor
    360  * @param {WebInspector.FileSystemModel} fileSystemModel
    361  * @param {string} origin
    362  * @param {string} type
    363  * @param {FileSystemAgent.Entry} backendRootEntry
    364  */
    365 WebInspector.FileSystemModel.FileSystem = function(fileSystemModel, origin, type, backendRootEntry)
    366 {
    367     this.origin = origin;
    368     this.type = type;
    369 
    370     this.root = new WebInspector.FileSystemModel.Directory(fileSystemModel, this, backendRootEntry);
    371 }
    372 
    373 WebInspector.FileSystemModel.FileSystem.prototype = {
    374     /**
    375      * @type {string}
    376      */
    377     get name()
    378     {
    379         return "filesystem:" + this.origin + "/" + this.type;
    380     }
    381 }
    382 
    383 /**
    384  * @constructor
    385  * @param {WebInspector.FileSystemModel} fileSystemModel
    386  * @param {WebInspector.FileSystemModel.FileSystem} fileSystem
    387  * @param {FileSystemAgent.Entry} backendEntry
    388  */
    389 WebInspector.FileSystemModel.Entry = function(fileSystemModel, fileSystem, backendEntry)
    390 {
    391     this._fileSystemModel = fileSystemModel;
    392     this._fileSystem = fileSystem;
    393 
    394     this._url = backendEntry.url;
    395     this._name = backendEntry.name;
    396     this._isDirectory = backendEntry.isDirectory;
    397 }
    398 
    399 /**
    400  * @param {WebInspector.FileSystemModel.Entry} x
    401  * @param {WebInspector.FileSystemModel.Entry} y
    402  * @return {number}
    403  */
    404 WebInspector.FileSystemModel.Entry.compare = function(x, y)
    405 {
    406     if (x.isDirectory != y.isDirectory)
    407         return y.isDirectory ? 1 : -1;
    408     return x.name.compareTo(y.name);
    409 }
    410 
    411 WebInspector.FileSystemModel.Entry.prototype = {
    412     /**
    413      * @type {WebInspector.FileSystemModel}
    414      */
    415     get fileSystemModel()
    416     {
    417         return this._fileSystemModel;
    418     },
    419 
    420     /**
    421      * @type {WebInspector.FileSystemModel.FileSystem}
    422      */
    423     get fileSystem()
    424     {
    425         return this._fileSystem;
    426     },
    427 
    428     /**
    429      * @type {string}
    430      */
    431     get url()
    432     {
    433         return this._url;
    434     },
    435 
    436     /**
    437      * @type {string}
    438      */
    439     get name()
    440     {
    441         return this._name;
    442     },
    443 
    444     /**
    445      * @type {boolean}
    446      */
    447     get isDirectory()
    448     {
    449         return this._isDirectory;
    450     },
    451 
    452     /**
    453      * @param {function(number, FileSystemAgent.Metadata)} callback
    454      */
    455     requestMetadata: function(callback)
    456     {
    457         this.fileSystemModel.requestMetadata(this, callback);
    458     },
    459 
    460     /**
    461      * @param {function(number)} callback
    462      */
    463     deleteEntry: function(callback)
    464     {
    465         this.fileSystemModel.deleteEntry(this, callback);
    466     }
    467 }
    468 
    469 /**
    470  * @constructor
    471  * @extends {WebInspector.FileSystemModel.Entry}
    472  * @param {WebInspector.FileSystemModel} fileSystemModel
    473  * @param {WebInspector.FileSystemModel.FileSystem} fileSystem
    474  * @param {FileSystemAgent.Entry} backendEntry
    475  */
    476 WebInspector.FileSystemModel.Directory = function(fileSystemModel, fileSystem, backendEntry)
    477 {
    478     WebInspector.FileSystemModel.Entry.call(this, fileSystemModel, fileSystem, backendEntry);
    479 }
    480 
    481 WebInspector.FileSystemModel.Directory.prototype = {
    482     /**
    483      * @param {function(number, Array.<WebInspector.FileSystemModel.Directory>)} callback
    484      */
    485     requestDirectoryContent: function(callback)
    486     {
    487         this.fileSystemModel.requestDirectoryContent(this, callback);
    488     },
    489 
    490     __proto__: WebInspector.FileSystemModel.Entry.prototype
    491 }
    492 
    493 /**
    494  * @constructor
    495  * @extends {WebInspector.FileSystemModel.Entry}
    496  * @param {WebInspector.FileSystemModel} fileSystemModel
    497  * @param {WebInspector.FileSystemModel.FileSystem} fileSystem
    498  * @param {FileSystemAgent.Entry} backendEntry
    499  */
    500 WebInspector.FileSystemModel.File = function(fileSystemModel, fileSystem, backendEntry)
    501 {
    502     WebInspector.FileSystemModel.Entry.call(this, fileSystemModel, fileSystem, backendEntry);
    503 
    504     this._mimeType = backendEntry.mimeType;
    505     this._resourceType = WebInspector.resourceTypes[backendEntry.resourceType];
    506     this._isTextFile = backendEntry.isTextFile;
    507 }
    508 
    509 WebInspector.FileSystemModel.File.prototype = {
    510     /**
    511      * @type {string}
    512      */
    513     get mimeType()
    514     {
    515         return this._mimeType;
    516     },
    517 
    518     /**
    519      * @type {WebInspector.ResourceType}
    520      */
    521     get resourceType()
    522     {
    523         return this._resourceType;
    524     },
    525 
    526     /**
    527      * @type {boolean}
    528      */
    529     get isTextFile()
    530     {
    531         return this._isTextFile;
    532     },
    533 
    534     /**
    535      * @param {boolean} readAsText
    536      * @param {number=} start
    537      * @param {number=} end
    538      * @param {string=} charset
    539      * @param {function(number, string=)=} callback
    540      */
    541     requestFileContent: function(readAsText, start, end, charset, callback)
    542     {
    543         this.fileSystemModel.requestFileContent(this, readAsText, start, end, charset, callback);
    544     },
    545 
    546     __proto__: WebInspector.FileSystemModel.Entry.prototype
    547 }
    548