ApplicationCacheItemsView.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  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. * @constructor
  27. * @extends {WebInspector.View}
  28. */
  29. WebInspector.ApplicationCacheItemsView = function(model, frameId)
  30. {
  31. WebInspector.View.call(this);
  32. this._model = model;
  33. this.element.addStyleClass("storage-view");
  34. this.element.addStyleClass("table");
  35. // FIXME: Needs better tooltip. (Localized)
  36. this.deleteButton = new WebInspector.StatusBarButton(WebInspector.UIString("Delete"), "delete-storage-status-bar-item");
  37. this.deleteButton.visible = false;
  38. this.deleteButton.addEventListener("click", this._deleteButtonClicked, this);
  39. this.connectivityIcon = document.createElement("div");
  40. this.connectivityMessage = document.createElement("span");
  41. this.connectivityMessage.className = "storage-application-cache-connectivity";
  42. this.connectivityMessage.textContent = "";
  43. this.divider = document.createElement("span");
  44. this.divider.className = "status-bar-item status-bar-divider";
  45. this.statusIcon = document.createElement("div");
  46. this.statusMessage = document.createElement("span");
  47. this.statusMessage.className = "storage-application-cache-status";
  48. this.statusMessage.textContent = "";
  49. this._frameId = frameId;
  50. this._emptyView = new WebInspector.EmptyView(WebInspector.UIString("No Application Cache information available."));
  51. this._emptyView.show(this.element);
  52. this._markDirty();
  53. var status = this._model.frameManifestStatus(frameId);
  54. this.updateStatus(status);
  55. this.updateNetworkState(this._model.onLine);
  56. // FIXME: Status bar items don't work well enough yet, so they are being hidden.
  57. // http://webkit.org/b/41637 Web Inspector: Give Semantics to "Refresh" and "Delete" Buttons in ApplicationCache DataGrid
  58. this.deleteButton.element.style.display = "none";
  59. }
  60. WebInspector.ApplicationCacheItemsView.prototype = {
  61. get statusBarItems()
  62. {
  63. return [
  64. this.deleteButton.element,
  65. this.connectivityIcon, this.connectivityMessage, this.divider,
  66. this.statusIcon, this.statusMessage
  67. ];
  68. },
  69. wasShown: function()
  70. {
  71. this._maybeUpdate();
  72. },
  73. willHide: function()
  74. {
  75. this.deleteButton.visible = false;
  76. },
  77. _maybeUpdate: function()
  78. {
  79. if (!this.isShowing() || !this._viewDirty)
  80. return;
  81. this._update();
  82. this._viewDirty = false;
  83. },
  84. _markDirty: function()
  85. {
  86. this._viewDirty = true;
  87. },
  88. /**
  89. * @param {number} status
  90. */
  91. updateStatus: function(status)
  92. {
  93. var oldStatus = this._status;
  94. this._status = status;
  95. var statusInformation = {};
  96. // We should never have UNCACHED status, since we remove frames with UNCACHED application cache status from the tree.
  97. statusInformation[applicationCache.UNCACHED] = { className: "red-ball", text: "UNCACHED" };
  98. statusInformation[applicationCache.IDLE] = { className: "green-ball", text: "IDLE" };
  99. statusInformation[applicationCache.CHECKING] = { className: "orange-ball", text: "CHECKING" };
  100. statusInformation[applicationCache.DOWNLOADING] = { className: "orange-ball", text: "DOWNLOADING" };
  101. statusInformation[applicationCache.UPDATEREADY] = { className: "green-ball", text: "UPDATEREADY" };
  102. statusInformation[applicationCache.OBSOLETE] = { className: "red-ball", text: "OBSOLETE" };
  103. var info = statusInformation[status] || statusInformation[applicationCache.UNCACHED];
  104. this.statusIcon.className = "storage-application-cache-status-icon " + info.className;
  105. this.statusMessage.textContent = info.text;
  106. if (this.isShowing() && this._status === applicationCache.IDLE && (oldStatus === applicationCache.UPDATEREADY || !this._resources))
  107. this._markDirty();
  108. this._maybeUpdate();
  109. },
  110. /**
  111. * @param {boolean} isNowOnline
  112. */
  113. updateNetworkState: function(isNowOnline)
  114. {
  115. if (isNowOnline) {
  116. this.connectivityIcon.className = "storage-application-cache-connectivity-icon green-ball";
  117. this.connectivityMessage.textContent = WebInspector.UIString("Online");
  118. } else {
  119. this.connectivityIcon.className = "storage-application-cache-connectivity-icon red-ball";
  120. this.connectivityMessage.textContent = WebInspector.UIString("Offline");
  121. }
  122. },
  123. _update: function()
  124. {
  125. this._model.requestApplicationCache(this._frameId, this._updateCallback.bind(this));
  126. },
  127. /**
  128. * @param {Object} applicationCache
  129. */
  130. _updateCallback: function(applicationCache)
  131. {
  132. if (!applicationCache || !applicationCache.manifestURL) {
  133. delete this._manifest;
  134. delete this._creationTime;
  135. delete this._updateTime;
  136. delete this._size;
  137. delete this._resources;
  138. this._emptyView.show(this.element);
  139. this.deleteButton.visible = false;
  140. if (this._dataGrid)
  141. this._dataGrid.element.addStyleClass("hidden");
  142. return;
  143. }
  144. // FIXME: are these variables needed anywhere else?
  145. this._manifest = applicationCache.manifestURL;
  146. this._creationTime = applicationCache.creationTime;
  147. this._updateTime = applicationCache.updateTime;
  148. this._size = applicationCache.size;
  149. this._resources = applicationCache.resources;
  150. if (!this._dataGrid)
  151. this._createDataGrid();
  152. this._populateDataGrid();
  153. this._dataGrid.autoSizeColumns(20, 80);
  154. this._dataGrid.element.removeStyleClass("hidden");
  155. this._emptyView.detach();
  156. this.deleteButton.visible = true;
  157. // FIXME: For Chrome, put creationTime and updateTime somewhere.
  158. // NOTE: localizedString has not yet been added.
  159. // WebInspector.UIString("(%s) Created: %s Updated: %s", this._size, this._creationTime, this._updateTime);
  160. },
  161. _createDataGrid: function()
  162. {
  163. var columns = [
  164. {title: WebInspector.UIString("Resource"), sort: WebInspector.DataGrid.Order.Ascending, sortable: true},
  165. {title: WebInspector.UIString("Type"), sortable: true},
  166. {title: WebInspector.UIString("Size"), align: WebInspector.DataGrid.Align.Right, sortable: true}
  167. ];
  168. this._dataGrid = new WebInspector.DataGrid(columns);
  169. this._dataGrid.show(this.element);
  170. this._dataGrid.addEventListener(WebInspector.DataGrid.Events.SortingChanged, this._populateDataGrid, this);
  171. },
  172. _populateDataGrid: function()
  173. {
  174. var selectedResource = this._dataGrid.selectedNode ? this._dataGrid.selectedNode.resource : null;
  175. var sortDirection = this._dataGrid.isSortOrderAscending() ? 1 : -1;
  176. function numberCompare(field, resource1, resource2)
  177. {
  178. return sortDirection * (resource1[field] - resource2[field]);
  179. }
  180. function localeCompare(field, resource1, resource2)
  181. {
  182. return sortDirection * (resource1[field] + "").localeCompare(resource2[field] + "")
  183. }
  184. var comparator;
  185. switch (parseInt(this._dataGrid.sortColumnIdentifier(), 10)) {
  186. case 0: comparator = localeCompare.bind(this, "name"); break;
  187. case 1: comparator = localeCompare.bind(this, "type"); break;
  188. case 2: comparator = numberCompare.bind(this, "size"); break;
  189. default: localeCompare.bind(this, "resource"); // FIXME: comparator = ?
  190. }
  191. this._resources.sort(comparator);
  192. this._dataGrid.rootNode().removeChildren();
  193. var nodeToSelect;
  194. for (var i = 0; i < this._resources.length; ++i) {
  195. var data = {};
  196. var resource = this._resources[i];
  197. data[0] = resource.url;
  198. data[1] = resource.type;
  199. data[2] = Number.bytesToString(resource.size);
  200. var node = new WebInspector.DataGridNode(data);
  201. node.resource = resource;
  202. node.selectable = true;
  203. this._dataGrid.rootNode().appendChild(node);
  204. if (resource === selectedResource) {
  205. nodeToSelect = node;
  206. nodeToSelect.selected = true;
  207. }
  208. }
  209. if (!nodeToSelect && this._dataGrid.rootNode().children.length)
  210. this._dataGrid.rootNode().children[0].selected = true;
  211. },
  212. _deleteButtonClicked: function(event)
  213. {
  214. if (!this._dataGrid || !this._dataGrid.selectedNode)
  215. return;
  216. // FIXME: Delete Button semantics are not yet defined. (Delete a single, or all?)
  217. this._deleteCallback(this._dataGrid.selectedNode);
  218. },
  219. _deleteCallback: function(node)
  220. {
  221. // FIXME: Should we delete a single (selected) resource or all resources?
  222. // InspectorBackend.deleteCachedResource(...)
  223. // this._update();
  224. },
  225. __proto__: WebInspector.View.prototype
  226. }