initial import
[vuplus_webkit] / 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: Needs better tooltip. (Localized)
34     this.deleteButton = new WebInspector.StatusBarButton(WebInspector.UIString("Delete"), "delete-storage-status-bar-item");
35     this.deleteButton.visible = false;
36     this.deleteButton.addEventListener("click", this._deleteButtonClicked.bind(this), false);
37
38     // FIXME: Needs better tooltip. (Localized)
39     this.refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item");
40     this.refreshButton.addEventListener("click", this._refreshButtonClicked.bind(this), false);
41
42     if (Preferences.onlineDetectionEnabled) {
43         this.connectivityIcon = document.createElement("img");
44         this.connectivityIcon.className = "storage-application-cache-connectivity-icon";
45         this.connectivityIcon.src = "";
46         this.connectivityMessage = document.createElement("span");
47         this.connectivityMessage.className = "storage-application-cache-connectivity";
48         this.connectivityMessage.textContent = "";
49     }
50
51     this.divider = document.createElement("span");
52     this.divider.className = "status-bar-item status-bar-divider";
53
54     this.statusIcon = document.createElement("img");
55     this.statusIcon.className = "storage-application-cache-status-icon";
56     this.statusIcon.src = "";
57     this.statusMessage = document.createElement("span");
58     this.statusMessage.className = "storage-application-cache-status";
59     this.statusMessage.textContent = "";
60
61     this._treeElement = treeElement;
62     this._appcacheDomain = appcacheDomain;
63
64     this._emptyView = new WebInspector.EmptyView(WebInspector.UIString("No Application Cache information available."));
65     this._emptyView.show(this.element);
66
67     this.updateStatus(applicationCache.UNCACHED);
68
69     // FIXME: Status bar items don't work well enough yet, so they are being hidden.
70     // http://webkit.org/b/41637 Web Inspector: Give Semantics to "Refresh" and "Delete" Buttons in ApplicationCache DataGrid
71     // http://webkit.org/b/60590 Application cache status always displayed as UNCACHED at first
72     // http://webkit.org/b/60793 Application cache status indicator gets stuck at DOWNLOADING after a failure
73     this.deleteButton.element.style.display = "none";
74     this.refreshButton.element.style.display = "none";
75     if (Preferences.onlineDetectionEnabled) {
76         this.connectivityIcon.style.display = "none";
77         this.connectivityMessage.style.display = "none";
78     }
79     this.divider.style.display = "none";
80     this.statusIcon.style.display = "none";
81     this.statusMessage.style.display = "none";
82
83 }
84
85 WebInspector.ApplicationCacheItemsView.prototype = {
86     get statusBarItems()
87     {
88         if (Preferences.onlineDetectionEnabled) {
89             return [
90                 this.refreshButton.element, this.deleteButton.element,
91                 this.connectivityIcon, this.connectivityMessage, this.divider,
92                 this.statusIcon, this.statusMessage
93             ];
94         } else {
95             return [
96                 this.refreshButton.element, this.deleteButton.element, this.divider,
97                 this.statusIcon, this.statusMessage
98             ];
99         }
100     },
101
102     show: function(parentElement)
103     {
104         WebInspector.View.prototype.show.call(this, parentElement);
105         this.updateNetworkState(navigator.onLine);
106         this._update();
107     },
108
109     hide: function()
110     {
111         WebInspector.View.prototype.hide.call(this);
112         this.deleteButton.visible = false;
113     },
114
115     updateStatus: function(status)
116     {
117         var statusInformation = {};
118         statusInformation[applicationCache.UNCACHED]    = { src: "Images/warningOrangeDot.png", text: "UNCACHED"    };
119         statusInformation[applicationCache.IDLE]        = { src: "Images/warningOrangeDot.png", text: "IDLE"        };
120         statusInformation[applicationCache.CHECKING]    = { src: "Images/successGreenDot.png",  text: "CHECKING"    };
121         statusInformation[applicationCache.DOWNLOADING] = { src: "Images/successGreenDot.png",  text: "DOWNLOADING" };
122         statusInformation[applicationCache.UPDATEREADY] = { src: "Images/successGreenDot.png",  text: "UPDATEREADY" };
123         statusInformation[applicationCache.OBSOLETE]    = { src: "Images/errorRedDot.png",      text: "OBSOLETE"    };
124
125         var info = statusInformation[status];
126         if (!info) {
127             console.error("Unknown Application Cache Status was Not Handled: %d", status);
128             return;
129         }
130
131         this.statusIcon.src = info.src;
132         this.statusMessage.textContent = info.text;
133     },
134
135     updateNetworkState: function(isNowOnline)
136     {
137         if (Preferences.onlineDetectionEnabled) {
138             if (isNowOnline) {
139                 this.connectivityIcon.src = "Images/successGreenDot.png";
140                 this.connectivityMessage.textContent = WebInspector.UIString("Online");
141             } else {
142                 this.connectivityIcon.src = "Images/errorRedDot.png";
143                 this.connectivityMessage.textContent = WebInspector.UIString("Offline");
144             }
145         }
146     },
147
148     _update: function()
149     {
150         WebInspector.ApplicationCacheDispatcher.getApplicationCachesAsync(this._updateCallback.bind(this));
151     },
152
153     _updateCallback: function(applicationCaches)
154     {
155         // FIXME: applicationCaches is just one cache.
156         // FIXME: are these variables needed anywhere else?
157         this._manifest = applicationCaches.manifest;
158         this._creationTime = applicationCaches.creationTime;
159         this._updateTime = applicationCaches.updateTime;
160         this._size = applicationCaches.size;
161         this._resources = applicationCaches.resources;
162         var lastPathComponent = applicationCaches.lastPathComponent;
163
164         if (!this._manifest) {
165             this._emptyView.show(this.element);
166             this.deleteButton.visible = false;
167             if (this._dataGrid)
168                 this._dataGrid.element.addStyleClass("hidden");
169             return;
170         }
171
172         if (!this._dataGrid)
173             this._createDataGrid();
174
175         this._populateDataGrid();
176         this._dataGrid.autoSizeColumns(20, 80);
177         this._dataGrid.element.removeStyleClass("hidden");
178         this._emptyView.hide();
179         this.deleteButton.visible = true;
180
181         var totalSizeString = Number.bytesToString(this._size);
182         this._treeElement.subtitle = WebInspector.UIString("%s (%s)", lastPathComponent, totalSizeString);
183
184         // FIXME: For Chrome, put creationTime and updateTime somewhere.
185         // NOTE: localizedString has not yet been added.
186         // WebInspector.UIString("(%s) Created: %s Updated: %s", this._size, this._creationTime, this._updateTime);
187     },
188
189     _createDataGrid: function()
190     {
191         var columns = { 0: {}, 1: {}, 2: {} };
192         columns[0].title = WebInspector.UIString("Resource");
193         columns[0].sort = "ascending";
194         columns[0].sortable = true;
195         columns[1].title = WebInspector.UIString("Type");
196         columns[1].sortable = true;
197         columns[2].title = WebInspector.UIString("Size");
198         columns[2].aligned = "right";
199         columns[2].sortable = true;
200         this._dataGrid = new WebInspector.DataGrid(columns);
201         this.element.appendChild(this._dataGrid.element);
202         this._dataGrid.addEventListener("sorting changed", this._populateDataGrid, this);
203         this._dataGrid.updateWidths();
204     },
205
206     _populateDataGrid: function()
207     {
208         var selectedResource = this._dataGrid.selectedNode ? this._dataGrid.selectedNode.resource : null;
209         var sortDirection = this._dataGrid.sortOrder === "ascending" ? 1 : -1;
210
211         function numberCompare(field, resource1, resource2)
212         {
213             return sortDirection * (resource1[field] - resource2[field]);
214         }
215         function localeCompare(field, resource1, resource2)
216         {
217              return sortDirection * (resource1[field] + "").localeCompare(resource2[field] + "")
218         }
219
220         var comparator;
221         switch (parseInt(this._dataGrid.sortColumnIdentifier)) {
222             case 0: comparator = localeCompare.bind(this, "name"); break;
223             case 1: comparator = localeCompare.bind(this, "type"); break;
224             case 2: comparator = numberCompare.bind(this, "size"); break;
225             default: localeCompare.bind(this, "resource"); // FIXME: comparator = ?
226         }
227
228         this._resources.sort(comparator);
229         this._dataGrid.removeChildren();
230
231         var nodeToSelect;
232         for (var i = 0; i < this._resources.length; ++i) {
233             var data = {};
234             var resource = this._resources[i];
235             data[0] = resource.name;
236             data[1] = resource.type;
237             data[2] = Number.bytesToString(resource.size);
238             var node = new WebInspector.DataGridNode(data);
239             node.resource = resource;
240             node.selectable = true;
241             this._dataGrid.appendChild(node);
242             if (resource === selectedResource) {
243                 nodeToSelect = node;
244                 nodeToSelect.selected = true;
245             }
246         }
247
248         if (!nodeToSelect)
249             this._dataGrid.children[0].selected = true;
250     },
251
252     onResize: function()
253     {
254         if (this._dataGrid)
255             this._dataGrid.updateWidths();
256     },
257
258     _deleteButtonClicked: function(event)
259     {
260         if (!this._dataGrid || !this._dataGrid.selectedNode)
261             return;
262
263         // FIXME: Delete Button semantics are not yet defined. (Delete a single, or all?)
264         this._deleteCallback(this._dataGrid.selectedNode);
265     },
266
267     _deleteCallback: function(node)
268     {
269         // FIXME: Should we delete a single (selected) resource or all resources?
270         // InspectorBackend.deleteCachedResource(...)
271         // this._update();
272     },
273
274     _refreshButtonClicked: function(event)
275     {
276         // FIXME: Is this a refresh button or a re-fetch manifest button?
277         // this._update();
278     }
279 }
280
281 WebInspector.ApplicationCacheItemsView.prototype.__proto__ = WebInspector.View.prototype;
282
283 WebInspector.ApplicationCacheDispatcher = function()
284 {
285 }
286
287 WebInspector.ApplicationCacheDispatcher.getApplicationCachesAsync = function(callback)
288 {
289     function mycallback(error, applicationCaches)
290     {
291         // FIXME: Currently, this list only returns a single application cache.
292         if (!error && applicationCaches)
293             callback(applicationCaches);
294     }
295
296     ApplicationCacheAgent.getApplicationCaches(mycallback);
297 }
298
299 WebInspector.ApplicationCacheDispatcher.prototype = {
300     updateApplicationCacheStatus: function(status)
301     {
302         WebInspector.panels.resources.updateApplicationCacheStatus(status);
303     },
304
305     updateNetworkState: function(isNowOnline)
306     {
307         WebInspector.panels.resources.updateNetworkState(isNowOnline);
308     }
309 }
310
311 InspectorBackend.registerApplicationCacheDispatcher(new WebInspector.ApplicationCacheDispatcher());