UNPKG

43.6 kBJavaScriptView Raw
1// 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.
4/* eslint-disable indent */
5(function(window) {
6
7 // DevToolsAPI ----------------------------------------------------------------
8
9 const DevToolsAPIImpl = class {
10 constructor() {
11 /**
12 * @type {number}
13 */
14 this._lastCallId = 0;
15
16 /**
17 * @type {!Object.<number, function(?Object)>}
18 */
19 this._callbacks = {};
20
21 /**
22 * @type {!Array.<!ExtensionDescriptor>}
23 */
24 this._pendingExtensionDescriptors = [];
25
26 /**
27 * @type {?function(!ExtensionDescriptor)}
28 */
29 this._addExtensionCallback = null;
30
31 /**
32 * @type {!Promise<string>}
33 */
34 this._initialTargetIdPromise = new Promise(resolve => {
35 this._setInitialTargetId = resolve;
36 });
37 }
38
39 /**
40 * @param {number} id
41 * @param {?Object} arg
42 */
43 embedderMessageAck(id, arg) {
44 const callback = this._callbacks[id];
45 delete this._callbacks[id];
46 if (callback) {
47 callback(arg);
48 }
49 }
50
51 /**
52 * @param {string} method
53 * @param {!Array.<*>} args
54 * @param {?function(?Object)} callback
55 */
56 sendMessageToEmbedder(method, args, callback) {
57 const callId = ++this._lastCallId;
58 if (callback) {
59 this._callbacks[callId] = callback;
60 }
61 const message = {'id': callId, 'method': method};
62 if (args.length) {
63 message.params = args;
64 }
65 DevToolsHost.sendMessageToEmbedder(JSON.stringify(message));
66 }
67
68 /**
69 * @param {string} method
70 * @param {!Array<*>} args
71 */
72 _dispatchOnInspectorFrontendAPI(method, args) {
73 const inspectorFrontendAPI = /** @type {!Object<string, function()>} */ (window['InspectorFrontendAPI']);
74 inspectorFrontendAPI[method].apply(inspectorFrontendAPI, args);
75 }
76
77 // API methods below this line --------------------------------------------
78
79 /**
80 * @param {!Array.<!ExtensionDescriptor>} extensions
81 */
82 addExtensions(extensions) {
83 // Support for legacy front-ends (<M41).
84 if (window['WebInspector'] && window['WebInspector']['addExtensions']) {
85 window['WebInspector']['addExtensions'](extensions);
86 } else {
87 // The addExtensions command is sent as the onload event happens for
88 // DevTools front-end. We should buffer this command until the frontend
89 // is ready for it.
90 if (this._addExtensionCallback) {
91 extensions.forEach(this._addExtensionCallback);
92 } else {
93 this._pendingExtensionDescriptors.push(...extensions);
94 }
95 }
96 }
97
98 /**
99 * @param {string} url
100 */
101 appendedToURL(url) {
102 this._dispatchOnInspectorFrontendAPI('appendedToURL', [url]);
103 }
104
105 /**
106 * @param {string} url
107 */
108 canceledSaveURL(url) {
109 this._dispatchOnInspectorFrontendAPI('canceledSaveURL', [url]);
110 }
111
112 contextMenuCleared() {
113 this._dispatchOnInspectorFrontendAPI('contextMenuCleared', []);
114 }
115
116 /**
117 * @param {string} id
118 */
119 contextMenuItemSelected(id) {
120 this._dispatchOnInspectorFrontendAPI('contextMenuItemSelected', [id]);
121 }
122
123 /**
124 * @param {number} count
125 */
126 deviceCountUpdated(count) {
127 this._dispatchOnInspectorFrontendAPI('deviceCountUpdated', [count]);
128 }
129
130 /**
131 * @param {!Adb.Config} config
132 */
133 devicesDiscoveryConfigChanged(config) {
134 this._dispatchOnInspectorFrontendAPI('devicesDiscoveryConfigChanged', [config]);
135 }
136
137 /**
138 * @param {!Adb.PortForwardingStatus} status
139 */
140 devicesPortForwardingStatusChanged(status) {
141 this._dispatchOnInspectorFrontendAPI('devicesPortForwardingStatusChanged', [status]);
142 }
143
144 /**
145 * @param {!Array.<!Adb.Device>} devices
146 */
147 devicesUpdated(devices) {
148 this._dispatchOnInspectorFrontendAPI('devicesUpdated', [devices]);
149 }
150
151 /**
152 * @param {string} message
153 */
154 dispatchMessage(message) {
155 this._dispatchOnInspectorFrontendAPI('dispatchMessage', [message]);
156 }
157
158 /**
159 * @param {string} messageChunk
160 * @param {number} messageSize
161 */
162 dispatchMessageChunk(messageChunk, messageSize) {
163 this._dispatchOnInspectorFrontendAPI('dispatchMessageChunk', [messageChunk, messageSize]);
164 }
165
166 enterInspectElementMode() {
167 this._dispatchOnInspectorFrontendAPI('enterInspectElementMode', []);
168 }
169
170 /**
171 * @param {!{r: number, g: number, b: number, a: number}} color
172 */
173 eyeDropperPickedColor(color) {
174 this._dispatchOnInspectorFrontendAPI('eyeDropperPickedColor', [color]);
175 }
176
177 /**
178 * @param {!Array.<!{fileSystemName: string, rootURL: string, fileSystemPath: string}>} fileSystems
179 */
180 fileSystemsLoaded(fileSystems) {
181 this._dispatchOnInspectorFrontendAPI('fileSystemsLoaded', [fileSystems]);
182 }
183
184 /**
185 * @param {string} fileSystemPath
186 */
187 fileSystemRemoved(fileSystemPath) {
188 this._dispatchOnInspectorFrontendAPI('fileSystemRemoved', [fileSystemPath]);
189 }
190
191 /**
192 * @param {?string} error
193 * @param {?{type: string, fileSystemName: string, rootURL: string, fileSystemPath: string}} fileSystem
194 */
195 fileSystemAdded(error, fileSystem) {
196 this._dispatchOnInspectorFrontendAPI('fileSystemAdded', [error, fileSystem]);
197 }
198
199 /**
200 * @param {!Array<string>} changedPaths
201 * @param {!Array<string>} addedPaths
202 * @param {!Array<string>} removedPaths
203 */
204 fileSystemFilesChangedAddedRemoved(changedPaths, addedPaths, removedPaths) {
205 // Support for legacy front-ends (<M58)
206 if (window['InspectorFrontendAPI'] && window['InspectorFrontendAPI']['fileSystemFilesChanged']) {
207 this._dispatchOnInspectorFrontendAPI(
208 'fileSystemFilesChanged', [changedPaths.concat(addedPaths).concat(removedPaths)]);
209 } else {
210 this._dispatchOnInspectorFrontendAPI(
211 'fileSystemFilesChangedAddedRemoved', [changedPaths, addedPaths, removedPaths]);
212 }
213 }
214
215 /**
216 * @param {number} requestId
217 * @param {string} fileSystemPath
218 * @param {number} totalWork
219 */
220 indexingTotalWorkCalculated(requestId, fileSystemPath, totalWork) {
221 this._dispatchOnInspectorFrontendAPI('indexingTotalWorkCalculated', [requestId, fileSystemPath, totalWork]);
222 }
223
224 /**
225 * @param {number} requestId
226 * @param {string} fileSystemPath
227 * @param {number} worked
228 */
229 indexingWorked(requestId, fileSystemPath, worked) {
230 this._dispatchOnInspectorFrontendAPI('indexingWorked', [requestId, fileSystemPath, worked]);
231 }
232
233 /**
234 * @param {number} requestId
235 * @param {string} fileSystemPath
236 */
237 indexingDone(requestId, fileSystemPath) {
238 this._dispatchOnInspectorFrontendAPI('indexingDone', [requestId, fileSystemPath]);
239 }
240
241 /**
242 * @param {{type: string, key: string, code: string, keyCode: number, modifiers: number}} event
243 */
244 keyEventUnhandled(event) {
245 event.keyIdentifier = keyCodeToKeyIdentifier(event.keyCode);
246 this._dispatchOnInspectorFrontendAPI('keyEventUnhandled', [event]);
247 }
248
249 /**
250 * @param {function(!ExtensionDescriptor)} callback
251 */
252 setAddExtensionCallback(callback) {
253 this._addExtensionCallback = callback;
254 if (this._pendingExtensionDescriptors.length) {
255 this._pendingExtensionDescriptors.forEach(this._addExtensionCallback);
256 this._pendingExtensionDescriptors = [];
257 }
258 }
259
260 reattachMainTarget() {
261 this._dispatchOnInspectorFrontendAPI('reattachMainTarget', []);
262 }
263
264 /**
265 * @param {boolean} hard
266 */
267 reloadInspectedPage(hard) {
268 this._dispatchOnInspectorFrontendAPI('reloadInspectedPage', [hard]);
269 }
270
271 /**
272 * @param {string} url
273 * @param {number} lineNumber
274 * @param {number} columnNumber
275 */
276 revealSourceLine(url, lineNumber, columnNumber) {
277 this._dispatchOnInspectorFrontendAPI('revealSourceLine', [url, lineNumber, columnNumber]);
278 }
279
280 /**
281 * @param {string} url
282 * @param {string=} fileSystemPath
283 */
284 savedURL(url, fileSystemPath) {
285 this._dispatchOnInspectorFrontendAPI('savedURL', [url, fileSystemPath]);
286 }
287
288 /**
289 * @param {number} requestId
290 * @param {string} fileSystemPath
291 * @param {!Array.<string>} files
292 */
293 searchCompleted(requestId, fileSystemPath, files) {
294 this._dispatchOnInspectorFrontendAPI('searchCompleted', [requestId, fileSystemPath, files]);
295 }
296
297 /**
298 * @param {string} tabId
299 */
300 setInspectedTabId(tabId) {
301 this._inspectedTabIdValue = tabId;
302
303 // Support for legacy front-ends (<M41).
304 if (window['WebInspector'] && window['WebInspector']['setInspectedTabId']) {
305 window['WebInspector']['setInspectedTabId'](tabId);
306 } else {
307 this._dispatchOnInspectorFrontendAPI('setInspectedTabId', [tabId]);
308 }
309 }
310
311 /**
312 * @param {string} targetId
313 */
314 setInitialTargetId(targetId) {
315 this._setInitialTargetId(targetId);
316 }
317
318 /**
319 * @return {string|undefined}
320 */
321 getInspectedTabId() {
322 return this._inspectedTabIdValue;
323 }
324
325 /**
326 * @param {boolean} useSoftMenu
327 */
328 setUseSoftMenu(useSoftMenu) {
329 this._dispatchOnInspectorFrontendAPI('setUseSoftMenu', [useSoftMenu]);
330 }
331
332 /**
333 * @param {string} panelName
334 */
335 showPanel(panelName) {
336 this._dispatchOnInspectorFrontendAPI('showPanel', [panelName]);
337 }
338
339 /**
340 * @param {number} id
341 * @param {string} chunk
342 * @param {boolean} encoded
343 */
344 streamWrite(id, chunk, encoded) {
345 this._dispatchOnInspectorFrontendAPI('streamWrite', [id, encoded ? this._decodeBase64(chunk) : chunk]);
346 }
347
348 /**
349 * @param {string} chunk
350 * @return {string}
351 */
352 _decodeBase64(chunk) {
353 const request = new XMLHttpRequest();
354 request.open('GET', 'data:text/plain;base64,' + chunk, false);
355 request.send(null);
356 if (request.status === 200) {
357 return request.responseText;
358 }
359 console.error('Error while decoding chunk in streamWrite');
360 return '';
361 }
362 };
363
364 const DevToolsAPI = new DevToolsAPIImpl();
365 window.DevToolsAPI = DevToolsAPI;
366
367 // InspectorFrontendHostImpl --------------------------------------------------
368
369 /**
370 * Enum for recordPerformanceHistogram
371 * Warning: There is another definition of this enum in the DevTools code
372 * base, keep them in sync:
373 * front_end/core/host/InspectorFrontendHostAPI.ts
374 * @readonly
375 * @enum {string}
376 */
377 const EnumeratedHistogram = {
378 ActionTaken: 'DevTools.ActionTaken',
379 PanelClosed: 'DevTools.PanelClosed',
380 PanelShown: 'DevTools.PanelShown',
381 SidebarPaneShown: 'DevTools.SidebarPaneShown',
382 KeyboardShortcutFired: 'DevTools.KeyboardShortcutFired',
383 IssueCreated: 'DevTools.IssueCreated',
384 IssuesPanelIssueExpanded: 'DevTools.IssuesPanelIssueExpanded',
385 IssuesPanelOpenedFrom: 'DevTools.IssuesPanelOpenedFrom',
386 IssuesPanelResourceOpened: 'DevTools.IssuesPanelResourceOpened',
387 KeybindSetSettingChanged: 'DevTools.KeybindSetSettingChanged',
388 DualScreenDeviceEmulated: 'DevTools.DualScreenDeviceEmulated',
389 ExperimentEnabledAtLaunch: 'DevTools.ExperimentEnabledAtLaunch',
390 ExperimentEnabled: 'DevTools.ExperimentEnabled',
391 ExperimentDisabled: 'DevTools.ExperimentDisabled',
392 DeveloperResourceLoaded: 'DevTools.DeveloperResourceLoaded',
393 DeveloperResourceScheme: 'DevTools.DeveloperResourceScheme',
394 LinearMemoryInspectorRevealedFrom: 'DevTools.LinearMemoryInspector.RevealedFrom',
395 LinearMemoryInspectorTarget: 'DevTools.LinearMemoryInspector.Target',
396 Language: 'DevTools.Language',
397 ConsoleShowsCorsErrors: 'DevTools.ConsoleShowsCorsErrors',
398 RecordingEdited: 'DevTools.RecordingEdited',
399 RecordingExported: 'DevTools.RecordingExported',
400 RecordingReplayFinished: 'DevTools.RecordingReplayFinished',
401 RecordingReplayStarted: 'DevTools.RecordingReplayStarted',
402 RecordingToggled: 'DevTools.RecordingToggled',
403 SyncSetting: 'DevTools.SyncSetting',
404 };
405
406 /**
407 * @implements {InspectorFrontendHostAPI}
408 */
409 const InspectorFrontendHostImpl = class {
410 /**
411 * @return {string}
412 */
413 getSelectionBackgroundColor() {
414 return '#6e86ff';
415 }
416
417 /**
418 * @return {string}
419 */
420 getSelectionForegroundColor() {
421 return '#ffffff';
422 }
423
424 /**
425 * @return {string}
426 */
427 getInactiveSelectionBackgroundColor() {
428 return '#c9c8c8';
429 }
430
431 /**
432 * @return {string}
433 */
434 getInactiveSelectionForegroundColor() {
435 return '#323232';
436 }
437
438 /**
439 * @override
440 * @return {string}
441 */
442 platform() {
443 return DevToolsHost.platform();
444 }
445
446 /**
447 * @override
448 */
449 loadCompleted() {
450 DevToolsAPI.sendMessageToEmbedder('loadCompleted', [], null);
451 // Support for legacy (<57) frontends.
452 if (window.Runtime && window.Runtime.queryParam) {
453 const panelToOpen = window.Runtime.queryParam('panel');
454 if (panelToOpen) {
455 window.DevToolsAPI.showPanel(panelToOpen);
456 }
457 }
458 }
459
460 /**
461 * @override
462 */
463 bringToFront() {
464 DevToolsAPI.sendMessageToEmbedder('bringToFront', [], null);
465 }
466
467 /**
468 * @override
469 */
470 closeWindow() {
471 DevToolsAPI.sendMessageToEmbedder('closeWindow', [], null);
472 }
473
474 /**
475 * @override
476 * @param {boolean} isDocked
477 * @param {function()} callback
478 */
479 setIsDocked(isDocked, callback) {
480 DevToolsAPI.sendMessageToEmbedder('setIsDocked', [isDocked], callback);
481 }
482
483 /**
484 * @override
485 * @param {string} trigger
486 * @param {function(!InspectorFrontendHostAPI.ShowSurveyResult): void} callback
487 */
488 showSurvey(trigger, callback) {
489 DevToolsAPI.sendMessageToEmbedder('showSurvey', [trigger], /** @type {function(?Object)} */ (callback));
490 }
491
492 /**
493 * @override
494 * @param {string} trigger
495 * @param {function(!InspectorFrontendHostAPI.CanShowSurveyResult): void} callback
496 */
497 canShowSurvey(trigger, callback) {
498 DevToolsAPI.sendMessageToEmbedder('canShowSurvey', [trigger], /** @type {function(?Object)} */ (callback));
499 }
500
501 /**
502 * Requests inspected page to be placed atop of the inspector frontend with specified bounds.
503 * @override
504 * @param {{x: number, y: number, width: number, height: number}} bounds
505 */
506 setInspectedPageBounds(bounds) {
507 DevToolsAPI.sendMessageToEmbedder('setInspectedPageBounds', [bounds], null);
508 }
509
510 /**
511 * @override
512 */
513 inspectElementCompleted() {
514 DevToolsAPI.sendMessageToEmbedder('inspectElementCompleted', [], null);
515 }
516
517 /**
518 * @override
519 * @param {string} url
520 * @param {string} headers
521 * @param {number} streamId
522 * @param {function(!InspectorFrontendHostAPI.LoadNetworkResourceResult): void} callback
523 */
524 loadNetworkResource(url, headers, streamId, callback) {
525 DevToolsAPI.sendMessageToEmbedder(
526 'loadNetworkResource', [url, headers, streamId], /** @type {function(?Object)} */ (callback));
527 }
528
529 /**
530 * @override
531 * @param {string} name
532 * @param {!{synced: (boolean|undefined)}} options
533 */
534 registerPreference(name, options) {
535 DevToolsAPI.sendMessageToEmbedder('registerPreference', [name, options], null);
536 }
537
538 /**
539 * @override
540 * @param {function(!Object<string, string>)} callback
541 */
542 getPreferences(callback) {
543 DevToolsAPI.sendMessageToEmbedder('getPreferences', [], /** @type {function(?Object)} */ (callback));
544 }
545
546 /**
547 * @override
548 * @param {string} name
549 * @param {string} value
550 */
551 setPreference(name, value) {
552 DevToolsAPI.sendMessageToEmbedder('setPreference', [name, value], null);
553 }
554
555 /**
556 * @override
557 * @param {string} name
558 */
559 removePreference(name) {
560 DevToolsAPI.sendMessageToEmbedder('removePreference', [name], null);
561 }
562
563 /**
564 * @override
565 */
566 clearPreferences() {
567 DevToolsAPI.sendMessageToEmbedder('clearPreferences', [], null);
568 }
569
570 /**
571 * @override
572 * @param {!function(!InspectorFrontendHostAPI.SyncInformation):void} callback
573 */
574 getSyncInformation(callback) {
575 DevToolsAPI.sendMessageToEmbedder('getSyncInformation', [], callback);
576 }
577
578 /**
579 * @override
580 * @param {string} origin
581 * @param {string} script
582 */
583 setInjectedScriptForOrigin(origin, script) {
584 DevToolsAPI.sendMessageToEmbedder('registerExtensionsAPI', [origin, script], null);
585 }
586
587 /**
588 * @override
589 * @param {string} url
590 */
591 inspectedURLChanged(url) {
592 DevToolsAPI.sendMessageToEmbedder('inspectedURLChanged', [url], null);
593 }
594
595 /**
596 * @override
597 * @param {string} text
598 */
599 copyText(text) {
600 DevToolsHost.copyText(text);
601 }
602
603 /**
604 * @override
605 * @param {string} url
606 */
607 openInNewTab(url) {
608 DevToolsAPI.sendMessageToEmbedder('openInNewTab', [url], null);
609 }
610
611 /**
612 * @override
613 * @param {string} fileSystemPath
614 */
615 showItemInFolder(fileSystemPath) {
616 DevToolsAPI.sendMessageToEmbedder('showItemInFolder', [fileSystemPath], null);
617 }
618
619 /**
620 * @override
621 * @param {string} url
622 * @param {string} content
623 * @param {boolean} forceSaveAs
624 */
625 save(url, content, forceSaveAs) {
626 DevToolsAPI.sendMessageToEmbedder('save', [url, content, forceSaveAs], null);
627 }
628
629 /**
630 * @override
631 * @param {string} url
632 * @param {string} content
633 */
634 append(url, content) {
635 DevToolsAPI.sendMessageToEmbedder('append', [url, content], null);
636 }
637
638 /**
639 * @override
640 * @param {string} url
641 */
642 close(url) {
643 }
644
645 /**
646 * @override
647 * @param {string} message
648 */
649 sendMessageToBackend(message) {
650 DevToolsAPI.sendMessageToEmbedder('dispatchProtocolMessage', [message], null);
651 }
652
653 /**
654 * @override
655 * @param {!InspectorFrontendHostAPI.EnumeratedHistogram} actionName
656 * @param {number} actionCode
657 * @param {number} bucketSize
658 */
659 recordEnumeratedHistogram(actionName, actionCode, bucketSize) {
660 if (!Object.values(EnumeratedHistogram).includes(actionName)) {
661 return;
662 }
663 DevToolsAPI.sendMessageToEmbedder('recordEnumeratedHistogram', [actionName, actionCode, bucketSize], null);
664 }
665
666 /**
667 * @override
668 * @param {string} histogramName
669 * @param {number} duration
670 */
671 recordPerformanceHistogram(histogramName, duration) {
672 DevToolsAPI.sendMessageToEmbedder('recordPerformanceHistogram', [histogramName, duration], null);
673 }
674
675 /**
676 * @override
677 * @param {string} umaName
678 */
679 recordUserMetricsAction(umaName) {
680 DevToolsAPI.sendMessageToEmbedder('recordUserMetricsAction', [umaName], null);
681 }
682
683 /**
684 * @override
685 */
686 requestFileSystems() {
687 DevToolsAPI.sendMessageToEmbedder('requestFileSystems', [], null);
688 }
689
690 /**
691 * @override
692 * @param {string=} type
693 */
694 addFileSystem(type) {
695 DevToolsAPI.sendMessageToEmbedder('addFileSystem', [type || ''], null);
696 }
697
698 /**
699 * @override
700 * @param {string} fileSystemPath
701 */
702 removeFileSystem(fileSystemPath) {
703 DevToolsAPI.sendMessageToEmbedder('removeFileSystem', [fileSystemPath], null);
704 }
705
706 /**
707 * @override
708 * @param {string} fileSystemId
709 * @param {string} registeredName
710 * @return {?FileSystem}
711 */
712 isolatedFileSystem(fileSystemId, registeredName) {
713 return DevToolsHost.isolatedFileSystem(fileSystemId, registeredName);
714 }
715
716 /**
717 * @override
718 * @param {!FileSystem} fileSystem
719 */
720 upgradeDraggedFileSystemPermissions(fileSystem) {
721 DevToolsHost.upgradeDraggedFileSystemPermissions(fileSystem);
722 }
723
724 /**
725 * @override
726 * @param {number} requestId
727 * @param {string} fileSystemPath
728 * @param {string} excludedFolders
729 */
730 indexPath(requestId, fileSystemPath, excludedFolders) {
731 // |excludedFolders| added in M67. For backward compatibility,
732 // pass empty array.
733 excludedFolders = excludedFolders || '[]';
734 DevToolsAPI.sendMessageToEmbedder('indexPath', [requestId, fileSystemPath, excludedFolders], null);
735 }
736
737 /**
738 * @override
739 * @param {number} requestId
740 */
741 stopIndexing(requestId) {
742 DevToolsAPI.sendMessageToEmbedder('stopIndexing', [requestId], null);
743 }
744
745 /**
746 * @override
747 * @param {number} requestId
748 * @param {string} fileSystemPath
749 * @param {string} query
750 */
751 searchInPath(requestId, fileSystemPath, query) {
752 DevToolsAPI.sendMessageToEmbedder('searchInPath', [requestId, fileSystemPath, query], null);
753 }
754
755 /**
756 * @override
757 * @return {number}
758 */
759 zoomFactor() {
760 return DevToolsHost.zoomFactor();
761 }
762
763 /**
764 * @override
765 */
766 zoomIn() {
767 DevToolsAPI.sendMessageToEmbedder('zoomIn', [], null);
768 }
769
770 /**
771 * @override
772 */
773 zoomOut() {
774 DevToolsAPI.sendMessageToEmbedder('zoomOut', [], null);
775 }
776
777 /**
778 * @override
779 */
780 resetZoom() {
781 DevToolsAPI.sendMessageToEmbedder('resetZoom', [], null);
782 }
783
784 /**
785 * @override
786 * @param {string} shortcuts
787 */
788 setWhitelistedShortcuts(shortcuts) {
789 DevToolsAPI.sendMessageToEmbedder('setWhitelistedShortcuts', [shortcuts], null);
790 }
791
792 /**
793 * @override
794 * @param {boolean} active
795 */
796 setEyeDropperActive(active) {
797 DevToolsAPI.sendMessageToEmbedder('setEyeDropperActive', [active], null);
798 }
799
800 /**
801 * @override
802 * @param {!Array<string>} certChain
803 */
804 showCertificateViewer(certChain) {
805 DevToolsAPI.sendMessageToEmbedder('showCertificateViewer', [JSON.stringify(certChain)], null);
806 }
807
808 /**
809 * Only needed to run Lighthouse on old devtools.
810 * @override
811 * @param {function()} callback
812 */
813 reattach(callback) {
814 DevToolsAPI.sendMessageToEmbedder('reattach', [], callback);
815 }
816
817 /**
818 * @override
819 */
820 readyForTest() {
821 DevToolsAPI.sendMessageToEmbedder('readyForTest', [], null);
822 }
823
824 /**
825 * @override
826 */
827 connectionReady() {
828 DevToolsAPI.sendMessageToEmbedder('connectionReady', [], null);
829 }
830
831 /**
832 * @override
833 * @param {boolean} value
834 */
835 setOpenNewWindowForPopups(value) {
836 DevToolsAPI.sendMessageToEmbedder('setOpenNewWindowForPopups', [value], null);
837 }
838
839 /**
840 * @override
841 * @param {!Adb.Config} config
842 */
843 setDevicesDiscoveryConfig(config) {
844 DevToolsAPI.sendMessageToEmbedder(
845 'setDevicesDiscoveryConfig',
846 [
847 config.discoverUsbDevices, config.portForwardingEnabled, JSON.stringify(config.portForwardingConfig),
848 config.networkDiscoveryEnabled, JSON.stringify(config.networkDiscoveryConfig)
849 ],
850 null);
851 }
852
853 /**
854 * @override
855 * @param {boolean} enabled
856 */
857 setDevicesUpdatesEnabled(enabled) {
858 DevToolsAPI.sendMessageToEmbedder('setDevicesUpdatesEnabled', [enabled], null);
859 }
860
861 /**
862 * @override
863 * @param {string} pageId
864 * @param {string} action
865 */
866 performActionOnRemotePage(pageId, action) {
867 DevToolsAPI.sendMessageToEmbedder('performActionOnRemotePage', [pageId, action], null);
868 }
869
870 /**
871 * @override
872 * @param {string} browserId
873 * @param {string} url
874 */
875 openRemotePage(browserId, url) {
876 DevToolsAPI.sendMessageToEmbedder('openRemotePage', [browserId, url], null);
877 }
878
879 /**
880 * @override
881 */
882 openNodeFrontend() {
883 DevToolsAPI.sendMessageToEmbedder('openNodeFrontend', [], null);
884 }
885
886 /**
887 * @override
888 * @param {number} x
889 * @param {number} y
890 * @param {!Array.<!InspectorFrontendHostAPI.ContextMenuDescriptor>} items
891 * @param {!Document} document
892 */
893 showContextMenuAtPoint(x, y, items, document) {
894 DevToolsHost.showContextMenuAtPoint(x, y, items, document);
895 }
896
897 /**
898 * @override
899 * @return {boolean}
900 */
901 isHostedMode() {
902 return DevToolsHost.isHostedMode();
903 }
904
905 /**
906 * @override
907 * @param {function(!ExtensionDescriptor)} callback
908 */
909 setAddExtensionCallback(callback) {
910 DevToolsAPI.setAddExtensionCallback(callback);
911 }
912
913 // Backward-compatible methods below this line --------------------------------------------
914
915 /**
916 * Support for legacy front-ends (<M65).
917 * @return {boolean}
918 */
919 isUnderTest() {
920 return false;
921 }
922
923 /**
924 * Support for legacy front-ends (<M50).
925 * @param {string} message
926 */
927 sendFrontendAPINotification(message) {
928 }
929
930 /**
931 * Support for legacy front-ends (<M41).
932 * @return {string}
933 */
934 port() {
935 return 'unknown';
936 }
937
938 /**
939 * Support for legacy front-ends (<M38).
940 * @param {number} zoomFactor
941 */
942 setZoomFactor(zoomFactor) {
943 }
944
945 /**
946 * Support for legacy front-ends (<M34).
947 */
948 sendMessageToEmbedder() {
949 }
950
951 /**
952 * Support for legacy front-ends (<M34).
953 * @param {string} dockSide
954 */
955 requestSetDockSide(dockSide) {
956 DevToolsAPI.sendMessageToEmbedder('setIsDocked', [dockSide !== 'undocked'], null);
957 }
958
959 /**
960 * Support for legacy front-ends (<M34).
961 * @return {boolean}
962 */
963 supportsFileSystems() {
964 return true;
965 }
966
967 /**
968 * Support for legacy front-ends (<M44).
969 * @param {number} actionCode
970 */
971 recordActionTaken(actionCode) {
972 // Do not record actions, as that may crash the DevTools renderer.
973 }
974
975 /**
976 * Support for legacy front-ends (<M44).
977 * @param {number} panelCode
978 */
979 recordPanelShown(panelCode) {
980 // Do not record actions, as that may crash the DevTools renderer.
981 }
982
983 /**
984 * @return {!Promise<string>}
985 */
986 initialTargetId() {
987 return DevToolsAPI._initialTargetIdPromise;
988 }
989 };
990
991 window.InspectorFrontendHost = new InspectorFrontendHostImpl();
992
993 // DevToolsApp ---------------------------------------------------------------
994
995 function installObjectObserve() {
996 /** @type {!Array<string>} */
997 const properties = [
998 'advancedSearchConfig',
999 'auditsPanelSplitViewState',
1000 'auditsSidebarWidth',
1001 'blockedURLs',
1002 'breakpoints',
1003 'cacheDisabled',
1004 'colorFormat',
1005 'consoleHistory',
1006 'consoleTimestampsEnabled',
1007 'cpuProfilerView',
1008 'cssSourceMapsEnabled',
1009 'currentDockState',
1010 'customColorPalette',
1011 'customDevicePresets',
1012 'customEmulatedDeviceList',
1013 'customFormatters',
1014 'customUserAgent',
1015 'databaseTableViewVisibleColumns',
1016 'dataGrid-cookiesTable',
1017 'dataGrid-DOMStorageItemsView',
1018 'debuggerSidebarHidden',
1019 'disablePausedStateOverlay',
1020 'domBreakpoints',
1021 'domWordWrap',
1022 'elementsPanelSplitViewState',
1023 'elementsSidebarWidth',
1024 'emulation.deviceHeight',
1025 'emulation.deviceModeValue',
1026 'emulation.deviceOrientationOverride',
1027 'emulation.deviceScale',
1028 'emulation.deviceScaleFactor',
1029 'emulation.deviceUA',
1030 'emulation.deviceWidth',
1031 'emulation.locationOverride',
1032 'emulation.showDeviceMode',
1033 'emulation.showRulers',
1034 'enableAsyncStackTraces',
1035 'eventListenerBreakpoints',
1036 'fileMappingEntries',
1037 'fileSystemMapping',
1038 'FileSystemViewSidebarWidth',
1039 'fileSystemViewSplitViewState',
1040 'filterBar-consoleView',
1041 'filterBar-networkPanel',
1042 'filterBar-promisePane',
1043 'filterBar-timelinePanel',
1044 'frameViewerHideChromeWindow',
1045 'heapSnapshotRetainersViewSize',
1046 'heapSnapshotSplitViewState',
1047 'hideCollectedPromises',
1048 'hideNetworkMessages',
1049 'highlightNodeOnHoverInOverlay',
1050 'inlineVariableValues',
1051 'Inspector.drawerSplitView',
1052 'Inspector.drawerSplitViewState',
1053 'InspectorView.panelOrder',
1054 'InspectorView.screencastSplitView',
1055 'InspectorView.screencastSplitViewState',
1056 'InspectorView.splitView',
1057 'InspectorView.splitViewState',
1058 'javaScriptDisabled',
1059 'jsSourceMapsEnabled',
1060 'lastActivePanel',
1061 'lastDockState',
1062 'lastSelectedSourcesSidebarPaneTab',
1063 'lastSnippetEvaluationIndex',
1064 'layerDetailsSplitView',
1065 'layerDetailsSplitViewState',
1066 'layersPanelSplitViewState',
1067 'layersShowInternalLayers',
1068 'layersSidebarWidth',
1069 'messageLevelFilters',
1070 'messageURLFilters',
1071 'monitoringXHREnabled',
1072 'navigatorGroupByFolder',
1073 'navigatorHidden',
1074 'networkColorCodeResourceTypes',
1075 'networkConditions',
1076 'networkConditionsCustomProfiles',
1077 'networkHideDataURL',
1078 'networkLogColumnsVisibility',
1079 'networkLogLargeRows',
1080 'networkLogShowOverview',
1081 'networkPanelSplitViewState',
1082 'networkRecordFilmStripSetting',
1083 'networkResourceTypeFilters',
1084 'networkShowPrimaryLoadWaterfall',
1085 'networkSidebarWidth',
1086 'openLinkHandler',
1087 'pauseOnCaughtException',
1088 'pauseOnExceptionEnabled',
1089 'preserveConsoleLog',
1090 'prettyPrintInfobarDisabled',
1091 'previouslyViewedFiles',
1092 'profilesPanelSplitViewState',
1093 'profilesSidebarWidth',
1094 'promiseStatusFilters',
1095 'recordAllocationStacks',
1096 'requestHeaderFilterSetting',
1097 'request-info-formData-category-expanded',
1098 'request-info-general-category-expanded',
1099 'request-info-queryString-category-expanded',
1100 'request-info-requestHeaders-category-expanded',
1101 'request-info-requestPayload-category-expanded',
1102 'request-info-responseHeaders-category-expanded',
1103 'resources',
1104 'resourcesLastSelectedItem',
1105 'resourcesPanelSplitViewState',
1106 'resourcesSidebarWidth',
1107 'resourceViewTab',
1108 'savedURLs',
1109 'screencastEnabled',
1110 'scriptsPanelNavigatorSidebarWidth',
1111 'searchInContentScripts',
1112 'selectedAuditCategories',
1113 'selectedColorPalette',
1114 'selectedProfileType',
1115 'shortcutPanelSwitch',
1116 'showAdvancedHeapSnapshotProperties',
1117 'showEventListenersForAncestors',
1118 'showFrameowkrListeners',
1119 'showHeaSnapshotObjectsHiddenProperties',
1120 'showInheritedComputedStyleProperties',
1121 'showMediaQueryInspector',
1122 'showNativeFunctionsInJSProfile',
1123 'showUAShadowDOM',
1124 'showWhitespacesInEditor',
1125 'sidebarPosition',
1126 'skipContentScripts',
1127 'skipStackFramesPattern',
1128 'sourceMapInfobarDisabled',
1129 'sourcesPanelDebuggerSidebarSplitViewState',
1130 'sourcesPanelNavigatorSplitViewState',
1131 'sourcesPanelSplitSidebarRatio',
1132 'sourcesPanelSplitViewState',
1133 'sourcesSidebarWidth',
1134 'standardEmulatedDeviceList',
1135 'StylesPaneSplitRatio',
1136 'stylesPaneSplitViewState',
1137 'textEditorAutocompletion',
1138 'textEditorAutoDetectIndent',
1139 'textEditorBracketMatching',
1140 'textEditorIndent',
1141 'textEditorTabMovesFocus',
1142 'timelineCaptureFilmStrip',
1143 'timelineCaptureLayersAndPictures',
1144 'timelineCaptureMemory',
1145 'timelineCaptureNetwork',
1146 'timeline-details',
1147 'timelineEnableJSSampling',
1148 'timelineOverviewMode',
1149 'timelinePanelDetailsSplitViewState',
1150 'timelinePanelRecorsSplitViewState',
1151 'timelinePanelTimelineStackSplitViewState',
1152 'timelinePerspective',
1153 'timeline-split',
1154 'timelineTreeGroupBy',
1155 'timeline-view',
1156 'timelineViewMode',
1157 'uiTheme',
1158 'watchExpressions',
1159 'WebInspector.Drawer.lastSelectedView',
1160 'WebInspector.Drawer.showOnLoad',
1161 'workspaceExcludedFolders',
1162 'workspaceFolderExcludePattern',
1163 'workspaceInfobarDisabled',
1164 'workspaceMappingInfobarDisabled',
1165 'xhrBreakpoints'
1166 ];
1167
1168 /**
1169 * @this {!{_storage: Object, _name: string}}
1170 */
1171 function settingRemove() {
1172 this._storage[this._name] = undefined;
1173 }
1174
1175 /**
1176 * @param {!Object} object
1177 * @param {function(!Array<!{name: string}>)} observer
1178 */
1179 function objectObserve(object, observer) {
1180 if (window['WebInspector']) {
1181 const settingPrototype = /** @type {!Object} */ (window['WebInspector']['Setting']['prototype']);
1182 if (typeof settingPrototype['remove'] === 'function') {
1183 settingPrototype['remove'] = settingRemove;
1184 }
1185 }
1186 /** @type {!Set<string>} */
1187 const changedProperties = new Set();
1188 let scheduled = false;
1189
1190 function scheduleObserver() {
1191 if (scheduled) {
1192 return;
1193 }
1194 scheduled = true;
1195 queueMicrotask(callObserver);
1196 }
1197
1198 function callObserver() {
1199 scheduled = false;
1200 const changes = /** @type {!Array<!{name: string}>} */ ([]);
1201 changedProperties.forEach(function(name) {
1202 changes.push({name: name});
1203 });
1204 changedProperties.clear();
1205 observer.call(null, changes);
1206 }
1207
1208 /** @type {!Map<string, *>} */
1209 const storage = new Map();
1210
1211 /**
1212 * @param {string} property
1213 */
1214 function defineProperty(property) {
1215 if (property in object) {
1216 storage.set(property, object[property]);
1217 delete object[property];
1218 }
1219
1220 Object.defineProperty(object, property, {
1221 /**
1222 * @return {*}
1223 */
1224 get: function() {
1225 return storage.get(property);
1226 },
1227
1228 /**
1229 * @param {*} value
1230 */
1231 set: function(value) {
1232 storage.set(property, value);
1233 changedProperties.add(property);
1234 scheduleObserver();
1235 }
1236 });
1237 }
1238
1239 for (let i = 0; i < properties.length; ++i) {
1240 defineProperty(properties[i]);
1241 }
1242 }
1243
1244 window.Object.observe = objectObserve;
1245 }
1246
1247 /** @type {!Map<number, string>} */
1248 const staticKeyIdentifiers = new Map([
1249 [0x12, 'Alt'],
1250 [0x11, 'Control'],
1251 [0x10, 'Shift'],
1252 [0x14, 'CapsLock'],
1253 [0x5b, 'Win'],
1254 [0x5c, 'Win'],
1255 [0x0c, 'Clear'],
1256 [0x28, 'Down'],
1257 [0x23, 'End'],
1258 [0x0a, 'Enter'],
1259 [0x0d, 'Enter'],
1260 [0x2b, 'Execute'],
1261 [0x70, 'F1'],
1262 [0x71, 'F2'],
1263 [0x72, 'F3'],
1264 [0x73, 'F4'],
1265 [0x74, 'F5'],
1266 [0x75, 'F6'],
1267 [0x76, 'F7'],
1268 [0x77, 'F8'],
1269 [0x78, 'F9'],
1270 [0x79, 'F10'],
1271 [0x7a, 'F11'],
1272 [0x7b, 'F12'],
1273 [0x7c, 'F13'],
1274 [0x7d, 'F14'],
1275 [0x7e, 'F15'],
1276 [0x7f, 'F16'],
1277 [0x80, 'F17'],
1278 [0x81, 'F18'],
1279 [0x82, 'F19'],
1280 [0x83, 'F20'],
1281 [0x84, 'F21'],
1282 [0x85, 'F22'],
1283 [0x86, 'F23'],
1284 [0x87, 'F24'],
1285 [0x2f, 'Help'],
1286 [0x24, 'Home'],
1287 [0x2d, 'Insert'],
1288 [0x25, 'Left'],
1289 [0x22, 'PageDown'],
1290 [0x21, 'PageUp'],
1291 [0x13, 'Pause'],
1292 [0x2c, 'PrintScreen'],
1293 [0x27, 'Right'],
1294 [0x91, 'Scroll'],
1295 [0x29, 'Select'],
1296 [0x26, 'Up'],
1297 [0x2e, 'U+007F'], // Standard says that DEL becomes U+007F.
1298 [0xb0, 'MediaNextTrack'],
1299 [0xb1, 'MediaPreviousTrack'],
1300 [0xb2, 'MediaStop'],
1301 [0xb3, 'MediaPlayPause'],
1302 [0xad, 'VolumeMute'],
1303 [0xae, 'VolumeDown'],
1304 [0xaf, 'VolumeUp'],
1305 ]);
1306
1307 /**
1308 * @param {number} keyCode
1309 * @return {string}
1310 */
1311 function keyCodeToKeyIdentifier(keyCode) {
1312 let result = staticKeyIdentifiers.get(keyCode);
1313 if (result !== undefined) {
1314 return result;
1315 }
1316 result = 'U+';
1317 const hexString = keyCode.toString(16).toUpperCase();
1318 for (let i = hexString.length; i < 4; ++i) {
1319 result += '0';
1320 }
1321 result += hexString;
1322 return result;
1323 }
1324
1325 function installBackwardsCompatibility() {
1326 const majorVersion = getRemoteMajorVersion();
1327 if (!majorVersion) {
1328 return;
1329 }
1330
1331 /** @type {!Array<string>} */
1332 const styleRules = [];
1333 // Shadow DOM V0 polyfill
1334 if (majorVersion <= 73 && !Element.prototype.createShadowRoot) {
1335 Element.prototype.createShadowRoot = function() {
1336 try {
1337 return this.attachShadow({mode: 'open'});
1338 } catch (e) {
1339 // some elements we use to add shadow roots can no
1340 // longer have shadow roots.
1341 const fakeShadowHost = document.createElement('span');
1342 this.appendChild(fakeShadowHost);
1343 fakeShadowHost.className = 'fake-shadow-host';
1344 return fakeShadowHost.createShadowRoot();
1345 }
1346 };
1347
1348 const origAdd = DOMTokenList.prototype.add;
1349 DOMTokenList.prototype.add = function(...tokens) {
1350 if (tokens[0].startsWith('insertion-point') || tokens[0].startsWith('tabbed-pane-header')) {
1351 this._myElement.slot = '.' + tokens[0];
1352 }
1353 return origAdd.apply(this, tokens);
1354 };
1355
1356 const origCreateElement = Document.prototype.createElement;
1357 Document.prototype.createElement = function(tagName, ...rest) {
1358 if (tagName === 'content') {
1359 tagName = 'slot';
1360 }
1361 const element = origCreateElement.call(this, tagName, ...rest);
1362 element.classList._myElement = element;
1363 return element;
1364 };
1365
1366 Object.defineProperty(HTMLSlotElement.prototype, 'select', {
1367 set(selector) {
1368 this.name = selector;
1369 }
1370 });
1371 }
1372
1373 // Custom Elements V0 polyfill
1374 if (majorVersion <= 73 && !Document.prototype.hasOwnProperty('registerElement')) {
1375 const fakeRegistry = new Map();
1376 Document.prototype.registerElement = function(typeExtension, options) {
1377 const {prototype, extends: localName} = options;
1378 const document = this;
1379 const callback = function() {
1380 const element = document.createElement(localName || typeExtension);
1381 const skip = new Set(['constructor', '__proto__']);
1382 for (const key of Object.keys(Object.getOwnPropertyDescriptors(prototype.__proto__ || {}))) {
1383 if (skip.has(key)) {
1384 continue;
1385 }
1386 element[key] = prototype[key];
1387 }
1388 element.setAttribute('is', typeExtension);
1389 if (element['createdCallback']) {
1390 element['createdCallback']();
1391 }
1392 return element;
1393 };
1394 fakeRegistry.set(typeExtension, callback);
1395 return callback;
1396 };
1397
1398 const origCreateElement = Document.prototype.createElement;
1399 Document.prototype.createElement = function(tagName, fakeCustomElementType) {
1400 const fakeConstructor = fakeRegistry.get(fakeCustomElementType);
1401 if (fakeConstructor) {
1402 return fakeConstructor();
1403 }
1404 return origCreateElement.call(this, tagName, fakeCustomElementType);
1405 };
1406
1407 // DevTools front-ends mistakenly assume that
1408 // classList.toggle('a', undefined) works as
1409 // classList.toggle('a', false) rather than as
1410 // classList.toggle('a');
1411 const originalDOMTokenListToggle = DOMTokenList.prototype.toggle;
1412 DOMTokenList.prototype.toggle = function(token, force) {
1413 if (arguments.length === 1) {
1414 force = !this.contains(token);
1415 }
1416 return originalDOMTokenListToggle.call(this, token, Boolean(force));
1417 };
1418 }
1419
1420 if (majorVersion <= 66) {
1421 /** @type {(!function(number, number):Element|undefined)} */
1422 ShadowRoot.prototype.__originalShadowRootElementFromPoint;
1423
1424 if (!ShadowRoot.prototype.__originalShadowRootElementFromPoint) {
1425 ShadowRoot.prototype.__originalShadowRootElementFromPoint = ShadowRoot.prototype.elementFromPoint;
1426 /**
1427 * @param {number} x
1428 * @param {number} y
1429 * @return {Element}
1430 */
1431 ShadowRoot.prototype.elementFromPoint = function(x, y) {
1432 const originalResult = ShadowRoot.prototype.__originalShadowRootElementFromPoint.apply(this, arguments);
1433 if (this.host && originalResult === this.host) {
1434 return null;
1435 }
1436 return originalResult;
1437 };
1438 }
1439 }
1440
1441 if (majorVersion <= 53) {
1442 Object.defineProperty(window.KeyboardEvent.prototype, 'keyIdentifier', {
1443 /**
1444 * @return {string}
1445 * @this {KeyboardEvent}
1446 */
1447 get: function() {
1448 return keyCodeToKeyIdentifier(this.keyCode);
1449 }
1450 });
1451 }
1452
1453 if (majorVersion <= 50) {
1454 installObjectObserve();
1455 }
1456
1457 if (majorVersion <= 45) {
1458 /**
1459 * @param {string} property
1460 * @return {!CSSValue|null}
1461 * @this {CSSStyleDeclaration}
1462 */
1463 function getValue(property) {
1464 // Note that |property| comes from another context, so we can't use === here.
1465 // eslint-disable-next-line eqeqeq
1466 if (property == 'padding-left') {
1467 return /** @type {!CSSValue} */ ({
1468 /**
1469 * @return {number}
1470 * @this {!{__paddingLeft: number}}
1471 */
1472 getFloatValue: function() {
1473 return this.__paddingLeft;
1474 },
1475 __paddingLeft: parseFloat(this.paddingLeft)
1476 });
1477 }
1478 throw new Error('getPropertyCSSValue is undefined');
1479 }
1480
1481 window.CSSStyleDeclaration.prototype.getPropertyCSSValue = getValue;
1482
1483 function CSSPrimitiveValue() {
1484 }
1485 CSSPrimitiveValue.CSS_PX = 5;
1486 window.CSSPrimitiveValue = CSSPrimitiveValue;
1487 }
1488
1489 if (majorVersion <= 45) {
1490 styleRules.push('* { min-width: 0; min-height: 0; }');
1491 }
1492
1493 if (majorVersion <= 71) {
1494 styleRules.push(
1495 '.coverage-toolbar-container, .animation-timeline-toolbar-container, .computed-properties { flex-basis: auto; }');
1496 }
1497
1498 if (majorVersion <= 50) {
1499 Event.prototype.deepPath = undefined;
1500 }
1501
1502 if (majorVersion <= 54) {
1503 window.FileError = /** @type {!function (new: FileError) : ?} */ ({
1504 NOT_FOUND_ERR: DOMException.NOT_FOUND_ERR,
1505 ABORT_ERR: DOMException.ABORT_ERR,
1506 INVALID_MODIFICATION_ERR: DOMException.INVALID_MODIFICATION_ERR,
1507 NOT_READABLE_ERR: 0 // No matching DOMException, so code will be 0.
1508 });
1509 }
1510
1511 installExtraStyleRules(styleRules);
1512 }
1513
1514 /**
1515 * @return {?number}
1516 */
1517 function getRemoteMajorVersion() {
1518 try {
1519 const remoteVersion = new URLSearchParams(window.location.search).get('remoteVersion');
1520 if (!remoteVersion) {
1521 return null;
1522 }
1523 const majorVersion = parseInt(remoteVersion.split('.')[0], 10);
1524 return majorVersion;
1525 } catch (e) {
1526 return null;
1527 }
1528 }
1529
1530 /**
1531 * @param {!Array<string>} styleRules
1532 */
1533 function installExtraStyleRules(styleRules) {
1534 if (!styleRules.length) {
1535 return;
1536 }
1537 const styleText = styleRules.join('\n');
1538 document.head.appendChild(createStyleElement(styleText));
1539
1540 const origCreateShadowRoot = HTMLElement.prototype.createShadowRoot;
1541 HTMLElement.prototype.createShadowRoot = function(...args) {
1542 const shadowRoot = origCreateShadowRoot.call(this, ...args);
1543 shadowRoot.appendChild(createStyleElement(styleText));
1544 return shadowRoot;
1545 };
1546 }
1547
1548 /**
1549 * @param {string} styleText
1550 * @return {!Element}
1551 */
1552 function createStyleElement(styleText) {
1553 const style = document.createElement('style');
1554 style.textContent = styleText;
1555 return style;
1556 }
1557
1558 installBackwardsCompatibility();
1559
1560})(window);