summaryrefslogtreecommitdiffstats
path: root/content/browser/resources
diff options
context:
space:
mode:
authorekaramad <ekaramad@google.com>2015-08-10 19:18:07 -0700
committerCommit bot <commit-bot@chromium.org>2015-08-11 02:18:41 +0000
commitbd5885d3edbcc9e69ff93acc4fed2d4633aaf20b (patch)
treec7f35269b2fe45e2966d8328983956814fca7c8a /content/browser/resources
parent3c44dfef03524ac42b74916de37248bb4cb919c8 (diff)
downloadchromium_src-bd5885d3edbcc9e69ff93acc4fed2d4633aaf20b.zip
chromium_src-bd5885d3edbcc9e69ff93acc4fed2d4633aaf20b.tar.gz
chromium_src-bd5885d3edbcc9e69ff93acc4fed2d4633aaf20b.tar.bz2
Implements "chrome://appcache-internals" based on WebUI API
Redid the "chrome://appcache-internals" page so that the new implementation is: 1- Based on "WebUIController" and similar to "chrome://indexed-db-internals". 2- Looks into "all" storage paritions when fetching application cache data. This was previously reported as a bug since the application cache for <webview> was not being shown on "chrome://appcache-internals". BUG=343683 Committed: https://crrev.com/8fc82b21621f21ea8d2d8cb483cb14295d1f6e1f Cr-Commit-Position: refs/heads/master@{#342671} Review URL: https://codereview.chromium.org/1191383004 Cr-Commit-Position: refs/heads/master@{#342774}
Diffstat (limited to 'content/browser/resources')
-rw-r--r--content/browser/resources/appcache/OWNERS3
-rw-r--r--content/browser/resources/appcache/appcache_internals.css76
-rw-r--r--content/browser/resources/appcache/appcache_internals.html107
-rw-r--r--content/browser/resources/appcache/appcache_internals.js304
4 files changed, 490 insertions, 0 deletions
diff --git a/content/browser/resources/appcache/OWNERS b/content/browser/resources/appcache/OWNERS
new file mode 100644
index 0000000..9572490
--- /dev/null
+++ b/content/browser/resources/appcache/OWNERS
@@ -0,0 +1,3 @@
+dgrogan@chromium.org
+michaeln@chromium.org
+jsbell@chromium.org
diff --git a/content/browser/resources/appcache/appcache_internals.css b/content/browser/resources/appcache/appcache_internals.css
new file mode 100644
index 0000000..0844ed5
--- /dev/null
+++ b/content/browser/resources/appcache/appcache_internals.css
@@ -0,0 +1,76 @@
+/* Copyright 2015 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+.appcache-summary {
+ background-color: rgb(235, 239, 249);
+ border-top: 1px solid rgb(156, 194, 239);
+ margin-bottom: 6px;
+ margin-top: 12px;
+ padding: 3px;
+ font-weight: bold;
+}
+
+.appcache-item {
+ margin-bottom: 15px;
+ margin-top: 6px;
+ position: relative;
+}
+
+.appcache-url {
+ color: rgb(85, 102, 221);
+ display: inline-block;
+ max-width: 500px;
+ overflow: hidden;
+ padding-bottom: 1px;
+ padding-top: 4px;
+ text-decoration: none;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.appcache-info-template-table {
+ table-layout: fixed;
+}
+
+.appcache-info-properties {
+ word-wrap: break-word;
+}
+
+.appcache-info-url {
+ color: rgb(85, 102, 221);
+ display: inline-block;
+}
+
+.appcache-manifest-url {
+ color: rgb(85, 102, 221);
+ display: inline-block;
+ max-width: 500px;
+ overflow: hidden;
+ padding-bottom: 1px;
+ padding-top: 4px;
+ text-decoration: none;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.appcache-info-item {
+ margin-bottom: 10px;
+ margin-top: 6px;
+ margin-left: 6px;
+ position: relative;
+}
+
+.appcache-manifest-commands a {
+ -webkit-margin-end: 16px;
+ color: #777;
+}
+
+.appcache-info-template-file-url {
+ width: 200px;
+ height:25px;
+}
+
+.appcache-info-template-file-url {
+ color: rgb(60, 102, 221);
+}
diff --git a/content/browser/resources/appcache/appcache_internals.html b/content/browser/resources/appcache/appcache_internals.html
new file mode 100644
index 0000000..688c4c3
--- /dev/null
+++ b/content/browser/resources/appcache/appcache_internals.html
@@ -0,0 +1,107 @@
+<!--
+ Copyright 2015 The Chromium Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+-->
+<!DOCTYPE html>
+<html i18n-values="dir:textdirection;lang:language">
+ <head>
+ <meta charset="utf-8">
+ <title>AppCache</title>
+ <link rel="stylesheet" href="chrome://resources/css/tabs.css">
+ <link rel="stylesheet" href="chrome://resources/css/widgets.css">
+ <link rel="stylesheet" href="appcache_internals.css">
+ </head>
+ <body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">
+ <!-- templates -->
+ <div style="display:none">
+ <div id="appcache-list-template"
+ jsvalues=".partitionPath:$this.partition_path">
+ <div class="appcache-summary">
+ <span jsdisplay="$this.partition_path">
+ <span>Instances in: </span>
+ <span jscontent="$this.partition_path"></span>
+ </span>
+ <span jsdisplay="!$this.partition_path">
+ <span>Instances: Incognito </span>
+ </span>
+ <span jscontent="'(' + $this.appcache_vector.length + ')'">
+ </span>
+ </div>
+ <div class="appcache-item" jsselect="$this.appcache_vector">
+ <a class="appcache-url" jscontent="originURL"
+ jsvalues="href:originURL"
+ target="_blank"></a>
+ <div jsselect="manifests">
+ <div class="appcache-info-item" jsvalues="$manifestURL:manifestURL;
+ $groupId:groupId;">
+ <div class="appcache-manifest">
+ <span> Manifest: </span>
+ <a class="appcache-info-url" jscontent="manifestURL"
+ jsvalues="href:manifestURL;"
+ target="_blank"></a>
+ </div>
+ <div class="appcache-size">
+ <span> Size: </span>
+ <span jscontent="size"></span>
+ </div>
+ <div class="appcache-dates">
+ <ul>
+ <li>
+ <span> Creation Time: </span>
+ <span jscontent="new Date(creationTime)"></span>
+ </li>
+ <li>
+ <span> Last Access Time: </span>
+ <span jscontent="new Date(lastAccessTime)"></span>
+ </li>
+ <li>
+ <span> Last Update Time: </span>
+ <span jscontent="new Date(lastUpdateTime)"></span>
+ </li>
+ </ul>
+ </div>
+ <div class="appcache-manifest-commands"
+ jsvalues=".manifestURL:$manifestURL;.groupId:$groupId">
+ <table>
+ <tr>
+ <td>
+ <a href="#" class="remove-manifest"> Remove Item </a>
+ </td>
+ <td>
+ <a href="#" class="view-details"> View Details </a>
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div class="appcache-details"
+ jsvalues=".manifestURL:$manifestURL;.groupId:$groupId;">
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div id="appcache-info-template" jsselect="$this.items">
+ <span>
+ <a href="#" class="appcache-info-template-file-url"
+ jscontent="fileUrl" jsvalues=".responseId:responseId">
+ </a>
+ </span>
+ <span jscontent="size"></span>
+ <span jscontent="properties"></span>
+ </div>
+ </div>
+ <h1>Application Cache</h1>
+ <div class="content">
+ <div id="appcache-list">
+ </div>
+ <script src="chrome://resources/js/util.js"></script>
+ <script src="chrome://resources/js/cr.js"></script>
+ <script src="appcache_internals.js"></script>
+ <script src="chrome://resources/js/load_time_data.js"></script>
+ <script src="chrome://resources/js/jstemplate_compiled.js"></script>
+ <script src="strings.js"></script>
+ <script src="chrome://resources/js/i18n_template.js"></script>
+ </body>
+</html>
diff --git a/content/browser/resources/appcache/appcache_internals.js b/content/browser/resources/appcache/appcache_internals.js
new file mode 100644
index 0000000..49388eb
--- /dev/null
+++ b/content/browser/resources/appcache/appcache_internals.js
@@ -0,0 +1,304 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('appcache', function() {
+ 'use strict';
+
+ var VIEW_DETAILS_TEXT = 'View Details';
+ var HIDE_DETAILS_TEXT = 'Hide Details';
+ var GET_ALL_APPCACHE = 'getAllAppCache';
+ var DELETE_APPCACHE = 'deleteAppCache';
+ var GET_APPCACHE_DETAILS = 'getAppCacheDetails';
+ var GET_FILE_DETAILS = 'getFileDetails';
+
+ var manifestsToView = [];
+ var manifestsToDelete = [];
+ var fileDetailsRequests = [];
+
+ function Manifest(url, path, link) {
+ this.url = url;
+ this.path = path;
+ this.link = link;
+ }
+
+ function FileRequest(fileURL, manifestURL, path, groupId, responseId) {
+ this.fileURL = fileURL;
+ this.partitionPath = path;
+ this.manifestURL = manifestURL;
+ this.groupId = groupId;
+ this.responseId = responseId;
+ }
+
+ function getFirstAncestor(node, selector) {
+ while(node) {
+ if (selector(node)) {
+ break;
+ }
+ node = node.parentNode;
+ }
+ return node;
+ }
+
+ function getItemByProperties(list, properties, values) {
+ return list.find(function(candidate) {
+ return properties.every(function(key, i) {
+ return candidate[key] == values[i];
+ });
+ }) || null;
+ }
+
+ function removeFromList(list, item, properties) {
+ var pos = 0;
+ while (pos < list.length) {
+ var candidate = list[pos];
+ if (properties.every(function(key) {
+ return candidate[key] == item[key];
+ })) {
+ list.splice(pos, 1);
+ } else {
+ pos++;
+ }
+ }
+ }
+
+ function initialize() {
+ chrome.send(GET_ALL_APPCACHE);
+ }
+
+
+ function onAllAppCacheInfoReady(partition_path, data) {
+ var template = jstGetTemplate('appcache-list-template');
+ var container = $('appcache-list');
+ container.appendChild(template);
+ jstProcess(new JsEvalContext(
+ {appcache_vector: data, partition_path: partition_path}),
+ template);
+ var removeLinks = container.querySelectorAll('a.remove-manifest');
+ for (var i = 0; i < removeLinks.length; ++i) {
+ removeLinks[i].onclick = deleteAppCacheInfoEventHandler;
+ }
+ var viewLinks = container.querySelectorAll('a.view-details');
+ for (i = 0; i < viewLinks.length; ++i) {
+ viewLinks[i].onclick = getAppCacheInfoEventHandler;
+ }
+ }
+
+ function getAppCacheInfoEventHandler(event) {
+ var link = event.target;
+ if (link.text.indexOf(VIEW_DETAILS_TEXT) === -1) {
+ hideAppCacheInfo(link);
+ } else {
+ var manifestURL = getFirstAncestor(link, function(node) {
+ return !!node.manifestURL;
+ }).manifestURL;
+ var partitionPath = getFirstAncestor(link, function(node) {
+ return !!node.partitionPath;
+ }).partitionPath;
+ var manifest = new Manifest(manifestURL, partitionPath, link);
+ if (getItemByProperties(manifestsToView,
+ ['url', 'path'],
+ [manifestURL, partitionPath])) {
+ return;
+ }
+ manifestsToView.push(manifest);
+ chrome.send(GET_APPCACHE_DETAILS, [partitionPath, manifestURL]);
+ }
+ }
+
+ function hideAppCacheInfo(link) {
+ getFirstAncestor(link, function(node) {
+ return node.className === 'appcache-info-item';
+ }).querySelector('.appcache-details').innerHTML = '';
+ link.text = VIEW_DETAILS_TEXT;
+ }
+
+ function onAppCacheDetailsReady(manifestURL, partitionPath, details) {
+ if (!details) {
+ console.log('Cannot show details for "' + manifestURL + '" on partition '
+ + '"' + partitionPath + '".');
+ return;
+ }
+ var manifest = getItemByProperties(
+ manifestsToView, ['url', 'path'], [manifestURL, partitionPath]);
+ var link = manifest.link;
+ removeFromList(manifestsToView, manifest, ['url', 'path']);
+ var container = getFirstAncestor(link, function(node) {
+ return node.className === 'appcache-info-item';
+ }).querySelector('.appcache-details');
+ var template = jstGetTemplate('appcache-info-template');
+ container.appendChild(template);
+ jstProcess(
+ new JsEvalContext({items: simplifyAppCacheInfo(details)}), template);
+ var fileLinks =
+ container.querySelectorAll('a.appcache-info-template-file-url');
+ for (var i = 0; i < fileLinks.length; ++i) {
+ fileLinks[i].onclick = getFileContentsEventHandler;
+ }
+ link.text = HIDE_DETAILS_TEXT;
+ }
+
+ function simplifyAppCacheInfo(detailsVector) {
+ var simpleVector = [];
+ for (var index = 0; index < detailsVector.length; ++index) {
+ var details = detailsVector[index];
+ var properties = [];
+ if (details.isManifest) {
+ properties.push('Manifest');
+ }
+ if (details.isExplicit) {
+ properties.push('Explicit');
+ }
+ if (details.isMaster) {
+ properties.push('Master');
+ }
+ if (details.isForeign) {
+ properties.push('Foreign');
+ }
+ if (details.isIntercept) {
+ properties.push('Intercept');
+ }
+ if (details.isFallback) {
+ properties.push('Fallback');
+ }
+ properties = properties.join(',');
+ simpleVector.push({
+ size : details.size,
+ properties : properties,
+ fileUrl : details.url,
+ responseId : details.responseId
+ });
+ }
+ return simpleVector;
+ }
+
+ function deleteAppCacheInfoEventHandler(event) {
+ var link = event.target;
+ var manifestURL = getFirstAncestor(link, function(node) {
+ return !!node.manifestURL;
+ }).manifestURL;
+ var partitionPath = getFirstAncestor(link, function(node) {
+ return !!node.partitionPath;
+ }).partitionPath;
+ var manifest = new Manifest(manifestURL, partitionPath, link);
+ manifestsToDelete.push(manifest);
+ chrome.send(DELETE_APPCACHE, [partitionPath, manifestURL]);
+ }
+
+ function onAppCacheInfoDeleted(partitionPath, manifestURL, deleted) {
+ var manifest = getItemByProperties(
+ manifestsToDelete, ['url', 'path'], [manifestURL, partitionPath]);
+ if (manifest && deleted) {
+ var link = manifest.link;
+ var appcacheItemNode = getFirstAncestor(link, function(node) {
+ return node.className === 'appcache-info-item';
+ });
+ var appcacheNode = getFirstAncestor(link, function(node) {
+ return node.className === 'appcache-item';
+ });
+ appcacheItemNode.parentNode.removeChild(appcacheItemNode);
+ if (appcacheNode.querySelectorAll('.appcache-info-item').length === 0) {
+ appcacheNode.parentNode.removeChild(appcacheNode);
+ }
+ } else if (!deleted) {
+ // For some reason, the delete command failed.
+ console.log('Manifest "' + manifestURL + '" on partition "'
+ + partitionPath + ' cannot be accessed.');
+ }
+ }
+
+ function getFileContentsEventHandler(event) {
+ var link = event.target;
+ var partitionPath = getFirstAncestor(link, function(node) {
+ return !!node.partitionPath;
+ }).partitionPath;
+ var manifestURL = getFirstAncestor(link, function(node) {
+ return !!node.manifestURL;
+ }).manifestURL;
+ var groupId = getFirstAncestor(link, function(node) {
+ return !!node.groupId;
+ }).groupId;
+ var responseId = link.responseId;
+
+ if (!getItemByProperties(fileDetailsRequests,
+ ['manifestURL', 'groupId', 'responseId'],
+ [manifestURL, groupId, responseId])) {
+ var fileRequest = new FileRequest(link.innerText, manifestURL,
+ partitionPath, groupId, responseId);
+ fileDetailsRequests.push(fileRequest);
+ chrome.send(GET_FILE_DETAILS,
+ [partitionPath, manifestURL, groupId, responseId]);
+ }
+ }
+
+ function onFileDetailsFailed(response, code) {
+ var request =
+ getItemByProperties(
+ fileDetailsRequests,
+ ['manifestURL', 'groupId', 'responseId'],
+ [response.manifestURL, response.groupId, response.responseId]);
+ console.log('Failed to get file information for file "'
+ + request.fileURL + '" from partition "'
+ + request.partitionPath + '" (net result code:' + code +').');
+ removeFromList(
+ fileDetailsRequests,
+ request,
+ ['manifestURL', 'groupId', 'responseId']);
+ }
+
+ function onFileDetailsReady(response, headers, raw_data) {
+ var request =
+ getItemByProperties(
+ fileDetailsRequests,
+ ['manifestURL', 'groupId', 'responseId'],
+ [response.manifestURL, response.groupId, response.responseId]);
+ removeFromList(
+ fileDetailsRequests,
+ request,
+ ['manifestURL', 'groupId', 'responseId']);
+ var doc = window.open().document;
+ var head = document.createElement('head');
+ doc.title = 'File Details: '.concat(request.fileURL);
+ var headersDiv = doc.createElement('div');
+ headersDiv.innerHTML = headers;
+ doc.body.appendChild(headersDiv);
+ var hexDumpDiv = doc.createElement('div');
+ hexDumpDiv.innerHTML = raw_data;
+ var linkToManifest = doc.createElement('a');
+ linkToManifest.style.color = "#3C66DD";
+ linkToManifest.href = request.fileURL;
+ linkToManifest.target = '_blank';
+ linkToManifest.innerHTML = request.fileURL;
+
+ doc.body.appendChild(linkToManifest);
+ doc.body.appendChild(headersDiv);
+ doc.body.appendChild(hexDumpDiv);
+
+ copyStylesFrom(document, doc);
+ }
+
+ function copyStylesFrom(src, dest) {
+ var styles = src.querySelector('style');
+ if (dest.getElementsByTagName('style').length < 1) {
+ dest.head.appendChild(dest.createElement('style'));
+ }
+ var destStyle= dest.querySelector('style');
+ var tmp = '';
+ for (var i = 0; i < styles.length; ++i) {
+ tmp += styles[i].innerHTML;
+ }
+ destStyle.innerHTML = tmp;
+ }
+
+ return {
+ initialize: initialize,
+ onAllAppCacheInfoReady: onAllAppCacheInfoReady,
+ onAppCacheInfoDeleted: onAppCacheInfoDeleted,
+ onAppCacheDetailsReady : onAppCacheDetailsReady,
+ onFileDetailsReady : onFileDetailsReady,
+ onFileDetailsFailed: onFileDetailsFailed
+ };
+
+});
+
+document.addEventListener('DOMContentLoaded', appcache.initialize);