inspector.ts 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import { internalContextBridge } from '@electron/internal/renderer/api/context-bridge';
  2. import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
  3. import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils';
  4. import { webFrame } from 'electron/renderer';
  5. import { IPC_MESSAGES } from '../common/ipc-messages';
  6. const { contextIsolationEnabled } = internalContextBridge;
  7. /* Corrects for some Inspector adaptations needed in Electron.
  8. * 1) Use menu API to show context menu.
  9. * 2) Correct for Chromium returning undefined for filesystem.
  10. * 3) Use dialog API to override file chooser dialog.
  11. */
  12. window.onload = function () {
  13. if (contextIsolationEnabled) {
  14. internalContextBridge.overrideGlobalValueFromIsolatedWorld([
  15. 'InspectorFrontendHost', 'showContextMenuAtPoint'
  16. ], createMenu);
  17. internalContextBridge.overrideGlobalValueFromIsolatedWorld([
  18. 'Persistence', 'FileSystemWorkspaceBinding', 'completeURL'
  19. ], completeURL);
  20. internalContextBridge.overrideGlobalValueFromIsolatedWorld([
  21. 'UI', 'createFileSelectorElement'
  22. ], createFileSelectorElement);
  23. } else {
  24. window.InspectorFrontendHost!.showContextMenuAtPoint = createMenu;
  25. window.Persistence!.FileSystemWorkspaceBinding.completeURL = completeURL;
  26. window.UI!.createFileSelectorElement = createFileSelectorElement;
  27. }
  28. };
  29. // Extra / is needed as a result of MacOS requiring absolute paths
  30. function completeURL (project: string, path: string) {
  31. project = 'file:///';
  32. return `${project}${path}`;
  33. }
  34. // The DOM implementation expects (message?: string) => boolean
  35. window.confirm = function (message?: string, title?: string) {
  36. return ipcRendererUtils.invokeSync(IPC_MESSAGES.INSPECTOR_CONFIRM, message, title) as boolean;
  37. };
  38. const useEditMenuItems = function (x: number, y: number, items: ContextMenuItem[]) {
  39. return items.length === 0 && document.elementsFromPoint(x, y).some(function (element) {
  40. return element.nodeName === 'INPUT' ||
  41. element.nodeName === 'TEXTAREA' ||
  42. (element as HTMLElement).isContentEditable;
  43. });
  44. };
  45. const createMenu = function (x: number, y: number, items: ContextMenuItem[]) {
  46. const isEditMenu = useEditMenuItems(x, y, items);
  47. ipcRendererInternal.invoke<number>(IPC_MESSAGES.INSPECTOR_CONTEXT_MENU, items, isEditMenu).then(id => {
  48. if (typeof id === 'number') {
  49. webFrame.executeJavaScript(`window.DevToolsAPI.contextMenuItemSelected(${JSON.stringify(id)})`);
  50. }
  51. webFrame.executeJavaScript('window.DevToolsAPI.contextMenuCleared()');
  52. });
  53. };
  54. const showFileChooserDialog = function (callback: (blob: File) => void) {
  55. ipcRendererInternal.invoke<[ string, any ]>(IPC_MESSAGES.INSPECTOR_SELECT_FILE).then(([path, data]) => {
  56. if (path && data) {
  57. callback(dataToHtml5FileObject(path, data));
  58. }
  59. });
  60. };
  61. const dataToHtml5FileObject = function (path: string, data: any) {
  62. return new File([data], path);
  63. };
  64. const createFileSelectorElement = function (this: any, callback: () => void) {
  65. const fileSelectorElement = document.createElement('span');
  66. fileSelectorElement.style.display = 'none';
  67. fileSelectorElement.click = showFileChooserDialog.bind(this, callback);
  68. return fileSelectorElement;
  69. };