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