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.<string, !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);
    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         if (!backendEntries) {
    211             callback(errorCode);
    212             return;
    213         }
    214 
    215         var entries = [];
    216         for (var i = 0; i < backendEntries.length; ++i) {
    217             if (backendEntries[i].isDirectory)
    218                 entries.push(new WebInspector.FileSystemModel.Directory(this, parentDirectory.fileSystem, backendEntries[i]));
    219             else
    220                 entries.push(new WebInspector.FileSystemModel.File(this, parentDirectory.fileSystem, backendEntries[i]));
    221         }
    222 
    223         callback(errorCode, entries);
    224     },
    225 
    226     /**
    227      * @param {!WebInspector.FileSystemModel.Entry} entry
    228      * @param {function(number, !FileSystemAgent.Metadata=)} callback
    229      */
    230     requestMetadata: function(entry, callback)
    231     {
    232         /**
    233          * @param {?Protocol.Error} error
    234          * @param {number} errorCode
    235          * @param {!FileSystemAgent.Metadata=} metadata
    236          */
    237         function innerCallback(error, errorCode, metadata)
    238         {
    239             if (error) {
    240                 callback(FileError.SECURITY_ERR);
    241                 return;
    242             }
    243 
    244             callback(errorCode, metadata);
    245         }
    246 
    247         FileSystemAgent.requestMetadata(entry.url, innerCallback.bind(this));
    248     },
    249 
    250     /**
    251      * @param {!WebInspector.FileSystemModel.File} file
    252      * @param {boolean} readAsText
    253      * @param {number=} start
    254      * @param {number=} end
    255      * @param {string=} charset
    256      * @param {function(number, string=, string=)=} callback
    257      */
    258     requestFileContent: function(file, readAsText, start, end, charset, callback)
    259     {
    260         this._requestFileContent(file.url, readAsText, start, end, charset, callback);
    261     },
    262 
    263     /**
    264      * @param {string} url
    265      * @param {boolean} readAsText
    266      * @param {number=} start
    267      * @param {number=} end
    268      * @param {string=} charset
    269      * @param {function(number, string=, string=)=} callback
    270      */
    271     _requestFileContent: function(url, readAsText, start, end, charset, callback)
    272     {
    273         /**
    274          * @param {?Protocol.Error} error
    275          * @param {number} errorCode
    276          * @param {string=} content
    277          * @param {string=} charset
    278          */
    279         function innerCallback(error, errorCode, content, charset)
    280         {
    281             if (error) {
    282                 if (callback)
    283                     callback(FileError.SECURITY_ERR);
    284                 return;
    285             }
    286 
    287             if (callback)
    288                 callback(errorCode, content, charset);
    289         }
    290 
    291         FileSystemAgent.requestFileContent(url, readAsText, start, end, charset, innerCallback.bind(this));
    292     },
    293     /**
    294      * @param {!WebInspector.FileSystemModel.Entry} entry
    295      * @param {function(number)=} callback
    296      */
    297     deleteEntry: function(entry, callback)
    298     {
    299         var fileSystemModel = this;
    300         if (entry === entry.fileSystem.root)
    301             this._deleteEntry(entry.url, hookFileSystemDeletion);
    302         else
    303             this._deleteEntry(entry.url, callback);
    304 
    305         function hookFileSystemDeletion(errorCode)
    306         {
    307             callback(errorCode);
    308             if (!errorCode)
    309                 fileSystemModel._removeFileSystem(entry.fileSystem);
    310         }
    311     },
    312 
    313     /**
    314      * @param {string} url
    315      * @param {function(number)=} callback
    316      */
    317     _deleteEntry: function(url, callback)
    318     {
    319         /**
    320          * @param {?Protocol.Error} error
    321          * @param {number} errorCode
    322          */
    323         function innerCallback(error, errorCode)
    324         {
    325             if (error) {
    326                 if (callback)
    327                     callback(FileError.SECURITY_ERR);
    328                 return;
    329             }
    330 
    331             if (callback)
    332                 callback(errorCode);
    333         }
    334 
    335         FileSystemAgent.deleteEntry(url, innerCallback.bind(this));
    336     },
    337 
    338     /**
    339      * @param {!WebInspector.FileSystemModel.FileSystem} fileSystem
    340      */
    341     _removeFileSystem: function(fileSystem)
    342     {
    343         var origin = fileSystem.origin;
    344         var type = fileSystem.type;
    345         if (this._fileSystemsForOrigin[origin] && this._fileSystemsForOrigin[origin][type]) {
    346             delete this._fileSystemsForOrigin[origin][type];
    347             this._fileSystemRemoved(fileSystem);
    348 
    349             if (Object.isEmpty(this._fileSystemsForOrigin[origin]))
    350                 delete this._fileSystemsForOrigin[origin];
    351         }
    352     },
    353 
    354     __proto__: WebInspector.Object.prototype
    355 }
    356 
    357 
    358 WebInspector.FileSystemModel.EventTypes = {
    359     FileSystemAdded: "FileSystemAdded",
    360     FileSystemRemoved: "FileSystemRemoved"
    361 }
    362 
    363 /**
    364  * @constructor
    365  * @param {!WebInspector.FileSystemModel} fileSystemModel
    366  * @param {string} origin
    367  * @param {string} type
    368  * @param {!FileSystemAgent.Entry} backendRootEntry
    369  */
    370 WebInspector.FileSystemModel.FileSystem = function(fileSystemModel, origin, type, backendRootEntry)
    371 {
    372     this.origin = origin;
    373     this.type = type;
    374 
    375     this.root = new WebInspector.FileSystemModel.Directory(fileSystemModel, this, backendRootEntry);
    376 }
    377 
    378 WebInspector.FileSystemModel.FileSystem.prototype = {
    379     /**
    380      * @type {string}
    381      */
    382     get name()
    383     {
    384         return "filesystem:" + this.origin + "/" + this.type;
    385     }
    386 }
    387 
    388 /**
    389  * @constructor
    390  * @param {!WebInspector.FileSystemModel} fileSystemModel
    391  * @param {!WebInspector.FileSystemModel.FileSystem} fileSystem
    392  * @param {!FileSystemAgent.Entry} backendEntry
    393  */
    394 WebInspector.FileSystemModel.Entry = function(fileSystemModel, fileSystem, backendEntry)
    395 {
    396     this._fileSystemModel = fileSystemModel;
    397     this._fileSystem = fileSystem;
    398 
    399     this._url = backendEntry.url;
    400     this._name = backendEntry.name;
    401     this._isDirectory = backendEntry.isDirectory;
    402 }
    403 
    404 /**
    405  * @param {!WebInspector.FileSystemModel.Entry} x
    406  * @param {!WebInspector.FileSystemModel.Entry} y
    407  * @return {number}
    408  */
    409 WebInspector.FileSystemModel.Entry.compare = function(x, y)
    410 {
    411     if (x.isDirectory != y.isDirectory)
    412         return y.isDirectory ? 1 : -1;
    413     return x.name.compareTo(y.name);
    414 }
    415 
    416 WebInspector.FileSystemModel.Entry.prototype = {
    417     /**
    418      * @type {!WebInspector.FileSystemModel}
    419      */
    420     get fileSystemModel()
    421     {
    422         return this._fileSystemModel;
    423     },
    424 
    425     /**
    426      * @type {!WebInspector.FileSystemModel.FileSystem}
    427      */
    428     get fileSystem()
    429     {
    430         return this._fileSystem;
    431     },
    432 
    433     /**
    434      * @type {string}
    435      */
    436     get url()
    437     {
    438         return this._url;
    439     },
    440 
    441     /**
    442      * @type {string}
    443      */
    444     get name()
    445     {
    446         return this._name;
    447     },
    448 
    449     /**
    450      * @type {boolean}
    451      */
    452     get isDirectory()
    453     {
    454         return this._isDirectory;
    455     },
    456 
    457     /**
    458      * @param {function(number, !FileSystemAgent.Metadata)} callback
    459      */
    460     requestMetadata: function(callback)
    461     {
    462         this.fileSystemModel.requestMetadata(this, callback);
    463     },
    464 
    465     /**
    466      * @param {function(number)} callback
    467      */
    468     deleteEntry: function(callback)
    469     {
    470         this.fileSystemModel.deleteEntry(this, callback);
    471     }
    472 }
    473 
    474 /**
    475  * @constructor
    476  * @extends {WebInspector.FileSystemModel.Entry}
    477  * @param {!WebInspector.FileSystemModel} fileSystemModel
    478  * @param {!WebInspector.FileSystemModel.FileSystem} fileSystem
    479  * @param {!FileSystemAgent.Entry} backendEntry
    480  */
    481 WebInspector.FileSystemModel.Directory = function(fileSystemModel, fileSystem, backendEntry)
    482 {
    483     WebInspector.FileSystemModel.Entry.call(this, fileSystemModel, fileSystem, backendEntry);
    484 }
    485 
    486 WebInspector.FileSystemModel.Directory.prototype = {
    487     /**
    488      * @param {function(number, !Array.<!WebInspector.FileSystemModel.Directory>)} callback
    489      */
    490     requestDirectoryContent: function(callback)
    491     {
    492         this.fileSystemModel.requestDirectoryContent(this, callback);
    493     },
    494 
    495     __proto__: WebInspector.FileSystemModel.Entry.prototype
    496 }
    497 
    498 /**
    499  * @constructor
    500  * @extends {WebInspector.FileSystemModel.Entry}
    501  * @param {!WebInspector.FileSystemModel} fileSystemModel
    502  * @param {!WebInspector.FileSystemModel.FileSystem} fileSystem
    503  * @param {!FileSystemAgent.Entry} backendEntry
    504  */
    505 WebInspector.FileSystemModel.File = function(fileSystemModel, fileSystem, backendEntry)
    506 {
    507     WebInspector.FileSystemModel.Entry.call(this, fileSystemModel, fileSystem, backendEntry);
    508 
    509     this._mimeType = backendEntry.mimeType;
    510     this._resourceType = WebInspector.resourceTypes[backendEntry.resourceType];
    511     this._isTextFile = backendEntry.isTextFile;
    512 }
    513 
    514 WebInspector.FileSystemModel.File.prototype = {
    515     /**
    516      * @type {string}
    517      */
    518     get mimeType()
    519     {
    520         return this._mimeType;
    521     },
    522 
    523     /**
    524      * @type {!WebInspector.ResourceType}
    525      */
    526     get resourceType()
    527     {
    528         return this._resourceType;
    529     },
    530 
    531     /**
    532      * @type {boolean}
    533      */
    534     get isTextFile()
    535     {
    536         return this._isTextFile;
    537     },
    538 
    539     /**
    540      * @param {boolean} readAsText
    541      * @param {number=} start
    542      * @param {number=} end
    543      * @param {string=} charset
    544      * @param {function(number, string=)=} callback
    545      */
    546     requestFileContent: function(readAsText, start, end, charset, callback)
    547     {
    548         this.fileSystemModel.requestFileContent(this, readAsText, start, end, charset, callback);
    549     },
    550 
    551     __proto__: WebInspector.FileSystemModel.Entry.prototype
    552 }
    553