Skip to content

Commit fb2dd05

Browse files
danilsomsikovDevtools-frontend LUCI CQ
authored andcommitted
[VE] Inspection support
See cl/705822975 for the counterpart Bug: 383991864 Change-Id: I529d7b5b667605b464e75c44f8ca5240727668b2 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6093863 Auto-Submit: Danil Somsikov <[email protected]> Reviewed-by: Simon Zünd <[email protected]> Commit-Queue: Danil Somsikov <[email protected]>
1 parent 1f736ce commit fb2dd05

File tree

5 files changed

+89
-23
lines changed

5 files changed

+89
-23
lines changed

front_end/entrypoints/main/MainImpl.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,9 +611,40 @@ export class MainImpl {
611611
this.#resolveReadyForTestPromise();
612612
// Asynchronously run the extensions.
613613
window.setTimeout(this.#lateInitialization.bind(this), 100);
614+
await this.#maybeInstallVeInspectionBinding();
615+
614616
MainImpl.timeEnd('Main._initializeTarget');
615617
}
616618

619+
async #maybeInstallVeInspectionBinding(): Promise<void> {
620+
const primaryPageTarget = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
621+
const url = primaryPageTarget?.targetInfo()?.url;
622+
const origin = url ? Common.ParsedURL.ParsedURL.extractOrigin(url as Platform.DevToolsPath.UrlString) : undefined;
623+
624+
const binding = '__devtools_ve_inspection_binding__';
625+
if (primaryPageTarget && await VisualLogging.isUnderInspection(origin)) {
626+
const runtimeModel = primaryPageTarget.model(SDK.RuntimeModel.RuntimeModel);
627+
await runtimeModel?.addBinding({name: binding});
628+
runtimeModel?.addEventListener(SDK.RuntimeModel.Events.BindingCalled, event => {
629+
if (event.data.name === binding) {
630+
VisualLogging.setVeDebuggingEnabled(event.data.payload === 'true', (query: string) => {
631+
VisualLogging.setVeDebuggingEnabled(false);
632+
void runtimeModel?.defaultExecutionContext()?.evaluate(
633+
{
634+
expression: `window.inspect(${JSON.stringify(query)})`,
635+
includeCommandLineAPI: false,
636+
silent: true,
637+
returnByValue: false,
638+
generatePreview: false,
639+
},
640+
/* userGesture */ false,
641+
/* awaitPromise */ false);
642+
});
643+
}
644+
});
645+
}
646+
}
647+
617648
// TODO(crbug.com/350668580) Move this to AISettingsTab once the setting is only available
618649
// there and not in the general settings screen anymore.
619650
// The ConsoleInsightsEnabledSetting represents the toggle/checkbox allowing the user to turn the feature on/off.

front_end/ui/visual_logging/Debugging.test.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,6 @@
55
import * as VisualLogging from './visual_logging-testing.js';
66

77
describe('LoggingDriver', () => {
8-
it('marks loggable elements for debugging', async () => {
9-
// @ts-ignore
10-
globalThis.setVeDebuggingEnabled(true);
11-
const element = document.createElement('div');
12-
VisualLogging.LoggingState.getOrCreateLoggingState(element, {ve: 1});
13-
VisualLogging.Debugging.processForDebugging(element);
14-
assert.strictEqual(element.style.outline, 'red solid 1px');
15-
});
16-
178
it('builds a debug string', () => {
189
assert.strictEqual(VisualLogging.Debugging.debugString({ve: 1}), 'TreeItem');
1910
assert.strictEqual(VisualLogging.Debugging.debugString({ve: 1, context: '42'}), 'TreeItem; context: 42');

front_end/ui/visual_logging/Debugging.ts

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,28 @@ import {getLoggingState, type LoggingState} from './LoggingState.js';
1010

1111
let veDebuggingEnabled = false;
1212
let debugPopover: HTMLElement|null = null;
13+
let hightlightedElement: HTMLElement|null = null;
1314
const nonDomDebugElements = new WeakMap<Loggable, HTMLElement>();
15+
let onInspect: ((query: string) => void)|undefined = undefined;
1416

15-
function setVeDebuggingEnabled(enabled: boolean): void {
17+
export function setVeDebuggingEnabled(enabled: boolean, inpsect?: (query: string) => void): void {
1618
veDebuggingEnabled = enabled;
1719
if (enabled && !debugPopover) {
1820
debugPopover = document.createElement('div');
1921
debugPopover.classList.add('ve-debug');
2022
debugPopover.style.position = 'absolute';
21-
debugPopover.style.bottom = '100px';
22-
debugPopover.style.left = '100px';
23-
debugPopover.style.background = 'black';
24-
debugPopover.style.color = 'white';
23+
debugPopover.style.background = 'var(--sys-color-cdt-base-container)';
24+
debugPopover.style.borderRadius = '2px';
25+
debugPopover.style.padding = '8px';
26+
debugPopover.style.boxShadow = 'var(--drop-shadow)';
2527
debugPopover.style.zIndex = '100000';
2628
document.body.appendChild(debugPopover);
2729
}
30+
onInspect = inpsect;
31+
if (!enabled && hightlightedElement) {
32+
hightlightedElement.style.backgroundColor = '';
33+
hightlightedElement.style.outline = '';
34+
}
2835
}
2936

3037
// @ts-ignore
@@ -35,40 +42,62 @@ export function processForDebugging(loggable: Loggable): void {
3542
if (!veDebuggingEnabled || !loggingState || loggingState.processedForDebugging) {
3643
return;
3744
}
38-
if (loggable instanceof Element) {
45+
if (loggable instanceof HTMLElement) {
3946
processElementForDebugging(loggable, loggingState);
4047
} else {
4148
processNonDomLoggableForDebugging(loggable, loggingState);
4249
}
4350
}
4451

45-
function showDebugPopover(content: string): void {
52+
function showDebugPopover(content: string, rect?: DOMRect): void {
4653
if (!debugPopover) {
4754
return;
4855
}
56+
if (rect) {
57+
debugPopover.style.left = `${rect.left}px`;
58+
debugPopover.style.top = `${rect.bottom + 8}px`;
59+
}
4960
debugPopover.style.display = 'block';
50-
debugPopover.innerHTML = content;
61+
debugPopover.textContent = content;
5162
}
5263

53-
function processElementForDebugging(element: Element, loggingState: LoggingState): void {
64+
function processElementForDebugging(element: HTMLElement, loggingState: LoggingState): void {
5465
if (element.tagName === 'OPTION') {
5566
if (loggingState.parent?.selectOpen && debugPopover) {
5667
debugPopover.innerHTML += '<br>' + debugString(loggingState.config);
5768
loggingState.processedForDebugging = true;
5869
}
5970
} else {
60-
(element as HTMLElement).style.outline = 'solid 1px red';
71+
element.addEventListener('mousedown', event => {
72+
if (event.currentTarget === hightlightedElement && onInspect && debugPopover && veDebuggingEnabled) {
73+
onInspect(debugPopover.textContent || '');
74+
event.stopImmediatePropagation();
75+
event.preventDefault();
76+
}
77+
}, {capture: true});
6178
element.addEventListener('mouseenter', () => {
79+
if (!veDebuggingEnabled) {
80+
return;
81+
}
82+
if (hightlightedElement) {
83+
hightlightedElement.style.backgroundColor = '';
84+
hightlightedElement.style.outline = '';
85+
}
86+
element.style.backgroundColor = '#A7C3E4';
87+
element.style.outline = 'dashed 1px #7327C6';
88+
hightlightedElement = element;
6289
assertNotNullOrUndefined(debugPopover);
6390
const pathToRoot = [loggingState];
6491
let ancestor = loggingState.parent;
6592
while (ancestor) {
66-
pathToRoot.push(ancestor);
93+
pathToRoot.unshift(ancestor);
6794
ancestor = ancestor.parent;
6895
}
69-
showDebugPopover(pathToRoot.map(s => debugString(s.config)).join('<br>'));
96+
showDebugPopover(pathToRoot.map(s => elementKey(s.config)).join(' > '), element.getBoundingClientRect());
7097
}, {capture: true});
7198
element.addEventListener('mouseleave', () => {
99+
element.style.backgroundColor = '';
100+
element.style.outline = '';
72101
assertNotNullOrUndefined(debugPopover);
73102
debugPopover.style.display = 'none';
74103
}, {capture: true});
@@ -305,6 +334,10 @@ function processNonDomLoggableForDebugging(loggable: Loggable, loggingState: Log
305334
}
306335
}
307336

337+
function elementKey(config: LoggingConfig): string {
338+
return `${VisualElements[config.ve]}${config.context ? `: ${config.context}` : ''}`;
339+
}
340+
308341
export function debugString(config: LoggingConfig): string {
309342
const components = [VisualElements[config.ve]];
310343
if (config.context) {

front_end/ui/visual_logging/LoggingEvents.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ function contextFromKeyCodes(event: Event): string|undefined {
152152
return components.join('-');
153153
}
154154

155-
async function contextAsNumber(context: string|undefined): Promise<number|undefined> {
155+
export async function contextAsNumber(context: string|undefined): Promise<number|undefined> {
156156
if (typeof context === 'undefined') {
157157
return undefined;
158158
}

front_end/ui/visual_logging/visual_logging.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import * as LoggingEvents from './LoggingEvents.js';
99
import * as NonDomState from './NonDomState.js';
1010

1111
export type Loggable = LoggableModule.Loggable;
12-
export {setVeDebugLoggingEnabled, DebugLoggingFormat} from './Debugging.js';
12+
export {setVeDebugLoggingEnabled, DebugLoggingFormat, setVeDebuggingEnabled} from './Debugging.js';
1313
export {startLogging, stopLogging, addDocument} from './LoggingDriver.js';
1414
export {logImpressions} from './LoggingEvents.js';
1515
export const logClick = (loggable: Loggable, event: Event, options: {doubleClick?: boolean} = {}): void =>
@@ -28,6 +28,17 @@ export function registerLoggable(loggable: Loggable, config: string, parent: Log
2828
void LoggingDriver.scheduleProcessing();
2929
}
3030

31+
export async function isUnderInspection(origin?: string): Promise<boolean> {
32+
if (!origin) {
33+
return false;
34+
}
35+
const context = await LoggingEvents.contextAsNumber(origin);
36+
if (!context) {
37+
return false;
38+
}
39+
return [431010711, -1313957874, -1093325535].includes(context);
40+
}
41+
3142
/**
3243
* Action visual elements are either buttons or menu items that trigger a given action. Use the
3344
* context to differentiate between different actions, and make sure that buttons and menu items

0 commit comments

Comments
 (0)