blob: f7a7fd7d790e6510474c4243f89b1cff49b18053 [file] [log] [blame]
// Copyright 2018 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.
(function() {
'use strict';
/**
* Reference to the backend providing all the data.
* @type {mojom.ProcessInternalsHandlerProxy}
*/
let uiHandler = null;
/**
* @param {string} id Tab id.
* @return {boolean} True if successful.
*/
function selectTab(id) {
const tabContents = document.querySelectorAll('#content > div');
const tabHeaders = $('navigation').querySelectorAll('.tab-header');
let found = false;
for (let i = 0; i < tabContents.length; i++) {
const tabContent = tabContents[i];
const tabHeader = tabHeaders[i];
const isTargetTab = tabContent.id == id;
found = found || isTargetTab;
tabContent.classList.toggle('selected', isTargetTab);
tabHeader.classList.toggle('selected', isTargetTab);
}
if (!found) {
return false;
}
window.location.hash = id;
return true;
}
function onHashChange() {
let hash = window.location.hash.slice(1).toLowerCase();
if (!selectTab(hash)) {
selectTab('general');
}
}
function setupTabs() {
const tabContents = document.querySelectorAll('#content > div');
for (let i = 0; i < tabContents.length; i++) {
const tabContent = tabContents[i];
const tabName = tabContent.querySelector('.content-header').textContent;
let tabHeader = document.createElement('div');
tabHeader.className = 'tab-header';
let button = document.createElement('button');
button.textContent = tabName;
tabHeader.appendChild(button);
tabHeader.addEventListener('click', selectTab.bind(null, tabContent.id));
$('navigation').appendChild(tabHeader);
}
onHashChange();
}
/**
* Root of the WebContents tree.
* @type {cr.ui.Tree|null}
*/
let treeViewRoot = null;
/**
* Initialize and return |treeViewRoot|.
* @return {cr.ui.Tree} Initialized |treeViewRoot|.
*/
function getTreeViewRoot() {
if (!treeViewRoot) {
cr.ui.decorate('#tree-view', cr.ui.Tree);
treeViewRoot = /** @type {cr.ui.Tree} */ ($('tree-view'));
treeViewRoot.detail = {payload: {}, children: {}};
}
return treeViewRoot;
}
/**
* Initialize and return a tree item representing a FrameInfo object and
* recursively creates its subframe objects.
* @param {mojom.FrameInfo} frame
* @return {Array}
*/
function frameToTreeItem(frame) {
// Compose the string which will appear in the entry for this frame.
let itemLabel = `Frame[${frame.processId}:${frame.routingId}]:`;
itemLabel += ` SI:${frame.siteInstance.id}`;
if (frame.siteInstance.locked) {
itemLabel += ', locked';
}
if (frame.siteInstance.siteUrl) {
itemLabel += `, site:${frame.siteInstance.siteUrl.url}`;
}
if (frame.lastCommittedUrl) {
itemLabel += ` | url: ${frame.lastCommittedUrl.url}`;
}
let item = new cr.ui.TreeItem(
{label: itemLabel, detail: {payload: {}, children: {}}});
item.mayHaveChildren_ = true;
item.expanded = true;
item.icon = '';
let frameCount = 1;
for (const subframe of frame.subframes) {
let result = frameToTreeItem(subframe);
const subItem = result[0];
const count = result[1];
frameCount += count;
item.add(subItem);
}
return [item, frameCount];
}
/**
* Initialize and return a tree item representing the WebContentsInfo object
* and contains all frames in it as a subtree.
* @param {mojom.WebContentsInfo} webContents
* @return {!cr.ui.TreeItem}
*/
function webContentsToTreeItem(webContents) {
let itemLabel = 'WebContents: ';
if (webContents.title.length > 0) {
itemLabel += webContents.title + ', ';
}
let item = new cr.ui.TreeItem(
{label: itemLabel, detail: {payload: {}, children: {}}});
item.mayHaveChildren_ = true;
item.expanded = true;
item.icon = '';
let result = frameToTreeItem(webContents.rootFrame);
const rootItem = result[0];
const count = result[1];
itemLabel += `${count} frame` + (count > 1 ? 's.' : '.');
item.label = itemLabel;
item.add(rootItem);
return item;
}
/**
* This is a callback which is invoked when the data for WebContents
* associated with the browser profile is received from the browser process.
* @param {mojom.ProcessInternalsHandler_GetAllWebContentsInfo_ResponseParams}
* input
*/
function populateWebContentsTab(input) {
let tree = getTreeViewRoot();
// Clear the tree first before populating it with the new content.
tree.innerText = '';
for (const webContents of input.infos) {
const item = webContentsToTreeItem(webContents);
tree.add(item);
}
}
/**
* Function which retrieves the data for all WebContents associated with the
* current browser profile. The result is passed to populateWebContentsTab.
*/
function loadWebContentsInfo() {
uiHandler.getAllWebContentsInfo().then(populateWebContentsTab);
}
document.addEventListener('DOMContentLoaded', function() {
// Setup Mojo interface to the backend.
uiHandler = mojom.ProcessInternalsHandler.getProxy();
// Get the Site Isolation mode and populate it.
uiHandler.getIsolationMode().then((response) => {
$('isolation-mode').innerText = response.mode;
});
uiHandler.getIsolatedOriginsSize().then((response) => {
$('isolated-origins').innerText = response.size;
});
// Setup the tabbed UI
setupTabs();
// Start loading the information about WebContents.
loadWebContentsInfo();
$('refresh-button').addEventListener('click', loadWebContentsInfo);
});
})();