blob: 4489c397916003070e226ae34be27d61375e27a0 [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.
4/* eslint-disable indent */
5(function(window) {
6
7 // DevToolsAPI ----------------------------------------------------------------
8
9 /**
10 * @unrestricted
11 */
12 const DevToolsAPIImpl = class {
13 constructor() {
14 /**
15 * @type {number}
16 */
17 this._lastCallId = 0;
18
19 /**
20 * @type {!Object.<number, function(?Object)>}
21 */
22 this._callbacks = {};
23 }
24
25 /**
26 * @param {number} id
27 * @param {?Object} arg
28 */
29 embedderMessageAck(id, arg) {
30 const callback = this._callbacks[id];
31 delete this._callbacks[id];
32 if (callback)
33 callback(arg);
34 }
35
36 /**
37 * @param {string} method
38 * @param {!Array.<*>} args
39 * @param {?function(?Object)} callback
40 */
41 sendMessageToEmbedder(method, args, callback) {
42 const callId = ++this._lastCallId;
43 if (callback)
44 this._callbacks[callId] = callback;
45 const message = {'id': callId, 'method': method};
46 if (args.length)
47 message.params = args;
48 DevToolsHost.sendMessageToEmbedder(JSON.stringify(message));
49 }
50
51 /**
52 * @param {string} method
53 * @param {!Array<*>} args
54 */
55 _dispatchOnInspectorFrontendAPI(method, args) {
56 const inspectorFrontendAPI = /** @type {!Object<string, function()>} */ (window['InspectorFrontendAPI']);
57 inspectorFrontendAPI[method].apply(inspectorFrontendAPI, args);
58 }
59
60 // API methods below this line --------------------------------------------
61
62 /**
63 * @param {!Array.<!ExtensionDescriptor>} extensions
64 */
65 addExtensions(extensions) {
66 // Support for legacy front-ends (<M41).
67 if (window['WebInspector'] && window['WebInspector']['addExtensions']) {
68 window['WebInspector']['addExtensions'](extensions);
69 } else if (window['InspectorFrontendAPI']) {
70 // The addExtensions command is sent as the onload event happens for
71 // DevTools front-end. In case of hosted mode, this
72 // happens before the InspectorFrontendAPI is initialized.
73 this._dispatchOnInspectorFrontendAPI('addExtensions', [extensions]);
74 }
75 }
76
77 /**
78 * @param {string} url
79 */
80 appendedToURL(url) {
81 this._dispatchOnInspectorFrontendAPI('appendedToURL', [url]);
82 }
83
84 /**
85 * @param {string} url
86 */
87 canceledSaveURL(url) {
88 this._dispatchOnInspectorFrontendAPI('canceledSaveURL', [url]);
89 }
90
91 contextMenuCleared() {
92 this._dispatchOnInspectorFrontendAPI('contextMenuCleared', []);
93 }
94
95 /**
96 * @param {string} id
97 */
98 contextMenuItemSelected(id) {
99 this._dispatchOnInspectorFrontendAPI('contextMenuItemSelected', [id]);
100 }
101
102 /**
103 * @param {number} count
104 */
105 deviceCountUpdated(count) {
106 this._dispatchOnInspectorFrontendAPI('deviceCountUpdated', [count]);
107 }
108
109 /**
110 * @param {!Adb.Config} config
111 */
112 devicesDiscoveryConfigChanged(config) {
113 this._dispatchOnInspectorFrontendAPI('devicesDiscoveryConfigChanged', [config]);
114 }
115
116 /**
117 * @param {!Adb.PortForwardingStatus} status
118 */
119 devicesPortForwardingStatusChanged(status) {
120 this._dispatchOnInspectorFrontendAPI('devicesPortForwardingStatusChanged', [status]);
121 }
122
123 /**
124 * @param {!Array.<!Adb.Device>} devices
125 */
126 devicesUpdated(devices) {
127 this._dispatchOnInspectorFrontendAPI('devicesUpdated', [devices]);
128 }
129
130 /**
131 * @param {string} message
132 */
133 dispatchMessage(message) {
134 this._dispatchOnInspectorFrontendAPI('dispatchMessage', [message]);
135 }
136
137 /**
138 * @param {string} messageChunk
139 * @param {number} messageSize
140 */
141 dispatchMessageChunk(messageChunk, messageSize) {
142 this._dispatchOnInspectorFrontendAPI('dispatchMessageChunk', [messageChunk, messageSize]);
143 }
144
145 enterInspectElementMode() {
146 this._dispatchOnInspectorFrontendAPI('enterInspectElementMode', []);
147 }
148
149 /**
150 * @param {!{r: number, g: number, b: number, a: number}} color
151 */
152 eyeDropperPickedColor(color) {
153 this._dispatchOnInspectorFrontendAPI('eyeDropperPickedColor', [color]);
154 }
155
156 /**
157 * @param {!Array.<!{fileSystemName: string, rootURL: string, fileSystemPath: string}>} fileSystems
158 */
159 fileSystemsLoaded(fileSystems) {
160 this._dispatchOnInspectorFrontendAPI('fileSystemsLoaded', [fileSystems]);
161 }
162
163 /**
164 * @param {string} fileSystemPath
165 */
166 fileSystemRemoved(fileSystemPath) {
167 this._dispatchOnInspectorFrontendAPI('fileSystemRemoved', [fileSystemPath]);
168 }
169
170 /**
171 * @param {?string} error
172 * @param {?{type: string, fileSystemName: string, rootURL: string, fileSystemPath: string}} fileSystem
173 */
174 fileSystemAdded(error, fileSystem) {
175 this._dispatchOnInspectorFrontendAPI('fileSystemAdded', [error, fileSystem]);
176 }
177
178 /**
179 * @param {!Array<string>} changedPaths
180 * @param {!Array<string>} addedPaths
181 * @param {!Array<string>} removedPaths
182 */
183 fileSystemFilesChangedAddedRemoved(changedPaths, addedPaths, removedPaths) {
184 // Support for legacy front-ends (<M58)
185 if (window['InspectorFrontendAPI'] && window['InspectorFrontendAPI']['fileSystemFilesChanged']) {
186 this._dispatchOnInspectorFrontendAPI(
187 'fileSystemFilesChanged', [changedPaths.concat(addedPaths).concat(removedPaths)]);
188 } else {
189 this._dispatchOnInspectorFrontendAPI(
190 'fileSystemFilesChangedAddedRemoved', [changedPaths, addedPaths, removedPaths]);
191 }
192 }
193
194 /**
195 * @param {number} requestId
196 * @param {string} fileSystemPath
197 * @param {number} totalWork
198 */
199 indexingTotalWorkCalculated(requestId, fileSystemPath, totalWork) {
200 this._dispatchOnInspectorFrontendAPI('indexingTotalWorkCalculated', [requestId, fileSystemPath, totalWork]);
201 }
202
203 /**
204 * @param {number} requestId
205 * @param {string} fileSystemPath
206 * @param {number} worked
207 */
208 indexingWorked(requestId, fileSystemPath, worked) {
209 this._dispatchOnInspectorFrontendAPI('indexingWorked', [requestId, fileSystemPath, worked]);
210 }
211
212 /**
213 * @param {number} requestId
214 * @param {string} fileSystemPath
215 */
216 indexingDone(requestId, fileSystemPath) {
217 this._dispatchOnInspectorFrontendAPI('indexingDone', [requestId, fileSystemPath]);
218 }
219
220 /**
221 * @param {{type: string, key: string, code: string, keyCode: number, modifiers: number}} event
222 */
223 keyEventUnhandled(event) {
224 event.keyIdentifier = keyCodeToKeyIdentifier(event.keyCode);
225 this._dispatchOnInspectorFrontendAPI('keyEventUnhandled', [event]);
226 }
227
228 /**
229 * @param {boolean} hard
230 */
231 reloadInspectedPage(hard) {
232 this._dispatchOnInspectorFrontendAPI('reloadInspectedPage', [hard]);
233 }
234
235 /**
236 * @param {string} url
237 * @param {number} lineNumber
238 * @param {number} columnNumber
239 */
240 revealSourceLine(url, lineNumber, columnNumber) {
241 this._dispatchOnInspectorFrontendAPI('revealSourceLine', [url, lineNumber, columnNumber]);
242 }
243
244 /**
245 * @param {string} url
246 * @param {string=} fileSystemPath
247 */
248 savedURL(url, fileSystemPath) {
249 this._dispatchOnInspectorFrontendAPI('savedURL', [url, fileSystemPath]);
250 }
251
252 /**
253 * @param {number} requestId
254 * @param {string} fileSystemPath
255 * @param {!Array.<string>} files
256 */
257 searchCompleted(requestId, fileSystemPath, files) {
258 this._dispatchOnInspectorFrontendAPI('searchCompleted', [requestId, fileSystemPath, files]);
259 }
260
261 /**
262 * @param {string} tabId
263 */
264 setInspectedTabId(tabId) {
265 // Support for legacy front-ends (<M41).
266 if (window['WebInspector'] && window['WebInspector']['setInspectedTabId'])
267 window['WebInspector']['setInspectedTabId'](tabId);
268 else
269 this._dispatchOnInspectorFrontendAPI('setInspectedTabId', [tabId]);
270 }
271
272 /**
273 * @param {boolean} useSoftMenu
274 */
275 setUseSoftMenu(useSoftMenu) {
276 this._dispatchOnInspectorFrontendAPI('setUseSoftMenu', [useSoftMenu]);
277 }
278
279 /**
280 * @param {string} panelName
281 */
282 showPanel(panelName) {
283 this._dispatchOnInspectorFrontendAPI('showPanel', [panelName]);
284 }
285
286 /**
287 * @param {number} id
288 * @param {string} chunk
289 * @param {boolean} encoded
290 */
291 streamWrite(id, chunk, encoded) {
292 this._dispatchOnInspectorFrontendAPI('streamWrite', [id, encoded ? this._decodeBase64(chunk) : chunk]);
293 }
294
295 /**
296 * @param {string} chunk
297 * @return {string}
298 */
299 _decodeBase64(chunk) {
300 const request = new XMLHttpRequest();
301 request.open('GET', 'data:text/plain;base64,' + chunk, false);
302 request.send(null);
303 if (request.status === 200) {
304 return request.responseText;
305 } else {
306 console.error('Error while decoding chunk in streamWrite');
307 return '';
308 }
309 }
310 };
311
312 const DevToolsAPI = new DevToolsAPIImpl();
313 window.DevToolsAPI = DevToolsAPI;
314
315 // InspectorFrontendHostImpl --------------------------------------------------
316
317 /**
318 * @implements {InspectorFrontendHostAPI}
319 * @unrestricted
320 */
321 const InspectorFrontendHostImpl = class {
322 /**
323 * @override
324 * @return {string}
325 */
326 getSelectionBackgroundColor() {
327 return DevToolsHost.getSelectionBackgroundColor();
328 }
329
330 /**
331 * @override
332 * @return {string}
333 */
334 getSelectionForegroundColor() {
335 return DevToolsHost.getSelectionForegroundColor();
336 }
337
338 /**
339 * @override
340 * @return {string}
341 */
342 getInactiveSelectionBackgroundColor() {
343 return DevToolsHost.getInactiveSelectionBackgroundColor();
344 }
345
346 /**
347 * @override
348 * @return {string}
349 */
350 getInactiveSelectionForegroundColor() {
351 return DevToolsHost.getInactiveSelectionForegroundColor();
352 }
353
354 /**
355 * @override
356 * @return {string}
357 */
358 platform() {
359 return DevToolsHost.platform();
360 }
361
362 /**
363 * @override
364 */
365 loadCompleted() {
366 DevToolsAPI.sendMessageToEmbedder('loadCompleted', [], null);
367 // Support for legacy (<57) frontends.
368 if (window.Runtime && window.Runtime.queryParam) {
369 const panelToOpen = window.Runtime.queryParam('panel');
370 if (panelToOpen)
371 window.DevToolsAPI.showPanel(panelToOpen);
372 }
373 }
374
375 /**
376 * @override
377 */
378 bringToFront() {
379 DevToolsAPI.sendMessageToEmbedder('bringToFront', [], null);
380 }
381
382 /**
383 * @override
384 */
385 closeWindow() {
386 DevToolsAPI.sendMessageToEmbedder('closeWindow', [], null);
387 }
388
389 /**
390 * @override
391 * @param {boolean} isDocked
392 * @param {function()} callback
393 */
394 setIsDocked(isDocked, callback) {
395 DevToolsAPI.sendMessageToEmbedder('setIsDocked', [isDocked], callback);
396 }
397
398 /**
399 * Requests inspected page to be placed atop of the inspector frontend with specified bounds.
400 * @override
401 * @param {{x: number, y: number, width: number, height: number}} bounds
402 */
403 setInspectedPageBounds(bounds) {
404 DevToolsAPI.sendMessageToEmbedder('setInspectedPageBounds', [bounds], null);
405 }
406
407 /**
408 * @override
409 */
410 inspectElementCompleted() {
411 DevToolsAPI.sendMessageToEmbedder('inspectElementCompleted', [], null);
412 }
413
414 /**
415 * @override
416 * @param {string} url
417 * @param {string} headers
418 * @param {number} streamId
419 * @param {function(!InspectorFrontendHostAPI.LoadNetworkResourceResult)} callback
420 */
421 loadNetworkResource(url, headers, streamId, callback) {
422 DevToolsAPI.sendMessageToEmbedder(
423 'loadNetworkResource', [url, headers, streamId], /** @type {function(?Object)} */ (callback));
424 }
425
426 /**
427 * @override
428 * @param {function(!Object<string, string>)} callback
429 */
430 getPreferences(callback) {
431 DevToolsAPI.sendMessageToEmbedder('getPreferences', [], /** @type {function(?Object)} */ (callback));
432 }
433
434 /**
435 * @override
436 * @param {string} name
437 * @param {string} value
438 */
439 setPreference(name, value) {
440 DevToolsAPI.sendMessageToEmbedder('setPreference', [name, value], null);
441 }
442
443 /**
444 * @override
445 * @param {string} name
446 */
447 removePreference(name) {
448 DevToolsAPI.sendMessageToEmbedder('removePreference', [name], null);
449 }
450
451 /**
452 * @override
453 */
454 clearPreferences() {
455 DevToolsAPI.sendMessageToEmbedder('clearPreferences', [], null);
456 }
457
458 /**
459 * @override
460 * @param {string} origin
461 * @param {string} script
462 */
463 setInjectedScriptForOrigin(origin, script) {
464 DevToolsAPI.sendMessageToEmbedder('registerExtensionsAPI', [origin, script], null);
465 }
466
467 /**
468 * @override
469 * @param {string} url
470 */
471 inspectedURLChanged(url) {
472 DevToolsAPI.sendMessageToEmbedder('inspectedURLChanged', [url], null);
473 }
474
475 /**
476 * @override
477 * @param {string} text
478 */
479 copyText(text) {
480 DevToolsHost.copyText(text);
481 }
482
483 /**
484 * @override
485 * @param {string} url
486 */
487 openInNewTab(url) {
488 DevToolsAPI.sendMessageToEmbedder('openInNewTab', [url], null);
489 }
490
491 /**
492 * @override
493 * @param {string} fileSystemPath
494 */
495 showItemInFolder(fileSystemPath) {
496 DevToolsAPI.sendMessageToEmbedder('showItemInFolder', [fileSystemPath], null);
497 }
498
499 /**
500 * @override
501 * @param {string} url
502 * @param {string} content
503 * @param {boolean} forceSaveAs
504 */
505 save(url, content, forceSaveAs) {
506 DevToolsAPI.sendMessageToEmbedder('save', [url, content, forceSaveAs], null);
507 }
508
509 /**
510 * @override
511 * @param {string} url
512 * @param {string} content
513 */
514 append(url, content) {
515 DevToolsAPI.sendMessageToEmbedder('append', [url, content], null);
516 }
517
518 /**
519 * @override
Pavel Feldmanf1a36ee2018-07-28 16:10:25520 * @param {string} url
521 */
522 close(url) {
523 }
524
525 /**
526 * @override
Blink Reformat4c46d092018-04-07 15:32:37527 * @param {string} message
528 */
529 sendMessageToBackend(message) {
530 DevToolsAPI.sendMessageToEmbedder('dispatchProtocolMessage', [message], null);
531 }
532
533 /**
534 * @override
535 * @param {string} actionName
536 * @param {number} actionCode
537 * @param {number} bucketSize
538 */
539 recordEnumeratedHistogram(actionName, actionCode, bucketSize) {
540 // Support for M49 frontend.
541 if (actionName === 'DevTools.DrawerShown')
542 return;
543 DevToolsAPI.sendMessageToEmbedder('recordEnumeratedHistogram', [actionName, actionCode, bucketSize], null);
544 }
545
546 /**
547 * @override
548 */
549 requestFileSystems() {
550 DevToolsAPI.sendMessageToEmbedder('requestFileSystems', [], null);
551 }
552
553 /**
554 * @override
555 * @param {string=} type
556 */
557 addFileSystem(type) {
558 DevToolsAPI.sendMessageToEmbedder('addFileSystem', [type || ''], null);
559 }
560
561 /**
562 * @override
563 * @param {string} fileSystemPath
564 */
565 removeFileSystem(fileSystemPath) {
566 DevToolsAPI.sendMessageToEmbedder('removeFileSystem', [fileSystemPath], null);
567 }
568
569 /**
570 * @override
571 * @param {string} fileSystemId
572 * @param {string} registeredName
573 * @return {?DOMFileSystem}
574 */
575 isolatedFileSystem(fileSystemId, registeredName) {
576 return DevToolsHost.isolatedFileSystem(fileSystemId, registeredName);
577 }
578
579 /**
580 * @override
581 * @param {!FileSystem} fileSystem
582 */
583 upgradeDraggedFileSystemPermissions(fileSystem) {
584 DevToolsHost.upgradeDraggedFileSystemPermissions(fileSystem);
585 }
586
587 /**
588 * @override
589 * @param {number} requestId
590 * @param {string} fileSystemPath
591 * @param {string} excludedFolders
592 */
593 indexPath(requestId, fileSystemPath, excludedFolders) {
594 // |excludedFolders| added in M67. For backward compatibility,
595 // pass empty array.
596 excludedFolders = excludedFolders || '[]';
597 DevToolsAPI.sendMessageToEmbedder('indexPath', [requestId, fileSystemPath, excludedFolders], null);
598 }
599
600 /**
601 * @override
602 * @param {number} requestId
603 */
604 stopIndexing(requestId) {
605 DevToolsAPI.sendMessageToEmbedder('stopIndexing', [requestId], null);
606 }
607
608 /**
609 * @override
610 * @param {number} requestId
611 * @param {string} fileSystemPath
612 * @param {string} query
613 */
614 searchInPath(requestId, fileSystemPath, query) {
615 DevToolsAPI.sendMessageToEmbedder('searchInPath', [requestId, fileSystemPath, query], null);
616 }
617
618 /**
619 * @override
620 * @return {number}
621 */
622 zoomFactor() {
623 return DevToolsHost.zoomFactor();
624 }
625
626 /**
627 * @override
628 */
629 zoomIn() {
630 DevToolsAPI.sendMessageToEmbedder('zoomIn', [], null);
631 }
632
633 /**
634 * @override
635 */
636 zoomOut() {
637 DevToolsAPI.sendMessageToEmbedder('zoomOut', [], null);
638 }
639
640 /**
641 * @override
642 */
643 resetZoom() {
644 DevToolsAPI.sendMessageToEmbedder('resetZoom', [], null);
645 }
646
647 /**
648 * @override
649 * @param {string} shortcuts
650 */
651 setWhitelistedShortcuts(shortcuts) {
652 DevToolsAPI.sendMessageToEmbedder('setWhitelistedShortcuts', [shortcuts], null);
653 }
654
655 /**
656 * @override
657 * @param {boolean} active
658 */
659 setEyeDropperActive(active) {
660 DevToolsAPI.sendMessageToEmbedder('setEyeDropperActive', [active], null);
661 }
662
663 /**
664 * @override
665 * @param {!Array<string>} certChain
666 */
667 showCertificateViewer(certChain) {
668 DevToolsAPI.sendMessageToEmbedder('showCertificateViewer', [JSON.stringify(certChain)], null);
669 }
670
671 /**
672 * @override
673 * @param {function()} callback
674 */
675 reattach(callback) {
676 DevToolsAPI.sendMessageToEmbedder('reattach', [], callback);
677 }
678
679 /**
680 * @override
681 */
682 readyForTest() {
683 DevToolsAPI.sendMessageToEmbedder('readyForTest', [], null);
684 }
685
686 /**
687 * @override
688 */
689 connectionReady() {
690 DevToolsAPI.sendMessageToEmbedder('connectionReady', [], null);
691 }
692
693 /**
694 * @override
695 * @param {boolean} value
696 */
697 setOpenNewWindowForPopups(value) {
698 DevToolsAPI.sendMessageToEmbedder('setOpenNewWindowForPopups', [value], null);
699 }
700
701 /**
702 * @override
703 * @param {!Adb.Config} config
704 */
705 setDevicesDiscoveryConfig(config) {
706 DevToolsAPI.sendMessageToEmbedder(
707 'setDevicesDiscoveryConfig',
708 [
709 config.discoverUsbDevices, config.portForwardingEnabled, JSON.stringify(config.portForwardingConfig),
710 config.networkDiscoveryEnabled, JSON.stringify(config.networkDiscoveryConfig)
711 ],
712 null);
713 }
714
715 /**
716 * @override
717 * @param {boolean} enabled
718 */
719 setDevicesUpdatesEnabled(enabled) {
720 DevToolsAPI.sendMessageToEmbedder('setDevicesUpdatesEnabled', [enabled], null);
721 }
722
723 /**
724 * @override
725 * @param {string} pageId
726 * @param {string} action
727 */
728 performActionOnRemotePage(pageId, action) {
729 DevToolsAPI.sendMessageToEmbedder('performActionOnRemotePage', [pageId, action], null);
730 }
731
732 /**
733 * @override
734 * @param {string} browserId
735 * @param {string} url
736 */
737 openRemotePage(browserId, url) {
738 DevToolsAPI.sendMessageToEmbedder('openRemotePage', [browserId, url], null);
739 }
740
741 /**
742 * @override
743 */
744 openNodeFrontend() {
745 DevToolsAPI.sendMessageToEmbedder('openNodeFrontend', [], null);
746 }
747
748 /**
749 * @override
750 * @param {number} x
751 * @param {number} y
752 * @param {!Array.<!InspectorFrontendHostAPI.ContextMenuDescriptor>} items
753 * @param {!Document} document
754 */
755 showContextMenuAtPoint(x, y, items, document) {
756 DevToolsHost.showContextMenuAtPoint(x, y, items, document);
757 }
758
759 /**
760 * @override
761 * @return {boolean}
762 */
763 isHostedMode() {
764 return DevToolsHost.isHostedMode();
765 }
766
767 // Backward-compatible methods below this line --------------------------------------------
768
769 /**
770 * Support for legacy front-ends (<M65).
771 * @return {boolean}
772 */
773 isUnderTest() {
774 return false;
775 }
776
777 /**
778 * Support for legacy front-ends (<M50).
779 * @param {string} message
780 */
781 sendFrontendAPINotification(message) {
782 }
783
784 /**
785 * Support for legacy front-ends (<M41).
786 * @return {string}
787 */
788 port() {
789 return 'unknown';
790 }
791
792 /**
793 * Support for legacy front-ends (<M38).
794 * @param {number} zoomFactor
795 */
796 setZoomFactor(zoomFactor) {
797 }
798
799 /**
800 * Support for legacy front-ends (<M34).
801 */
802 sendMessageToEmbedder() {
803 }
804
805 /**
806 * Support for legacy front-ends (<M34).
807 * @param {string} dockSide
808 */
809 requestSetDockSide(dockSide) {
810 DevToolsAPI.sendMessageToEmbedder('setIsDocked', [dockSide !== 'undocked'], null);
811 }
812
813 /**
814 * Support for legacy front-ends (<M34).
815 * @return {boolean}
816 */
817 supportsFileSystems() {
818 return true;
819 }
820
821 /**
Blink Reformat4c46d092018-04-07 15:32:37822 * Support for legacy front-ends (<M44).
823 * @param {number} actionCode
824 */
825 recordActionTaken(actionCode) {
826 this.recordEnumeratedHistogram('DevTools.ActionTaken', actionCode, 100);
827 }
828
829 /**
830 * Support for legacy front-ends (<M44).
831 * @param {number} panelCode
832 */
833 recordPanelShown(panelCode) {
834 this.recordEnumeratedHistogram('DevTools.PanelShown', panelCode, 20);
835 }
836 };
837
838 window.InspectorFrontendHost = new InspectorFrontendHostImpl();
839
840 // DevToolsApp ---------------------------------------------------------------
841
842 function installObjectObserve() {
843 /** @type {!Array<string>} */
844 const properties = [
845 'advancedSearchConfig',
846 'auditsPanelSplitViewState',
847 'auditsSidebarWidth',
848 'blockedURLs',
849 'breakpoints',
850 'cacheDisabled',
851 'colorFormat',
852 'consoleHistory',
853 'consoleTimestampsEnabled',
854 'cpuProfilerView',
855 'cssSourceMapsEnabled',
856 'currentDockState',
857 'customColorPalette',
858 'customDevicePresets',
859 'customEmulatedDeviceList',
860 'customFormatters',
861 'customUserAgent',
862 'databaseTableViewVisibleColumns',
863 'dataGrid-cookiesTable',
864 'dataGrid-DOMStorageItemsView',
865 'debuggerSidebarHidden',
866 'disableDataSaverInfobar',
867 'disablePausedStateOverlay',
868 'domBreakpoints',
869 'domWordWrap',
870 'elementsPanelSplitViewState',
871 'elementsSidebarWidth',
872 'emulation.deviceHeight',
873 'emulation.deviceModeValue',
874 'emulation.deviceOrientationOverride',
875 'emulation.deviceScale',
876 'emulation.deviceScaleFactor',
877 'emulation.deviceUA',
878 'emulation.deviceWidth',
879 'emulation.geolocationOverride',
880 'emulation.showDeviceMode',
881 'emulation.showRulers',
882 'enableAsyncStackTraces',
883 'eventListenerBreakpoints',
884 'fileMappingEntries',
885 'fileSystemMapping',
886 'FileSystemViewSidebarWidth',
887 'fileSystemViewSplitViewState',
888 'filterBar-consoleView',
889 'filterBar-networkPanel',
890 'filterBar-promisePane',
891 'filterBar-timelinePanel',
892 'frameViewerHideChromeWindow',
893 'heapSnapshotRetainersViewSize',
894 'heapSnapshotSplitViewState',
895 'hideCollectedPromises',
896 'hideNetworkMessages',
897 'highlightNodeOnHoverInOverlay',
898 'highResolutionCpuProfiling',
899 'inlineVariableValues',
900 'Inspector.drawerSplitView',
901 'Inspector.drawerSplitViewState',
902 'InspectorView.panelOrder',
903 'InspectorView.screencastSplitView',
904 'InspectorView.screencastSplitViewState',
905 'InspectorView.splitView',
906 'InspectorView.splitViewState',
907 'javaScriptDisabled',
908 'jsSourceMapsEnabled',
909 'lastActivePanel',
910 'lastDockState',
911 'lastSelectedSourcesSidebarPaneTab',
912 'lastSnippetEvaluationIndex',
913 'layerDetailsSplitView',
914 'layerDetailsSplitViewState',
915 'layersPanelSplitViewState',
916 'layersShowInternalLayers',
917 'layersSidebarWidth',
918 'messageLevelFilters',
919 'messageURLFilters',
920 'monitoringXHREnabled',
921 'navigatorGroupByFolder',
922 'navigatorHidden',
923 'networkColorCodeResourceTypes',
924 'networkConditions',
925 'networkConditionsCustomProfiles',
926 'networkHideDataURL',
927 'networkLogColumnsVisibility',
928 'networkLogLargeRows',
929 'networkLogShowOverview',
930 'networkPanelSplitViewState',
931 'networkRecordFilmStripSetting',
932 'networkResourceTypeFilters',
933 'networkShowPrimaryLoadWaterfall',
934 'networkSidebarWidth',
935 'openLinkHandler',
936 'pauseOnCaughtException',
937 'pauseOnExceptionEnabled',
938 'preserveConsoleLog',
939 'prettyPrintInfobarDisabled',
940 'previouslyViewedFiles',
941 'profilesPanelSplitViewState',
942 'profilesSidebarWidth',
943 'promiseStatusFilters',
944 'recordAllocationStacks',
945 'requestHeaderFilterSetting',
946 'request-info-formData-category-expanded',
947 'request-info-general-category-expanded',
948 'request-info-queryString-category-expanded',
949 'request-info-requestHeaders-category-expanded',
950 'request-info-requestPayload-category-expanded',
951 'request-info-responseHeaders-category-expanded',
952 'resources',
953 'resourcesLastSelectedItem',
954 'resourcesPanelSplitViewState',
955 'resourcesSidebarWidth',
956 'resourceViewTab',
957 'savedURLs',
958 'screencastEnabled',
959 'scriptsPanelNavigatorSidebarWidth',
960 'searchInContentScripts',
961 'selectedAuditCategories',
962 'selectedColorPalette',
963 'selectedProfileType',
964 'shortcutPanelSwitch',
965 'showAdvancedHeapSnapshotProperties',
966 'showEventListenersForAncestors',
967 'showFrameowkrListeners',
968 'showHeaSnapshotObjectsHiddenProperties',
969 'showInheritedComputedStyleProperties',
970 'showMediaQueryInspector',
971 'showNativeFunctionsInJSProfile',
972 'showUAShadowDOM',
973 'showWhitespacesInEditor',
974 'sidebarPosition',
975 'skipContentScripts',
976 'skipStackFramesPattern',
977 'sourceMapInfobarDisabled',
978 'sourcesPanelDebuggerSidebarSplitViewState',
979 'sourcesPanelNavigatorSplitViewState',
980 'sourcesPanelSplitSidebarRatio',
981 'sourcesPanelSplitViewState',
982 'sourcesSidebarWidth',
983 'standardEmulatedDeviceList',
984 'StylesPaneSplitRatio',
985 'stylesPaneSplitViewState',
986 'textEditorAutocompletion',
987 'textEditorAutoDetectIndent',
988 'textEditorBracketMatching',
989 'textEditorIndent',
990 'timelineCaptureFilmStrip',
991 'timelineCaptureLayersAndPictures',
992 'timelineCaptureMemory',
993 'timelineCaptureNetwork',
994 'timeline-details',
995 'timelineEnableJSSampling',
996 'timelineOverviewMode',
997 'timelinePanelDetailsSplitViewState',
998 'timelinePanelRecorsSplitViewState',
999 'timelinePanelTimelineStackSplitViewState',
1000 'timelinePerspective',
1001 'timeline-split',
1002 'timelineTreeGroupBy',
1003 'timeline-view',
1004 'timelineViewMode',
1005 'uiTheme',
1006 'watchExpressions',
1007 'WebInspector.Drawer.lastSelectedView',
1008 'WebInspector.Drawer.showOnLoad',
1009 'workspaceExcludedFolders',
1010 'workspaceFolderExcludePattern',
1011 'workspaceInfobarDisabled',
1012 'workspaceMappingInfobarDisabled',
1013 'xhrBreakpoints'
1014 ];
1015
1016 /**
1017 * @this {!{_storage: Object, _name: string}}
1018 */
1019 function settingRemove() {
1020 this._storage[this._name] = undefined;
1021 }
1022
1023 /**
1024 * @param {!Object} object
1025 * @param {function(!Array<!{name: string}>)} observer
1026 */
1027 function objectObserve(object, observer) {
1028 if (window['WebInspector']) {
1029 const settingPrototype = /** @type {!Object} */ (window['WebInspector']['Setting']['prototype']);
1030 if (typeof settingPrototype['remove'] === 'function')
1031 settingPrototype['remove'] = settingRemove;
1032 }
1033 /** @type {!Set<string>} */
1034 const changedProperties = new Set();
1035 let scheduled = false;
1036
1037 function scheduleObserver() {
1038 if (scheduled)
1039 return;
1040 scheduled = true;
1041 setImmediate(callObserver);
1042 }
1043
1044 function callObserver() {
1045 scheduled = false;
1046 const changes = /** @type {!Array<!{name: string}>} */ ([]);
1047 changedProperties.forEach(function(name) {
1048 changes.push({name: name});
1049 });
1050 changedProperties.clear();
1051 observer.call(null, changes);
1052 }
1053
1054 /** @type {!Map<string, *>} */
1055 const storage = new Map();
1056
1057 /**
1058 * @param {string} property
1059 */
1060 function defineProperty(property) {
1061 if (property in object) {
1062 storage.set(property, object[property]);
1063 delete object[property];
1064 }
1065
1066 Object.defineProperty(object, property, {
1067 /**
1068 * @return {*}
1069 */
1070 get: function() {
1071 return storage.get(property);
1072 },
1073
1074 /**
1075 * @param {*} value
1076 */
1077 set: function(value) {
1078 storage.set(property, value);
1079 changedProperties.add(property);
1080 scheduleObserver();
1081 }
1082 });
1083 }
1084
1085 for (let i = 0; i < properties.length; ++i)
1086 defineProperty(properties[i]);
1087 }
1088
1089 window.Object.observe = objectObserve;
1090 }
1091
1092 /** @type {!Map<number, string>} */
1093 const staticKeyIdentifiers = new Map([
1094 [0x12, 'Alt'],
1095 [0x11, 'Control'],
1096 [0x10, 'Shift'],
1097 [0x14, 'CapsLock'],
1098 [0x5b, 'Win'],
1099 [0x5c, 'Win'],
1100 [0x0c, 'Clear'],
1101 [0x28, 'Down'],
1102 [0x23, 'End'],
1103 [0x0a, 'Enter'],
1104 [0x0d, 'Enter'],
1105 [0x2b, 'Execute'],
1106 [0x70, 'F1'],
1107 [0x71, 'F2'],
1108 [0x72, 'F3'],
1109 [0x73, 'F4'],
1110 [0x74, 'F5'],
1111 [0x75, 'F6'],
1112 [0x76, 'F7'],
1113 [0x77, 'F8'],
1114 [0x78, 'F9'],
1115 [0x79, 'F10'],
1116 [0x7a, 'F11'],
1117 [0x7b, 'F12'],
1118 [0x7c, 'F13'],
1119 [0x7d, 'F14'],
1120 [0x7e, 'F15'],
1121 [0x7f, 'F16'],
1122 [0x80, 'F17'],
1123 [0x81, 'F18'],
1124 [0x82, 'F19'],
1125 [0x83, 'F20'],
1126 [0x84, 'F21'],
1127 [0x85, 'F22'],
1128 [0x86, 'F23'],
1129 [0x87, 'F24'],
1130 [0x2f, 'Help'],
1131 [0x24, 'Home'],
1132 [0x2d, 'Insert'],
1133 [0x25, 'Left'],
1134 [0x22, 'PageDown'],
1135 [0x21, 'PageUp'],
1136 [0x13, 'Pause'],
1137 [0x2c, 'PrintScreen'],
1138 [0x27, 'Right'],
1139 [0x91, 'Scroll'],
1140 [0x29, 'Select'],
1141 [0x26, 'Up'],
1142 [0x2e, 'U+007F'], // Standard says that DEL becomes U+007F.
1143 [0xb0, 'MediaNextTrack'],
1144 [0xb1, 'MediaPreviousTrack'],
1145 [0xb2, 'MediaStop'],
1146 [0xb3, 'MediaPlayPause'],
1147 [0xad, 'VolumeMute'],
1148 [0xae, 'VolumeDown'],
1149 [0xaf, 'VolumeUp'],
1150 ]);
1151
1152 /**
1153 * @param {number} keyCode
1154 * @return {string}
1155 */
1156 function keyCodeToKeyIdentifier(keyCode) {
1157 let result = staticKeyIdentifiers.get(keyCode);
1158 if (result !== undefined)
1159 return result;
1160 result = 'U+';
1161 const hexString = keyCode.toString(16).toUpperCase();
1162 for (let i = hexString.length; i < 4; ++i)
1163 result += '0';
1164 result += hexString;
1165 return result;
1166 }
1167
1168 function installBackwardsCompatibility() {
1169 if (window.location.href.indexOf('/remote/') === -1)
1170 return;
1171
1172 // Support for legacy (<M65) frontends.
1173 /** @type {(!function(number, number):Element|undefined)} */
1174 ShadowRoot.prototype.__originalShadowRootElementFromPoint;
1175
1176 if (!ShadowRoot.prototype.__originalShadowRootElementFromPoint) {
1177 ShadowRoot.prototype.__originalShadowRootElementFromPoint = ShadowRoot.prototype.elementFromPoint;
1178 /**
1179 * @param {number} x
1180 * @param {number} y
1181 * @return {Element}
1182 */
1183 ShadowRoot.prototype.elementFromPoint = function(x, y) {
1184 const originalResult = ShadowRoot.prototype.__originalShadowRootElementFromPoint.apply(this, arguments);
1185 if (this.host && originalResult === this.host)
1186 return null;
1187 return originalResult;
1188 };
1189 }
1190
1191 // Support for legacy (<M53) frontends.
1192 if (!window.KeyboardEvent.prototype.hasOwnProperty('keyIdentifier')) {
1193 Object.defineProperty(window.KeyboardEvent.prototype, 'keyIdentifier', {
1194 /**
1195 * @return {string}
1196 * @this {KeyboardEvent}
1197 */
1198 get: function() {
1199 return keyCodeToKeyIdentifier(this.keyCode);
1200 }
1201 });
1202 }
1203
1204 // Support for legacy (<M50) frontends.
1205 installObjectObserve();
1206
1207 /**
1208 * @param {string} property
1209 * @return {!CSSValue|null}
1210 * @this {CSSStyleDeclaration}
1211 */
1212 function getValue(property) {
1213 // Note that |property| comes from another context, so we can't use === here.
1214 // eslint-disable-next-line eqeqeq
1215 if (property == 'padding-left') {
1216 return /** @type {!CSSValue} */ ({
1217 /**
1218 * @return {number}
1219 * @this {!{__paddingLeft: number}}
1220 */
1221 getFloatValue: function() {
1222 return this.__paddingLeft;
1223 },
1224 __paddingLeft: parseFloat(this.paddingLeft)
1225 });
1226 }
1227 throw new Error('getPropertyCSSValue is undefined');
1228 }
1229
1230 // Support for legacy (<M41) frontends.
1231 window.CSSStyleDeclaration.prototype.getPropertyCSSValue = getValue;
1232
1233 function CSSPrimitiveValue() {
1234 }
1235 CSSPrimitiveValue.CSS_PX = 5;
1236 window.CSSPrimitiveValue = CSSPrimitiveValue;
1237
1238 // Support for legacy (<M44) frontends.
1239 const styleElement = window.document.createElement('style');
1240 styleElement.type = 'text/css';
1241 styleElement.textContent = 'html /deep/ * { min-width: 0; min-height: 0; }';
1242
1243 // Support for quirky border-image behavior (<M51), see:
1244 // https://bugs.chromium.org/p/chromium/issues/detail?id=559258
1245 styleElement.textContent +=
1246 '\nhtml /deep/ .cm-breakpoint .CodeMirror-linenumber { border-style: solid !important; }';
1247 styleElement.textContent +=
1248 '\nhtml /deep/ .cm-breakpoint.cm-breakpoint-conditional .CodeMirror-linenumber { border-style: solid !important; }';
1249 window.document.head.appendChild(styleElement);
1250
1251 // Support for legacy (<M49) frontends.
1252 Event.prototype.deepPath = undefined;
1253
1254 // Support for legacy (<53) frontends.
1255 window.FileError = /** @type {!function (new: FileError) : ?} */ ({
1256 NOT_FOUND_ERR: DOMException.NOT_FOUND_ERR,
1257 ABORT_ERR: DOMException.ABORT_ERR,
1258 INVALID_MODIFICATION_ERR: DOMException.INVALID_MODIFICATION_ERR,
1259 NOT_READABLE_ERR: 0 // No matching DOMException, so code will be 0.
1260 });
1261 }
1262
1263 function windowLoaded() {
1264 window.removeEventListener('DOMContentLoaded', windowLoaded, false);
1265 installBackwardsCompatibility();
1266 }
1267
1268 if (window.document.head &&
1269 (window.document.readyState === 'complete' || window.document.readyState === 'interactive'))
1270 installBackwardsCompatibility();
1271 else
1272 window.addEventListener('DOMContentLoaded', windowLoaded, false);
1273
1274 /** @type {(!function(string, boolean=):boolean)|undefined} */
1275 DOMTokenList.prototype.__originalDOMTokenListToggle;
1276
1277 if (!DOMTokenList.prototype.__originalDOMTokenListToggle) {
1278 DOMTokenList.prototype.__originalDOMTokenListToggle = DOMTokenList.prototype.toggle;
1279 /**
1280 * @param {string} token
1281 * @param {boolean=} force
1282 * @return {boolean}
1283 */
1284 DOMTokenList.prototype.toggle = function(token, force) {
1285 if (arguments.length === 1)
1286 force = !this.contains(token);
1287 return this.__originalDOMTokenListToggle(token, !!force);
1288 };
1289 }
1290
1291})(window);