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