Commit 3e836e2d authored by Christoph Schwering's avatar Christoph Schwering Committed by Commit Bot

Added controls over log display for chrome://autofill-internals/.

This commit adds checkboxes to filter the types of log events
displayed in chrome://autofill-internals/, an auto-scrolling
mechanism, and visual markers in order to aid with visually
processing the logs.

NOTRY=true
To skip android-binary-size bot due to a bug (crbug.com/1045024).
Other try-bots have passed.

Change-Id: I64db7aa5055757ef80f1981a659be76d7fa37291
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2017354
Commit-Queue: Dominic Battré <battre@chromium.org>
Reviewed-by: default avatarDominic Battré <battre@chromium.org>
Cr-Commit-Position: refs/heads/master@{#736484}
parent 91112ab9
......@@ -3,6 +3,37 @@
* found in the LICENSE file.
*/
html {
scroll-behavior: smooth;
}
.sticky-bar {
background-color: white;
border-bottom: 1px solid black;
color: black;
overflow: auto;
padding-bottom: 1.5ex;
position: sticky;
top: 0;
}
#log-display-config {
display: none; /* only visible for Autofill, not for Password Manager */
font-size: 120%;
padding: 1ex;
}
#log-display-config label {
padding-inline-end: 1em;
}
#marker-fake-button {
background-color: lightgray;
border: 1px solid black;
margin-inline-end: 1em;
padding: .5ex;
}
#logging-note {
font-style: italic;
}
......@@ -48,10 +79,21 @@
vertical-align: top;
}
.log-entry {
.log-entry,
.marker {
padding: 3px;
}
.marker {
background-color: red;
font-size: 200%;
white-space: pre;
}
.marker::before {
content: 'Position marked: ';
}
/*
* Colors can be taken from
* https://material.io/design/color/#tools-for-picking-colors
......@@ -86,6 +128,46 @@
background-color: #B2EBF2;
}
/*
* Checkboxes add/remove hide-<Scope> classes to the #log-entries. Hiding of the
* relevant <div>'s and adjacent <hr>'s is implemented by these classes.
*/
.hide-Context .log-entry[scope='Context'],
.hide-Context .log-entry[scope='Context'] + hr {
display: none;
}
.hide-Parsing .log-entry[scope='Parsing'],
.hide-Parsing .log-entry[scope='Parsing'] + hr {
display: none;
}
.hide-AbortParsing .log-entry[scope='AbortParsing'],
.hide-AbortParsing .log-entry[scope='AbortParsing'] + hr {
display: none;
}
.hide-Filling .log-entry[scope='Filling'],
.hide-Filling .log-entry[scope='Filling'] + hr {
display: none;
}
.hide-Submission .log-entry[scope='Submission'],
.hide-Submission .log-entry[scope='Submission'] + hr {
display: none;
}
.hide-AutofillServer .log-entry[scope='AutofillServer'],
.hide-AutofillServer .log-entry[scope='AutofillServer'] + hr {
display: none;
}
.hide-Metrics .log-entry[scope='Metrics'],
.hide-Metrics .log-entry[scope='Metrics'] + hr {
display: none;
}
.form {
border: 1px black solid;
margin: 3px;
......
......@@ -11,7 +11,13 @@
<link rel="stylesheet" href="autofill_and_password_manager_internals.css">
</head>
<body>
<h1 id="h1-title"></h1>
<div>
<h1 id="h1-title"></h1>
<div id="log-display-config">
<span id="marker-fake-button">Add Marker</span>
<input type="checkbox" id="enable-autoscroll" checked><label for="enable-autoscroll">Enable autoscroll</label>
</div>
</div>
<div id="logging-note"></div>
<div id="logging-note-incognito"></div>
<div id="version-info">
......
......@@ -2,15 +2,78 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Autoscrolling keeps the page scrolled down. Intended usage is as follows:
// before modifying the DOM, check needsScrollDown(), and afterwards invoke
// scrollDown() if needsScrollDown() was true.
function isScrolledDown() {
return window.innerHeight + window.scrollY >= document.body.offsetHeight;
}
let autoScrollActive = false; // True iff autoscroll is currently scrolling.
let autoScrollTimer = null; // Timer for resetting |autoScrollActive|.
function needsScrollDown() {
const checkbox = document.getElementById('enable-autoscroll');
return autoScrollActive || (isScrolledDown() && checkbox && checkbox.checked);
}
function scrollDown() {
autoScrollActive = true;
window.scrollTo(0, document.body.scrollHeight);
(function unsetAutoScrollActiveAfterIdletime() {
if (isScrolledDown()) {
autoScrollActive = false;
} else {
clearTimeout(autoScrollTimer);
autoScrollTimer = setTimeout(unsetAutoScrollActiveAfterIdletime, 50);
}
})();
}
// The configuration of log display can be represented in the URI fragment.
// Below are utility functions for setting/getting these parameters.
function keyValueRegExp(key) {
return new RegExp(`\\b${key}=([^&]+)`);
}
function setUrlHashParam(key, value) {
key = encodeURIComponent(key);
value = encodeURIComponent(value);
const keyValue = `${key}=${value}`;
const replaced = window.location.hash.replace(keyValueRegExp(key), keyValue);
if (window.location.hash !== replaced) {
window.location.hash = replaced;
} else {
window.location.hash +=
(window.location.hash.length > 0 ? '&' : '') + keyValue;
}
}
function getUrlHashParam(key) {
key = encodeURIComponent(key);
const match = window.location.hash.match(keyValueRegExp(key));
if (!match || match[1] === undefined) {
return undefined;
}
return encodeURIComponent(match[1]);
}
function addLog(logText) {
const logDiv = $('log-entries');
if (!logDiv) {
return;
}
const scrollAfterInsert = needsScrollDown();
logDiv.appendChild(document.createElement('hr'));
const textDiv = document.createElement('div');
textDiv.innerText = logText;
logDiv.appendChild(textDiv);
if (scrollAfterInsert) {
scrollDown();
}
}
// Converts an internal representation of nodes to actual DOM nodes that can
......@@ -46,6 +109,7 @@ function addRawLog(node) {
if (!logDiv) {
return;
}
const scrollAfterInsert = needsScrollDown();
logDiv.appendChild(document.createElement('hr'));
if (node.type === 'fragment') {
if ('children' in node) {
......@@ -56,6 +120,9 @@ function addRawLog(node) {
} else {
logDiv.appendChild(nodeToDomNode(node));
}
if (scrollAfterInsert) {
scrollDown();
}
}
function setUpAutofillInternals() {
......@@ -66,6 +133,7 @@ function setUpAutofillInternals() {
captured when all autofill-internals pages are closed.";
document.getElementById("logging-note-incognito").innerText =
"Captured autofill logs are not available in Incognito.";
setUpLogDisplayConfig();
}
function setUpPasswordManagerInternals() {
......@@ -93,6 +161,84 @@ function notifyAboutVariations(variations) {
variationsList.appendChild(list);
}
// Sets up the top bar with checkboxes to show/hide the different sorts of log
// event types, a checkbox to enable/disable autoscroll, and a (fake) button to
// add visual markers (it's fake to keep Autofill from parsing the form).
function setUpLogDisplayConfig() {
const SCOPES = [
'Context',
'Parsing',
'AbortParsing',
'Filling',
'Submission',
'AutofillServer',
'Metrics',
];
const displayConfigDiv = document.getElementById('log-display-config');
const logDiv = document.getElementById('log-entries');
const autoScrollInput = document.getElementById('enable-autoscroll');
displayConfigDiv.style.display = 'block';
displayConfigDiv.parentElement.classList.add('sticky-bar');
// Initialize the auto-scroll checkbox.
autoScrollInput.checked = getUrlHashParam('autoscroll') !== 'n';
autoScrollInput.addEventListener('change', (event) => {
setUrlHashParam('autoscroll', autoScrollInput.checked ? 'y' : 'n');
});
// Create and initialize filter checkboxes: remove/add hide-<Scope> class to
// |logDiv| when (un)checked.
for (const scope of SCOPES) {
const input = document.createElement('input');
input.setAttribute('type', 'checkbox');
input.setAttribute('id', `checkbox-${scope}`);
input.checked = getUrlHashParam(scope) !== 'n';
function changeHandler() {
setUrlHashParam(scope, input.checked ? 'y' : 'n');
const cls = `hide-${scope}`;
const scrollAfterInsert = needsScrollDown();
if (!input.checked) {
logDiv.classList.add(cls);
} else {
logDiv.classList.remove(cls);
}
if (scrollAfterInsert) {
scrollDown();
}
}
input.addEventListener('change', changeHandler);
changeHandler(); // Call once to initialize |logDiv|'s classes.
const label = document.createElement('label');
label.setAttribute('for', `checkbox-${scope}`);
label.innerText = scope;
displayConfigDiv.appendChild(input);
displayConfigDiv.appendChild(label);
}
// Initialize marker field: when pressed, add fake log event.
let markerCounter = 0;
const markerFakeButton = document.getElementById('marker-fake-button');
markerFakeButton.addEventListener('click', () => {
++markerCounter;
const scrollAfterInsert = needsScrollDown();
addRawLog({
type: 'element',
value: 'div',
attributes: {'class': 'marker', 'contenteditable': 'true'},
children: [{type: 'text', value: `#${markerCounter} `}]
});
if (scrollAfterInsert) {
scrollDown();
// Focus marker div, set caret at end of line.
const markerNode = logDiv.lastChild;
const textNode = markerNode.lastChild;
markerNode.focus();
window.getSelection().collapse(textNode, textNode.length);
}
});
}
document.addEventListener("DOMContentLoaded", function(event) {
chrome.send('loaded');
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment