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