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