Home | History | Annotate | Download | only in resources
      1 /*
      2  * Copyright (C) 2007, 2008, 2010 Apple Inc.  All rights reserved.
      3  * Copyright (C) 2009 Joseph Pecoraro
      4  * Copyright (C) 2013 Samsung Electronics. All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  *
     10  * 1.  Redistributions of source code must retain the above copyright
     11  *     notice, this list of conditions and the following disclaimer.
     12  * 2.  Redistributions in binary form must reproduce the above copyright
     13  *     notice, this list of conditions and the following disclaimer in the
     14  *     documentation and/or other materials provided with the distribution.
     15  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     16  *     its contributors may be used to endorse or promote products derived
     17  *     from this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     22  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 importScript("ApplicationCacheItemsView.js");
     32 importScript("CookieItemsView.js");
     33 importScript("DOMStorageItemsView.js");
     34 importScript("DatabaseQueryView.js");
     35 importScript("DatabaseTableView.js");
     36 importScript("DirectoryContentView.js");
     37 importScript("IndexedDBViews.js");
     38 importScript("FileContentView.js");
     39 importScript("FileSystemView.js");
     40 
     41 /**
     42  * @constructor
     43  * @extends {WebInspector.PanelWithSidebarTree}
     44  */
     45 WebInspector.ResourcesPanel = function(database)
     46 {
     47     WebInspector.PanelWithSidebarTree.call(this, "resources");
     48     this.registerRequiredCSS("resourcesPanel.css");
     49 
     50     WebInspector.settings.resourcesLastSelectedItem = WebInspector.settings.createSetting("resourcesLastSelectedItem", {});
     51 
     52     this.sidebarElement().classList.add("filter-all", "children", "small", "outline-disclosure");
     53     this.sidebarTree.element.classList.remove("sidebar-tree");
     54 
     55     this.resourcesListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Frames"), "Frames", ["frame-storage-tree-item"]);
     56     this.sidebarTree.appendChild(this.resourcesListTreeElement);
     57 
     58     this.databasesListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Web SQL"), "Databases", ["database-storage-tree-item"]);
     59     this.sidebarTree.appendChild(this.databasesListTreeElement);
     60 
     61     this.indexedDBListTreeElement = new WebInspector.IndexedDBTreeElement(this);
     62     this.sidebarTree.appendChild(this.indexedDBListTreeElement);
     63 
     64     this.localStorageListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Local Storage"), "LocalStorage", ["domstorage-storage-tree-item", "local-storage"]);
     65     this.sidebarTree.appendChild(this.localStorageListTreeElement);
     66 
     67     this.sessionStorageListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Session Storage"), "SessionStorage", ["domstorage-storage-tree-item", "session-storage"]);
     68     this.sidebarTree.appendChild(this.sessionStorageListTreeElement);
     69 
     70     this.cookieListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Cookies"), "Cookies", ["cookie-storage-tree-item"]);
     71     this.sidebarTree.appendChild(this.cookieListTreeElement);
     72 
     73     this.applicationCacheListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Application Cache"), "ApplicationCache", ["application-cache-storage-tree-item"]);
     74     this.sidebarTree.appendChild(this.applicationCacheListTreeElement);
     75 
     76     if (WebInspector.experimentsSettings.fileSystemInspection.isEnabled()) {
     77         this.fileSystemListTreeElement = new WebInspector.FileSystemListTreeElement(this);
     78         this.sidebarTree.appendChild(this.fileSystemListTreeElement);
     79     }
     80 
     81     var mainView = new WebInspector.VBox();
     82     this.storageViews = mainView.element.createChild("div", "resources-main diff-container");
     83     var statusBarContainer = mainView.element.createChild("div", "resources-status-bar");
     84     this.storageViewStatusBarItemsContainer = statusBarContainer.createChild("div", "status-bar");
     85     mainView.show(this.mainElement());
     86 
     87     /** @type {!Map.<!WebInspector.Database, !Object.<string, !WebInspector.DatabaseTableView>>} */
     88     this._databaseTableViews = new Map();
     89     /** @type {!Map.<!WebInspector.Database, !WebInspector.DatabaseQueryView>} */
     90     this._databaseQueryViews = new Map();
     91     /** @type {!Map.<!WebInspector.Database, !WebInspector.DatabaseTreeElement>} */
     92     this._databaseTreeElements = new Map();
     93     /** @type {!Map.<!WebInspector.DOMStorage, !WebInspector.DOMStorageItemsView>} */
     94     this._domStorageViews = new Map();
     95     /** @type {!Map.<!WebInspector.DOMStorage, !WebInspector.DOMStorageTreeElement>} */
     96     this._domStorageTreeElements = new Map();
     97     /** @type {!Object.<string, !WebInspector.CookieItemsView>} */
     98     this._cookieViews = {};
     99     /** @type {!Object.<string, boolean>} */
    100     this._domains = {};
    101 
    102     this.sidebarElement().addEventListener("mousemove", this._onmousemove.bind(this), false);
    103     this.sidebarElement().addEventListener("mouseout", this._onmouseout.bind(this), false);
    104 
    105     /**
    106      * @this {WebInspector.ResourcesPanel}
    107      * @return {?WebInspector.SourceFrame}
    108      */
    109     function sourceFrameGetter()
    110     {
    111         var view = this.visibleView;
    112         if (view && view instanceof WebInspector.SourceFrame)
    113             return /** @type {!WebInspector.SourceFrame} */ (view);
    114         return null;
    115     }
    116     WebInspector.GoToLineDialog.install(this, sourceFrameGetter.bind(this));
    117 
    118     if (WebInspector.resourceTreeModel.cachedResourcesLoaded())
    119         this._cachedResourcesLoaded();
    120 
    121     WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._loadEventFired, this);
    122     WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.CachedResourcesLoaded, this._cachedResourcesLoaded, this);
    123     WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.WillLoadCachedResources, this._resetWithFrames, this);
    124 
    125     WebInspector.databaseModel.databases().forEach(this._addDatabase.bind(this));
    126     WebInspector.databaseModel.addEventListener(WebInspector.DatabaseModel.Events.DatabaseAdded, this._databaseAdded, this);
    127 }
    128 
    129 WebInspector.ResourcesPanel.prototype = {
    130     /**
    131      * @return {boolean}
    132      */
    133     canSearch: function()
    134     {
    135         return false;
    136     },
    137 
    138     wasShown: function()
    139     {
    140         WebInspector.Panel.prototype.wasShown.call(this);
    141         this._initialize();
    142     },
    143 
    144     _initialize: function()
    145     {
    146         if (!this._initialized && this.isShowing() && this._cachedResourcesWereLoaded) {
    147             var target = /** @type {!WebInspector.Target} */ (WebInspector.targetManager.activeTarget());
    148             this._populateResourceTree();
    149             this._populateDOMStorageTree();
    150             this._populateApplicationCacheTree(target);
    151             this.indexedDBListTreeElement._initialize();
    152             if (WebInspector.experimentsSettings.fileSystemInspection.isEnabled())
    153                 this.fileSystemListTreeElement._initialize();
    154             this._initDefaultSelection();
    155             this._initialized = true;
    156         }
    157     },
    158 
    159     _loadEventFired: function()
    160     {
    161         this._initDefaultSelection();
    162     },
    163 
    164     _initDefaultSelection: function()
    165     {
    166         if (!this._initialized)
    167             return;
    168 
    169         var itemURL = WebInspector.settings.resourcesLastSelectedItem.get();
    170         if (itemURL) {
    171             for (var treeElement = this.sidebarTree.children[0]; treeElement; treeElement = treeElement.traverseNextTreeElement(false, this.sidebarTree, true)) {
    172                 if (treeElement.itemURL === itemURL) {
    173                     treeElement.revealAndSelect(true);
    174                     return;
    175                 }
    176             }
    177         }
    178 
    179         var mainResource = WebInspector.resourceTreeModel.inspectedPageURL() && this.resourcesListTreeElement && this.resourcesListTreeElement.expanded
    180                 ? WebInspector.resourceTreeModel.resourceForURL(WebInspector.resourceTreeModel.inspectedPageURL())
    181                 : null;
    182         if (mainResource)
    183             this.showResource(mainResource);
    184     },
    185 
    186     _resetWithFrames: function()
    187     {
    188         this.resourcesListTreeElement.removeChildren();
    189         this._treeElementForFrameId = {};
    190         this._reset();
    191     },
    192 
    193     _reset: function()
    194     {
    195         this._domains = {};
    196         var queryViews = this._databaseQueryViews.values();
    197         for (var i = 0; i < queryViews.length; ++i)
    198             queryViews[i].removeEventListener(WebInspector.DatabaseQueryView.Events.SchemaUpdated, this._updateDatabaseTables, this);
    199         this._databaseTableViews.clear();
    200         this._databaseQueryViews.clear();
    201         this._databaseTreeElements.clear();
    202         this._domStorageViews.clear();
    203         this._domStorageTreeElements.clear();
    204         this._cookieViews = {};
    205 
    206         this.databasesListTreeElement.removeChildren();
    207         this.localStorageListTreeElement.removeChildren();
    208         this.sessionStorageListTreeElement.removeChildren();
    209         this.cookieListTreeElement.removeChildren();
    210 
    211         if (this.visibleView && !(this.visibleView instanceof WebInspector.StorageCategoryView))
    212             this.visibleView.detach();
    213 
    214         this.storageViewStatusBarItemsContainer.removeChildren();
    215 
    216         if (this.sidebarTree.selectedTreeElement)
    217             this.sidebarTree.selectedTreeElement.deselect();
    218     },
    219 
    220     _populateResourceTree: function()
    221     {
    222         this._treeElementForFrameId = {};
    223         WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameAdded, this._frameAdded, this);
    224         WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, this._frameNavigated, this);
    225         WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameDetached, this._frameDetached, this);
    226         WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.ResourceAdded, this._resourceAdded, this);
    227 
    228         /**
    229          * @param {!WebInspector.ResourceTreeFrame} frame
    230          * @this {WebInspector.ResourcesPanel}
    231          */
    232         function populateFrame(frame)
    233         {
    234             this._frameAdded({data:frame});
    235             for (var i = 0; i < frame.childFrames.length; ++i)
    236                 populateFrame.call(this, frame.childFrames[i]);
    237 
    238             var resources = frame.resources();
    239             for (var i = 0; i < resources.length; ++i)
    240                 this._resourceAdded({data:resources[i]});
    241         }
    242         populateFrame.call(this, WebInspector.resourceTreeModel.mainFrame);
    243     },
    244 
    245     _frameAdded: function(event)
    246     {
    247         var frame = event.data;
    248         var parentFrame = frame.parentFrame;
    249 
    250         var parentTreeElement = parentFrame ? this._treeElementForFrameId[parentFrame.id] : this.resourcesListTreeElement;
    251         if (!parentTreeElement) {
    252             console.warn("No frame to route " + frame.url + " to.")
    253             return;
    254         }
    255 
    256         var frameTreeElement = new WebInspector.FrameTreeElement(this, frame);
    257         this._treeElementForFrameId[frame.id] = frameTreeElement;
    258         parentTreeElement.appendChild(frameTreeElement);
    259     },
    260 
    261     _frameDetached: function(event)
    262     {
    263         var frame = event.data;
    264         var frameTreeElement = this._treeElementForFrameId[frame.id];
    265         if (!frameTreeElement)
    266             return;
    267 
    268         delete this._treeElementForFrameId[frame.id];
    269         if (frameTreeElement.parent)
    270             frameTreeElement.parent.removeChild(frameTreeElement);
    271     },
    272 
    273     _resourceAdded: function(event)
    274     {
    275         var resource = event.data;
    276         var frameId = resource.frameId;
    277 
    278         if (resource.statusCode >= 301 && resource.statusCode <= 303)
    279             return;
    280 
    281         var frameTreeElement = this._treeElementForFrameId[frameId];
    282         if (!frameTreeElement) {
    283             // This is a frame's main resource, it will be retained
    284             // and re-added by the resource manager;
    285             return;
    286         }
    287 
    288         frameTreeElement.appendResource(resource);
    289     },
    290 
    291     _frameNavigated: function(event)
    292     {
    293         var frame = event.data;
    294 
    295         if (!frame.parentFrame)
    296             this._reset();
    297 
    298         var frameId = frame.id;
    299         var frameTreeElement = this._treeElementForFrameId[frameId];
    300         if (frameTreeElement)
    301             frameTreeElement.frameNavigated(frame);
    302 
    303         var applicationCacheFrameTreeElement = this._applicationCacheFrameElements[frameId];
    304         if (applicationCacheFrameTreeElement)
    305             applicationCacheFrameTreeElement.frameNavigated(frame);
    306     },
    307 
    308     _cachedResourcesLoaded: function()
    309     {
    310         this._cachedResourcesWereLoaded = true;
    311         this._initialize();
    312     },
    313 
    314     /**
    315      * @param {!WebInspector.Event} event
    316      */
    317     _databaseAdded: function(event)
    318     {
    319         var database = /** @type {!WebInspector.Database} */ (event.data);
    320         this._addDatabase(database);
    321     },
    322 
    323     /**
    324      * @param {!WebInspector.Database} database
    325      */
    326     _addDatabase: function(database)
    327     {
    328         var databaseTreeElement = new WebInspector.DatabaseTreeElement(this, database);
    329         this._databaseTreeElements.put(database, databaseTreeElement);
    330         this.databasesListTreeElement.appendChild(databaseTreeElement);
    331     },
    332 
    333     addDocumentURL: function(url)
    334     {
    335         var parsedURL = url.asParsedURL();
    336         if (!parsedURL)
    337             return;
    338 
    339         var domain = parsedURL.host;
    340         if (!this._domains[domain]) {
    341             this._domains[domain] = true;
    342 
    343             var cookieDomainTreeElement = new WebInspector.CookieTreeElement(this, domain);
    344             this.cookieListTreeElement.appendChild(cookieDomainTreeElement);
    345         }
    346     },
    347 
    348     /**
    349      * @param {!WebInspector.Event} event
    350      */
    351     _domStorageAdded: function(event)
    352     {
    353         var domStorage = /** @type {!WebInspector.DOMStorage} */ (event.data);
    354         this._addDOMStorage(domStorage);
    355     },
    356 
    357     /**
    358      * @param {!WebInspector.DOMStorage} domStorage
    359      */
    360     _addDOMStorage: function(domStorage)
    361     {
    362         console.assert(!this._domStorageTreeElements.get(domStorage));
    363 
    364         var domStorageTreeElement = new WebInspector.DOMStorageTreeElement(this, domStorage, (domStorage.isLocalStorage ? "local-storage" : "session-storage"));
    365         this._domStorageTreeElements.put(domStorage, domStorageTreeElement);
    366         if (domStorage.isLocalStorage)
    367             this.localStorageListTreeElement.appendChild(domStorageTreeElement);
    368         else
    369             this.sessionStorageListTreeElement.appendChild(domStorageTreeElement);
    370     },
    371 
    372     /**
    373      * @param {!WebInspector.Event} event
    374      */
    375     _domStorageRemoved: function(event)
    376     {
    377         var domStorage = /** @type {!WebInspector.DOMStorage} */ (event.data);
    378         this._removeDOMStorage(domStorage);
    379     },
    380 
    381     /**
    382      * @param {!WebInspector.DOMStorage} domStorage
    383      */
    384     _removeDOMStorage: function(domStorage)
    385     {
    386         var treeElement = this._domStorageTreeElements.get(domStorage);
    387         if (!treeElement)
    388             return;
    389         var wasSelected = treeElement.selected;
    390         var parentListTreeElement = treeElement.parent;
    391         parentListTreeElement.removeChild(treeElement);
    392         if (wasSelected)
    393             parentListTreeElement.select();
    394         this._domStorageTreeElements.remove(domStorage);
    395         this._domStorageViews.remove(domStorage);
    396     },
    397 
    398     /**
    399      * @param {!WebInspector.Database} database
    400      */
    401     selectDatabase: function(database)
    402     {
    403         if (database) {
    404             this._showDatabase(database);
    405             this._databaseTreeElements.get(database).select();
    406         }
    407     },
    408 
    409     /**
    410      * @param {!WebInspector.DOMStorage} domStorage
    411      */
    412     selectDOMStorage: function(domStorage)
    413     {
    414         if (domStorage) {
    415             this._showDOMStorage(domStorage);
    416             this._domStorageTreeElements.get(domStorage).select();
    417         }
    418     },
    419 
    420     /**
    421      * @param {!WebInspector.Resource} resource
    422      * @param {number=} line
    423      * @param {number=} column
    424      * @return {boolean}
    425      */
    426     showResource: function(resource, line, column)
    427     {
    428         var resourceTreeElement = this._findTreeElementForResource(resource);
    429         if (resourceTreeElement)
    430             resourceTreeElement.revealAndSelect(true);
    431 
    432         if (typeof line === "number") {
    433             var resourceSourceFrame = this._resourceSourceFrameViewForResource(resource);
    434             if (resourceSourceFrame)
    435                 resourceSourceFrame.revealPosition(line, column, true);
    436         }
    437         return true;
    438     },
    439 
    440     _showResourceView: function(resource)
    441     {
    442         var view = this._resourceViewForResource(resource);
    443         if (!view) {
    444             this.visibleView.detach();
    445             return;
    446         }
    447         this._innerShowView(view);
    448     },
    449 
    450     /**
    451      * @param {!WebInspector.Resource} resource
    452      * @return {?WebInspector.View}
    453      */
    454     _resourceViewForResource: function(resource)
    455     {
    456         if (WebInspector.ResourceView.hasTextContent(resource)) {
    457             var treeElement = this._findTreeElementForResource(resource);
    458             if (!treeElement)
    459                 return null;
    460             return treeElement.sourceView();
    461         }
    462         return WebInspector.ResourceView.nonSourceViewForResource(resource);
    463     },
    464 
    465     /**
    466      * @param {!WebInspector.Resource} resource
    467      * @return {?WebInspector.ResourceSourceFrame}
    468      */
    469     _resourceSourceFrameViewForResource: function(resource)
    470     {
    471         var resourceView = this._resourceViewForResource(resource);
    472         if (resourceView && resourceView instanceof WebInspector.ResourceSourceFrame)
    473             return /** @type {!WebInspector.ResourceSourceFrame} */ (resourceView);
    474         return null;
    475     },
    476 
    477     /**
    478      * @param {!WebInspector.Database} database
    479      * @param {string=} tableName
    480      */
    481     _showDatabase: function(database, tableName)
    482     {
    483         if (!database)
    484             return;
    485 
    486         var view;
    487         if (tableName) {
    488             var tableViews = this._databaseTableViews.get(database);
    489             if (!tableViews) {
    490                 tableViews = /** @type {!Object.<string, !WebInspector.DatabaseTableView>} */ ({});
    491                 this._databaseTableViews.put(database, tableViews);
    492             }
    493             view = tableViews[tableName];
    494             if (!view) {
    495                 view = new WebInspector.DatabaseTableView(database, tableName);
    496                 tableViews[tableName] = view;
    497             }
    498         } else {
    499             view = this._databaseQueryViews.get(database);
    500             if (!view) {
    501                 view = new WebInspector.DatabaseQueryView(database);
    502                 this._databaseQueryViews.put(database, view);
    503                 view.addEventListener(WebInspector.DatabaseQueryView.Events.SchemaUpdated, this._updateDatabaseTables, this);
    504             }
    505         }
    506 
    507         this._innerShowView(view);
    508     },
    509 
    510     /**
    511      * @param {!WebInspector.View} view
    512      */
    513     showIndexedDB: function(view)
    514     {
    515         this._innerShowView(view);
    516     },
    517 
    518     /**
    519      * @param {!WebInspector.DOMStorage} domStorage
    520      */
    521     _showDOMStorage: function(domStorage)
    522     {
    523         if (!domStorage)
    524             return;
    525 
    526         var view;
    527         view = this._domStorageViews.get(domStorage);
    528         if (!view) {
    529             view = new WebInspector.DOMStorageItemsView(domStorage);
    530             this._domStorageViews.put(domStorage, view);
    531         }
    532 
    533         this._innerShowView(view);
    534     },
    535 
    536     /**
    537      * @param {!WebInspector.CookieTreeElement} treeElement
    538      * @param {string} cookieDomain
    539      */
    540     showCookies: function(treeElement, cookieDomain)
    541     {
    542         var view = this._cookieViews[cookieDomain];
    543         if (!view) {
    544             view = new WebInspector.CookieItemsView(treeElement, cookieDomain);
    545             this._cookieViews[cookieDomain] = view;
    546         }
    547 
    548         this._innerShowView(view);
    549     },
    550 
    551     /**
    552      * @param {string} cookieDomain
    553      */
    554     clearCookies: function(cookieDomain)
    555     {
    556         this._cookieViews[cookieDomain].clear();
    557     },
    558 
    559     showApplicationCache: function(frameId)
    560     {
    561         if (!this._applicationCacheViews[frameId])
    562             this._applicationCacheViews[frameId] = new WebInspector.ApplicationCacheItemsView(this._applicationCacheModel, frameId);
    563 
    564         this._innerShowView(this._applicationCacheViews[frameId]);
    565     },
    566 
    567     /**
    568      *  @param {!WebInspector.View} view
    569      */
    570     showFileSystem: function(view)
    571     {
    572         this._innerShowView(view);
    573     },
    574 
    575     showCategoryView: function(categoryName)
    576     {
    577         if (!this._categoryView)
    578             this._categoryView = new WebInspector.StorageCategoryView();
    579         this._categoryView.setText(categoryName);
    580         this._innerShowView(this._categoryView);
    581     },
    582 
    583     _innerShowView: function(view)
    584     {
    585         if (this.visibleView === view)
    586             return;
    587 
    588         if (this.visibleView)
    589             this.visibleView.detach();
    590 
    591         view.show(this.storageViews);
    592         this.visibleView = view;
    593 
    594         this.storageViewStatusBarItemsContainer.removeChildren();
    595         var statusBarItems = view.statusBarItems || [];
    596         for (var i = 0; i < statusBarItems.length; ++i)
    597             this.storageViewStatusBarItemsContainer.appendChild(statusBarItems[i]);
    598     },
    599 
    600     closeVisibleView: function()
    601     {
    602         if (!this.visibleView)
    603             return;
    604         this.visibleView.detach();
    605         delete this.visibleView;
    606     },
    607 
    608     _updateDatabaseTables: function(event)
    609     {
    610         var database = event.data;
    611 
    612         if (!database)
    613             return;
    614 
    615         var databasesTreeElement = this._databaseTreeElements.get(database);
    616         if (!databasesTreeElement)
    617             return;
    618 
    619         databasesTreeElement.shouldRefreshChildren = true;
    620         var tableViews = this._databaseTableViews.get(database);
    621 
    622         if (!tableViews)
    623             return;
    624 
    625         var tableNamesHash = {};
    626         var self = this;
    627         function tableNamesCallback(tableNames)
    628         {
    629             var tableNamesLength = tableNames.length;
    630             for (var i = 0; i < tableNamesLength; ++i)
    631                 tableNamesHash[tableNames[i]] = true;
    632 
    633             for (var tableName in tableViews) {
    634                 if (!(tableName in tableNamesHash)) {
    635                     if (self.visibleView === tableViews[tableName])
    636                         self.closeVisibleView();
    637                     delete tableViews[tableName];
    638                 }
    639             }
    640         }
    641         database.getTableNames(tableNamesCallback);
    642     },
    643 
    644     _populateDOMStorageTree: function()
    645     {
    646         WebInspector.domStorageModel.storages().forEach(this._addDOMStorage.bind(this));
    647         WebInspector.domStorageModel.addEventListener(WebInspector.DOMStorageModel.Events.DOMStorageAdded, this._domStorageAdded, this);
    648         WebInspector.domStorageModel.addEventListener(WebInspector.DOMStorageModel.Events.DOMStorageRemoved, this._domStorageRemoved, this);
    649     },
    650 
    651     /**
    652      * @param {!WebInspector.Target} target
    653      */
    654     _populateApplicationCacheTree: function(target)
    655     {
    656         this._applicationCacheModel = new WebInspector.ApplicationCacheModel(target);
    657 
    658         this._applicationCacheViews = {};
    659         this._applicationCacheFrameElements = {};
    660         this._applicationCacheManifestElements = {};
    661 
    662         this._applicationCacheModel.addEventListener(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestAdded, this._applicationCacheFrameManifestAdded, this);
    663         this._applicationCacheModel.addEventListener(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestRemoved, this._applicationCacheFrameManifestRemoved, this);
    664 
    665         this._applicationCacheModel.addEventListener(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestStatusUpdated, this._applicationCacheFrameManifestStatusChanged, this);
    666         this._applicationCacheModel.addEventListener(WebInspector.ApplicationCacheModel.EventTypes.NetworkStateChanged, this._applicationCacheNetworkStateChanged, this);
    667     },
    668 
    669     _applicationCacheFrameManifestAdded: function(event)
    670     {
    671         var frameId = event.data;
    672         var manifestURL = this._applicationCacheModel.frameManifestURL(frameId);
    673         var status = this._applicationCacheModel.frameManifestStatus(frameId)
    674 
    675         var manifestTreeElement = this._applicationCacheManifestElements[manifestURL]
    676         if (!manifestTreeElement) {
    677             manifestTreeElement = new WebInspector.ApplicationCacheManifestTreeElement(this, manifestURL);
    678             this.applicationCacheListTreeElement.appendChild(manifestTreeElement);
    679             this._applicationCacheManifestElements[manifestURL] = manifestTreeElement;
    680         }
    681 
    682         var frameTreeElement = new WebInspector.ApplicationCacheFrameTreeElement(this, frameId, manifestURL);
    683         manifestTreeElement.appendChild(frameTreeElement);
    684         manifestTreeElement.expand();
    685         this._applicationCacheFrameElements[frameId] = frameTreeElement;
    686     },
    687 
    688     _applicationCacheFrameManifestRemoved: function(event)
    689     {
    690         var frameId = event.data;
    691         var frameTreeElement = this._applicationCacheFrameElements[frameId];
    692         if (!frameTreeElement)
    693             return;
    694 
    695         var manifestURL = frameTreeElement.manifestURL;
    696         delete this._applicationCacheFrameElements[frameId];
    697         delete this._applicationCacheViews[frameId];
    698         frameTreeElement.parent.removeChild(frameTreeElement);
    699 
    700         var manifestTreeElement = this._applicationCacheManifestElements[manifestURL];
    701         if (manifestTreeElement.children.length !== 0)
    702             return;
    703 
    704         delete this._applicationCacheManifestElements[manifestURL];
    705         manifestTreeElement.parent.removeChild(manifestTreeElement);
    706     },
    707 
    708     _applicationCacheFrameManifestStatusChanged: function(event)
    709     {
    710         var frameId = event.data;
    711         var status = this._applicationCacheModel.frameManifestStatus(frameId)
    712 
    713         if (this._applicationCacheViews[frameId])
    714             this._applicationCacheViews[frameId].updateStatus(status);
    715     },
    716 
    717     _applicationCacheNetworkStateChanged: function(event)
    718     {
    719         var isNowOnline = event.data;
    720 
    721         for (var manifestURL in this._applicationCacheViews)
    722             this._applicationCacheViews[manifestURL].updateNetworkState(isNowOnline);
    723     },
    724 
    725     _findTreeElementForResource: function(resource)
    726     {
    727         function getParent(object)
    728         {
    729             // Redirects, XHRs do not belong to the tree, it is fine to silently return false here.
    730             return null;
    731         }
    732 
    733         return this.sidebarTree.findTreeElement(resource, getParent);
    734     },
    735 
    736     showView: function(view)
    737     {
    738         if (view)
    739             this.showResource(view.resource);
    740     },
    741 
    742     _onmousemove: function(event)
    743     {
    744         var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY);
    745         if (!nodeUnderMouse)
    746             return;
    747 
    748         var listNode = nodeUnderMouse.enclosingNodeOrSelfWithNodeName("li");
    749         if (!listNode)
    750             return;
    751 
    752         var element = listNode.treeElement;
    753         if (this._previousHoveredElement === element)
    754             return;
    755 
    756         if (this._previousHoveredElement) {
    757             this._previousHoveredElement.hovered = false;
    758             delete this._previousHoveredElement;
    759         }
    760 
    761         if (element instanceof WebInspector.FrameTreeElement) {
    762             this._previousHoveredElement = element;
    763             element.hovered = true;
    764         }
    765     },
    766 
    767     _onmouseout: function(event)
    768     {
    769         if (this._previousHoveredElement) {
    770             this._previousHoveredElement.hovered = false;
    771             delete this._previousHoveredElement;
    772         }
    773     },
    774 
    775     __proto__: WebInspector.PanelWithSidebarTree.prototype
    776 }
    777 
    778 /**
    779  * @constructor
    780  * @implements {WebInspector.Revealer}
    781  */
    782 WebInspector.ResourcesPanel.ResourceRevealer = function()
    783 {
    784 }
    785 
    786 WebInspector.ResourcesPanel.ResourceRevealer.prototype = {
    787     /**
    788      * @param {!Object} resource
    789      * @param {number=} lineNumber
    790      */
    791     reveal: function(resource, lineNumber)
    792     {
    793         if (resource instanceof WebInspector.Resource)
    794             /** @type {!WebInspector.ResourcesPanel} */ (WebInspector.inspectorView.showPanel("resources")).showResource(resource, lineNumber);
    795     }
    796 }
    797 
    798 /**
    799  * @constructor
    800  * @extends {TreeElement}
    801  * @param {!WebInspector.ResourcesPanel} storagePanel
    802  * @param {?Object} representedObject
    803  * @param {string} title
    804  * @param {?Array.<string>=} iconClasses
    805  * @param {boolean=} hasChildren
    806  * @param {boolean=} noIcon
    807  */
    808 WebInspector.BaseStorageTreeElement = function(storagePanel, representedObject, title, iconClasses, hasChildren, noIcon)
    809 {
    810     TreeElement.call(this, "", representedObject, hasChildren);
    811     this._storagePanel = storagePanel;
    812     this._titleText = title;
    813     this._iconClasses = iconClasses;
    814     this._noIcon = noIcon;
    815 }
    816 
    817 WebInspector.BaseStorageTreeElement.prototype = {
    818     onattach: function()
    819     {
    820         this.listItemElement.removeChildren();
    821         if (this._iconClasses) {
    822             for (var i = 0; i < this._iconClasses.length; ++i)
    823                 this.listItemElement.classList.add(this._iconClasses[i]);
    824         }
    825 
    826         var selectionElement = document.createElement("div");
    827         selectionElement.className = "selection";
    828         this.listItemElement.appendChild(selectionElement);
    829 
    830         if (!this._noIcon) {
    831             this.imageElement = document.createElement("img");
    832             this.imageElement.className = "icon";
    833             this.listItemElement.appendChild(this.imageElement);
    834         }
    835 
    836         this.titleElement = document.createElement("div");
    837         this.titleElement.className = "base-storage-tree-element-title";
    838         this._titleTextNode = document.createTextNode("");
    839         this.titleElement.appendChild(this._titleTextNode);
    840         this._updateTitle();
    841         this._updateSubtitle();
    842         this.listItemElement.appendChild(this.titleElement);
    843     },
    844 
    845     get displayName()
    846     {
    847         return this._displayName;
    848     },
    849 
    850     _updateDisplayName: function()
    851     {
    852         this._displayName = this._titleText || "";
    853         if (this._subtitleText)
    854             this._displayName += " (" + this._subtitleText + ")";
    855     },
    856 
    857     _updateTitle: function()
    858     {
    859         this._updateDisplayName();
    860 
    861         if (!this.titleElement)
    862             return;
    863 
    864         this._titleTextNode.textContent = this._titleText || "";
    865     },
    866 
    867     _updateSubtitle: function()
    868     {
    869         this._updateDisplayName();
    870 
    871         if (!this.titleElement)
    872             return;
    873 
    874         if (this._subtitleText) {
    875             if (!this._subtitleElement) {
    876                 this._subtitleElement = document.createElement("span");
    877                 this._subtitleElement.className = "base-storage-tree-element-subtitle";
    878                 this.titleElement.appendChild(this._subtitleElement);
    879             }
    880             this._subtitleElement.textContent = "(" + this._subtitleText + ")";
    881         } else if (this._subtitleElement) {
    882             this.titleElement.removeChild(this._subtitleElement);
    883             delete this._subtitleElement;
    884         }
    885     },
    886 
    887     /**
    888      * @override
    889      * @return {boolean}
    890      */
    891     onselect: function(selectedByUser)
    892     {
    893         if (!selectedByUser)
    894             return false;
    895         var itemURL = this.itemURL;
    896         if (itemURL)
    897             WebInspector.settings.resourcesLastSelectedItem.set(itemURL);
    898         return false;
    899     },
    900 
    901     /**
    902      * @override
    903      */
    904     onreveal: function()
    905     {
    906         if (this.listItemElement)
    907             this.listItemElement.scrollIntoViewIfNeeded(false);
    908     },
    909 
    910     get titleText()
    911     {
    912         return this._titleText;
    913     },
    914 
    915     set titleText(titleText)
    916     {
    917         this._titleText = titleText;
    918         this._updateTitle();
    919     },
    920 
    921     get subtitleText()
    922     {
    923         return this._subtitleText;
    924     },
    925 
    926     set subtitleText(subtitleText)
    927     {
    928         this._subtitleText = subtitleText;
    929         this._updateSubtitle();
    930     },
    931 
    932     __proto__: TreeElement.prototype
    933 }
    934 
    935 /**
    936  * @constructor
    937  * @extends {WebInspector.BaseStorageTreeElement}
    938  * @param {!WebInspector.ResourcesPanel} storagePanel
    939  * @param {string} categoryName
    940  * @param {string} settingsKey
    941  * @param {?Array.<string>=} iconClasses
    942  * @param {boolean=} noIcon
    943  */
    944 WebInspector.StorageCategoryTreeElement = function(storagePanel, categoryName, settingsKey, iconClasses, noIcon)
    945 {
    946     WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, categoryName, iconClasses, false, noIcon);
    947     this._expandedSettingKey = "resources" + settingsKey + "Expanded";
    948     WebInspector.settings[this._expandedSettingKey] = WebInspector.settings.createSetting(this._expandedSettingKey, settingsKey === "Frames");
    949     this._categoryName = categoryName;
    950     this._target = /** @type {!WebInspector.Target} */ (WebInspector.targetManager.activeTarget());
    951 }
    952 
    953 WebInspector.StorageCategoryTreeElement.prototype = {
    954     /**
    955      * @return {!WebInspector.Target}
    956      */
    957     target: function()
    958     {
    959         return this._target;
    960     },
    961 
    962     get itemURL()
    963     {
    964         return "category://" + this._categoryName;
    965     },
    966 
    967     /**
    968      * @override
    969      * @return {boolean}
    970      */
    971     onselect: function(selectedByUser)
    972     {
    973         WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser);
    974         this._storagePanel.showCategoryView(this._categoryName);
    975         return false;
    976     },
    977 
    978     /**
    979      * @override
    980      */
    981     onattach: function()
    982     {
    983         WebInspector.BaseStorageTreeElement.prototype.onattach.call(this);
    984         if (WebInspector.settings[this._expandedSettingKey].get())
    985             this.expand();
    986     },
    987 
    988     /**
    989      * @override
    990      */
    991     onexpand: function()
    992     {
    993         WebInspector.settings[this._expandedSettingKey].set(true);
    994     },
    995 
    996     /**
    997      * @override
    998      */
    999     oncollapse: function()
   1000     {
   1001         WebInspector.settings[this._expandedSettingKey].set(false);
   1002     },
   1003 
   1004     __proto__: WebInspector.BaseStorageTreeElement.prototype
   1005 }
   1006 
   1007 /**
   1008  * @constructor
   1009  * @extends {WebInspector.BaseStorageTreeElement}
   1010  */
   1011 WebInspector.FrameTreeElement = function(storagePanel, frame)
   1012 {
   1013     WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, "", ["frame-storage-tree-item"]);
   1014     this._frame = frame;
   1015     this.frameNavigated(frame);
   1016 }
   1017 
   1018 WebInspector.FrameTreeElement.prototype = {
   1019     frameNavigated: function(frame)
   1020     {
   1021         this.removeChildren();
   1022         this._frameId = frame.id;
   1023 
   1024         this.titleText = frame.name;
   1025         this.subtitleText = new WebInspector.ParsedURL(frame.url).displayName;
   1026 
   1027         this._categoryElements = {};
   1028         this._treeElementForResource = {};
   1029 
   1030         this._storagePanel.addDocumentURL(frame.url);
   1031     },
   1032 
   1033     get itemURL()
   1034     {
   1035         return "frame://" + encodeURI(this.displayName);
   1036     },
   1037 
   1038     /**
   1039      * @override
   1040      * @return {boolean}
   1041      */
   1042     onselect: function(selectedByUser)
   1043     {
   1044         WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser);
   1045         this._storagePanel.showCategoryView(this.displayName);
   1046 
   1047         this.listItemElement.classList.remove("hovered");
   1048         DOMAgent.hideHighlight();
   1049         return false;
   1050     },
   1051 
   1052     set hovered(hovered)
   1053     {
   1054         if (hovered) {
   1055             this.listItemElement.classList.add("hovered");
   1056             DOMAgent.highlightFrame(this._frameId, WebInspector.Color.PageHighlight.Content.toProtocolRGBA(), WebInspector.Color.PageHighlight.ContentOutline.toProtocolRGBA());
   1057         } else {
   1058             this.listItemElement.classList.remove("hovered");
   1059             DOMAgent.hideHighlight();
   1060         }
   1061     },
   1062 
   1063     appendResource: function(resource)
   1064     {
   1065         if (resource.isHidden())
   1066             return;
   1067         var categoryName = resource.type.name();
   1068         var categoryElement = resource.type === WebInspector.resourceTypes.Document ? this : this._categoryElements[categoryName];
   1069         if (!categoryElement) {
   1070             categoryElement = new WebInspector.StorageCategoryTreeElement(this._storagePanel, resource.type.categoryTitle(), categoryName, null, true);
   1071             this._categoryElements[resource.type.name()] = categoryElement;
   1072             this._insertInPresentationOrder(this, categoryElement);
   1073         }
   1074         var resourceTreeElement = new WebInspector.FrameResourceTreeElement(this._storagePanel, resource);
   1075         this._insertInPresentationOrder(categoryElement, resourceTreeElement);
   1076         this._treeElementForResource[resource.url] = resourceTreeElement;
   1077     },
   1078 
   1079     /**
   1080      * @param {string} url
   1081      * @return {?WebInspector.Resource}
   1082      */
   1083     resourceByURL: function(url)
   1084     {
   1085         var treeElement = this._treeElementForResource[url];
   1086         return treeElement ? treeElement.representedObject : null;
   1087     },
   1088 
   1089     appendChild: function(treeElement)
   1090     {
   1091         this._insertInPresentationOrder(this, treeElement);
   1092     },
   1093 
   1094     _insertInPresentationOrder: function(parentTreeElement, childTreeElement)
   1095     {
   1096         // Insert in the alphabetical order, first frames, then resources. Document resource goes last.
   1097         function typeWeight(treeElement)
   1098         {
   1099             if (treeElement instanceof WebInspector.StorageCategoryTreeElement)
   1100                 return 2;
   1101             if (treeElement instanceof WebInspector.FrameTreeElement)
   1102                 return 1;
   1103             return 3;
   1104         }
   1105 
   1106         function compare(treeElement1, treeElement2)
   1107         {
   1108             var typeWeight1 = typeWeight(treeElement1);
   1109             var typeWeight2 = typeWeight(treeElement2);
   1110 
   1111             var result;
   1112             if (typeWeight1 > typeWeight2)
   1113                 result = 1;
   1114             else if (typeWeight1 < typeWeight2)
   1115                 result = -1;
   1116             else {
   1117                 var title1 = treeElement1.displayName || treeElement1.titleText;
   1118                 var title2 = treeElement2.displayName || treeElement2.titleText;
   1119                 result = title1.localeCompare(title2);
   1120             }
   1121             return result;
   1122         }
   1123 
   1124         var children = parentTreeElement.children;
   1125         var i;
   1126         for (i = 0; i < children.length; ++i) {
   1127             if (compare(childTreeElement, children[i]) < 0)
   1128                 break;
   1129         }
   1130         parentTreeElement.insertChild(childTreeElement, i);
   1131     },
   1132 
   1133     __proto__: WebInspector.BaseStorageTreeElement.prototype
   1134 }
   1135 
   1136 /**
   1137  * @constructor
   1138  * @extends {WebInspector.BaseStorageTreeElement}
   1139  */
   1140 WebInspector.FrameResourceTreeElement = function(storagePanel, resource)
   1141 {
   1142     WebInspector.BaseStorageTreeElement.call(this, storagePanel, resource, resource.displayName, ["resource-sidebar-tree-item", "resources-type-" + resource.type.name()]);
   1143     this._resource = resource;
   1144     this._resource.addEventListener(WebInspector.Resource.Events.MessageAdded, this._consoleMessageAdded, this);
   1145     this._resource.addEventListener(WebInspector.Resource.Events.MessagesCleared, this._consoleMessagesCleared, this);
   1146     this.tooltip = resource.url;
   1147 }
   1148 
   1149 WebInspector.FrameResourceTreeElement.prototype = {
   1150     get itemURL()
   1151     {
   1152         return this._resource.url;
   1153     },
   1154 
   1155     /**
   1156      * @override
   1157      * @return {boolean}
   1158      */
   1159     onselect: function(selectedByUser)
   1160     {
   1161         WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser);
   1162         this._storagePanel._showResourceView(this._resource);
   1163         return false;
   1164     },
   1165 
   1166     /**
   1167      * @override
   1168      * @return {boolean}
   1169      */
   1170     ondblclick: function(event)
   1171     {
   1172         InspectorFrontendHost.openInNewTab(this._resource.url);
   1173         return false;
   1174     },
   1175 
   1176     /**
   1177      * @override
   1178      */
   1179     onattach: function()
   1180     {
   1181         WebInspector.BaseStorageTreeElement.prototype.onattach.call(this);
   1182 
   1183         if (this._resource.type === WebInspector.resourceTypes.Image) {
   1184             var previewImage = document.createElement("img");
   1185             previewImage.className = "image-resource-icon-preview";
   1186             this._resource.populateImageSource(previewImage);
   1187 
   1188             var iconElement = document.createElement("div");
   1189             iconElement.className = "icon";
   1190             iconElement.appendChild(previewImage);
   1191             this.listItemElement.replaceChild(iconElement, this.imageElement);
   1192         }
   1193 
   1194         this._statusElement = document.createElement("div");
   1195         this._statusElement.className = "status";
   1196         this.listItemElement.insertBefore(this._statusElement, this.titleElement);
   1197 
   1198         this.listItemElement.draggable = true;
   1199         this.listItemElement.addEventListener("dragstart", this._ondragstart.bind(this), false);
   1200         this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
   1201 
   1202         this._updateErrorsAndWarningsBubbles();
   1203     },
   1204 
   1205     /**
   1206      * @param {!MouseEvent} event
   1207      * @return {boolean}
   1208      */
   1209     _ondragstart: function(event)
   1210     {
   1211         event.dataTransfer.setData("text/plain", this._resource.content);
   1212         event.dataTransfer.effectAllowed = "copy";
   1213         return true;
   1214     },
   1215 
   1216     _handleContextMenuEvent: function(event)
   1217     {
   1218         var contextMenu = new WebInspector.ContextMenu(event);
   1219         contextMenu.appendApplicableItems(this._resource);
   1220         contextMenu.show();
   1221     },
   1222 
   1223     _setBubbleText: function(x)
   1224     {
   1225         if (!this._bubbleElement) {
   1226             this._bubbleElement = document.createElement("div");
   1227             this._bubbleElement.className = "bubble";
   1228             this._statusElement.appendChild(this._bubbleElement);
   1229         }
   1230 
   1231         this._bubbleElement.textContent = x;
   1232     },
   1233 
   1234     _resetBubble: function()
   1235     {
   1236         if (this._bubbleElement) {
   1237             this._bubbleElement.textContent = "";
   1238             this._bubbleElement.classList.remove("warning");
   1239             this._bubbleElement.classList.remove("error");
   1240         }
   1241     },
   1242 
   1243     _updateErrorsAndWarningsBubbles: function()
   1244     {
   1245         if (this._storagePanel.currentQuery)
   1246             return;
   1247 
   1248         this._resetBubble();
   1249 
   1250         if (this._resource.warnings || this._resource.errors)
   1251             this._setBubbleText(this._resource.warnings + this._resource.errors);
   1252 
   1253         if (this._resource.warnings)
   1254             this._bubbleElement.classList.add("warning");
   1255 
   1256         if (this._resource.errors)
   1257             this._bubbleElement.classList.add("error");
   1258     },
   1259 
   1260     _consoleMessagesCleared: function()
   1261     {
   1262         // FIXME: move to the SourceFrame.
   1263         if (this._sourceView)
   1264             this._sourceView.clearMessages();
   1265 
   1266         this._updateErrorsAndWarningsBubbles();
   1267     },
   1268 
   1269     _consoleMessageAdded: function(event)
   1270     {
   1271         var msg = event.data;
   1272         if (this._sourceView)
   1273             this._sourceView.addMessage(msg);
   1274         this._updateErrorsAndWarningsBubbles();
   1275     },
   1276 
   1277     /**
   1278      * @return {!WebInspector.ResourceSourceFrame}
   1279      */
   1280     sourceView: function()
   1281     {
   1282         if (!this._sourceView) {
   1283             var sourceFrame = new WebInspector.ResourceSourceFrame(this._resource);
   1284             sourceFrame.setHighlighterType(this._resource.canonicalMimeType());
   1285             this._sourceView = sourceFrame;
   1286             if (this._resource.messages) {
   1287                 for (var i = 0; i < this._resource.messages.length; i++)
   1288                     this._sourceView.addMessage(this._resource.messages[i]);
   1289             }
   1290         }
   1291         return this._sourceView;
   1292     },
   1293 
   1294     __proto__: WebInspector.BaseStorageTreeElement.prototype
   1295 }
   1296 
   1297 /**
   1298  * @constructor
   1299  * @extends {WebInspector.BaseStorageTreeElement}
   1300  * @param {!WebInspector.ResourcesPanel} storagePanel
   1301  * @param {!WebInspector.Database} database
   1302  */
   1303 WebInspector.DatabaseTreeElement = function(storagePanel, database)
   1304 {
   1305     WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, database.name, ["database-storage-tree-item"], true);
   1306     this._database = database;
   1307 }
   1308 
   1309 WebInspector.DatabaseTreeElement.prototype = {
   1310     get itemURL()
   1311     {
   1312         return "database://" + encodeURI(this._database.name);
   1313     },
   1314 
   1315     /**
   1316      * @override
   1317      * @return {boolean}
   1318      */
   1319     onselect: function(selectedByUser)
   1320     {
   1321         WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser);
   1322         this._storagePanel._showDatabase(this._database);
   1323         return false;
   1324     },
   1325 
   1326     /**
   1327      * @override
   1328      */
   1329     onexpand: function()
   1330     {
   1331         this._updateChildren();
   1332     },
   1333 
   1334     _updateChildren: function()
   1335     {
   1336         this.removeChildren();
   1337 
   1338         /**
   1339          * @param {!Array.<string>} tableNames
   1340          * @this {WebInspector.DatabaseTreeElement}
   1341          */
   1342         function tableNamesCallback(tableNames)
   1343         {
   1344             var tableNamesLength = tableNames.length;
   1345             for (var i = 0; i < tableNamesLength; ++i)
   1346                 this.appendChild(new WebInspector.DatabaseTableTreeElement(this._storagePanel, this._database, tableNames[i]));
   1347         }
   1348         this._database.getTableNames(tableNamesCallback.bind(this));
   1349     },
   1350 
   1351     __proto__: WebInspector.BaseStorageTreeElement.prototype
   1352 }
   1353 
   1354 /**
   1355  * @constructor
   1356  * @extends {WebInspector.BaseStorageTreeElement}
   1357  */
   1358 WebInspector.DatabaseTableTreeElement = function(storagePanel, database, tableName)
   1359 {
   1360     WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, tableName, ["database-storage-tree-item"]);
   1361     this._database = database;
   1362     this._tableName = tableName;
   1363 }
   1364 
   1365 WebInspector.DatabaseTableTreeElement.prototype = {
   1366     get itemURL()
   1367     {
   1368         return "database://" + encodeURI(this._database.name) + "/" + encodeURI(this._tableName);
   1369     },
   1370 
   1371     /**
   1372      * @override
   1373      * @return {boolean}
   1374      */
   1375     onselect: function(selectedByUser)
   1376     {
   1377         WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser);
   1378         this._storagePanel._showDatabase(this._database, this._tableName);
   1379         return false;
   1380     },
   1381 
   1382     __proto__: WebInspector.BaseStorageTreeElement.prototype
   1383 }
   1384 
   1385 /**
   1386  * @constructor
   1387  * @extends {WebInspector.StorageCategoryTreeElement}
   1388  * @param {!WebInspector.ResourcesPanel} storagePanel
   1389  */
   1390 WebInspector.IndexedDBTreeElement = function(storagePanel)
   1391 {
   1392     WebInspector.StorageCategoryTreeElement.call(this, storagePanel, WebInspector.UIString("IndexedDB"), "IndexedDB", ["indexed-db-storage-tree-item"]);
   1393 }
   1394 
   1395 WebInspector.IndexedDBTreeElement.prototype = {
   1396     _initialize: function()
   1397     {
   1398         this._createIndexedDBModel();
   1399     },
   1400 
   1401     onattach: function()
   1402     {
   1403         WebInspector.StorageCategoryTreeElement.prototype.onattach.call(this);
   1404         this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
   1405     },
   1406 
   1407     _handleContextMenuEvent: function(event)
   1408     {
   1409         var contextMenu = new WebInspector.ContextMenu(event);
   1410         contextMenu.appendItem(WebInspector.UIString("Refresh IndexedDB"), this.refreshIndexedDB.bind(this));
   1411         contextMenu.show();
   1412     },
   1413 
   1414     _createIndexedDBModel: function()
   1415     {
   1416         this._indexedDBModel = new WebInspector.IndexedDBModel(this.target());
   1417         this._idbDatabaseTreeElements = [];
   1418         this._indexedDBModel.addEventListener(WebInspector.IndexedDBModel.EventTypes.DatabaseAdded, this._indexedDBAdded, this);
   1419         this._indexedDBModel.addEventListener(WebInspector.IndexedDBModel.EventTypes.DatabaseRemoved, this._indexedDBRemoved, this);
   1420         this._indexedDBModel.addEventListener(WebInspector.IndexedDBModel.EventTypes.DatabaseLoaded, this._indexedDBLoaded, this);
   1421     },
   1422 
   1423     refreshIndexedDB: function()
   1424     {
   1425         if (!this._indexedDBModel) {
   1426             this._createIndexedDBModel();
   1427             return;
   1428         }
   1429 
   1430         this._indexedDBModel.refreshDatabaseNames();
   1431     },
   1432 
   1433     /**
   1434      * @param {!WebInspector.Event} event
   1435      */
   1436     _indexedDBAdded: function(event)
   1437     {
   1438         var databaseId = /** @type {!WebInspector.IndexedDBModel.DatabaseId} */ (event.data);
   1439 
   1440         var idbDatabaseTreeElement = new WebInspector.IDBDatabaseTreeElement(this._storagePanel, this._indexedDBModel, databaseId);
   1441         this._idbDatabaseTreeElements.push(idbDatabaseTreeElement);
   1442         this.appendChild(idbDatabaseTreeElement);
   1443 
   1444         this._indexedDBModel.refreshDatabase(databaseId);
   1445     },
   1446 
   1447     /**
   1448      * @param {!WebInspector.Event} event
   1449      */
   1450     _indexedDBRemoved: function(event)
   1451     {
   1452         var databaseId = /** @type {!WebInspector.IndexedDBModel.DatabaseId} */ (event.data);
   1453 
   1454         var idbDatabaseTreeElement = this._idbDatabaseTreeElement(databaseId)
   1455         if (!idbDatabaseTreeElement)
   1456             return;
   1457 
   1458         idbDatabaseTreeElement.clear();
   1459         this.removeChild(idbDatabaseTreeElement);
   1460         this._idbDatabaseTreeElements.remove(idbDatabaseTreeElement);
   1461     },
   1462 
   1463     /**
   1464      * @param {!WebInspector.Event} event
   1465      */
   1466     _indexedDBLoaded: function(event)
   1467     {
   1468         var database = /** @type {!WebInspector.IndexedDBModel.Database} */ (event.data);
   1469 
   1470         var idbDatabaseTreeElement = this._idbDatabaseTreeElement(database.databaseId)
   1471         if (!idbDatabaseTreeElement)
   1472             return;
   1473 
   1474         idbDatabaseTreeElement.update(database);
   1475     },
   1476 
   1477     /**
   1478      * @param {!WebInspector.IndexedDBModel.DatabaseId} databaseId
   1479      * @return {?WebInspector.IDBDatabaseTreeElement}
   1480      */
   1481     _idbDatabaseTreeElement: function(databaseId)
   1482     {
   1483         var index = -1;
   1484         for (var i = 0; i < this._idbDatabaseTreeElements.length; ++i) {
   1485             if (this._idbDatabaseTreeElements[i]._databaseId.equals(databaseId)) {
   1486                 index = i;
   1487                 break;
   1488             }
   1489         }
   1490         if (index !== -1)
   1491             return this._idbDatabaseTreeElements[i];
   1492         return null;
   1493     },
   1494 
   1495     __proto__: WebInspector.StorageCategoryTreeElement.prototype
   1496 }
   1497 
   1498 /**
   1499  * @constructor
   1500  * @extends {WebInspector.StorageCategoryTreeElement}
   1501  * @param {!WebInspector.ResourcesPanel} storagePanel
   1502  */
   1503 WebInspector.FileSystemListTreeElement = function(storagePanel)
   1504 {
   1505     WebInspector.StorageCategoryTreeElement.call(this, storagePanel, WebInspector.UIString("FileSystem"), "FileSystem", ["file-system-storage-tree-item"]);
   1506 }
   1507 
   1508 WebInspector.FileSystemListTreeElement.prototype = {
   1509     _initialize: function()
   1510     {
   1511         this._refreshFileSystem();
   1512     },
   1513 
   1514     onattach: function()
   1515     {
   1516         WebInspector.StorageCategoryTreeElement.prototype.onattach.call(this);
   1517         this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
   1518     },
   1519 
   1520     _handleContextMenuEvent: function(event)
   1521     {
   1522         var contextMenu = new WebInspector.ContextMenu(event);
   1523         contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Refresh FileSystem list" : "Refresh FileSystem List"), this._refreshFileSystem.bind(this));
   1524         contextMenu.show();
   1525     },
   1526 
   1527     _fileSystemAdded: function(event)
   1528     {
   1529         var fileSystem = /** @type {!WebInspector.FileSystemModel.FileSystem} */ (event.data);
   1530         var fileSystemTreeElement = new WebInspector.FileSystemTreeElement(this._storagePanel, fileSystem);
   1531         this.appendChild(fileSystemTreeElement);
   1532     },
   1533 
   1534     _fileSystemRemoved: function(event)
   1535     {
   1536         var fileSystem = /** @type {!WebInspector.FileSystemModel.FileSystem} */ (event.data);
   1537         var fileSystemTreeElement = this._fileSystemTreeElementByName(fileSystem.name);
   1538         if (!fileSystemTreeElement)
   1539             return;
   1540         fileSystemTreeElement.clear();
   1541         this.removeChild(fileSystemTreeElement);
   1542     },
   1543 
   1544     _fileSystemTreeElementByName: function(fileSystemName)
   1545     {
   1546         for (var i = 0; i < this.children.length; ++i) {
   1547             var child = /** @type {!WebInspector.FileSystemTreeElement} */ (this.children[i]);
   1548             if (child.fileSystemName === fileSystemName)
   1549                 return this.children[i];
   1550         }
   1551         return null;
   1552     },
   1553 
   1554     _refreshFileSystem: function()
   1555     {
   1556         if (!this._fileSystemModel) {
   1557             this._fileSystemModel = new WebInspector.FileSystemModel(this.target());
   1558             this._fileSystemModel.addEventListener(WebInspector.FileSystemModel.EventTypes.FileSystemAdded, this._fileSystemAdded, this);
   1559             this._fileSystemModel.addEventListener(WebInspector.FileSystemModel.EventTypes.FileSystemRemoved, this._fileSystemRemoved, this);
   1560         }
   1561 
   1562         this._fileSystemModel.refreshFileSystemList();
   1563     },
   1564 
   1565     __proto__: WebInspector.StorageCategoryTreeElement.prototype
   1566 }
   1567 
   1568 /**
   1569  * @constructor
   1570  * @extends {WebInspector.BaseStorageTreeElement}
   1571  * @param {!WebInspector.ResourcesPanel} storagePanel
   1572  * @param {!WebInspector.IndexedDBModel} model
   1573  * @param {!WebInspector.IndexedDBModel.DatabaseId} databaseId
   1574  */
   1575 WebInspector.IDBDatabaseTreeElement = function(storagePanel, model, databaseId)
   1576 {
   1577     WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, databaseId.name + " - " + databaseId.securityOrigin, ["indexed-db-storage-tree-item"]);
   1578     this._model = model;
   1579     this._databaseId = databaseId;
   1580     this._idbObjectStoreTreeElements = {};
   1581 }
   1582 
   1583 WebInspector.IDBDatabaseTreeElement.prototype = {
   1584     get itemURL()
   1585     {
   1586         return "indexedDB://" + this._databaseId.securityOrigin + "/" + this._databaseId.name;
   1587     },
   1588 
   1589     onattach: function()
   1590     {
   1591         WebInspector.BaseStorageTreeElement.prototype.onattach.call(this);
   1592         this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
   1593     },
   1594 
   1595     _handleContextMenuEvent: function(event)
   1596     {
   1597         var contextMenu = new WebInspector.ContextMenu(event);
   1598         contextMenu.appendItem(WebInspector.UIString("Refresh IndexedDB"), this._refreshIndexedDB.bind(this));
   1599         contextMenu.show();
   1600     },
   1601 
   1602     _refreshIndexedDB: function()
   1603     {
   1604         this._model.refreshDatabaseNames();
   1605     },
   1606 
   1607     /**
   1608      * @param {!WebInspector.IndexedDBModel.Database} database
   1609      */
   1610     update: function(database)
   1611     {
   1612         this._database = database;
   1613         var objectStoreNames = {};
   1614         for (var objectStoreName in this._database.objectStores) {
   1615             var objectStore = this._database.objectStores[objectStoreName];
   1616             objectStoreNames[objectStore.name] = true;
   1617             if (!this._idbObjectStoreTreeElements[objectStore.name]) {
   1618                 var idbObjectStoreTreeElement = new WebInspector.IDBObjectStoreTreeElement(this._storagePanel, this._model, this._databaseId, objectStore);
   1619                 this._idbObjectStoreTreeElements[objectStore.name] = idbObjectStoreTreeElement;
   1620                 this.appendChild(idbObjectStoreTreeElement);
   1621             }
   1622             this._idbObjectStoreTreeElements[objectStore.name].update(objectStore);
   1623         }
   1624         for (var objectStoreName in this._idbObjectStoreTreeElements) {
   1625             if (!objectStoreNames[objectStoreName])
   1626                 this._objectStoreRemoved(objectStoreName);
   1627         }
   1628 
   1629         if (this.children.length) {
   1630             this.hasChildren = true;
   1631             this.expand();
   1632         }
   1633 
   1634         if (this._view)
   1635             this._view.update(database);
   1636 
   1637         this._updateTooltip();
   1638     },
   1639 
   1640     _updateTooltip: function()
   1641     {
   1642         this.tooltip = WebInspector.UIString("Version") + ": " + this._database.version;
   1643     },
   1644 
   1645     /**
   1646      * @override
   1647      * @return {boolean}
   1648      */
   1649     onselect: function(selectedByUser)
   1650     {
   1651         WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser);
   1652         if (!this._view)
   1653             this._view = new WebInspector.IDBDatabaseView(this._database);
   1654 
   1655         this._storagePanel.showIndexedDB(this._view);
   1656         return false;
   1657     },
   1658 
   1659     /**
   1660      * @param {string} objectStoreName
   1661      */
   1662     _objectStoreRemoved: function(objectStoreName)
   1663     {
   1664         var objectStoreTreeElement = this._idbObjectStoreTreeElements[objectStoreName];
   1665         objectStoreTreeElement.clear();
   1666         this.removeChild(objectStoreTreeElement);
   1667         delete this._idbObjectStoreTreeElements[objectStoreName];
   1668     },
   1669 
   1670     clear: function()
   1671     {
   1672         for (var objectStoreName in this._idbObjectStoreTreeElements)
   1673             this._objectStoreRemoved(objectStoreName);
   1674     },
   1675 
   1676     __proto__: WebInspector.BaseStorageTreeElement.prototype
   1677 }
   1678 
   1679 /**
   1680  * @constructor
   1681  * @extends {WebInspector.BaseStorageTreeElement}
   1682  * @param {!WebInspector.ResourcesPanel} storagePanel
   1683  * @param {!WebInspector.IndexedDBModel} model
   1684  * @param {!WebInspector.IndexedDBModel.DatabaseId} databaseId
   1685  * @param {!WebInspector.IndexedDBModel.ObjectStore} objectStore
   1686  */
   1687 WebInspector.IDBObjectStoreTreeElement = function(storagePanel, model, databaseId, objectStore)
   1688 {
   1689     WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, objectStore.name, ["indexed-db-object-store-storage-tree-item"]);
   1690     this._model = model;
   1691     this._databaseId = databaseId;
   1692     this._idbIndexTreeElements = {};
   1693 }
   1694 
   1695 WebInspector.IDBObjectStoreTreeElement.prototype = {
   1696     get itemURL()
   1697     {
   1698         return "indexedDB://" + this._databaseId.securityOrigin + "/" + this._databaseId.name + "/" + this._objectStore.name;
   1699     },
   1700 
   1701     onattach: function()
   1702     {
   1703         WebInspector.BaseStorageTreeElement.prototype.onattach.call(this);
   1704         this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
   1705     },
   1706 
   1707     _handleContextMenuEvent: function(event)
   1708     {
   1709         var contextMenu = new WebInspector.ContextMenu(event);
   1710         contextMenu.appendItem(WebInspector.UIString("Clear"), this._clearObjectStore.bind(this));
   1711         contextMenu.show();
   1712     },
   1713 
   1714     _clearObjectStore: function()
   1715     {
   1716         /**
   1717          * @this {WebInspector.IDBObjectStoreTreeElement}
   1718          */
   1719         function callback() {
   1720             this.update(this._objectStore);
   1721         }
   1722         this._model.clearObjectStore(this._databaseId, this._objectStore.name, callback.bind(this));
   1723     },
   1724 
   1725    /**
   1726      * @param {!WebInspector.IndexedDBModel.ObjectStore} objectStore
   1727      */
   1728     update: function(objectStore)
   1729     {
   1730         this._objectStore = objectStore;
   1731 
   1732         var indexNames = {};
   1733         for (var indexName in this._objectStore.indexes) {
   1734             var index = this._objectStore.indexes[indexName];
   1735             indexNames[index.name] = true;
   1736             if (!this._idbIndexTreeElements[index.name]) {
   1737                 var idbIndexTreeElement = new WebInspector.IDBIndexTreeElement(this._storagePanel, this._model, this._databaseId, this._objectStore, index);
   1738                 this._idbIndexTreeElements[index.name] = idbIndexTreeElement;
   1739                 this.appendChild(idbIndexTreeElement);
   1740             }
   1741             this._idbIndexTreeElements[index.name].update(index);
   1742         }
   1743         for (var indexName in this._idbIndexTreeElements) {
   1744             if (!indexNames[indexName])
   1745                 this._indexRemoved(indexName);
   1746         }
   1747         for (var indexName in this._idbIndexTreeElements) {
   1748             if (!indexNames[indexName]) {
   1749                 this.removeChild(this._idbIndexTreeElements[indexName]);
   1750                 delete this._idbIndexTreeElements[indexName];
   1751             }
   1752         }
   1753 
   1754         if (this.children.length) {
   1755             this.hasChildren = true;
   1756             this.expand();
   1757         }
   1758 
   1759         if (this._view)
   1760             this._view.update(this._objectStore);
   1761 
   1762         this._updateTooltip();
   1763     },
   1764 
   1765     _updateTooltip: function()
   1766     {
   1767 
   1768         var keyPathString = this._objectStore.keyPathString;
   1769         var tooltipString = keyPathString !== null ? (WebInspector.UIString("Key path: ") + keyPathString) : "";
   1770         if (this._objectStore.autoIncrement)
   1771             tooltipString += "\n" + WebInspector.UIString("autoIncrement");
   1772         this.tooltip = tooltipString
   1773     },
   1774 
   1775     /**
   1776      * @override
   1777      * @return {boolean}
   1778      */
   1779     onselect: function(selectedByUser)
   1780     {
   1781         WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser);
   1782         if (!this._view)
   1783             this._view = new WebInspector.IDBDataView(this._model, this._databaseId, this._objectStore, null);
   1784 
   1785         this._storagePanel.showIndexedDB(this._view);
   1786         return false;
   1787     },
   1788 
   1789     /**
   1790      * @param {string} indexName
   1791      */
   1792     _indexRemoved: function(indexName)
   1793     {
   1794         var indexTreeElement = this._idbIndexTreeElements[indexName];
   1795         indexTreeElement.clear();
   1796         this.removeChild(indexTreeElement);
   1797         delete this._idbIndexTreeElements[indexName];
   1798     },
   1799 
   1800     clear: function()
   1801     {
   1802         for (var indexName in this._idbIndexTreeElements)
   1803             this._indexRemoved(indexName);
   1804         if (this._view)
   1805             this._view.clear();
   1806     },
   1807 
   1808     __proto__: WebInspector.BaseStorageTreeElement.prototype
   1809 }
   1810 
   1811 /**
   1812  * @constructor
   1813  * @extends {WebInspector.BaseStorageTreeElement}
   1814  * @param {!WebInspector.ResourcesPanel} storagePanel
   1815  * @param {!WebInspector.IndexedDBModel} model
   1816  * @param {!WebInspector.IndexedDBModel.DatabaseId} databaseId
   1817  * @param {!WebInspector.IndexedDBModel.ObjectStore} objectStore
   1818  * @param {!WebInspector.IndexedDBModel.Index} index
   1819  */
   1820 WebInspector.IDBIndexTreeElement = function(storagePanel, model, databaseId, objectStore, index)
   1821 {
   1822     WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, index.name, ["indexed-db-index-storage-tree-item"]);
   1823     this._model = model;
   1824     this._databaseId = databaseId;
   1825     this._objectStore = objectStore;
   1826     this._index = index;
   1827 }
   1828 
   1829 WebInspector.IDBIndexTreeElement.prototype = {
   1830     get itemURL()
   1831     {
   1832         return "indexedDB://" + this._databaseId.securityOrigin + "/" + this._databaseId.name + "/" + this._objectStore.name + "/" + this._index.name;
   1833     },
   1834 
   1835     /**
   1836      * @param {!WebInspector.IndexedDBModel.Index} index
   1837      */
   1838     update: function(index)
   1839     {
   1840         this._index = index;
   1841 
   1842         if (this._view)
   1843             this._view.update(this._index);
   1844 
   1845         this._updateTooltip();
   1846     },
   1847 
   1848     _updateTooltip: function()
   1849     {
   1850         var tooltipLines = [];
   1851         var keyPathString = this._index.keyPathString;
   1852         tooltipLines.push(WebInspector.UIString("Key path: ") + keyPathString);
   1853         if (this._index.unique)
   1854             tooltipLines.push(WebInspector.UIString("unique"));
   1855         if (this._index.multiEntry)
   1856             tooltipLines.push(WebInspector.UIString("multiEntry"));
   1857         this.tooltip = tooltipLines.join("\n");
   1858     },
   1859 
   1860     /**
   1861      * @override
   1862      * @return {boolean}
   1863      */
   1864     onselect: function(selectedByUser)
   1865     {
   1866         WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser);
   1867         if (!this._view)
   1868             this._view = new WebInspector.IDBDataView(this._model, this._databaseId, this._objectStore, this._index);
   1869 
   1870         this._storagePanel.showIndexedDB(this._view);
   1871         return false;
   1872     },
   1873 
   1874     clear: function()
   1875     {
   1876         if (this._view)
   1877             this._view.clear();
   1878     },
   1879 
   1880     __proto__: WebInspector.BaseStorageTreeElement.prototype
   1881 }
   1882 
   1883 /**
   1884  * @constructor
   1885  * @extends {WebInspector.BaseStorageTreeElement}
   1886  */
   1887 WebInspector.DOMStorageTreeElement = function(storagePanel, domStorage, className)
   1888 {
   1889     WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, domStorage.securityOrigin ? domStorage.securityOrigin : WebInspector.UIString("Local Files"), ["domstorage-storage-tree-item", className]);
   1890     this._domStorage = domStorage;
   1891 }
   1892 
   1893 WebInspector.DOMStorageTreeElement.prototype = {
   1894     get itemURL()
   1895     {
   1896         return "storage://" + this._domStorage.securityOrigin + "/" + (this._domStorage.isLocalStorage ? "local" : "session");
   1897     },
   1898 
   1899     /**
   1900      * @override
   1901      * @return {boolean}
   1902      */
   1903     onselect: function(selectedByUser)
   1904     {
   1905         WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser);
   1906         this._storagePanel._showDOMStorage(this._domStorage);
   1907         return false;
   1908     },
   1909 
   1910     __proto__: WebInspector.BaseStorageTreeElement.prototype
   1911 }
   1912 
   1913 /**
   1914  * @constructor
   1915  * @extends {WebInspector.BaseStorageTreeElement}
   1916  */
   1917 WebInspector.CookieTreeElement = function(storagePanel, cookieDomain)
   1918 {
   1919     WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, cookieDomain ? cookieDomain : WebInspector.UIString("Local Files"), ["cookie-storage-tree-item"]);
   1920     this._cookieDomain = cookieDomain;
   1921 }
   1922 
   1923 WebInspector.CookieTreeElement.prototype = {
   1924     get itemURL()
   1925     {
   1926         return "cookies://" + this._cookieDomain;
   1927     },
   1928 
   1929     onattach: function()
   1930     {
   1931         WebInspector.BaseStorageTreeElement.prototype.onattach.call(this);
   1932         this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
   1933     },
   1934 
   1935     /**
   1936      * @param {!Event} event
   1937      */
   1938     _handleContextMenuEvent: function(event)
   1939     {
   1940         var contextMenu = new WebInspector.ContextMenu(event);
   1941         contextMenu.appendItem(WebInspector.UIString("Clear"), this._clearCookies.bind(this));
   1942         contextMenu.show();
   1943     },
   1944 
   1945     /**
   1946      * @param {string} domain
   1947      */
   1948     _clearCookies: function(domain)
   1949     {
   1950         this._storagePanel.clearCookies(this._cookieDomain);
   1951     },
   1952 
   1953     /**
   1954      * @override
   1955      * @return {boolean}
   1956      */
   1957     onselect: function(selectedByUser)
   1958     {
   1959         WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser);
   1960         this._storagePanel.showCookies(this, this._cookieDomain);
   1961         return false;
   1962     },
   1963 
   1964     __proto__: WebInspector.BaseStorageTreeElement.prototype
   1965 }
   1966 
   1967 /**
   1968  * @constructor
   1969  * @extends {WebInspector.BaseStorageTreeElement}
   1970  */
   1971 WebInspector.ApplicationCacheManifestTreeElement = function(storagePanel, manifestURL)
   1972 {
   1973     var title = new WebInspector.ParsedURL(manifestURL).displayName;
   1974     WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, title, ["application-cache-storage-tree-item"]);
   1975     this.tooltip = manifestURL;
   1976     this._manifestURL = manifestURL;
   1977 }
   1978 
   1979 WebInspector.ApplicationCacheManifestTreeElement.prototype = {
   1980     get itemURL()
   1981     {
   1982         return "appcache://" + this._manifestURL;
   1983     },
   1984 
   1985     get manifestURL()
   1986     {
   1987         return this._manifestURL;
   1988     },
   1989 
   1990     /**
   1991      * @override
   1992      * @return {boolean}
   1993      */
   1994     onselect: function(selectedByUser)
   1995     {
   1996         WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser);
   1997         this._storagePanel.showCategoryView(this._manifestURL);
   1998         return false;
   1999     },
   2000 
   2001     __proto__: WebInspector.BaseStorageTreeElement.prototype
   2002 }
   2003 
   2004 /**
   2005  * @constructor
   2006  * @extends {WebInspector.BaseStorageTreeElement}
   2007  */
   2008 WebInspector.ApplicationCacheFrameTreeElement = function(storagePanel, frameId, manifestURL)
   2009 {
   2010     WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, "", ["frame-storage-tree-item"]);
   2011     this._frameId = frameId;
   2012     this._manifestURL = manifestURL;
   2013     this._refreshTitles();
   2014 }
   2015 
   2016 WebInspector.ApplicationCacheFrameTreeElement.prototype = {
   2017     get itemURL()
   2018     {
   2019         return "appcache://" + this._manifestURL + "/" + encodeURI(this.displayName);
   2020     },
   2021 
   2022     get frameId()
   2023     {
   2024         return this._frameId;
   2025     },
   2026 
   2027     get manifestURL()
   2028     {
   2029         return this._manifestURL;
   2030     },
   2031 
   2032     _refreshTitles: function()
   2033     {
   2034         var frame = WebInspector.resourceTreeModel.frameForId(this._frameId);
   2035         if (!frame) {
   2036             this.subtitleText = WebInspector.UIString("new frame");
   2037             return;
   2038         }
   2039         this.titleText = frame.name;
   2040         this.subtitleText = new WebInspector.ParsedURL(frame.url).displayName;
   2041     },
   2042 
   2043     frameNavigated: function()
   2044     {
   2045         this._refreshTitles();
   2046     },
   2047 
   2048     /**
   2049      * @override
   2050      * @return {boolean}
   2051      */
   2052     onselect: function(selectedByUser)
   2053     {
   2054         WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser);
   2055         this._storagePanel.showApplicationCache(this._frameId);
   2056         return false;
   2057     },
   2058 
   2059     __proto__: WebInspector.BaseStorageTreeElement.prototype
   2060 }
   2061 
   2062 /**
   2063  * @constructor
   2064  * @extends {WebInspector.BaseStorageTreeElement}
   2065  * @param {!WebInspector.ResourcesPanel} storagePanel
   2066  * @param {!WebInspector.FileSystemModel.FileSystem} fileSystem
   2067  */
   2068 WebInspector.FileSystemTreeElement = function(storagePanel, fileSystem)
   2069 {
   2070     var displayName = fileSystem.type + " - " + fileSystem.origin;
   2071     WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, displayName, ["file-system-storage-tree-item"]);
   2072     this._fileSystem = fileSystem;
   2073 }
   2074 
   2075 WebInspector.FileSystemTreeElement.prototype = {
   2076     get fileSystemName()
   2077     {
   2078         return this._fileSystem.name;
   2079     },
   2080 
   2081     get itemURL()
   2082     {
   2083         return "filesystem://" + this._fileSystem.name;
   2084     },
   2085 
   2086     /**
   2087      * @override
   2088      * @return {boolean}
   2089      */
   2090     onselect: function(selectedByUser)
   2091     {
   2092         WebInspector.BaseStorageTreeElement.prototype.onselect.call(this, selectedByUser);
   2093         this._fileSystemView = new WebInspector.FileSystemView(this._fileSystem);
   2094         this._storagePanel.showFileSystem(this._fileSystemView);
   2095         return false;
   2096     },
   2097 
   2098     clear: function()
   2099     {
   2100         if (this.fileSystemView && this._storagePanel.visibleView === this.fileSystemView)
   2101             this._storagePanel.closeVisibleView();
   2102     },
   2103 
   2104     __proto__: WebInspector.BaseStorageTreeElement.prototype
   2105 }
   2106 
   2107 /**
   2108  * @constructor
   2109  * @extends {WebInspector.VBox}
   2110  */
   2111 WebInspector.StorageCategoryView = function()
   2112 {
   2113     WebInspector.VBox.call(this);
   2114 
   2115     this.element.classList.add("storage-view");
   2116     this._emptyView = new WebInspector.EmptyView("");
   2117     this._emptyView.show(this.element);
   2118 }
   2119 
   2120 WebInspector.StorageCategoryView.prototype = {
   2121     setText: function(text)
   2122     {
   2123         this._emptyView.text = text;
   2124     },
   2125 
   2126     __proto__: WebInspector.VBox.prototype
   2127 }
   2128