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