1. /* global chrome */
    
  2. 
    
  3. 'use strict';
    
  4. 
    
  5. window.addEventListener('pageshow', function ({target}) {
    
  6.   // Firefox's behaviour for injecting this content script can be unpredictable
    
  7.   // While navigating the history, some content scripts might not be re-injected and still be alive
    
  8.   if (!window.__REACT_DEVTOOLS_PROXY_INJECTED__) {
    
  9.     window.__REACT_DEVTOOLS_PROXY_INJECTED__ = true;
    
  10. 
    
  11.     connectPort();
    
  12.     sayHelloToBackendManager();
    
  13. 
    
  14.     // The backend waits to install the global hook until notified by the content script.
    
  15.     // In the event of a page reload, the content script might be loaded before the backend manager is injected.
    
  16.     // Because of this we need to poll the backend manager until it has been initialized.
    
  17.     const intervalID = setInterval(() => {
    
  18.       if (backendInitialized) {
    
  19.         clearInterval(intervalID);
    
  20.       } else {
    
  21.         sayHelloToBackendManager();
    
  22.       }
    
  23.     }, 500);
    
  24.   }
    
  25. });
    
  26. 
    
  27. window.addEventListener('pagehide', function ({target}) {
    
  28.   if (target !== window.document) {
    
  29.     return;
    
  30.   }
    
  31. 
    
  32.   delete window.__REACT_DEVTOOLS_PROXY_INJECTED__;
    
  33. });
    
  34. 
    
  35. let port = null;
    
  36. let backendInitialized: boolean = false;
    
  37. 
    
  38. function sayHelloToBackendManager() {
    
  39.   window.postMessage(
    
  40.     {
    
  41.       source: 'react-devtools-content-script',
    
  42.       hello: true,
    
  43.     },
    
  44.     '*',
    
  45.   );
    
  46. }
    
  47. 
    
  48. function handleMessageFromDevtools(message) {
    
  49.   window.postMessage(
    
  50.     {
    
  51.       source: 'react-devtools-content-script',
    
  52.       payload: message,
    
  53.     },
    
  54.     '*',
    
  55.   );
    
  56. }
    
  57. 
    
  58. function handleMessageFromPage(event) {
    
  59.   if (event.source !== window || !event.data) {
    
  60.     return;
    
  61.   }
    
  62. 
    
  63.   switch (event.data.source) {
    
  64.     // This is a message from a bridge (initialized by a devtools backend)
    
  65.     case 'react-devtools-bridge': {
    
  66.       backendInitialized = true;
    
  67. 
    
  68.       port.postMessage(event.data.payload);
    
  69.       break;
    
  70.     }
    
  71. 
    
  72.     // This is a message from the backend manager, which runs in ExecutionWorld.MAIN
    
  73.     // and can't use `chrome.runtime.sendMessage`
    
  74.     case 'react-devtools-backend-manager': {
    
  75.       const {source, payload} = event.data;
    
  76. 
    
  77.       chrome.runtime.sendMessage({
    
  78.         source,
    
  79.         payload,
    
  80.       });
    
  81.       break;
    
  82.     }
    
  83.   }
    
  84. }
    
  85. 
    
  86. function handleDisconnect() {
    
  87.   window.removeEventListener('message', handleMessageFromPage);
    
  88.   port = null;
    
  89. 
    
  90.   connectPort();
    
  91. }
    
  92. 
    
  93. // Creates port from application page to the React DevTools' service worker
    
  94. // Which then connects it with extension port
    
  95. function connectPort() {
    
  96.   port = chrome.runtime.connect({
    
  97.     name: 'proxy',
    
  98.   });
    
  99. 
    
  100.   window.addEventListener('message', handleMessageFromPage);
    
  101. 
    
  102.   port.onMessage.addListener(handleMessageFromDevtools);
    
  103.   port.onDisconnect.addListener(handleDisconnect);
    
  104. }