2011-01-13 Mikhail Naganov <mnaganov@chromium.org>
[WebKit-https.git] / Source / WebCore / inspector / front-end / ApplicationCacheItemsView.js
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 WebInspector.ApplicationCacheItemsView = function(treeElement, appcacheDomain)
27 {
28     WebInspector.View.call(this);
29
30     this.element.addStyleClass("storage-view");
31     this.element.addStyleClass("table");
32
33     // FIXME: Delete Button semantics are not yet defined.
34     // FIXME: Needs better tooltip. (Localized)
35     this.deleteButton = new WebInspector.StatusBarButton(WebInspector.UIString("Delete"), "delete-storage-status-bar-item");
36     this.deleteButton.visible = false;
37     this.deleteButton.addEventListener("click", this._deleteButtonClicked.bind(this), false);
38
39     // FIXME: Refresh Button semantics are not yet defined.
40     // FIXME: Needs better tooltip. (Localized)
41     this.refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item");
42     this.refreshButton.addEventListener("click", this._refreshButtonClicked.bind(this), false);
43
44     if (Preferences.onlineDetectionEnabled) {
45         this.connectivityIcon = document.createElement("img");
46         this.connectivityIcon.className = "storage-application-cache-connectivity-icon";
47         this.connectivityIcon.src = "";
48         this.connectivityMessage = document.createElement("span");
49         this.connectivityMessage.className = "storage-application-cache-connectivity";
50         this.connectivityMessage.textContent = "";
51     }
52
53     this.divider = document.createElement("span");
54     this.divider.className = "status-bar-item status-bar-divider";
55
56     this.statusIcon = document.createElement("img");
57     this.statusIcon.className = "storage-application-cache-status-icon";
58     this.statusIcon.src = "";
59     this.statusMessage = document.createElement("span");
60     this.statusMessage.className = "storage-application-cache-status";
61     this.statusMessage.textContent = "";
62
63     this._treeElement = treeElement;
64     this._appcacheDomain = appcacheDomain;
65
66     this._emptyMsgElement = document.createElement("div");
67     this._emptyMsgElement.className = "storage-empty-view";
68     this._emptyMsgElement.textContent = WebInspector.UIString("No Application Cache information available.");
69     this.element.appendChild(this._emptyMsgElement);
70
71     this.updateStatus(applicationCache.UNCACHED);
72 }
73
74 WebInspector.ApplicationCacheItemsView.prototype = {
75     get statusBarItems()
76     {
77         if (Preferences.onlineDetectionEnabled) {
78             return [
79                 this.refreshButton.element, this.deleteButton.element,
80                 this.connectivityIcon, this.connectivityMessage, this.divider,
81                 this.statusIcon, this.statusMessage
82             ];
83         } else {
84             return [
85                 this.refreshButton.element, this.deleteButton.element, this.divider,
86                 this.statusIcon, this.statusMessage
87             ];
88         }
89     },
90
91     show: function(parentElement)
92     {
93         WebInspector.View.prototype.show.call(this, parentElement);
94         this.updateNetworkState(navigator.onLine);
95         this._update();
96     },
97
98     hide: function()
99     {
100         WebInspector.View.prototype.hide.call(this);
101         this.deleteButton.visible = false;
102     },
103
104     updateStatus: function(status)
105     {
106         var statusInformation = {};
107         statusInformation[applicationCache.UNCACHED]    = { src: "Images/warningOrangeDot.png", text: "UNCACHED"    };
108         statusInformation[applicationCache.IDLE]        = { src: "Images/warningOrangeDot.png", text: "IDLE"        };
109         statusInformation[applicationCache.CHECKING]    = { src: "Images/successGreenDot.png",  text: "CHECKING"    };
110         statusInformation[applicationCache.DOWNLOADING] = { src: "Images/successGreenDot.png",  text: "DOWNLOADING" };
111         statusInformation[applicationCache.UPDATEREADY] = { src: "Images/successGreenDot.png",  text: "UPDATEREADY" };
112         statusInformation[applicationCache.OBSOLETE]    = { src: "Images/errorRedDot.png",      text: "OBSOLETE"    };
113
114         var info = statusInformation[status];
115         if (!info) {
116             console.error("Unknown Application Cache Status was Not Handled: %d", status);
117             return;
118         }
119
120         this.statusIcon.src = info.src;
121         this.statusMessage.textContent = info.text;
122     },
123
124     updateNetworkState: function(isNowOnline)
125     {
126         if (Preferences.onlineDetectionEnabled) {
127             if (isNowOnline) {
128                 this.connectivityIcon.src = "Images/successGreenDot.png";
129                 this.connectivityMessage.textContent = WebInspector.UIString("Online");
130             } else {
131                 this.connectivityIcon.src = "Images/errorRedDot.png";
132                 this.connectivityMessage.textContent = WebInspector.UIString("Offline");
133             }
134         }
135     },
136
137     _update: function()
138     {
139         WebInspector.ApplicationCache.getApplicationCachesAsync(this._updateCallback.bind(this));
140     },
141
142     _updateCallback: function(applicationCaches)
143     {
144         // FIXME: applicationCaches is just one cache.
145         // FIXME: are these variables needed anywhere else?
146         this._manifest = applicationCaches.manifest;
147         this._creationTime = applicationCaches.creationTime;
148         this._updateTime = applicationCaches.updateTime;
149         this._size = applicationCaches.size;
150         this._resources = applicationCaches.resources;
151         var lastPathComponent = applicationCaches.lastPathComponent;
152
153         if (!this._manifest) {
154             this._emptyMsgElement.removeStyleClass("hidden");
155             this.deleteButton.visible = false;
156             if (this._dataGrid)
157                 this._dataGrid.element.addStyleClass("hidden");
158             return;
159         }
160
161         if (!this._dataGrid)
162             this._createDataGrid();
163
164         this._populateDataGrid();
165         this._dataGrid.autoSizeColumns(20, 80);
166         this._dataGrid.element.removeStyleClass("hidden");
167         this._emptyMsgElement.addStyleClass("hidden");
168         this.deleteButton.visible = true;
169
170         var totalSizeString = Number.bytesToString(this._size);
171         this._treeElement.subtitle = WebInspector.UIString("%s (%s)", lastPathComponent, totalSizeString);
172
173         // FIXME: For Chrome, put creationTime and updateTime somewhere.
174         // NOTE: localizedString has not yet been added.
175         // WebInspector.UIString("(%s) Created: %s Updated: %s", this._size, this._creationTime, this._updateTime);
176     },
177
178     _createDataGrid: function()
179     {
180         var columns = { 0: {}, 1: {}, 2: {} };
181         columns[0].title = WebInspector.UIString("Resource");
182         columns[0].sort = "ascending";
183         columns[0].sortable = true;
184         columns[1].title = WebInspector.UIString("Type");
185         columns[1].sortable = true;
186         columns[2].title = WebInspector.UIString("Size");
187         columns[2].aligned = "right";
188         columns[2].sortable = true;
189         this._dataGrid = new WebInspector.DataGrid(columns);
190         this.element.appendChild(this._dataGrid.element);
191         this._dataGrid.addEventListener("sorting changed", this._populateDataGrid, this);
192         this._dataGrid.updateWidths();
193     },
194
195     _populateDataGrid: function()
196     {
197         var selectedResource = this._dataGrid.selectedNode ? this._dataGrid.selectedNode.resource : null;
198         var sortDirection = this._dataGrid.sortOrder === "ascending" ? 1 : -1;
199
200         function numberCompare(field, resource1, resource2)
201         {
202             return sortDirection * (resource1[field] - resource2[field]);
203         }
204         function localeCompare(field, resource1, resource2)
205         {
206              return sortDirection * (resource1[field] + "").localeCompare(resource2[field] + "")
207         }
208
209         var comparator;
210         switch (parseInt(this._dataGrid.sortColumnIdentifier)) {
211             case 0: comparator = localeCompare.bind(this, "name"); break;
212             case 1: comparator = localeCompare.bind(this, "type"); break;
213             case 2: comparator = numberCompare.bind(this, "size"); break;
214             default: localeCompare.bind(this, "resource"); // FIXME: comparator = ?
215         }
216
217         this._resources.sort(comparator);
218         this._dataGrid.removeChildren();
219
220         var nodeToSelect;
221         for (var i = 0; i < this._resources.length; ++i) {
222             var data = {};
223             var resource = this._resources[i];
224             data[0] = resource.name;
225             data[1] = resource.type;
226             data[2] = Number.bytesToString(resource.size);
227             var node = new WebInspector.DataGridNode(data);
228             node.resource = resource;
229             node.selectable = true;
230             this._dataGrid.appendChild(node);
231             if (resource === selectedResource) {
232                 nodeToSelect = node;
233                 nodeToSelect.selected = true;
234             }
235         }
236
237         if (!nodeToSelect)
238             this._dataGrid.children[0].selected = true;
239     },
240
241     resize: function()
242     {
243         if (this._dataGrid)
244             this._dataGrid.updateWidths();
245     },
246
247     _deleteButtonClicked: function(event)
248     {
249         if (!this._dataGrid || !this._dataGrid.selectedNode)
250             return;
251
252         // FIXME: Delete Button semantics are not yet defined. (Delete a single, or all?)
253         this._deleteCallback(this._dataGrid.selectedNode);
254     },
255
256     _deleteCallback: function(node)
257     {
258         // FIXME: Should we delete a single (selected) resource or all resources?
259         // InspectorBackend.deleteCachedResource(...)
260         // this._update();
261     },
262
263     _refreshButtonClicked: function(event)
264     {
265         // FIXME: Is this a refresh button or a re-fetch manifest button?
266         // this._update();
267     }
268 }
269
270 WebInspector.ApplicationCacheItemsView.prototype.__proto__ = WebInspector.View.prototype;