blob: 7f9703671cb384d0f3ecabbdd1d48d443456a09a [file] [log] [blame]
Blink Reformat4c46d092018-04-07 15:32:371// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Nikolay Vitkovb4e8dc72025-01-07 13:03:024
Blink Reformat4c46d092018-04-07 15:32:375(function(window) {
6
Nikolay Vitkov42be2662023-01-12 15:32:357// DevToolsAPI ----------------------------------------------------------------
Blink Reformat4c46d092018-04-07 15:32:378
Philip Pfaffe2d19bcb2023-06-23 10:55:229/**
10 * @typedef {{runtimeAllowedHosts: !Array<string>, runtimeBlockedHosts: !Array<string>}} ExtensionHostsPolicy
11 */
12/**
13 * @typedef {{startPage: string, name: string, exposeExperimentalAPIs: boolean, hostsPolicy?: ExtensionHostsPolicy}} ExtensionDescriptor
14 */
Nikolay Vitkov42be2662023-01-12 15:32:3515const DevToolsAPIImpl = class {
16 constructor() {
Blink Reformat4c46d092018-04-07 15:32:3717 /**
Nikolay Vitkov42be2662023-01-12 15:32:3518 * @type {number}
Blink Reformat4c46d092018-04-07 15:32:3719 */
Nikolay Vitkov42be2662023-01-12 15:32:3520 this._lastCallId = 0;
Blink Reformat4c46d092018-04-07 15:32:3721
22 /**
Nikolay Vitkov42be2662023-01-12 15:32:3523 * @type {!Object.<number, function(?Object)>}
Blink Reformat4c46d092018-04-07 15:32:3724 */
Nikolay Vitkov42be2662023-01-12 15:32:3525 this._callbacks = {};
Blink Reformat4c46d092018-04-07 15:32:3726
27 /**
Nikolay Vitkov42be2662023-01-12 15:32:3528 * @type {!Array.<!ExtensionDescriptor>}
Blink Reformat4c46d092018-04-07 15:32:3729 */
Nikolay Vitkov42be2662023-01-12 15:32:3530 this._pendingExtensionDescriptors = [];
Blink Reformat4c46d092018-04-07 15:32:3731
32 /**
Philip Pfaffe2d19bcb2023-06-23 10:55:2233 * @type {?function(!ExtensionDescriptor): void}
Blink Reformat4c46d092018-04-07 15:32:3734 */
Nikolay Vitkov42be2662023-01-12 15:32:3535 this._addExtensionCallback = null;
Blink Reformat4c46d092018-04-07 15:32:3736
37 /**
Nikolay Vitkov42be2662023-01-12 15:32:3538 * @type {!Array<string>}
Danil Somsikov1f747672022-02-02 10:44:4439 */
Nikolay Vitkov42be2662023-01-12 15:32:3540 this._originsForbiddenForExtensions = [];
Danil Somsikov1f747672022-02-02 10:44:4441
42 /**
Nikolay Vitkov42be2662023-01-12 15:32:3543 * @type {!Promise<string>}
Danil Somsikov1f747672022-02-02 10:44:4444 */
Nikolay Vitkov42be2662023-01-12 15:32:3545 this._initialTargetIdPromise = new Promise(resolve => {
46 this._setInitialTargetId = resolve;
47 });
Blink Reformat4c46d092018-04-07 15:32:3748 }
49
Nikolay Vitkov42be2662023-01-12 15:32:3550 /**
51 * @param {number} id
52 * @param {?Object} arg
53 */
54 embedderMessageAck(id, arg) {
55 const callback = this._callbacks[id];
56 delete this._callbacks[id];
57 if (callback) {
58 callback(arg);
59 }
60 }
Blink Reformat4c46d092018-04-07 15:32:3761
62 /**
Nikolay Vitkov42be2662023-01-12 15:32:3563 * @param {string} method
64 * @param {!Array.<*>} args
65 * @param {?function(?Object)} callback
66 */
67 sendMessageToEmbedder(method, args, callback) {
68 const callId = ++this._lastCallId;
69 if (callback) {
70 this._callbacks[callId] = callback;
71 }
Paul Irish9657a012024-09-04 18:37:3772 const message = {id: callId, method};
Nikolay Vitkov42be2662023-01-12 15:32:3573 if (args.length) {
74 message.params = args;
75 }
76 DevToolsHost.sendMessageToEmbedder(JSON.stringify(message));
77 }
78
79 /**
80 * @param {string} method
81 * @param {!Array<*>} args
82 */
83 _dispatchOnInspectorFrontendAPI(method, args) {
84 const inspectorFrontendAPI = /** @type {!Object<string, function()>} */ (window['InspectorFrontendAPI']);
Simon Zünd1a2246d2024-05-17 05:37:1085 if (!inspectorFrontendAPI) {
86 // This is the case for device_mode_emulation_frame entrypoint. It's created via `window.open` from
87 // the DevTools window, so it shares a context with DevTools but has a separate DevToolsUIBinding and `window` object.
88 // We can safely ignore the events since they also arrive on the DevTools `window` object.
89 return;
90 }
Nikolay Vitkov42be2662023-01-12 15:32:3591 inspectorFrontendAPI[method].apply(inspectorFrontendAPI, args);
92 }
93
94 // API methods below this line --------------------------------------------
95
96 /**
97 * @param {!Array.<!ExtensionDescriptor>} extensions
98 */
99 addExtensions(extensions) {
100 // Support for legacy front-ends (<M41).
101 if (window['WebInspector'] && window['WebInspector']['addExtensions']) {
102 window['WebInspector']['addExtensions'](extensions);
Nikolay Vitkov42be2662023-01-12 15:32:35103 // The addExtensions command is sent as the onload event happens for
104 // DevTools front-end. We should buffer this command until the frontend
105 // is ready for it.
Nikolay Vitkovd1ebd9e2025-02-26 10:19:45106 } else if (this._addExtensionCallback) {
107 extensions.forEach(this._addExtensionCallback);
108 } else {
109 this._pendingExtensionDescriptors.push(...extensions);
Nikolay Vitkov42be2662023-01-12 15:32:35110 }
111 }
112
113 /**
114 * @param {!Array<string>} forbiddenOrigins
115 */
116 setOriginsForbiddenForExtensions(forbiddenOrigins) {
117 this._originsForbiddenForExtensions = forbiddenOrigins;
118 }
119
120 /**
121 * @return {!Array<string>}
122 */
123 getOriginsForbiddenForExtensions() {
124 return this._originsForbiddenForExtensions;
125 }
126
127 /**
128 * @param {string} url
129 */
130 appendedToURL(url) {
131 this._dispatchOnInspectorFrontendAPI('appendedToURL', [url]);
132 }
133
134 /**
135 * @param {string} url
136 */
137 canceledSaveURL(url) {
138 this._dispatchOnInspectorFrontendAPI('canceledSaveURL', [url]);
139 }
140
141 contextMenuCleared() {
142 this._dispatchOnInspectorFrontendAPI('contextMenuCleared', []);
143 }
144
145 /**
146 * @param {string} id
147 */
148 contextMenuItemSelected(id) {
149 this._dispatchOnInspectorFrontendAPI('contextMenuItemSelected', [id]);
150 }
151
152 /**
153 * @param {number} count
154 */
155 deviceCountUpdated(count) {
156 this._dispatchOnInspectorFrontendAPI('deviceCountUpdated', [count]);
157 }
158
159 /**
160 * @param {!Adb.Config} config
161 */
162 devicesDiscoveryConfigChanged(config) {
163 this._dispatchOnInspectorFrontendAPI('devicesDiscoveryConfigChanged', [config]);
164 }
165
166 /**
167 * @param {!Adb.PortForwardingStatus} status
168 */
169 devicesPortForwardingStatusChanged(status) {
170 this._dispatchOnInspectorFrontendAPI('devicesPortForwardingStatusChanged', [status]);
171 }
172
173 /**
174 * @param {!Array.<!Adb.Device>} devices
175 */
176 devicesUpdated(devices) {
177 this._dispatchOnInspectorFrontendAPI('devicesUpdated', [devices]);
178 }
179
180 /**
181 * @param {string} message
182 */
183 dispatchMessage(message) {
184 this._dispatchOnInspectorFrontendAPI('dispatchMessage', [message]);
185 }
186
187 /**
188 * @param {string} messageChunk
189 * @param {number} messageSize
190 */
191 dispatchMessageChunk(messageChunk, messageSize) {
192 this._dispatchOnInspectorFrontendAPI('dispatchMessageChunk', [messageChunk, messageSize]);
193 }
194
195 enterInspectElementMode() {
196 this._dispatchOnInspectorFrontendAPI('enterInspectElementMode', []);
197 }
198
199 /**
200 * @param {!{r: number, g: number, b: number, a: number}} color
201 */
202 eyeDropperPickedColor(color) {
203 this._dispatchOnInspectorFrontendAPI('eyeDropperPickedColor', [color]);
204 }
205
206 /**
207 * @param {!Array.<!{fileSystemName: string, rootURL: string, fileSystemPath: string}>} fileSystems
208 */
209 fileSystemsLoaded(fileSystems) {
210 this._dispatchOnInspectorFrontendAPI('fileSystemsLoaded', [fileSystems]);
211 }
212
213 /**
214 * @param {string} fileSystemPath
215 */
216 fileSystemRemoved(fileSystemPath) {
217 this._dispatchOnInspectorFrontendAPI('fileSystemRemoved', [fileSystemPath]);
218 }
219
220 /**
221 * @param {?string} error
222 * @param {?{type: string, fileSystemName: string, rootURL: string, fileSystemPath: string}} fileSystem
223 */
224 fileSystemAdded(error, fileSystem) {
225 this._dispatchOnInspectorFrontendAPI('fileSystemAdded', [error, fileSystem]);
226 }
227
228 /**
229 * @param {!Array<string>} changedPaths
230 * @param {!Array<string>} addedPaths
231 * @param {!Array<string>} removedPaths
232 */
233 fileSystemFilesChangedAddedRemoved(changedPaths, addedPaths, removedPaths) {
234 // Support for legacy front-ends (<M58)
235 if (window['InspectorFrontendAPI'] && window['InspectorFrontendAPI']['fileSystemFilesChanged']) {
236 this._dispatchOnInspectorFrontendAPI(
237 'fileSystemFilesChanged', [changedPaths.concat(addedPaths).concat(removedPaths)]);
238 } else {
239 this._dispatchOnInspectorFrontendAPI(
240 'fileSystemFilesChangedAddedRemoved', [changedPaths, addedPaths, removedPaths]);
241 }
242 }
243
244 /**
245 * @param {number} requestId
246 * @param {string} fileSystemPath
247 * @param {number} totalWork
248 */
249 indexingTotalWorkCalculated(requestId, fileSystemPath, totalWork) {
250 this._dispatchOnInspectorFrontendAPI('indexingTotalWorkCalculated', [requestId, fileSystemPath, totalWork]);
251 }
252
253 /**
254 * @param {number} requestId
255 * @param {string} fileSystemPath
256 * @param {number} worked
257 */
258 indexingWorked(requestId, fileSystemPath, worked) {
259 this._dispatchOnInspectorFrontendAPI('indexingWorked', [requestId, fileSystemPath, worked]);
260 }
261
262 /**
263 * @param {number} requestId
264 * @param {string} fileSystemPath
265 */
266 indexingDone(requestId, fileSystemPath) {
267 this._dispatchOnInspectorFrontendAPI('indexingDone', [requestId, fileSystemPath]);
268 }
269
270 /**
271 * @param {{type: string, key: string, code: string, keyCode: number, modifiers: number}} event
272 */
273 keyEventUnhandled(event) {
274 event.keyIdentifier = keyCodeToKeyIdentifier(event.keyCode);
275 this._dispatchOnInspectorFrontendAPI('keyEventUnhandled', [event]);
276 }
277
278 /**
279 * @param {function(!ExtensionDescriptor)} callback
280 */
281 setAddExtensionCallback(callback) {
282 this._addExtensionCallback = callback;
283 if (this._pendingExtensionDescriptors.length) {
284 this._pendingExtensionDescriptors.forEach(this._addExtensionCallback);
285 this._pendingExtensionDescriptors = [];
286 }
287 }
288
Nikolay Vitkov42be2662023-01-12 15:32:35289 /**
290 * @param {boolean} hard
291 */
292 reloadInspectedPage(hard) {
293 this._dispatchOnInspectorFrontendAPI('reloadInspectedPage', [hard]);
294 }
295
296 /**
297 * @param {string} url
298 * @param {number} lineNumber
299 * @param {number} columnNumber
300 */
301 revealSourceLine(url, lineNumber, columnNumber) {
302 this._dispatchOnInspectorFrontendAPI('revealSourceLine', [url, lineNumber, columnNumber]);
303 }
304
305 /**
306 * @param {string} url
307 * @param {string=} fileSystemPath
308 */
309 savedURL(url, fileSystemPath) {
310 this._dispatchOnInspectorFrontendAPI('savedURL', [url, fileSystemPath]);
311 }
312
313 /**
314 * @param {number} requestId
315 * @param {string} fileSystemPath
316 * @param {!Array.<string>} files
317 */
318 searchCompleted(requestId, fileSystemPath, files) {
319 this._dispatchOnInspectorFrontendAPI('searchCompleted', [requestId, fileSystemPath, files]);
320 }
321
Kateryna Prokopenko2f96e302024-01-19 12:24:59322 colorThemeChanged() {
323 this._dispatchOnInspectorFrontendAPI('colorThemeChanged', []);
324 }
325
Nikolay Vitkov42be2662023-01-12 15:32:35326 /**
327 * @param {string} tabId
328 */
329 setInspectedTabId(tabId) {
330 this._inspectedTabIdValue = tabId;
331
332 // Support for legacy front-ends (<M41).
333 if (window['WebInspector'] && window['WebInspector']['setInspectedTabId']) {
334 window['WebInspector']['setInspectedTabId'](tabId);
335 } else {
336 this._dispatchOnInspectorFrontendAPI('setInspectedTabId', [tabId]);
337 }
338 }
339
340 /**
341 * @param {string} targetId
342 */
343 setInitialTargetId(targetId) {
344 this._setInitialTargetId(targetId);
345 }
346
347 /**
348 * @return {string|undefined}
349 */
350 getInspectedTabId() {
351 return this._inspectedTabIdValue;
352 }
353
354 /**
355 * @param {boolean} useSoftMenu
356 */
357 setUseSoftMenu(useSoftMenu) {
358 this._dispatchOnInspectorFrontendAPI('setUseSoftMenu', [useSoftMenu]);
359 }
360
361 /**
362 * @param {string} panelName
363 */
364 showPanel(panelName) {
365 this._dispatchOnInspectorFrontendAPI('showPanel', [panelName]);
366 }
367
368 /**
369 * @param {number} id
370 * @param {string} chunk
371 * @param {boolean} encoded
372 */
373 streamWrite(id, chunk, encoded) {
374 this._dispatchOnInspectorFrontendAPI('streamWrite', [id, encoded ? this._decodeBase64(chunk) : chunk]);
375 }
376
377 /**
378 * @param {string} chunk
Blink Reformat4c46d092018-04-07 15:32:37379 * @return {string}
380 */
Nikolay Vitkov42be2662023-01-12 15:32:35381 _decodeBase64(chunk) {
382 const request = new XMLHttpRequest();
383 request.open('GET', 'data:text/plain;base64,' + chunk, false);
384 request.send(null);
385 if (request.status === 200) {
386 return request.responseText;
Tim van der Lippe1d6e57a2019-09-30 11:55:34387 }
Nikolay Vitkov42be2662023-01-12 15:32:35388 console.error('Error while decoding chunk in streamWrite');
389 return '';
390 }
391};
392
393const DevToolsAPI = new DevToolsAPIImpl();
394window.DevToolsAPI = DevToolsAPI;
395
396// InspectorFrontendHostImpl --------------------------------------------------
397
398/**
399 * Enum for recordPerformanceHistogram
400 * Warning: There is another definition of this enum in the DevTools code
401 * base, keep them in sync:
402 * front_end/core/host/InspectorFrontendHostAPI.ts
403 * @readonly
404 * @enum {string}
405 */
406const EnumeratedHistogram = {
Benedikt Meurereaa17742025-02-07 11:42:03407 // LINT.IfChange(EnumeratedHistogram)
Nikolay Vitkov42be2662023-01-12 15:32:35408 ActionTaken: 'DevTools.ActionTaken',
Nikolay Vitkov42be2662023-01-12 15:32:35409 CSSHintShown: 'DevTools.CSSHintShown',
410 DeveloperResourceLoaded: 'DevTools.DeveloperResourceLoaded',
411 DeveloperResourceScheme: 'DevTools.DeveloperResourceScheme',
412 ExperimentDisabled: 'DevTools.ExperimentDisabled',
Changhao Han70cfccd2023-07-24 09:31:14413 ExperimentDisabledAtLaunch: 'DevTools.ExperimentDisabledAtLaunch',
Nikolay Vitkov42be2662023-01-12 15:32:35414 ExperimentEnabled: 'DevTools.ExperimentEnabled',
415 ExperimentEnabledAtLaunch: 'DevTools.ExperimentEnabledAtLaunch',
416 IssueCreated: 'DevTools.IssueCreated',
417 IssuesPanelIssueExpanded: 'DevTools.IssuesPanelIssueExpanded',
418 IssuesPanelOpenedFrom: 'DevTools.IssuesPanelOpenedFrom',
419 IssuesPanelResourceOpened: 'DevTools.IssuesPanelResourceOpened',
420 KeybindSetSettingChanged: 'DevTools.KeybindSetSettingChanged',
421 KeyboardShortcutFired: 'DevTools.KeyboardShortcutFired',
422 Language: 'DevTools.Language',
423 LighthouseModeRun: 'DevTools.LighthouseModeRun',
Adam Raineb50d50e2023-10-12 17:42:50424 LighthouseCategoryUsed: 'DevTools.LighthouseCategoryUsed',
Nikolay Vitkov42be2662023-01-12 15:32:35425 PanelShown: 'DevTools.PanelShown',
Ergun Erdogmusd7e4db32024-01-19 13:03:43426 PanelShownInLocation: 'DevTools.PanelShownInLocation',
Randolf Jungd3ea3e62023-04-11 09:10:09427 RecordingAssertion: 'DevTools.RecordingAssertion',
Nikolay Vitkov42be2662023-01-12 15:32:35428 RecordingCodeToggled: 'DevTools.RecordingCodeToggled',
429 RecordingCopiedToClipboard: 'DevTools.RecordingCopiedToClipboard',
430 RecordingEdited: 'DevTools.RecordingEdited',
431 RecordingExported: 'DevTools.RecordingExported',
432 RecordingReplayFinished: 'DevTools.RecordingReplayFinished',
433 RecordingReplaySpeed: 'DevTools.RecordingReplaySpeed',
434 RecordingReplayStarted: 'DevTools.RecordingReplayStarted',
435 RecordingToggled: 'DevTools.RecordingToggled',
436 SidebarPaneShown: 'DevTools.SidebarPaneShown',
Simon Zünddc8c1452023-05-16 09:53:50437 SourcesPanelFileDebugged: 'DevTools.SourcesPanelFileDebugged',
Nikolay Vitkov42be2662023-01-12 15:32:35438 SourcesPanelFileOpened: 'DevTools.SourcesPanelFileOpened',
439 NetworkPanelResponsePreviewOpened: 'DevTools.NetworkPanelResponsePreviewOpened',
Alina Varkki428dfcf2024-12-17 12:33:53440 TimelineNavigationSettingState: 'DevTools.TimelineNavigationSettingState',
Nikolay Vitkov42be2662023-01-12 15:32:35441 SyncSetting: 'DevTools.SyncSetting',
Changhao Han2df6fc22023-05-22 09:36:32442 SwatchActivated: 'DevTools.SwatchActivated',
Ergun Erdogmus2ef1c1e2023-08-08 08:34:34443 AnimationPlaybackRateChanged: 'DevTools.AnimationPlaybackRateChanged',
444 AnimationPointDragged: 'DevTools.AnimationPointDragged',
Benedikt Meurereaa17742025-02-07 11:42:03445 // LINT.ThenChange(/front_end/core/host/InspectorFrontendHostAPI.ts:EnumeratedHistogram)
Nikolay Vitkov42be2662023-01-12 15:32:35446};
447
448/**
449 * @implements {InspectorFrontendHostAPI}
450 */
451const InspectorFrontendHostImpl = class {
452 /**
453 * @return {string}
454 */
455 getSelectionBackgroundColor() {
456 return '#6e86ff';
Blink Reformat4c46d092018-04-07 15:32:37457 }
458
Nikolay Vitkov42be2662023-01-12 15:32:35459 /**
460 * @return {string}
461 */
462 getSelectionForegroundColor() {
463 return '#ffffff';
464 }
Blink Reformat4c46d092018-04-07 15:32:37465
Nikolay Vitkov42be2662023-01-12 15:32:35466 /**
467 * @return {string}
468 */
469 getInactiveSelectionBackgroundColor() {
470 return '#c9c8c8';
471 }
Joel Einbinder82b1d8e2018-12-08 01:01:37472
Nikolay Vitkov42be2662023-01-12 15:32:35473 /**
474 * @return {string}
475 */
476 getInactiveSelectionForegroundColor() {
477 return '#323232';
478 }
Joel Einbinder82b1d8e2018-12-08 01:01:37479
Nikolay Vitkov42be2662023-01-12 15:32:35480 /**
481 * @override
482 * @return {string}
483 */
484 platform() {
485 return DevToolsHost.platform();
486 }
Joel Einbinder82b1d8e2018-12-08 01:01:37487
Nikolay Vitkov42be2662023-01-12 15:32:35488 /**
489 * @override
490 */
491 loadCompleted() {
492 DevToolsAPI.sendMessageToEmbedder('loadCompleted', [], null);
493 // Support for legacy (<57) frontends.
494 if (window.Runtime && window.Runtime.queryParam) {
495 const panelToOpen = window.Runtime.queryParam('panel');
496 if (panelToOpen) {
497 window.DevToolsAPI.showPanel(panelToOpen);
Joel Einbinderf55cc942018-10-30 01:59:53498 }
Blink Reformat4c46d092018-04-07 15:32:37499 }
Nikolay Vitkov42be2662023-01-12 15:32:35500 }
Blink Reformat4c46d092018-04-07 15:32:37501
Nikolay Vitkov42be2662023-01-12 15:32:35502 /**
503 * @override
504 */
505 bringToFront() {
506 DevToolsAPI.sendMessageToEmbedder('bringToFront', [], null);
507 }
508
509 /**
510 * @override
511 */
512 closeWindow() {
513 DevToolsAPI.sendMessageToEmbedder('closeWindow', [], null);
514 }
515
516 /**
517 * @override
518 * @param {boolean} isDocked
519 * @param {function()} callback
520 */
521 setIsDocked(isDocked, callback) {
522 DevToolsAPI.sendMessageToEmbedder('setIsDocked', [isDocked], callback);
523 }
524
525 /**
526 * @override
527 * @param {string} trigger
528 * @param {function(!InspectorFrontendHostAPI.ShowSurveyResult): void} callback
529 */
530 showSurvey(trigger, callback) {
531 DevToolsAPI.sendMessageToEmbedder('showSurvey', [trigger], /** @type {function(?Object)} */ (callback));
532 }
533
534 /**
535 * @override
536 * @param {string} trigger
537 * @param {function(!InspectorFrontendHostAPI.CanShowSurveyResult): void} callback
538 */
539 canShowSurvey(trigger, callback) {
540 DevToolsAPI.sendMessageToEmbedder('canShowSurvey', [trigger], /** @type {function(?Object)} */ (callback));
541 }
542
543 /**
544 * Requests inspected page to be placed atop of the inspector frontend with specified bounds.
545 * @override
546 * @param {{x: number, y: number, width: number, height: number}} bounds
547 */
548 setInspectedPageBounds(bounds) {
549 DevToolsAPI.sendMessageToEmbedder('setInspectedPageBounds', [bounds], null);
550 }
551
552 /**
553 * @override
554 */
555 inspectElementCompleted() {
556 DevToolsAPI.sendMessageToEmbedder('inspectElementCompleted', [], null);
557 }
558
559 /**
560 * @override
561 * @param {string} url
562 * @param {string} headers
563 * @param {number} streamId
564 * @param {function(!InspectorFrontendHostAPI.LoadNetworkResourceResult): void} callback
565 */
566 loadNetworkResource(url, headers, streamId, callback) {
567 DevToolsAPI.sendMessageToEmbedder(
568 'loadNetworkResource', [url, headers, streamId], /** @type {function(?Object)} */ (callback));
569 }
570
571 /**
572 * @override
573 * @param {string} name
574 * @param {!{synced: (boolean|undefined)}} options
575 */
576 registerPreference(name, options) {
577 DevToolsAPI.sendMessageToEmbedder('registerPreference', [name, options], null);
578 }
579
580 /**
581 * @override
582 * @param {function(!Object<string, string>)} callback
583 */
584 getPreferences(callback) {
585 DevToolsAPI.sendMessageToEmbedder('getPreferences', [], /** @type {function(?Object)} */ (callback));
586 }
587
588 /**
589 * @override
590 * @param {string} name
591 * @param {function(string)} callback
592 */
593 getPreference(name, callback) {
594 DevToolsAPI.sendMessageToEmbedder('getPreference', [name], /** @type {function(string)} */ (callback));
595 }
596
597 /**
598 * @override
599 * @param {string} name
600 * @param {string} value
601 */
602 setPreference(name, value) {
603 DevToolsAPI.sendMessageToEmbedder('setPreference', [name, value], null);
604 }
605
606 /**
607 * @override
608 * @param {string} name
609 */
610 removePreference(name) {
611 DevToolsAPI.sendMessageToEmbedder('removePreference', [name], null);
612 }
613
614 /**
615 * @override
616 */
617 clearPreferences() {
618 DevToolsAPI.sendMessageToEmbedder('clearPreferences', [], null);
619 }
620
621 /**
622 * @override
623 * @param {!function(!InspectorFrontendHostAPI.SyncInformation):void} callback
624 */
625 getSyncInformation(callback) {
626 DevToolsAPI.sendMessageToEmbedder('getSyncInformation', [], callback);
627 }
628
629 /**
630 * @override
Wolfgang Beyer694eaa92024-06-03 11:03:58631 * @param {function(Object<string, Object<string, string|boolean>>):void} callback
632 */
633 getHostConfig(callback) {
Wolfgang Beyer9c165602024-08-14 09:52:32634 DevToolsAPI.sendMessageToEmbedder('getHostConfig', [], hostConfig => {
635 const majorVersion = getRemoteMajorVersion();
636 if (majorVersion && majorVersion < 129 && hostConfig?.aidaAvailability) {
637 return callback(this.hostConfigNewToOld(hostConfig));
638 }
Wolfgang Beyer9c165602024-08-14 09:52:32639 return callback(hostConfig);
640 });
641 }
642
Wolfgang Beyer9c165602024-08-14 09:52:32643 /**
644 * @param {Object<string, Object<string, string|boolean>>} newConfig
645 */
646 hostConfigNewToOld(newConfig) {
647 const devToolsConsoleInsights = {
648 enabled: (newConfig.devToolsConsoleInsights?.enabled && newConfig.aidaAvailability?.enabled) ?? false,
649 aidaModelId: newConfig.devToolsConsoleInsights?.modelId ?? '',
650 aidaTemperature: newConfig.devToolsConsoleInsights?.temperature ?? 0,
651 blockedByAge: newConfig.aidaAvailability?.blockedByAge ?? true,
652 blockedByEnterprisePolicy: newConfig.aidaAvailability?.blockedByEnterprisePolicy ?? true,
Wolfgang Beyer192d2c52024-08-27 14:00:03653 blockedByFeatureFlag:
654 (newConfig.devToolsConsoleInsights?.enabled && newConfig.aidaAvailability?.enabled) ?? false,
Wolfgang Beyer9c165602024-08-14 09:52:32655 blockedByGeo: newConfig.aidaAvailability?.blockedByGeo ?? true,
656 blockedByRollout: false,
657 disallowLogging: newConfig.aidaAvailability?.disallowLogging ?? true,
658 optIn: false,
659 };
660 const devToolsFreestylerDogfood = {
Wolfgang Beyer5d24a002024-10-04 13:32:18661 enabled: (newConfig.devToolsFreestyler?.enabled && newConfig.aidaAvailability?.enabled) ?? false,
662 aidaModelId: newConfig.devToolsFreestyler?.modelId ?? '',
663 aidaTemperature: newConfig.devToolsFreestyler?.temperature ?? 0,
Wolfgang Beyer9c165602024-08-14 09:52:32664 blockedByAge: newConfig.aidaAvailability?.blockedByAge ?? true,
665 blockedByEnterprisePolicy: newConfig.aidaAvailability?.blockedByEnterprisePolicy ?? true,
666 blockedByGeo: newConfig.aidaAvailability?.blockedByGeo ?? true,
667 };
668 return {
669 devToolsConsoleInsights,
670 devToolsFreestylerDogfood,
671 devToolsVeLogging: newConfig.devToolsVeLogging,
672 isOffTheRecord: newConfig.isOffTheRecord,
673 };
Wolfgang Beyer694eaa92024-06-03 11:03:58674 }
675
676 /**
677 * @override
Nikolay Vitkov42be2662023-01-12 15:32:35678 * @param {string} origin
679 * @param {string} script
680 */
681 setInjectedScriptForOrigin(origin, script) {
682 DevToolsAPI.sendMessageToEmbedder('registerExtensionsAPI', [origin, script], null);
683 }
684
685 /**
686 * @override
687 * @param {string} url
688 */
689 inspectedURLChanged(url) {
690 DevToolsAPI.sendMessageToEmbedder('inspectedURLChanged', [url], null);
691 }
692
693 /**
694 * @override
695 * @param {string} text
696 */
697 copyText(text) {
698 DevToolsHost.copyText(text);
699 }
700
701 /**
702 * @override
703 * @param {string} url
704 */
705 openInNewTab(url) {
706 DevToolsAPI.sendMessageToEmbedder('openInNewTab', [url], null);
707 }
708
709 /**
710 * @override
Eric Leese15a17e92024-02-21 16:07:39711 * @param {string} query
712 */
713 openSearchResultsInNewTab(query) {
714 DevToolsAPI.sendMessageToEmbedder('openSearchResultsInNewTab', [query], null);
715 }
716
717 /**
718 * @override
Nikolay Vitkov42be2662023-01-12 15:32:35719 * @param {string} fileSystemPath
720 */
721 showItemInFolder(fileSystemPath) {
722 DevToolsAPI.sendMessageToEmbedder('showItemInFolder', [fileSystemPath], null);
723 }
724
725 /**
726 * @override
727 * @param {string} url
728 * @param {string} content
729 * @param {boolean} forceSaveAs
Simon Zünda680f4c2024-05-16 07:11:50730 * @param {boolean} isBase64
Nikolay Vitkov42be2662023-01-12 15:32:35731 */
Simon Zünda680f4c2024-05-16 07:11:50732 save(url, content, forceSaveAs, isBase64) {
733 DevToolsAPI.sendMessageToEmbedder('save', [url, content, forceSaveAs, isBase64], null);
Nikolay Vitkov42be2662023-01-12 15:32:35734 }
735
736 /**
737 * @override
738 * @param {string} url
739 * @param {string} content
740 */
741 append(url, content) {
742 DevToolsAPI.sendMessageToEmbedder('append', [url, content], null);
743 }
744
745 /**
746 * @override
747 * @param {string} url
748 */
749 close(url) {
750 }
751
752 /**
753 * @override
754 * @param {string} message
755 */
756 sendMessageToBackend(message) {
757 DevToolsAPI.sendMessageToEmbedder('dispatchProtocolMessage', [message], null);
758 }
759
760 /**
761 * @override
Benedikt Meurer3f5c0032023-06-16 11:11:07762 * @param {string} histogramName
763 * @param {number} sample
764 * @param {number} min
765 * @param {number} exclusiveMax
766 * @param {number} bucketSize
767 */
768 recordCountHistogram(histogramName, sample, min, exclusiveMax, bucketSize) {
769 DevToolsAPI.sendMessageToEmbedder(
770 'recordCountHistogram', [histogramName, sample, min, exclusiveMax, bucketSize], null);
771 }
772
773 /**
774 * @override
Nikolay Vitkov42be2662023-01-12 15:32:35775 * @param {!InspectorFrontendHostAPI.EnumeratedHistogram} actionName
776 * @param {number} actionCode
777 * @param {number} bucketSize
778 */
779 recordEnumeratedHistogram(actionName, actionCode, bucketSize) {
780 if (!Object.values(EnumeratedHistogram).includes(actionName)) {
781 return;
782 }
783 DevToolsAPI.sendMessageToEmbedder('recordEnumeratedHistogram', [actionName, actionCode, bucketSize], null);
784 }
785
786 /**
787 * @override
788 * @param {string} histogramName
789 * @param {number} duration
790 */
791 recordPerformanceHistogram(histogramName, duration) {
792 DevToolsAPI.sendMessageToEmbedder('recordPerformanceHistogram', [histogramName, duration], null);
793 }
794
795 /**
796 * @override
797 * @param {string} umaName
798 */
799 recordUserMetricsAction(umaName) {
800 DevToolsAPI.sendMessageToEmbedder('recordUserMetricsAction', [umaName], null);
801 }
802
803 /**
804 * @override
805 */
Benedikt Meurerf43c9c72025-02-18 13:50:23806 connectAutomaticFileSystem(fileSystemPath, fileSystemUUID, addIfMissing, callback) {
807 DevToolsAPI.sendMessageToEmbedder(
808 'connectAutomaticFileSystem',
809 [fileSystemPath, fileSystemUUID, addIfMissing],
810 callback,
811 );
812 }
813
814 /**
815 * @override
816 */
817 disconnectAutomaticFileSystem(fileSystemPath) {
818 DevToolsAPI.sendMessageToEmbedder(
819 'disconnectAutomaticFileSystem',
820 [fileSystemPath],
821 null,
822 );
823 }
824
825 /**
826 * @override
827 */
Nikolay Vitkov42be2662023-01-12 15:32:35828 requestFileSystems() {
829 DevToolsAPI.sendMessageToEmbedder('requestFileSystems', [], null);
830 }
831
832 /**
833 * @override
834 * @param {string=} type
835 */
836 addFileSystem(type) {
837 DevToolsAPI.sendMessageToEmbedder('addFileSystem', [type || ''], null);
838 }
839
840 /**
841 * @override
842 * @param {string} fileSystemPath
843 */
844 removeFileSystem(fileSystemPath) {
845 DevToolsAPI.sendMessageToEmbedder('removeFileSystem', [fileSystemPath], null);
846 }
847
848 /**
849 * @override
850 * @param {string} fileSystemId
851 * @param {string} registeredName
852 * @return {?FileSystem}
853 */
854 isolatedFileSystem(fileSystemId, registeredName) {
855 return DevToolsHost.isolatedFileSystem(fileSystemId, registeredName);
856 }
857
858 /**
859 * @override
860 * @param {!FileSystem} fileSystem
861 */
862 upgradeDraggedFileSystemPermissions(fileSystem) {
863 DevToolsHost.upgradeDraggedFileSystemPermissions(fileSystem);
864 }
865
866 /**
867 * @override
868 * @param {number} requestId
869 * @param {string} fileSystemPath
870 * @param {string} excludedFolders
871 */
872 indexPath(requestId, fileSystemPath, excludedFolders) {
873 // |excludedFolders| added in M67. For backward compatibility,
874 // pass empty array.
875 excludedFolders = excludedFolders || '[]';
876 DevToolsAPI.sendMessageToEmbedder('indexPath', [requestId, fileSystemPath, excludedFolders], null);
877 }
878
879 /**
880 * @override
881 * @param {number} requestId
882 */
883 stopIndexing(requestId) {
884 DevToolsAPI.sendMessageToEmbedder('stopIndexing', [requestId], null);
885 }
886
887 /**
888 * @override
889 * @param {number} requestId
890 * @param {string} fileSystemPath
891 * @param {string} query
892 */
893 searchInPath(requestId, fileSystemPath, query) {
894 DevToolsAPI.sendMessageToEmbedder('searchInPath', [requestId, fileSystemPath, query], null);
895 }
896
897 /**
898 * @override
899 * @return {number}
900 */
901 zoomFactor() {
902 return DevToolsHost.zoomFactor();
903 }
904
905 /**
906 * @override
907 */
908 zoomIn() {
909 DevToolsAPI.sendMessageToEmbedder('zoomIn', [], null);
910 }
911
912 /**
913 * @override
914 */
915 zoomOut() {
916 DevToolsAPI.sendMessageToEmbedder('zoomOut', [], null);
917 }
918
919 /**
920 * @override
921 */
922 resetZoom() {
923 DevToolsAPI.sendMessageToEmbedder('resetZoom', [], null);
924 }
925
926 /**
927 * @override
928 * @param {string} shortcuts
929 */
930 setWhitelistedShortcuts(shortcuts) {
931 DevToolsAPI.sendMessageToEmbedder('setWhitelistedShortcuts', [shortcuts], null);
932 }
933
934 /**
935 * @override
936 * @param {boolean} active
937 */
938 setEyeDropperActive(active) {
939 DevToolsAPI.sendMessageToEmbedder('setEyeDropperActive', [active], null);
940 }
941
942 /**
943 * @override
944 * @param {!Array<string>} certChain
945 */
946 showCertificateViewer(certChain) {
947 DevToolsAPI.sendMessageToEmbedder('showCertificateViewer', [JSON.stringify(certChain)], null);
948 }
949
950 /**
951 * Only needed to run Lighthouse on old devtools.
952 * @override
953 * @param {function()} callback
954 */
955 reattach(callback) {
956 DevToolsAPI.sendMessageToEmbedder('reattach', [], callback);
957 }
958
959 /**
960 * @override
961 */
962 readyForTest() {
963 DevToolsAPI.sendMessageToEmbedder('readyForTest', [], null);
964 }
965
966 /**
967 * @override
968 */
969 connectionReady() {
970 DevToolsAPI.sendMessageToEmbedder('connectionReady', [], null);
971 }
972
973 /**
974 * @override
975 * @param {boolean} value
976 */
977 setOpenNewWindowForPopups(value) {
978 DevToolsAPI.sendMessageToEmbedder('setOpenNewWindowForPopups', [value], null);
979 }
980
981 /**
982 * @override
983 * @param {!Adb.Config} config
984 */
985 setDevicesDiscoveryConfig(config) {
986 DevToolsAPI.sendMessageToEmbedder(
987 'setDevicesDiscoveryConfig',
988 [
989 config.discoverUsbDevices, config.portForwardingEnabled, JSON.stringify(config.portForwardingConfig),
990 config.networkDiscoveryEnabled, JSON.stringify(config.networkDiscoveryConfig)
991 ],
992 null);
993 }
994
995 /**
996 * @override
997 * @param {boolean} enabled
998 */
999 setDevicesUpdatesEnabled(enabled) {
1000 DevToolsAPI.sendMessageToEmbedder('setDevicesUpdatesEnabled', [enabled], null);
1001 }
1002
1003 /**
1004 * @override
Nikolay Vitkov42be2662023-01-12 15:32:351005 * @param {string} browserId
1006 * @param {string} url
1007 */
1008 openRemotePage(browserId, url) {
1009 DevToolsAPI.sendMessageToEmbedder('openRemotePage', [browserId, url], null);
1010 }
1011
1012 /**
1013 * @override
1014 */
1015 openNodeFrontend() {
1016 DevToolsAPI.sendMessageToEmbedder('openNodeFrontend', [], null);
1017 }
1018
1019 /**
1020 * @override
1021 * @param {number} x
1022 * @param {number} y
1023 * @param {!Array.<!InspectorFrontendHostAPI.ContextMenuDescriptor>} items
1024 * @param {!Document} document
1025 */
1026 showContextMenuAtPoint(x, y, items, document) {
1027 DevToolsHost.showContextMenuAtPoint(x, y, items, document);
1028 }
1029
1030 /**
1031 * @override
1032 * @return {boolean}
1033 */
1034 isHostedMode() {
1035 return DevToolsHost.isHostedMode();
1036 }
1037
1038 /**
1039 * @override
1040 * @param {function(!ExtensionDescriptor)} callback
1041 */
1042 setAddExtensionCallback(callback) {
1043 DevToolsAPI.setAddExtensionCallback(callback);
1044 }
1045
Danil Somsikov9f18cf62023-09-21 11:43:451046 /**
1047 * @override
1048 * @param {InspectorFrontendHostAPI.ImpressionEvent} impressionEvent
1049 */
1050 recordImpression(impressionEvent) {
Danil Somsikov609b5862023-10-16 11:16:341051 DevToolsAPI.sendMessageToEmbedder('recordImpression', [impressionEvent], null);
Danil Somsikov9f18cf62023-09-21 11:43:451052 }
1053
1054 /**
1055 * @override
Simon Zünd66b5a892024-02-12 07:58:131056 * @param {InspectorFrontendHostAPI.ResizeEvent} resizeEvent
1057 */
1058 recordResize(resizeEvent) {
1059 DevToolsAPI.sendMessageToEmbedder('recordResize', [resizeEvent], null);
1060 }
1061
1062 /**
1063 * @override
Danil Somsikov9f18cf62023-09-21 11:43:451064 * @param {InspectorFrontendHostAPI.ClickEvent} clickEvent
1065 */
1066 recordClick(clickEvent) {
Danil Somsikov609b5862023-10-16 11:16:341067 DevToolsAPI.sendMessageToEmbedder('recordClick', [clickEvent], null);
Danil Somsikov9f18cf62023-09-21 11:43:451068 }
1069
1070 /**
1071 * @override
Danil Somsikov5e555eb2023-10-18 13:42:591072 * @param {InspectorFrontendHostAPI.HoverEvent} hoverEvent
1073 */
1074 recordHover(hoverEvent) {
1075 DevToolsAPI.sendMessageToEmbedder('recordHover', [hoverEvent], null);
1076 }
1077
1078 /**
1079 * @override
Danil Somsikov1aca65a2023-10-20 10:22:401080 * @param {InspectorFrontendHostAPI.DragEvent} dragEvent
1081 */
Simon Zünddd2e9f72023-11-29 07:18:001082 recordDrag(dragEvent) {
Danil Somsikov1aca65a2023-10-20 10:22:401083 DevToolsAPI.sendMessageToEmbedder('recordDrag', [dragEvent], null);
1084 }
1085
1086 /**
1087 * @override
Danil Somsikov9f18cf62023-09-21 11:43:451088 * @param {InspectorFrontendHostAPI.ChangeEvent} changeEvent
1089 */
1090 recordChange(changeEvent) {
Danil Somsikov609b5862023-10-16 11:16:341091 DevToolsAPI.sendMessageToEmbedder('recordChange', [changeEvent], null);
Danil Somsikov9f18cf62023-09-21 11:43:451092 }
1093
1094 /**
1095 * @override
1096 * @param {InspectorFrontendHostAPI.KeyDownEvent} keyDownEvent
1097 */
1098 recordKeyDown(keyDownEvent) {
Danil Somsikov609b5862023-10-16 11:16:341099 DevToolsAPI.sendMessageToEmbedder('recordKeyDown', [keyDownEvent], null);
Danil Somsikov9f18cf62023-09-21 11:43:451100 }
1101
Danil Somsikov79830ea2025-03-04 09:27:031102 /**
1103 * @override
1104 * @param {InspectorFrontendHostAPI.SettingAccessEvent} settingAccessEvent
1105 */
1106 recordSettingAccess(settingAccessEvent) {
1107 DevToolsAPI.sendMessageToEmbedder('recordSettingAccess', [settingAccessEvent], null);
1108 }
1109
Nikolay Vitkov42be2662023-01-12 15:32:351110 // Backward-compatible methods below this line --------------------------------------------
1111
1112 /**
1113 * Support for legacy front-ends (<M65).
1114 * @return {boolean}
1115 */
1116 isUnderTest() {
1117 return false;
1118 }
1119
1120 /**
1121 * Support for legacy front-ends (<M50).
1122 * @param {string} message
1123 */
1124 sendFrontendAPINotification(message) {
1125 }
1126
1127 /**
1128 * Support for legacy front-ends (<M41).
1129 * @return {string}
1130 */
1131 port() {
1132 return 'unknown';
1133 }
1134
1135 /**
1136 * Support for legacy front-ends (<M38).
1137 * @param {number} zoomFactor
1138 */
1139 setZoomFactor(zoomFactor) {
1140 }
1141
1142 /**
1143 * Support for legacy front-ends (<M34).
1144 */
1145 sendMessageToEmbedder() {
1146 }
1147
1148 /**
1149 * Support for legacy front-ends (<M34).
1150 * @param {string} dockSide
1151 */
1152 requestSetDockSide(dockSide) {
1153 DevToolsAPI.sendMessageToEmbedder('setIsDocked', [dockSide !== 'undocked'], null);
1154 }
1155
1156 /**
1157 * Support for legacy front-ends (<M34).
1158 * @return {boolean}
1159 */
1160 supportsFileSystems() {
1161 return true;
1162 }
1163
1164 /**
1165 * Support for legacy front-ends (<M44).
1166 * @param {number} actionCode
1167 */
1168 recordActionTaken(actionCode) {
1169 // Do not record actions, as that may crash the DevTools renderer.
1170 }
1171
1172 /**
1173 * Support for legacy front-ends (<M44).
1174 * @param {number} panelCode
1175 */
1176 recordPanelShown(panelCode) {
1177 // Do not record actions, as that may crash the DevTools renderer.
1178 }
1179
1180 /**
1181 * @return {!Promise<string>}
1182 */
1183 initialTargetId() {
1184 return DevToolsAPI._initialTargetIdPromise;
1185 }
Alex Rudenko13d80cf2023-08-24 12:46:561186
1187 /**
1188 * @param {string} request
Danil Somsikovfbf718f2024-02-22 07:51:261189 * @param {number} streamId
Alex Rudenko13d80cf2023-08-24 12:46:561190 * @param {function(!InspectorFrontendHostAPI.DoAidaConversationResult): void} cb
1191 */
Danil Somsikovd4a99302024-02-19 16:09:061192 doAidaConversation(request, streamId, cb) {
1193 DevToolsAPI.sendMessageToEmbedder('doAidaConversation', [request, streamId], cb);
Alex Rudenko13d80cf2023-08-24 12:46:561194 }
Danil Somsikovfbf718f2024-02-22 07:51:261195
1196 /**
1197 * @param {string} request
Nikolay Vitkov95d74c02024-07-18 09:22:001198 * @param {function(!InspectorFrontendHostAPI.AidaClientResult): void} cb
Danil Somsikovfbf718f2024-02-22 07:51:261199 */
Nikolay Vitkov95d74c02024-07-18 09:22:001200 registerAidaClientEvent(request, cb) {
1201 DevToolsAPI.sendMessageToEmbedder('registerAidaClientEvent', [request], cb);
Danil Somsikovfbf718f2024-02-22 07:51:261202 }
Nikolay Vitkov42be2662023-01-12 15:32:351203};
1204
1205window.InspectorFrontendHost = new InspectorFrontendHostImpl();
1206
1207// DevToolsApp ---------------------------------------------------------------
1208
1209function installObjectObserve() {
1210 /** @type {!Array<string>} */
1211 const properties = [
1212 'advancedSearchConfig',
1213 'auditsPanelSplitViewState',
1214 'auditsSidebarWidth',
1215 'blockedURLs',
1216 'breakpoints',
1217 'cacheDisabled',
1218 'colorFormat',
1219 'consoleHistory',
1220 'consoleTimestampsEnabled',
1221 'cpuProfilerView',
1222 'cssSourceMapsEnabled',
1223 'currentDockState',
1224 'customColorPalette',
1225 'customDevicePresets',
1226 'customEmulatedDeviceList',
1227 'customFormatters',
1228 'customUserAgent',
1229 'databaseTableViewVisibleColumns',
1230 'dataGrid-cookiesTable',
1231 'dataGrid-DOMStorageItemsView',
1232 'debuggerSidebarHidden',
1233 'disablePausedStateOverlay',
1234 'domBreakpoints',
1235 'domWordWrap',
1236 'elementsPanelSplitViewState',
1237 'elementsSidebarWidth',
1238 'emulation.deviceHeight',
1239 'emulation.deviceModeValue',
1240 'emulation.deviceOrientationOverride',
1241 'emulation.deviceScale',
1242 'emulation.deviceScaleFactor',
1243 'emulation.deviceUA',
1244 'emulation.deviceWidth',
1245 'emulation.locationOverride',
1246 'emulation.showDeviceMode',
1247 'emulation.showRulers',
1248 'enableAsyncStackTraces',
1249 'enableIgnoreListing',
1250 'eventListenerBreakpoints',
1251 'fileMappingEntries',
1252 'fileSystemMapping',
1253 'FileSystemViewSidebarWidth',
1254 'fileSystemViewSplitViewState',
1255 'filterBar-consoleView',
1256 'filterBar-networkPanel',
1257 'filterBar-promisePane',
1258 'filterBar-timelinePanel',
1259 'frameViewerHideChromeWindow',
1260 'heapSnapshotRetainersViewSize',
1261 'heapSnapshotSplitViewState',
1262 'hideCollectedPromises',
1263 'hideNetworkMessages',
1264 'highlightNodeOnHoverInOverlay',
1265 'inlineVariableValues',
1266 'Inspector.drawerSplitView',
1267 'Inspector.drawerSplitViewState',
1268 'InspectorView.panelOrder',
1269 'InspectorView.screencastSplitView',
1270 'InspectorView.screencastSplitViewState',
1271 'InspectorView.splitView',
1272 'InspectorView.splitViewState',
1273 'javaScriptDisabled',
1274 'jsSourceMapsEnabled',
1275 'lastActivePanel',
1276 'lastDockState',
1277 'lastSelectedSourcesSidebarPaneTab',
1278 'lastSnippetEvaluationIndex',
1279 'layerDetailsSplitView',
1280 'layerDetailsSplitViewState',
1281 'layersPanelSplitViewState',
1282 'layersShowInternalLayers',
1283 'layersSidebarWidth',
1284 'messageLevelFilters',
1285 'messageURLFilters',
1286 'monitoringXHREnabled',
1287 'navigatorGroupByAuthored',
1288 'navigatorGroupByFolder',
1289 'navigatorHidden',
1290 'networkColorCodeResourceTypes',
1291 'networkConditions',
1292 'networkConditionsCustomProfiles',
1293 'networkHideDataURL',
1294 'networkLogColumnsVisibility',
1295 'networkLogLargeRows',
1296 'networkLogShowOverview',
1297 'networkPanelSplitViewState',
1298 'networkRecordFilmStripSetting',
1299 'networkResourceTypeFilters',
1300 'networkShowPrimaryLoadWaterfall',
1301 'networkSidebarWidth',
1302 'openLinkHandler',
1303 'pauseOnUncaughtException',
1304 'pauseOnCaughtException',
1305 'pauseOnExceptionEnabled',
1306 'preserveConsoleLog',
1307 'prettyPrintInfobarDisabled',
1308 'previouslyViewedFiles',
1309 'profilesPanelSplitViewState',
1310 'profilesSidebarWidth',
1311 'promiseStatusFilters',
1312 'recordAllocationStacks',
1313 'requestHeaderFilterSetting',
1314 'request-info-formData-category-expanded',
1315 'request-info-general-category-expanded',
1316 'request-info-queryString-category-expanded',
1317 'request-info-requestHeaders-category-expanded',
1318 'request-info-requestPayload-category-expanded',
1319 'request-info-responseHeaders-category-expanded',
1320 'resources',
1321 'resourcesLastSelectedItem',
1322 'resourcesPanelSplitViewState',
1323 'resourcesSidebarWidth',
1324 'resourceViewTab',
1325 'savedURLs',
1326 'screencastEnabled',
1327 'scriptsPanelNavigatorSidebarWidth',
1328 'searchInContentScripts',
1329 'selectedAuditCategories',
1330 'selectedColorPalette',
1331 'selectedProfileType',
1332 'shortcutPanelSwitch',
1333 'showAdvancedHeapSnapshotProperties',
1334 'showEventListenersForAncestors',
1335 'showFrameowkrListeners',
1336 'showHeaSnapshotObjectsHiddenProperties',
1337 'showInheritedComputedStyleProperties',
1338 'showMediaQueryInspector',
Nikolay Vitkov42be2662023-01-12 15:32:351339 'showUAShadowDOM',
1340 'showWhitespacesInEditor',
1341 'sidebarPosition',
1342 'skipContentScripts',
1343 'automaticallyIgnoreListKnownThirdPartyScripts',
1344 'skipStackFramesPattern',
1345 'sourceMapInfobarDisabled',
Eric Leeseff8a2a52023-07-11 14:02:281346 'sourceMapSkippedInfobarDisabled',
Nikolay Vitkov42be2662023-01-12 15:32:351347 'sourcesPanelDebuggerSidebarSplitViewState',
1348 'sourcesPanelNavigatorSplitViewState',
1349 'sourcesPanelSplitSidebarRatio',
1350 'sourcesPanelSplitViewState',
1351 'sourcesSidebarWidth',
1352 'standardEmulatedDeviceList',
1353 'StylesPaneSplitRatio',
1354 'stylesPaneSplitViewState',
1355 'textEditorAutocompletion',
1356 'textEditorAutoDetectIndent',
1357 'textEditorBracketMatching',
1358 'textEditorIndent',
1359 'textEditorTabMovesFocus',
1360 'timelineCaptureFilmStrip',
1361 'timelineCaptureLayersAndPictures',
1362 'timelineCaptureMemory',
1363 'timelineCaptureNetwork',
1364 'timeline-details',
1365 'timelineEnableJSSampling',
1366 'timelineOverviewMode',
1367 'timelinePanelDetailsSplitViewState',
1368 'timelinePanelRecorsSplitViewState',
1369 'timelinePanelTimelineStackSplitViewState',
1370 'timelinePerspective',
1371 'timeline-split',
1372 'timelineTreeGroupBy',
1373 'timeline-view',
1374 'timelineViewMode',
1375 'uiTheme',
1376 'watchExpressions',
1377 'WebInspector.Drawer.lastSelectedView',
1378 'WebInspector.Drawer.showOnLoad',
1379 'workspaceExcludedFolders',
1380 'workspaceFolderExcludePattern',
1381 'workspaceInfobarDisabled',
1382 'workspaceMappingInfobarDisabled',
1383 'xhrBreakpoints'
1384 ];
1385
1386 /**
1387 * @this {!{_storage: Object, _name: string}}
1388 */
1389 function settingRemove() {
1390 this._storage[this._name] = undefined;
1391 }
1392
1393 /**
1394 * @param {!Object} object
1395 * @param {function(!Array<!{name: string}>)} observer
1396 */
1397 function objectObserve(object, observer) {
1398 if (window['WebInspector']) {
1399 const settingPrototype = /** @type {!Object} */ (window['WebInspector']['Setting']['prototype']);
1400 if (typeof settingPrototype['remove'] === 'function') {
1401 settingPrototype['remove'] = settingRemove;
1402 }
1403 }
1404 /** @type {!Set<string>} */
1405 const changedProperties = new Set();
1406 let scheduled = false;
1407
1408 function scheduleObserver() {
1409 if (scheduled) {
1410 return;
1411 }
1412 scheduled = true;
1413 queueMicrotask(callObserver);
1414 }
1415
1416 function callObserver() {
1417 scheduled = false;
1418 const changes = /** @type {!Array<!{name: string}>} */ ([]);
1419 changedProperties.forEach(function(name) {
Paul Irish9657a012024-09-04 18:37:371420 changes.push({name});
Nikolay Vitkov42be2662023-01-12 15:32:351421 });
1422 changedProperties.clear();
1423 observer.call(null, changes);
1424 }
1425
1426 /** @type {!Map<string, *>} */
1427 const storage = new Map();
1428
1429 /**
1430 * @param {string} property
1431 */
1432 function defineProperty(property) {
1433 if (property in object) {
1434 storage.set(property, object[property]);
1435 delete object[property];
1436 }
1437
1438 Object.defineProperty(object, property, {
Blink Reformat4c46d092018-04-07 15:32:371439 /**
Nikolay Vitkov42be2662023-01-12 15:32:351440 * @return {*}
Blink Reformat4c46d092018-04-07 15:32:371441 */
1442 get: function() {
Nikolay Vitkov42be2662023-01-12 15:32:351443 return storage.get(property);
1444 },
1445
1446 /**
1447 * @param {*} value
1448 */
1449 set: function(value) {
1450 storage.set(property, value);
1451 changedProperties.add(property);
1452 scheduleObserver();
Blink Reformat4c46d092018-04-07 15:32:371453 }
1454 });
1455 }
1456
Nikolay Vitkov42be2662023-01-12 15:32:351457 for (let i = 0; i < properties.length; ++i) {
1458 defineProperty(properties[i]);
Tim van der Lippe1d6e57a2019-09-30 11:55:341459 }
Joel Einbinderf55cc942018-10-30 01:59:531460 }
Blink Reformat4c46d092018-04-07 15:32:371461
Nikolay Vitkov42be2662023-01-12 15:32:351462 window.Object.observe = objectObserve;
1463}
1464
1465/** @type {!Map<number, string>} */
1466const staticKeyIdentifiers = new Map([
1467 [0x12, 'Alt'],
1468 [0x11, 'Control'],
1469 [0x10, 'Shift'],
1470 [0x14, 'CapsLock'],
1471 [0x5b, 'Win'],
1472 [0x5c, 'Win'],
1473 [0x0c, 'Clear'],
1474 [0x28, 'Down'],
1475 [0x23, 'End'],
1476 [0x0a, 'Enter'],
1477 [0x0d, 'Enter'],
1478 [0x2b, 'Execute'],
1479 [0x70, 'F1'],
1480 [0x71, 'F2'],
1481 [0x72, 'F3'],
1482 [0x73, 'F4'],
1483 [0x74, 'F5'],
1484 [0x75, 'F6'],
1485 [0x76, 'F7'],
1486 [0x77, 'F8'],
1487 [0x78, 'F9'],
1488 [0x79, 'F10'],
1489 [0x7a, 'F11'],
1490 [0x7b, 'F12'],
1491 [0x7c, 'F13'],
1492 [0x7d, 'F14'],
1493 [0x7e, 'F15'],
1494 [0x7f, 'F16'],
1495 [0x80, 'F17'],
1496 [0x81, 'F18'],
1497 [0x82, 'F19'],
1498 [0x83, 'F20'],
1499 [0x84, 'F21'],
1500 [0x85, 'F22'],
1501 [0x86, 'F23'],
1502 [0x87, 'F24'],
1503 [0x2f, 'Help'],
1504 [0x24, 'Home'],
1505 [0x2d, 'Insert'],
1506 [0x25, 'Left'],
1507 [0x22, 'PageDown'],
1508 [0x21, 'PageUp'],
1509 [0x13, 'Pause'],
1510 [0x2c, 'PrintScreen'],
1511 [0x27, 'Right'],
1512 [0x91, 'Scroll'],
1513 [0x29, 'Select'],
1514 [0x26, 'Up'],
1515 [0x2e, 'U+007F'], // Standard says that DEL becomes U+007F.
1516 [0xb0, 'MediaNextTrack'],
1517 [0xb1, 'MediaPreviousTrack'],
1518 [0xb2, 'MediaStop'],
1519 [0xb3, 'MediaPlayPause'],
1520 [0xad, 'VolumeMute'],
1521 [0xae, 'VolumeDown'],
1522 [0xaf, 'VolumeUp'],
1523]);
1524
1525/**
1526 * @param {number} keyCode
1527 * @return {string}
1528 */
1529function keyCodeToKeyIdentifier(keyCode) {
1530 let result = staticKeyIdentifiers.get(keyCode);
1531 if (result !== undefined) {
1532 return result;
1533 }
1534 result = 'U+';
1535 const hexString = keyCode.toString(16).toUpperCase();
1536 for (let i = hexString.length; i < 4; ++i) {
1537 result += '0';
1538 }
1539 result += hexString;
1540 return result;
1541}
1542
1543function installBackwardsCompatibility() {
1544 const majorVersion = getRemoteMajorVersion();
1545 if (!majorVersion) {
1546 return;
1547 }
1548
1549 /** @type {!Array<string>} */
1550 const styleRules = [];
1551 // Shadow DOM V0 polyfill
1552 if (majorVersion <= 73 && !Element.prototype.createShadowRoot) {
1553 Element.prototype.createShadowRoot = function() {
1554 try {
1555 return this.attachShadow({mode: 'open'});
Nikolay Vitkovb4e8dc72025-01-07 13:03:021556 } catch {
Nikolay Vitkov42be2662023-01-12 15:32:351557 // some elements we use to add shadow roots can no
1558 // longer have shadow roots.
1559 const fakeShadowHost = document.createElement('span');
1560 this.appendChild(fakeShadowHost);
1561 fakeShadowHost.className = 'fake-shadow-host';
1562 return fakeShadowHost.createShadowRoot();
Tim van der Lippe1d6e57a2019-09-30 11:55:341563 }
Nikolay Vitkov42be2662023-01-12 15:32:351564 };
1565
1566 const origAdd = DOMTokenList.prototype.add;
1567 DOMTokenList.prototype.add = function(...tokens) {
1568 if (tokens[0].startsWith('insertion-point') || tokens[0].startsWith('tabbed-pane-header')) {
1569 this._myElement.slot = '.' + tokens[0];
1570 }
1571 return origAdd.apply(this, tokens);
1572 };
1573
1574 const origCreateElement = Document.prototype.createElement;
1575 Document.prototype.createElement = function(tagName, ...rest) {
1576 if (tagName === 'content') {
1577 tagName = 'slot';
1578 }
1579 const element = origCreateElement.call(this, tagName, ...rest);
1580 element.classList._myElement = element;
1581 return element;
1582 };
1583
1584 Object.defineProperty(HTMLSlotElement.prototype, 'select', {
1585 set(selector) {
1586 this.name = selector;
1587 }
1588 });
Joel Einbinderf55cc942018-10-30 01:59:531589 }
1590
Nikolay Vitkov42be2662023-01-12 15:32:351591 // Custom Elements V0 polyfill
1592 if (majorVersion <= 73 && !Document.prototype.hasOwnProperty('registerElement')) {
1593 const fakeRegistry = new Map();
1594 Document.prototype.registerElement = function(typeExtension, options) {
1595 const {prototype, extends: localName} = options;
1596 const document = this;
1597 const callback = function() {
1598 const element = document.createElement(localName || typeExtension);
1599 const skip = new Set(['constructor', '__proto__']);
1600 for (const key of Object.keys(Object.getOwnPropertyDescriptors(prototype.__proto__ || {}))) {
1601 if (skip.has(key)) {
1602 continue;
1603 }
1604 element[key] = prototype[key];
1605 }
1606 element.setAttribute('is', typeExtension);
1607 if (element['createdCallback']) {
1608 element['createdCallback']();
1609 }
1610 return element;
1611 };
1612 fakeRegistry.set(typeExtension, callback);
1613 return callback;
1614 };
Joel Einbinderf55cc942018-10-30 01:59:531615
Nikolay Vitkov42be2662023-01-12 15:32:351616 const origCreateElement = Document.prototype.createElement;
1617 Document.prototype.createElement = function(tagName, fakeCustomElementType) {
1618 const fakeConstructor = fakeRegistry.get(fakeCustomElementType);
1619 if (fakeConstructor) {
1620 return fakeConstructor();
1621 }
1622 return origCreateElement.call(this, tagName, fakeCustomElementType);
1623 };
1624
1625 // DevTools front-ends mistakenly assume that
1626 // classList.toggle('a', undefined) works as
1627 // classList.toggle('a', false) rather than as
1628 // classList.toggle('a');
1629 const originalDOMTokenListToggle = DOMTokenList.prototype.toggle;
1630 DOMTokenList.prototype.toggle = function(token, force) {
1631 if (arguments.length === 1) {
1632 force = !this.contains(token);
1633 }
1634 return originalDOMTokenListToggle.call(this, token, Boolean(force));
Joel Einbinderf55cc942018-10-30 01:59:531635 };
1636 }
1637
Nikolay Vitkov42be2662023-01-12 15:32:351638 if (majorVersion <= 66) {
1639 /** @type {(!function(number, number):Element|undefined)} */
1640 ShadowRoot.prototype.__originalShadowRootElementFromPoint;
1641
1642 if (!ShadowRoot.prototype.__originalShadowRootElementFromPoint) {
1643 ShadowRoot.prototype.__originalShadowRootElementFromPoint = ShadowRoot.prototype.elementFromPoint;
1644 /**
1645 * @param {number} x
1646 * @param {number} y
1647 * @return {Element}
1648 */
1649 ShadowRoot.prototype.elementFromPoint = function(x, y) {
1650 const originalResult = ShadowRoot.prototype.__originalShadowRootElementFromPoint.apply(this, arguments);
1651 if (this.host && originalResult === this.host) {
1652 return null;
1653 }
1654 return originalResult;
1655 };
1656 }
Blink Reformat4c46d092018-04-07 15:32:371657 }
1658
Nikolay Vitkov42be2662023-01-12 15:32:351659 if (majorVersion <= 53) {
1660 Object.defineProperty(window.KeyboardEvent.prototype, 'keyIdentifier', {
1661 /**
1662 * @return {string}
1663 * @this {KeyboardEvent}
1664 */
1665 get: function() {
1666 return keyCodeToKeyIdentifier(this.keyCode);
1667 }
1668 });
1669 }
Blink Reformat4c46d092018-04-07 15:32:371670
Nikolay Vitkov42be2662023-01-12 15:32:351671 if (majorVersion <= 50) {
1672 installObjectObserve();
1673 }
1674
1675 if (majorVersion <= 71) {
1676 styleRules.push(
1677 '.coverage-toolbar-container, .animation-timeline-toolbar-container, .computed-properties { flex-basis: auto; }');
1678 }
1679
1680 if (majorVersion <= 50) {
1681 Event.prototype.deepPath = undefined;
1682 }
1683
1684 if (majorVersion <= 54) {
1685 window.FileError = /** @type {!function (new: FileError) : ?} */ ({
1686 NOT_FOUND_ERR: DOMException.NOT_FOUND_ERR,
1687 ABORT_ERR: DOMException.ABORT_ERR,
1688 INVALID_MODIFICATION_ERR: DOMException.INVALID_MODIFICATION_ERR,
1689 NOT_READABLE_ERR: 0 // No matching DOMException, so code will be 0.
1690 });
1691 }
1692
1693 installExtraStyleRules(styleRules);
1694}
1695
1696/**
1697 * @return {?number}
1698 */
1699function getRemoteMajorVersion() {
1700 try {
1701 const remoteVersion = new URLSearchParams(window.location.search).get('remoteVersion');
1702 if (!remoteVersion) {
1703 return null;
1704 }
1705 const majorVersion = parseInt(remoteVersion.split('.')[0], 10);
1706 return majorVersion;
Nikolay Vitkovb4e8dc72025-01-07 13:03:021707 } catch {
Nikolay Vitkov42be2662023-01-12 15:32:351708 return null;
1709 }
1710}
1711
1712/**
1713 * @param {!Array<string>} styleRules
1714 */
1715function installExtraStyleRules(styleRules) {
1716 if (!styleRules.length) {
1717 return;
1718 }
1719 const styleText = styleRules.join('\n');
1720 document.head.appendChild(createStyleElement(styleText));
1721
1722 const origCreateShadowRoot = HTMLElement.prototype.createShadowRoot;
1723 HTMLElement.prototype.createShadowRoot = function(...args) {
1724 const shadowRoot = origCreateShadowRoot.call(this, ...args);
1725 shadowRoot.appendChild(createStyleElement(styleText));
1726 return shadowRoot;
1727 };
1728}
1729
1730/**
1731 * @param {string} styleText
1732 * @return {!Element}
1733 */
1734function createStyleElement(styleText) {
1735 const style = document.createElement('style');
1736 style.textContent = styleText;
1737 return style;
1738}
1739
1740installBackwardsCompatibility();
Blink Reformat4c46d092018-04-07 15:32:371741})(window);