2 * Copyright (C) 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 WebInspector.ApplicationCacheItemsView = function(treeElement, appcacheDomain)
28 WebInspector.View.call(this);
30 this.element.addStyleClass("storage-view");
31 this.element.addStyleClass("table");
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);
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);
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 = "";
51 this.divider = document.createElement("span");
52 this.divider.className = "status-bar-item status-bar-divider";
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 = "";
61 this._treeElement = treeElement;
62 this._appcacheDomain = appcacheDomain;
64 this._emptyView = new WebInspector.EmptyView(WebInspector.UIString("No Application Cache information available."));
65 this._emptyView.show(this.element);
67 this.updateStatus(applicationCache.UNCACHED);
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";
79 this.divider.style.display = "none";
80 this.statusIcon.style.display = "none";
81 this.statusMessage.style.display = "none";
85 WebInspector.ApplicationCacheItemsView.prototype = {
88 if (Preferences.onlineDetectionEnabled) {
90 this.refreshButton.element, this.deleteButton.element,
91 this.connectivityIcon, this.connectivityMessage, this.divider,
92 this.statusIcon, this.statusMessage
96 this.refreshButton.element, this.deleteButton.element, this.divider,
97 this.statusIcon, this.statusMessage
102 show: function(parentElement)
104 WebInspector.View.prototype.show.call(this, parentElement);
105 this.updateNetworkState(navigator.onLine);
111 WebInspector.View.prototype.hide.call(this);
112 this.deleteButton.visible = false;
115 updateStatus: function(status)
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" };
125 var info = statusInformation[status];
127 console.error("Unknown Application Cache Status was Not Handled: %d", status);
131 this.statusIcon.src = info.src;
132 this.statusMessage.textContent = info.text;
135 updateNetworkState: function(isNowOnline)
137 if (Preferences.onlineDetectionEnabled) {
139 this.connectivityIcon.src = "Images/successGreenDot.png";
140 this.connectivityMessage.textContent = WebInspector.UIString("Online");
142 this.connectivityIcon.src = "Images/errorRedDot.png";
143 this.connectivityMessage.textContent = WebInspector.UIString("Offline");
150 WebInspector.ApplicationCacheDispatcher.getApplicationCachesAsync(this._updateCallback.bind(this));
153 _updateCallback: function(applicationCaches)
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;
164 if (!this._manifest) {
165 this._emptyView.show(this.element);
166 this.deleteButton.visible = false;
168 this._dataGrid.element.addStyleClass("hidden");
173 this._createDataGrid();
175 this._populateDataGrid();
176 this._dataGrid.autoSizeColumns(20, 80);
177 this._dataGrid.element.removeStyleClass("hidden");
178 this._emptyView.hide();
179 this.deleteButton.visible = true;
181 var totalSizeString = Number.bytesToString(this._size);
182 this._treeElement.subtitle = WebInspector.UIString("%s (%s)", lastPathComponent, totalSizeString);
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);
189 _createDataGrid: function()
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();
206 _populateDataGrid: function()
208 var selectedResource = this._dataGrid.selectedNode ? this._dataGrid.selectedNode.resource : null;
209 var sortDirection = this._dataGrid.sortOrder === "ascending" ? 1 : -1;
211 function numberCompare(field, resource1, resource2)
213 return sortDirection * (resource1[field] - resource2[field]);
215 function localeCompare(field, resource1, resource2)
217 return sortDirection * (resource1[field] + "").localeCompare(resource2[field] + "")
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 = ?
228 this._resources.sort(comparator);
229 this._dataGrid.removeChildren();
232 for (var i = 0; i < this._resources.length; ++i) {
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) {
244 nodeToSelect.selected = true;
249 this._dataGrid.children[0].selected = true;
255 this._dataGrid.updateWidths();
258 _deleteButtonClicked: function(event)
260 if (!this._dataGrid || !this._dataGrid.selectedNode)
263 // FIXME: Delete Button semantics are not yet defined. (Delete a single, or all?)
264 this._deleteCallback(this._dataGrid.selectedNode);
267 _deleteCallback: function(node)
269 // FIXME: Should we delete a single (selected) resource or all resources?
270 // InspectorBackend.deleteCachedResource(...)
274 _refreshButtonClicked: function(event)
276 // FIXME: Is this a refresh button or a re-fetch manifest button?
281 WebInspector.ApplicationCacheItemsView.prototype.__proto__ = WebInspector.View.prototype;
283 WebInspector.ApplicationCacheDispatcher = function()
287 WebInspector.ApplicationCacheDispatcher.getApplicationCachesAsync = function(callback)
289 function mycallback(error, applicationCaches)
291 // FIXME: Currently, this list only returns a single application cache.
292 if (!error && applicationCaches)
293 callback(applicationCaches);
296 ApplicationCacheAgent.getApplicationCaches(mycallback);
299 WebInspector.ApplicationCacheDispatcher.prototype = {
300 updateApplicationCacheStatus: function(status)
302 WebInspector.panels.resources.updateApplicationCacheStatus(status);
305 updateNetworkState: function(isNowOnline)
307 WebInspector.panels.resources.updateNetworkState(isNowOnline);
311 InspectorBackend.registerApplicationCacheDispatcher(new WebInspector.ApplicationCacheDispatcher());