OSDN Git Service

Merge Webkit at r70949: Initial merge by git.
[android-x86/external-webkit.git] / WebCore / inspector / front-end / StoragePanel.js
1 /*
2  * Copyright (C) 2007, 2008, 2010 Apple Inc.  All rights reserved.
3  * Copyright (C) 2009 Joseph Pecoraro
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 WebInspector.StoragePanel = function(database)
31 {
32     WebInspector.Panel.call(this, "storage");
33
34     this.createSidebar();
35     this.sidebarElement.addStyleClass("outline-disclosure filter-all children small");
36     this.sidebarTreeElement.removeStyleClass("sidebar-tree");
37
38     if (Preferences.networkPanelEnabled) {
39         this.resourcesListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Frames"), "frame-storage-tree-item");
40         this.sidebarTree.appendChild(this.resourcesListTreeElement);
41         this.resourcesListTreeElement.expand();
42         this._treeElementForFrameId = {};
43     }
44
45     this.databasesListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Databases"), "database-storage-tree-item");
46     this.sidebarTree.appendChild(this.databasesListTreeElement);
47     this.databasesListTreeElement.expand();
48
49     this.localStorageListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Local Storage"), "domstorage-storage-tree-item local-storage");
50     this.sidebarTree.appendChild(this.localStorageListTreeElement);
51     this.localStorageListTreeElement.expand();
52
53     this.sessionStorageListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Session Storage"), "domstorage-storage-tree-item session-storage");
54     this.sidebarTree.appendChild(this.sessionStorageListTreeElement);
55     this.sessionStorageListTreeElement.expand();
56
57     this.cookieListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Cookies"), "cookie-storage-tree-item");
58     this.sidebarTree.appendChild(this.cookieListTreeElement);
59     this.cookieListTreeElement.expand();
60     
61     this.applicationCacheListTreeElement = new WebInspector.StorageCategoryTreeElement(this, WebInspector.UIString("Application Cache"), "application-cache-storage-tree-item");
62     this.sidebarTree.appendChild(this.applicationCacheListTreeElement);
63     this.applicationCacheListTreeElement.expand();
64
65     this.storageViews = document.createElement("div");
66     this.storageViews.id = "storage-views";
67     this.element.appendChild(this.storageViews);
68
69     this.storageViewStatusBarItemsContainer = document.createElement("div");
70     this.storageViewStatusBarItemsContainer.className = "status-bar-items";
71
72     this._databases = [];
73     this._domStorage = [];
74     this._cookieViews = {};
75 }
76
77 WebInspector.StoragePanel.prototype = {
78     get toolbarItemLabel()
79     {
80         return Preferences.networkPanelEnabled ? WebInspector.UIString("Resources") : WebInspector.UIString("Storage");
81     },
82
83     get statusBarItems()
84     {
85         return [this.storageViewStatusBarItemsContainer];
86     },
87
88     reset: function()
89     {
90         for (var i = 0; i < this._databases.length; ++i) {
91             var database = this._databases[i];
92             delete database._tableViews;
93             delete database._queryView;
94         }
95         this._databases = [];
96
97         var domStorageLength = this._domStorage.length;
98         for (var i = 0; i < this._domStorage.length; ++i) {
99             var domStorage = this._domStorage[i];
100             delete domStorage._domStorageView;
101         }
102         this._domStorage = [];
103
104         this._cookieViews = {};
105
106         this._applicationCacheView = null;
107         delete this._cachedApplicationCacheViewStatus;
108
109         this.databasesListTreeElement.removeChildren();
110         this.localStorageListTreeElement.removeChildren();
111         this.sessionStorageListTreeElement.removeChildren();
112         this.cookieListTreeElement.removeChildren();
113         this.applicationCacheListTreeElement.removeChildren();
114
115         this.storageViews.removeChildren();
116
117         this.storageViewStatusBarItemsContainer.removeChildren();
118
119         if (this.sidebarTree.selectedTreeElement)
120             this.sidebarTree.selectedTreeElement.deselect();
121     },
122
123     addOrUpdateFrame: function(parentFrameId, frameId, displayName)
124     {
125         var frameTreeElement = this._treeElementForFrameId[frameId];
126         if (frameTreeElement) {
127             frameTreeElement.displayName = displayName;
128             return;
129         }
130
131         var parentTreeElement = parentFrameId ? this._treeElementForFrameId[parentFrameId] : this.resourcesListTreeElement;
132         if (!parentTreeElement) {
133             console.warning("No frame with id:" + parentFrameId + " to route " + displayName + " to.")
134             return;
135         }
136
137         var frameTreeElement = new WebInspector.FrameTreeElement(this, frameId, displayName);
138         this._treeElementForFrameId[frameId] = frameTreeElement;
139
140         // Insert in the alphabetical order, first frames, then resources.
141         var children = parentTreeElement.children;
142         for (var i = 0; i < children.length; ++i) {
143             var child = children[i];
144             if (!(child instanceof WebInspector.FrameTreeElement)) {
145                 parentTreeElement.insertChild(frameTreeElement, i);
146                 return;
147             }
148             if (child.displayName.localeCompare(frameTreeElement.displayName) > 0) {
149                 parentTreeElement.insertChild(frameTreeElement, i);
150                 return;
151             }
152         }
153         parentTreeElement.appendChild(frameTreeElement);
154     },
155
156     removeFrame: function(frameId)
157     {
158         var frameTreeElement = this._treeElementForFrameId[frameId];
159         if (!frameTreeElement)
160             return;
161         delete this._treeElementForFrameId[frameId];
162         if (frameTreeElement.parent)
163             frameTreeElement.parent.removeChild(frameTreeElement);
164     },
165
166     addResourceToFrame: function(frameId, resource)
167     {
168         var frameTreeElement = this._treeElementForFrameId[frameId];
169         if (!frameTreeElement) {
170             // This is a frame's main resource, it will be retained
171             // and re-added by the resource manager;
172             return;
173         }
174
175         var resourceTreeElement = new WebInspector.FrameResourceTreeElement(this, resource);
176
177         // Insert in the alphabetical order, first frames, then resources. Document resource goes first.
178         var children = frameTreeElement.children;
179         for (var i = 0; i < children.length; ++i) {
180             var child = children[i];
181             if (!(child instanceof WebInspector.FrameResourceTreeElement))
182                 continue;
183
184             if (resource.type === WebInspector.Resource.Type.Document ||
185                     (child._resource.type !== WebInspector.Resource.Type.Document && child._resource.displayName.localeCompare(resource.displayName) > 0)) {
186                 frameTreeElement.insertChild(resourceTreeElement, i);
187                 return;
188             }
189         }
190         frameTreeElement.appendChild(resourceTreeElement);
191     },
192
193     removeResourcesFromFrame: function(frameId)
194     {
195         var frameTreeElement = this._treeElementForFrameId[frameId];
196         if (frameTreeElement)
197             frameTreeElement.removeChildren();
198     },
199
200     addDatabase: function(database)
201     {
202         this._databases.push(database);
203
204         var databaseTreeElement = new WebInspector.DatabaseTreeElement(this, database);
205         database._databasesTreeElement = databaseTreeElement;
206         this.databasesListTreeElement.appendChild(databaseTreeElement);
207     },
208     
209     addCookieDomain: function(domain)
210     {
211         var cookieDomainTreeElement = new WebInspector.CookieTreeElement(this, domain);
212         this.cookieListTreeElement.appendChild(cookieDomainTreeElement);
213     },
214
215     addDOMStorage: function(domStorage)
216     {
217         this._domStorage.push(domStorage);
218         var domStorageTreeElement = new WebInspector.DOMStorageTreeElement(this, domStorage, (domStorage.isLocalStorage ? "local-storage" : "session-storage"));
219         domStorage._domStorageTreeElement = domStorageTreeElement;
220         if (domStorage.isLocalStorage)
221             this.localStorageListTreeElement.appendChild(domStorageTreeElement);
222         else
223             this.sessionStorageListTreeElement.appendChild(domStorageTreeElement);
224     },
225
226     addApplicationCache: function(domain)
227     {
228         var applicationCacheTreeElement = new WebInspector.ApplicationCacheTreeElement(this, domain);
229         this.applicationCacheListTreeElement.appendChild(applicationCacheTreeElement);
230     },
231
232     selectDatabase: function(databaseId)
233     {
234         var database;
235         for (var i = 0, len = this._databases.length; i < len; ++i) {
236             database = this._databases[i];
237             if (database.id === databaseId) {
238                 this.showDatabase(database);
239                 database._databasesTreeElement.select();
240                 return;
241             }
242         }
243     },
244
245     selectDOMStorage: function(storageId)
246     {
247         var domStorage = this._domStorageForId(storageId);
248         if (domStorage) {
249             this.showDOMStorage(domStorage);
250             domStorage._domStorageTreeElement.select();
251         }
252     },
253
254     canShowSourceLine: function(url, line)
255     {
256         return !!WebInspector.resourceManager.resourceForURL(url);
257     },
258
259     showSourceLine: function(url, line)
260     {
261         this.showResource(WebInspector.resourceManager.resourceForURL(url), line);
262     },
263
264     showResource: function(resource, line)
265     {
266         var resourceTreeElement = this._findTreeElementForResource(resource);
267         if (resourceTreeElement) {
268             resourceTreeElement.reveal();
269             resourceTreeElement.select();
270         }
271
272         if (line) {
273             var view = WebInspector.ResourceManager.resourceViewForResource(resource);
274             view.selectContentTab(true);
275             if (view.revealLine)
276                 view.revealLine(line);
277             if (view.highlightLine)
278                 view.highlightLine(line);
279         }
280         return true;
281     },
282
283     _showResourceView: function(resource)
284     {
285         var view = WebInspector.ResourceManager.resourceViewForResource(resource);
286         view.headersVisible = false;
287         this._innerShowView(view);
288     },
289
290     showDatabase: function(database, tableName)
291     {
292         if (!database)
293             return;
294
295         var view;
296         if (tableName) {
297             if (!("_tableViews" in database))
298                 database._tableViews = {};
299             view = database._tableViews[tableName];
300             if (!view) {
301                 view = new WebInspector.DatabaseTableView(database, tableName);
302                 database._tableViews[tableName] = view;
303             }
304         } else {
305             view = database._queryView;
306             if (!view) {
307                 view = new WebInspector.DatabaseQueryView(database);
308                 database._queryView = view;
309             }
310         }
311
312         this._innerShowView(view);
313     },
314
315     showDOMStorage: function(domStorage)
316     {
317         if (!domStorage)
318             return;
319
320         var view;
321         view = domStorage._domStorageView;
322         if (!view) {
323             view = new WebInspector.DOMStorageItemsView(domStorage);
324             domStorage._domStorageView = view;
325         }
326
327         this._innerShowView(view);
328     },
329
330     showCookies: function(treeElement, cookieDomain)
331     {
332         var view = this._cookieViews[cookieDomain];
333         if (!view) {
334             view = new WebInspector.CookieItemsView(treeElement, cookieDomain);
335             this._cookieViews[cookieDomain] = view;
336         }
337
338         this._innerShowView(view);
339     },
340
341     showApplicationCache: function(treeElement, appcacheDomain)
342     {
343         var view = this._applicationCacheView;
344         if (!view) {
345             view = new WebInspector.ApplicationCacheItemsView(treeElement, appcacheDomain);
346             this._applicationCacheView = view;
347         }
348
349         this._innerShowView(view);
350
351         if ("_cachedApplicationCacheViewStatus" in this)
352             this._applicationCacheView.updateStatus(this._cachedApplicationCacheViewStatus);
353     },
354
355     showCategoryView: function(categoryName)
356     {
357         if (!this._categoryView)
358             this._categoryView = new WebInspector.StorageCategoryView();
359         this._categoryView.setText(categoryName);
360         this._innerShowView(this._categoryView);
361     },
362
363     _innerShowView: function(view)
364     {
365         if (this.visibleView)
366             this.visibleView.hide();
367
368         view.show(this.storageViews);
369         this.visibleView = view;
370
371         this.storageViewStatusBarItemsContainer.removeChildren();
372         var statusBarItems = view.statusBarItems || [];
373         for (var i = 0; i < statusBarItems.length; ++i)
374             this.storageViewStatusBarItemsContainer.appendChild(statusBarItems[i]);
375     },
376
377     closeVisibleView: function()
378     {
379         if (this.visibleView)
380             this.visibleView.hide();
381         delete this.visibleView;
382     },
383
384     updateDatabaseTables: function(database)
385     {
386         if (!database || !database._databasesTreeElement)
387             return;
388
389         database._databasesTreeElement.shouldRefreshChildren = true;
390
391         if (!("_tableViews" in database))
392             return;
393
394         var tableNamesHash = {};
395         var self = this;
396         function tableNamesCallback(tableNames)
397         {
398             var tableNamesLength = tableNames.length;
399             for (var i = 0; i < tableNamesLength; ++i)
400                 tableNamesHash[tableNames[i]] = true;
401
402             for (var tableName in database._tableViews) {
403                 if (!(tableName in tableNamesHash)) {
404                     if (self.visibleView === database._tableViews[tableName])
405                         self.closeVisibleView();
406                     delete database._tableViews[tableName];
407                 }
408             }
409         }
410         database.getTableNames(tableNamesCallback);
411     },
412
413     dataGridForResult: function(columnNames, values)
414     {
415         var numColumns = columnNames.length;
416         if (!numColumns)
417             return null;
418
419         var columns = {};
420
421         for (var i = 0; i < columnNames.length; ++i) {
422             var column = {};
423             column.width = columnNames[i].length;
424             column.title = columnNames[i];
425             column.sortable = true;
426
427             columns[columnNames[i]] = column;
428         }
429
430         var nodes = [];
431         for (var i = 0; i < values.length / numColumns; ++i) {
432             var data = {};
433             for (var j = 0; j < columnNames.length; ++j)
434                 data[columnNames[j]] = values[numColumns * i + j];
435
436             var node = new WebInspector.DataGridNode(data, false);
437             node.selectable = false;
438             nodes.push(node);
439         }
440
441         var dataGrid = new WebInspector.DataGrid(columns);
442         var length = nodes.length;
443         for (var i = 0; i < length; ++i)
444             dataGrid.appendChild(nodes[i]);
445
446         dataGrid.addEventListener("sorting changed", this._sortDataGrid.bind(this, dataGrid), this);
447         return dataGrid;
448     },
449
450     _sortDataGrid: function(dataGrid)
451     {
452         var nodes = dataGrid.children.slice();
453         var sortColumnIdentifier = dataGrid.sortColumnIdentifier;
454         var sortDirection = dataGrid.sortOrder === "ascending" ? 1 : -1;
455         var columnIsNumeric = true;
456
457         for (var i = 0; i < nodes.length; i++) {
458             if (isNaN(Number(nodes[i].data[sortColumnIdentifier])))
459                 columnIsNumeric = false;
460         }
461
462         function comparator(dataGridNode1, dataGridNode2)
463         {
464             var item1 = dataGridNode1.data[sortColumnIdentifier];
465             var item2 = dataGridNode2.data[sortColumnIdentifier];
466
467             var comparison;
468             if (columnIsNumeric) {
469                 // Sort numbers based on comparing their values rather than a lexicographical comparison.
470                 var number1 = parseFloat(item1);
471                 var number2 = parseFloat(item2);
472                 comparison = number1 < number2 ? -1 : (number1 > number2 ? 1 : 0);
473             } else
474                 comparison = item1 < item2 ? -1 : (item1 > item2 ? 1 : 0);
475
476             return sortDirection * comparison;
477         }
478
479         nodes.sort(comparator);
480         dataGrid.removeChildren();
481         for (var i = 0; i < nodes.length; i++)
482             dataGrid.appendChild(nodes[i]);
483     },
484
485     updateDOMStorage: function(storageId)
486     {
487         var domStorage = this._domStorageForId(storageId);
488         if (!domStorage)
489             return;
490
491         var view = domStorage._domStorageView;
492         if (this.visibleView && view === this.visibleView)
493             domStorage._domStorageView.update();
494     },
495
496     updateApplicationCacheStatus: function(status)
497     {
498         this._cachedApplicationCacheViewStatus = status;
499         if (this._applicationCacheView && this._applicationCacheView === this.visibleView)
500             this._applicationCacheView.updateStatus(status);
501     },
502
503     updateNetworkState: function(isNowOnline)
504     {
505         if (this._applicationCacheView && this._applicationCacheView === this.visibleView)
506             this._applicationCacheView.updateNetworkState(isNowOnline);
507     },
508
509     updateManifest: function(manifest)
510     {
511         if (this._applicationCacheView && this._applicationCacheView === this.visibleView)
512             this._applicationCacheView.updateManifest(manifest);
513     },
514
515     _domStorageForId: function(storageId)
516     {
517         if (!this._domStorage)
518             return null;
519         var domStorageLength = this._domStorage.length;
520         for (var i = 0; i < domStorageLength; ++i) {
521             var domStorage = this._domStorage[i];
522             if (domStorage.id == storageId)
523                 return domStorage;
524         }
525         return null;
526     },
527
528     updateMainViewWidth: function(width)
529     {
530         this.storageViews.style.left = width + "px";
531         this.storageViewStatusBarItemsContainer.style.left = width + "px";
532         this.resize();
533     },
534
535     get searchableViews()
536     {
537         var views = [];
538
539         if (!Preferences.networkPanelEnabled)
540             return views;
541
542         const visibleView = this.visibleView;
543         if (visibleView instanceof WebInspector.ResourceView && visibleView.performSearch)
544             views.push(visibleView);
545
546         function callback(resourceTreeElement)
547         {
548             var resource = resourceTreeElement._resource;
549             var resourceView = WebInspector.ResourceManager.resourceViewForResource(resource);
550             if (resourceView.performSearch && resourceView !== visibleView)
551                 views.push(resourceView);
552         }
553         this._forAllResourceTreeElements(callback);
554         return views;
555     },
556
557     _forAllResourceTreeElements: function(callback)
558     {
559         var stop = false;
560         for (var treeElement = this.resourcesListTreeElement; !stop && treeElement; treeElement = treeElement.traverseNextTreeElement(false, this.resourcesListTreeElement, true)) {
561             if (treeElement instanceof WebInspector.FrameResourceTreeElement)
562                 stop = callback(treeElement);
563         }
564     },
565
566     searchMatchFound: function(view, matches)
567     {
568         if (!view.resource)
569             return;
570         var treeElement = this._findTreeElementForResource(view.resource);
571         if (treeElement)
572             treeElement.searchMatchFound(matches);
573     },
574
575     _findTreeElementForResource: function(resource)
576     {
577         function isAncestor(ancestor, object)
578         {
579             console.error("There should be no calls to isAncestor, but there was one for ", object);
580             return false;
581         }
582
583         function getParent(object)
584         {
585             console.error("There should be no calls to getParent, but there was one for ", object);
586             return null;
587         }
588
589         return this.sidebarTree.findTreeElement(resource, isAncestor, getParent);
590     },
591
592     searchCanceled: function(startingNewSearch)
593     {
594         WebInspector.Panel.prototype.searchCanceled.call(this, startingNewSearch);
595
596         if (startingNewSearch)
597             return;
598
599         function callback(resourceTreeElement)
600         {
601             resourceTreeElement._errorsWarningsUpdated();
602         }
603         this._forAllResourceTreeElements(callback);
604     },
605
606     performSearch: function(query)
607     {
608         function callback(resourceTreeElement)
609         {
610             resourceTreeElement._resetBubble();
611         }
612         this._forAllResourceTreeElements(callback);
613         WebInspector.Panel.prototype.performSearch.call(this, query);
614     },
615
616     showView: function(view)
617     {
618         if (view)
619             this.showResource(view.resource);
620     }
621 }
622
623 WebInspector.StoragePanel.prototype.__proto__ = WebInspector.Panel.prototype;
624
625 WebInspector.BaseStorageTreeElement = function(storagePanel, representedObject, title, iconClass, hasChildren)
626 {
627     TreeElement.call(this, "", representedObject, hasChildren);
628     this._storagePanel = storagePanel;
629     this._titleText = title;
630     this._iconClass = iconClass;
631 }
632
633 WebInspector.BaseStorageTreeElement.prototype = {
634     onattach: function()
635     {
636         this.listItemElement.removeChildren();
637         this.listItemElement.addStyleClass(this._iconClass);
638
639         var selectionElement = document.createElement("div");
640         selectionElement.className = "selection";
641         this.listItemElement.appendChild(selectionElement);
642
643         this.imageElement = document.createElement("img");
644         this.imageElement.className = "icon";
645         this.listItemElement.appendChild(this.imageElement);
646
647         this.titleElement = document.createElement("div");
648         this.titleElement.className = "base-storage-tree-element-title";
649         this.titleElement.textContent = this._titleText;
650         this.listItemElement.appendChild(this.titleElement);
651     },
652
653     onreveal: function()
654     {
655         if (this.listItemElement)
656             this.listItemElement.scrollIntoViewIfNeeded(false);
657     },
658
659     set titleText(titleText)
660     {
661         this._titleText = titleText;
662         this.titleElement.textContent = this._titleText;
663     },
664
665     isEventWithinDisclosureTriangle: function()
666     {
667         // Override it since we use margin-left in place of treeoutline's text-indent.
668         // Hence we need to take padding into consideration. This all is needed for leading
669         // icons in the tree.
670         const paddingLeft = 14;
671         var left = this.listItemElement.totalOffsetLeft + paddingLeft;
672         return event.pageX >= left && event.pageX <= left + this.arrowToggleWidth && this.hasChildren;
673     }
674 }
675
676 WebInspector.BaseStorageTreeElement.prototype.__proto__ = TreeElement.prototype;
677
678 WebInspector.StorageCategoryTreeElement = function(storagePanel, categoryName, iconClass)
679 {
680     WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, categoryName, iconClass, true);
681     this._categoryName = categoryName;
682 }
683
684 WebInspector.StorageCategoryTreeElement.prototype = {
685     onselect: function()
686     {
687         this._storagePanel.showCategoryView(this._categoryName);
688     }
689 }
690 WebInspector.StorageCategoryTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
691
692 WebInspector.FrameTreeElement = function(storagePanel, frameId, displayName)
693 {
694     WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, displayName, "frame-storage-tree-item");
695     this._frameId = frameId;
696     this._displayName = displayName;
697 }
698
699 WebInspector.FrameTreeElement.prototype = {
700     onselect: function()
701     {
702         this._storagePanel.showCategoryView(this._displayName);
703     },
704
705     get displayName()
706     {
707         return this._displayName;
708     },
709
710     set displayName(displayName)
711     {
712         this._displayName = displayName;
713         this.titleText = displayName;
714     }
715 }
716 WebInspector.FrameTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
717
718 WebInspector.FrameResourceTreeElement = function(storagePanel, resource)
719 {
720     WebInspector.BaseStorageTreeElement.call(this, storagePanel, resource, resource.displayName, "resource-sidebar-tree-item resources-category-" + resource.category.name);
721     this._resource = resource;
722     this._resource.addEventListener("errors-warnings-updated", this._errorsWarningsUpdated, this);
723     this.tooltip = resource.url;
724 }
725
726 WebInspector.FrameResourceTreeElement.prototype = {
727     onselect: function()
728     {
729         this._storagePanel._showResourceView(this._resource);
730     },
731
732     ondblclick: function(event)
733     {
734         InspectorBackend.openInInspectedWindow(this._resource.url);
735     },
736
737     onattach: function()
738     {
739         WebInspector.BaseStorageTreeElement.prototype.onattach.call(this);
740
741         if (this._resource.category === WebInspector.resourceCategories.images) {
742             var previewImage = document.createElement("img");
743             previewImage.className = "image-resource-icon-preview";
744             previewImage.src = this._resource.url;
745
746             var iconElement = document.createElement("div");
747             iconElement.className = "icon";
748             iconElement.appendChild(previewImage);
749             this.listItemElement.replaceChild(iconElement, this.imageElement);
750         }
751
752         this._statusElement = document.createElement("div");
753         this._statusElement.className = "status";
754         this.listItemElement.insertBefore(this._statusElement, this.titleElement);
755
756         this.listItemElement.draggable = true;
757         this.listItemElement.addEventListener("dragstart", this._ondragstart.bind(this), false);
758     },
759
760     _ondragstart: function(event)
761     {
762         event.dataTransfer.setData("text/plain", this._resource.url);
763         event.dataTransfer.setData("text/uri-list", this._resource.url + "\r\n");
764         event.dataTransfer.effectAllowed = "copy";
765         return true;
766     },
767
768     _setBubbleText: function(x)
769     {
770         if (!this._bubbleElement) {
771             this._bubbleElement = document.createElement("div");
772             this._bubbleElement.className = "bubble";
773             this._statusElement.appendChild(this._bubbleElement);
774         }
775
776         this._bubbleElement.textContent = x;
777     },
778
779     _resetBubble: function()
780     {
781         if (this._bubbleElement) {
782             this._bubbleElement.textContent = "";
783             this._bubbleElement.removeStyleClass("search-matches");
784             this._bubbleElement.removeStyleClass("warning");
785             this._bubbleElement.removeStyleClass("error");
786         }
787     },
788
789     searchMatchFound: function(matches)
790     {
791         this._resetBubble();
792
793         this._setBubbleText(matches);
794         this._bubbleElement.addStyleClass("search-matches");
795
796         // Expand, do not scroll into view.
797         var currentAncestor = this.parent;
798         while (currentAncestor && !currentAncestor.root) {
799             if (!currentAncestor.expanded)
800                 currentAncestor.expand();
801             currentAncestor = currentAncestor.parent;
802         }
803     },
804
805     _errorsWarningsUpdated: function()
806     {
807         // FIXME: move to the Script/SourceView.
808         if (!this._resource.warnings && !this._resource.errors) {
809             var view = WebInspector.ResourceManager.existingResourceViewForResource(this._resource);
810             if (view && view.clearMessages)
811                 view.clearMessages();
812         }
813
814         if (this._storagePanel.currentQuery)
815             return;
816
817         this._resetBubble();
818
819         if (this._resource.warnings || this._resource.errors)
820             this._setBubbleText(this._resource.warnings + this._resource.errors);
821
822         if (this._resource.warnings)
823             this._bubbleElement.addStyleClass("warning");
824
825         if (this._resource.errors)
826             this._bubbleElement.addStyleClass("error");
827     }
828 }
829
830 WebInspector.FrameResourceTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
831
832 WebInspector.DatabaseTreeElement = function(storagePanel, database)
833 {
834     WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, database.name, "database-storage-tree-item", true);
835     this._database = database;
836 }
837
838 WebInspector.DatabaseTreeElement.prototype = {
839     onselect: function()
840     {
841         this._storagePanel.showDatabase(this._database);
842     },
843
844     oncollapse: function()
845     {
846         // Request a refresh after every collapse so the next
847         // expand will have an updated table list.
848         this.shouldRefreshChildren = true;
849     },
850
851     onpopulate: function()
852     {
853         this.removeChildren();
854
855         function tableNamesCallback(tableNames)
856         {
857             var tableNamesLength = tableNames.length;
858             for (var i = 0; i < tableNamesLength; ++i)
859                 this.appendChild(new WebInspector.DatabaseTableTreeElement(this._storagePanel, this._database, tableNames[i]));
860         }
861         this._database.getTableNames(tableNamesCallback.bind(this));
862     }
863
864 }
865 WebInspector.DatabaseTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
866
867 WebInspector.DatabaseTableTreeElement = function(storagePanel, database, tableName)
868 {
869     WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, tableName, "database-storage-tree-item");
870     this._database = database;
871     this._tableName = tableName;
872 }
873
874 WebInspector.DatabaseTableTreeElement.prototype = {
875     onselect: function()
876     {
877         this._storagePanel.showDatabase(this._database, this._tableName);
878     }
879 }
880 WebInspector.DatabaseTableTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
881
882 WebInspector.DOMStorageTreeElement = function(storagePanel, domStorage, className)
883 {
884     WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, domStorage.domain ? domStorage.domain : WebInspector.UIString("Local Files"), "domstorage-storage-tree-item " + className);
885     this._domStorage = domStorage;
886 }
887
888 WebInspector.DOMStorageTreeElement.prototype = {
889     onselect: function()
890     {
891         this._storagePanel.showDOMStorage(this._domStorage);
892     }
893 }
894 WebInspector.DOMStorageTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
895
896 WebInspector.CookieTreeElement = function(storagePanel, cookieDomain)
897 {
898     WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, cookieDomain ? cookieDomain : WebInspector.UIString("Local Files"), "cookie-storage-tree-item");
899     this._cookieDomain = cookieDomain;
900 }
901
902 WebInspector.CookieTreeElement.prototype = {
903     onselect: function()
904     {
905         this._storagePanel.showCookies(this, this._cookieDomain);
906     }
907 }
908 WebInspector.CookieTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
909
910 WebInspector.ApplicationCacheTreeElement = function(storagePanel, appcacheDomain)
911 {
912     WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, appcacheDomain ? appcacheDomain : WebInspector.UIString("Local Files"), "application-cache-storage-tree-item");
913     this._appcacheDomain = appcacheDomain;
914 }
915
916 WebInspector.ApplicationCacheTreeElement.prototype = {
917     onselect: function()
918     {
919         this._storagePanel.showApplicationCache(this, this._appcacheDomain);
920     }
921 }
922 WebInspector.ApplicationCacheTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype;
923
924 WebInspector.StorageCategoryView = function()
925 {
926     WebInspector.View.call(this);
927
928     this.element.addStyleClass("storage-view");
929
930     this._emptyMsgElement = document.createElement("div");
931     this._emptyMsgElement.className = "storage-empty-view";
932     this.element.appendChild(this._emptyMsgElement);
933 }
934
935 WebInspector.StorageCategoryView.prototype = {
936     setText: function(text)
937     {
938         this._emptyMsgElement.textContent = text;
939     }
940 }
941
942 WebInspector.StorageCategoryView.prototype.__proto__ = WebInspector.View.prototype;