diff options
author | ekaramad <ekaramad@google.com> | 2015-08-10 19:18:07 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-08-11 02:18:41 +0000 |
commit | bd5885d3edbcc9e69ff93acc4fed2d4633aaf20b (patch) | |
tree | c7f35269b2fe45e2966d8328983956814fca7c8a /content/browser/resources | |
parent | 3c44dfef03524ac42b74916de37248bb4cb919c8 (diff) | |
download | chromium_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')
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); |