content-script.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. // This script runs in the context of the web page
  2. console.log( 'Three.js DevTools: Content script loaded at document.readyState:', document.readyState );
  3. // Function to inject the bridge script
  4. function injectBridge( target = document ) {
  5. const script = document.createElement( 'script' );
  6. script.src = chrome.runtime.getURL( 'bridge.js' );
  7. script.onload = function () {
  8. this.remove();
  9. };
  10. ( target.head || target.documentElement ).appendChild( script );
  11. return script;
  12. }
  13. // Also inject into any existing iframes
  14. function injectIntoIframes() {
  15. const iframes = document.querySelectorAll( 'iframe' );
  16. iframes.forEach( iframe => {
  17. try {
  18. injectBridge( iframe.contentDocument );
  19. } catch ( e ) {
  20. // Ignore cross-origin iframe errors
  21. console.log( 'DevTools: Could not inject into iframe:', e );
  22. }
  23. } );
  24. }
  25. // Initial injection
  26. injectBridge();
  27. injectIntoIframes();
  28. // Watch for new iframes being added
  29. const observer = new MutationObserver( mutations => {
  30. mutations.forEach( mutation => {
  31. mutation.addedNodes.forEach( node => {
  32. if ( node.tagName === 'IFRAME' ) {
  33. // Wait for iframe to load
  34. node.addEventListener( 'load', () => {
  35. try {
  36. injectBridge( node.contentDocument );
  37. } catch ( e ) {
  38. // Ignore cross-origin iframe errors
  39. // console.log( 'DevTools: Could not inject into iframe:', e );
  40. }
  41. } );
  42. }
  43. } );
  44. } );
  45. } );
  46. observer.observe( document.documentElement, {
  47. childList: true,
  48. subtree: true
  49. } );
  50. // Helper function to check if extension context is valid
  51. function isExtensionContextValid() {
  52. try {
  53. // This will throw if context is invalidated
  54. chrome.runtime.getURL( '' );
  55. return true;
  56. } catch ( error ) {
  57. return false;
  58. }
  59. }
  60. // Handle messages from the main window
  61. function handleMainWindowMessage( event ) {
  62. // Only accept messages from the same frame
  63. if ( event.source !== window ) {
  64. return;
  65. }
  66. const message = event.data;
  67. if ( ! message || message.id !== 'three-devtools' ) {
  68. return;
  69. }
  70. // Check extension context before sending message
  71. if ( ! isExtensionContextValid() ) {
  72. console.warn( 'Extension context invalidated, cannot send message' );
  73. return;
  74. }
  75. // Add source information
  76. const messageWithSource = {
  77. ...event.data,
  78. source: event.source === window ? 'main' : 'iframe'
  79. };
  80. // Forward to background page
  81. chrome.runtime.sendMessage( messageWithSource );
  82. }
  83. // Handle messages from iframes
  84. function handleIframeMessage( event ) {
  85. // Skip messages from main window
  86. if ( event.source === window ) {
  87. return;
  88. }
  89. const message = event.data;
  90. if ( ! message || message.id !== 'three-devtools' ) {
  91. return;
  92. }
  93. // Check extension context before sending message
  94. if ( ! isExtensionContextValid() ) {
  95. console.warn( 'Extension context invalidated, cannot send message' );
  96. return;
  97. }
  98. // Add source information
  99. const messageWithSource = {
  100. ...event.data,
  101. source: 'iframe'
  102. };
  103. // Forward to background page
  104. chrome.runtime.sendMessage( messageWithSource );
  105. }
  106. // Handle messages from devtools
  107. function handleDevtoolsMessage( message, sender, sendResponse ) {
  108. // Forward traverse requests to both main page and iframes
  109. if ( message.name === 'traverse' || message.name === 'reload-scene' || message.name === 'visibility' ) {
  110. // console.log( 'Content script: Forwarding message to page:', message );
  111. window.postMessage( message, '*' );
  112. // Also try to forward to all iframes
  113. const iframes = document.querySelectorAll( 'iframe' );
  114. iframes.forEach( iframe => {
  115. try {
  116. iframe.contentWindow.postMessage( message, '*' );
  117. } catch ( e ) {
  118. // Ignore cross-origin iframe errors
  119. }
  120. } );
  121. // Send immediate response to avoid "message channel closed" error
  122. sendResponse( { received: true } );
  123. }
  124. // Return false to indicate synchronous handling
  125. return false;
  126. }
  127. // Add event listeners
  128. window.addEventListener( 'message', handleMainWindowMessage, false );
  129. window.addEventListener( 'message', handleIframeMessage, false );
  130. chrome.runtime.onMessage.addListener( handleDevtoolsMessage );
  131. // Listen for messages from the panel
  132. chrome.runtime.onMessage.addListener( ( message, sender, sendResponse ) => {
  133. if ( message.name === 'visibility' ) {
  134. // Forward visibility state to the injected script
  135. window.postMessage( {
  136. id: 'three-devtools',
  137. name: 'panel-visibility', // Use a distinct name
  138. value: message.value
  139. }, '*' );
  140. }
  141. } );
粤ICP备19079148号