1. /**
    
  2.  * Supports render.html, a piece of the hydration fixture. See /hydration
    
  3.  */
    
  4. 
    
  5. 'use strict';
    
  6. 
    
  7. (function () {
    
  8.   var Fixture = null;
    
  9.   var output = document.getElementById('output');
    
  10.   var status = document.getElementById('status');
    
  11.   var hydrate = document.getElementById('hydrate');
    
  12.   var reload = document.getElementById('reload');
    
  13.   var renders = 0;
    
  14.   var failed = false;
    
  15. 
    
  16.   var needsReactDOM = getBooleanQueryParam('needsReactDOM');
    
  17.   var needsCreateElement = getBooleanQueryParam('needsCreateElement');
    
  18. 
    
  19.   function unmountComponent(node) {
    
  20.     // ReactDOM was moved into a separate package in 0.14
    
  21.     if (needsReactDOM) {
    
  22.       ReactDOM.unmountComponentAtNode(node);
    
  23.     } else if (React.unmountComponentAtNode) {
    
  24.       React.unmountComponentAtNode(node);
    
  25.     } else {
    
  26.       // Unmounting for React 0.4 and lower
    
  27.       React.unmountAndReleaseReactRootNode(node);
    
  28.     }
    
  29.   }
    
  30. 
    
  31.   function createElement(value) {
    
  32.     // React.createElement replaced function invocation in 0.12
    
  33.     if (needsCreateElement) {
    
  34.       return React.createElement(value);
    
  35.     } else {
    
  36.       return value();
    
  37.     }
    
  38.   }
    
  39. 
    
  40.   function getQueryParam(key) {
    
  41.     var pattern = new RegExp(key + '=([^&]+)(&|$)');
    
  42.     var matches = window.location.search.match(pattern);
    
  43. 
    
  44.     if (matches) {
    
  45.       return decodeURIComponent(matches[1]);
    
  46.     }
    
  47. 
    
  48.     handleError(new Error('No key found for' + key));
    
  49.   }
    
  50. 
    
  51.   function getBooleanQueryParam(key) {
    
  52.     return getQueryParam(key) === 'true';
    
  53.   }
    
  54. 
    
  55.   function setStatus(label) {
    
  56.     status.innerHTML = label;
    
  57.   }
    
  58. 
    
  59.   function prerender() {
    
  60.     setStatus('Generating markup');
    
  61. 
    
  62.     return Promise.resolve()
    
  63.       .then(function () {
    
  64.         const element = createElement(Fixture);
    
  65. 
    
  66.         // Server rendering moved to a separate package along with ReactDOM
    
  67.         // in 0.14.0
    
  68.         if (needsReactDOM) {
    
  69.           return ReactDOMServer.renderToString(element);
    
  70.         }
    
  71. 
    
  72.         // React.renderComponentToString was renamed in 0.12
    
  73.         if (React.renderToString) {
    
  74.           return React.renderToString(element);
    
  75.         }
    
  76. 
    
  77.         // React.renderComponentToString became synchronous in React 0.9.0
    
  78.         if (React.renderComponentToString.length === 1) {
    
  79.           return React.renderComponentToString(element);
    
  80.         }
    
  81. 
    
  82.         // Finally, React 0.4 and lower emits markup in a callback
    
  83.         return new Promise(function (resolve) {
    
  84.           React.renderComponentToString(element, resolve);
    
  85.         });
    
  86.       })
    
  87.       .then(function (string) {
    
  88.         output.innerHTML = string;
    
  89.         setStatus('Markup only (No React)');
    
  90.       })
    
  91.       .catch(handleError);
    
  92.   }
    
  93. 
    
  94.   function render() {
    
  95.     setStatus('Hydrating');
    
  96. 
    
  97.     var element = createElement(Fixture);
    
  98. 
    
  99.     // ReactDOM was split out into another package in 0.14
    
  100.     if (needsReactDOM) {
    
  101.       // Hydration changed to a separate method in React 16
    
  102.       if (ReactDOM.hydrate) {
    
  103.         ReactDOM.hydrate(element, output);
    
  104.       } else {
    
  105.         ReactDOM.render(element, output);
    
  106.       }
    
  107.     } else if (React.render) {
    
  108.       // React.renderComponent was renamed in 0.12
    
  109.       React.render(element, output);
    
  110.     } else {
    
  111.       React.renderComponent(element, output);
    
  112.     }
    
  113. 
    
  114.     setStatus(renders > 0 ? 'Re-rendered (' + renders + 'x)' : 'Hydrated');
    
  115.     renders += 1;
    
  116.     hydrate.innerHTML = 'Re-render';
    
  117.   }
    
  118. 
    
  119.   function handleError(error) {
    
  120.     console.log(error);
    
  121.     failed = true;
    
  122.     setStatus('Javascript Error');
    
  123.     output.innerHTML = error;
    
  124.   }
    
  125. 
    
  126.   function loadScript(src) {
    
  127.     return new Promise(function (resolve, reject) {
    
  128.       var script = document.createElement('script');
    
  129.       script.async = true;
    
  130.       script.src = src;
    
  131. 
    
  132.       script.onload = resolve;
    
  133.       script.onerror = function (error) {
    
  134.         reject(new Error('Unable to load ' + src));
    
  135.       };
    
  136. 
    
  137.       document.body.appendChild(script);
    
  138.     });
    
  139.   }
    
  140. 
    
  141.   function injectFixture(src) {
    
  142.     Fixture = new Function(src + '\nreturn Fixture;')();
    
  143. 
    
  144.     if (typeof Fixture === 'undefined') {
    
  145.       setStatus('Failed');
    
  146.       output.innerHTML = 'Please name your root component "Fixture"';
    
  147.     } else {
    
  148.       prerender().then(function () {
    
  149.         if (getBooleanQueryParam('hydrate')) {
    
  150.           render();
    
  151.         }
    
  152.       });
    
  153.     }
    
  154.   }
    
  155. 
    
  156.   function reloadFixture(code) {
    
  157.     renders = 0;
    
  158.     unmountComponent(output);
    
  159.     injectFixture(code);
    
  160.   }
    
  161. 
    
  162.   window.onerror = handleError;
    
  163. 
    
  164.   reload.onclick = function () {
    
  165.     window.location.reload();
    
  166.   };
    
  167. 
    
  168.   hydrate.onclick = render;
    
  169. 
    
  170.   loadScript(getQueryParam('reactPath'))
    
  171.     .then(function () {
    
  172.       if (needsReactDOM) {
    
  173.         return Promise.all([
    
  174.           loadScript(getQueryParam('reactDOMPath')),
    
  175.           loadScript(getQueryParam('reactDOMServerPath')),
    
  176.         ]);
    
  177.       }
    
  178.     })
    
  179.     .then(function () {
    
  180.       if (failed) {
    
  181.         return;
    
  182.       }
    
  183. 
    
  184.       window.addEventListener('message', function (event) {
    
  185.         var data = JSON.parse(event.data);
    
  186. 
    
  187.         switch (data.type) {
    
  188.           case 'code':
    
  189.             reloadFixture(data.payload);
    
  190.             break;
    
  191.           default:
    
  192.             throw new Error(
    
  193.               'Renderer Error: Unrecognized message "' + data.type + '"'
    
  194.             );
    
  195.         }
    
  196.       });
    
  197. 
    
  198.       window.parent.postMessage(JSON.stringify({type: 'ready'}), '*');
    
  199.     })
    
  200.     .catch(handleError);
    
  201. })();