content-script.js 4.0 KB

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