inspector.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. 'use strict'
  2. window.onload = function () {
  3. // Use menu API to show context menu.
  4. window.InspectorFrontendHost.showContextMenuAtPoint = createMenu
  5. // correct for Chromium returning undefined for filesystem
  6. window.Persistence.FileSystemWorkspaceBinding.completeURL = completeURL
  7. // Use dialog API to override file chooser dialog.
  8. window.UI.createFileSelectorElement = createFileSelectorElement
  9. }
  10. // Extra / is needed as a result of MacOS requiring absolute paths
  11. function completeURL (project, path) {
  12. project = 'file:///'
  13. return `${project}${path}`
  14. }
  15. window.confirm = function (message, title) {
  16. const { dialog } = require('electron').remote
  17. if (title == null) {
  18. title = ''
  19. }
  20. return !dialog.showMessageBox({
  21. message: message,
  22. title: title,
  23. buttons: ['OK', 'Cancel'],
  24. cancelId: 1
  25. })
  26. }
  27. const convertToMenuTemplate = function (items) {
  28. return items.map(function (item) {
  29. const transformed = item.type === 'subMenu' ? {
  30. type: 'submenu',
  31. label: item.label,
  32. enabled: item.enabled,
  33. submenu: convertToMenuTemplate(item.subItems)
  34. } : item.type === 'separator' ? {
  35. type: 'separator'
  36. } : item.type === 'checkbox' ? {
  37. type: 'checkbox',
  38. label: item.label,
  39. enabled: item.enabled,
  40. checked: item.checked
  41. } : {
  42. type: 'normal',
  43. label: item.label,
  44. enabled: item.enabled
  45. }
  46. if (item.id != null) {
  47. transformed.click = function () {
  48. window.DevToolsAPI.contextMenuItemSelected(item.id)
  49. return window.DevToolsAPI.contextMenuCleared()
  50. }
  51. }
  52. return transformed
  53. })
  54. }
  55. const createMenu = function (x, y, items) {
  56. const { remote } = require('electron')
  57. const { Menu } = remote
  58. let template = convertToMenuTemplate(items)
  59. if (useEditMenuItems(x, y, template)) {
  60. template = getEditMenuItems()
  61. }
  62. const menu = Menu.buildFromTemplate(template)
  63. // The menu is expected to show asynchronously.
  64. setTimeout(function () {
  65. menu.popup({ window: remote.getCurrentWindow() })
  66. })
  67. }
  68. const useEditMenuItems = function (x, y, items) {
  69. return items.length === 0 && document.elementsFromPoint(x, y).some(function (element) {
  70. return element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA' || element.isContentEditable
  71. })
  72. }
  73. const getEditMenuItems = function () {
  74. return [
  75. {
  76. role: 'undo'
  77. },
  78. {
  79. role: 'redo'
  80. },
  81. {
  82. type: 'separator'
  83. },
  84. {
  85. role: 'cut'
  86. },
  87. {
  88. role: 'copy'
  89. },
  90. {
  91. role: 'paste'
  92. },
  93. {
  94. role: 'pasteAndMatchStyle'
  95. },
  96. {
  97. role: 'delete'
  98. },
  99. {
  100. role: 'selectAll'
  101. }
  102. ]
  103. }
  104. const showFileChooserDialog = function (callback) {
  105. const { dialog } = require('electron').remote
  106. const files = dialog.showOpenDialog({})
  107. if (files != null) {
  108. callback(pathToHtml5FileObject(files[0]))
  109. }
  110. }
  111. const pathToHtml5FileObject = function (path) {
  112. const fs = require('fs')
  113. const blob = new Blob([fs.readFileSync(path)])
  114. blob.name = path
  115. return blob
  116. }
  117. const createFileSelectorElement = function (callback) {
  118. const fileSelectorElement = document.createElement('span')
  119. fileSelectorElement.style.display = 'none'
  120. fileSelectorElement.click = showFileChooserDialog.bind(this, callback)
  121. return fileSelectorElement
  122. }