blob: 8e4a9478353abdd65d678b594a002e59e2e31eb8 [file] [log] [blame]
// 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);