• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
26WebInspector.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
74WebInspector.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.ApplicationCacheDispatcher.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
270WebInspector.ApplicationCacheItemsView.prototype.__proto__ = WebInspector.View.prototype;
271
272WebInspector.ApplicationCacheDispatcher = function()
273{
274}
275
276WebInspector.ApplicationCacheDispatcher.getApplicationCachesAsync = function(callback)
277{
278    function mycallback(error, applicationCaches)
279    {
280        // FIXME: Currently, this list only returns a single application cache.
281        if (!error && applicationCaches)
282            callback(applicationCaches);
283    }
284
285    ApplicationCacheAgent.getApplicationCaches(mycallback);
286}
287
288WebInspector.ApplicationCacheDispatcher.prototype = {
289    updateApplicationCacheStatus: function(status)
290    {
291        WebInspector.panels.resources.updateApplicationCacheStatus(status);
292    },
293
294    updateNetworkState: function(isNowOnline)
295    {
296        WebInspector.panels.resources.updateNetworkState(isNowOnline);
297    }
298}
299
300InspectorBackend.registerDomainDispatcher("ApplicationCache", new WebInspector.ApplicationCacheDispatcher());
301