No Description

utils.js 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. 'use strict';
  2. import { Dimensions, Platform } from 'react-native';
  3. import Immutable from 'immutable';
  4. function appendFilesToHead(files, script) {
  5. return files.reduceRight((combinedScript, file) => {
  6. const { rel, type, href } = file;
  7. return `
  8. var link = document.createElement('link');
  9. link.rel = '${rel}';
  10. link.type = '${type}';
  11. link.href = '${href}';
  12. document.head.appendChild(link);
  13. ${combinedScript}
  14. `;
  15. }, script);
  16. }
  17. const screenWidth = Dimensions.get('window').width;
  18. const bodyStyle = `
  19. body {
  20. margin: 0;
  21. padding: 0;
  22. }
  23. `;
  24. function appendStylesToHead(styles, script) {
  25. const currentStyles = styles ? bodyStyle + styles : bodyStyle;
  26. // Escape any single quotes or newlines in the CSS with .replace()
  27. const escaped = currentStyles.replace(/\'/g, "\\'").replace(/\n/g, '\\n');
  28. return `
  29. var styleElement = document.createElement('style');
  30. styleElement.innerHTML = '${escaped}';
  31. document.head.appendChild(styleElement);
  32. ${script}
  33. `;
  34. }
  35. function getReloadRelatedData(props) {
  36. const { files, customStyle, customScript, style, source } = props;
  37. return {
  38. source,
  39. files,
  40. customStyle,
  41. customScript,
  42. style
  43. };
  44. }
  45. function isChanged(newValue, oldValue) {
  46. return !Immutable.is(Immutable.fromJS(newValue), Immutable.fromJS(oldValue));
  47. }
  48. function getInjectedSource(html, script) {
  49. return `
  50. ${html}
  51. <script>
  52. ${script}
  53. </script>
  54. `;
  55. }
  56. function getScript(props, getScript) {
  57. const { files, customStyle, customScript, style } = getReloadRelatedData(props);
  58. let script = getScript(style);
  59. script = files && files.length > 0 ? appendFilesToHead(files, script) : script;
  60. script = appendStylesToHead(customStyle, script);
  61. customScript && (script = customScript + script);
  62. return script;
  63. }
  64. export function getWidth(style) {
  65. return style && style.width ? style.width : screenWidth;
  66. }
  67. export function isEqual(newProps, oldProps) {
  68. return isChanged(getReloadRelatedData(newProps), getReloadRelatedData(oldProps));
  69. }
  70. export function setState(props, getBaseScript) {
  71. const { source, baseUrl } = props;
  72. const script = getScript(props, getBaseScript);
  73. let state = {};
  74. if (source.html) {
  75. let currentSource = { html: getInjectedSource(source.html, script) };
  76. baseUrl && Object.assign(currentSource, { baseUrl });
  77. Object.assign(state, { source: currentSource });
  78. } else {
  79. let currentSource = Object.assign({}, source);
  80. baseUrl && Object.assign(currentSource, { baseUrl });
  81. Object.assign(state, {
  82. source: currentSource,
  83. script
  84. });
  85. }
  86. return state;
  87. }
  88. export function handleSizeUpdated(height, width, onSizeUpdated) {
  89. onSizeUpdated &&
  90. onSizeUpdated({
  91. height,
  92. width
  93. });
  94. }
  95. export function isSizeChanged(height, oldHeight, width, oldWidth) {
  96. if (!height || !width) {
  97. return;
  98. }
  99. return height !== oldHeight || width !== oldWidth;
  100. }
  101. export const domMutationObserveScript = `
  102. var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
  103. var observer = new MutationObserver(updateSize);
  104. observer.observe(document, {
  105. subtree: true,
  106. attributes: true
  107. });
  108. `;
  109. export function updateSizeWithMessage(element) {
  110. return `
  111. var updateSizeInterval = null;
  112. var height = 0;
  113. function updateSize(event) {
  114. if (!window.hasOwnProperty('ReactNativeWebView') || !window.ReactNativeWebView.hasOwnProperty('postMessage')) {
  115. !updateSizeInterval && (updateSizeInterval = setInterval(updateSize, 200));
  116. return;
  117. }
  118. clearInterval(updateSizeInterval)
  119. height = ${element}.offsetHeight || window.innerHeight;
  120. width = ${element}.offsetWidth || window.innerWidth;
  121. window.ReactNativeWebView.postMessage(JSON.stringify({ width: width, height: height, event: event }));
  122. }
  123. `;
  124. }
  125. export function getStateFromProps(props, state) {
  126. const { height: oldHeight, width: oldWidth } = state;
  127. const height = props.style ? props.style.height : null;
  128. const width = props.style ? props.style.width : null;
  129. if (isSizeChanged(height, oldHeight, width, oldWidth)) {
  130. return {
  131. height: height || oldHeight,
  132. width: width || oldWidth,
  133. isSizeChanged: true
  134. };
  135. }
  136. return null;
  137. }
  138. // add viewport setting to meta for WKWebView
  139. const makeScalePageToFit = `
  140. var meta = document.createElement('meta');
  141. meta.setAttribute('name', 'viewport');
  142. meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);
  143. `;
  144. export function getBaseScript(style) {
  145. return `
  146. ;
  147. if (!document.getElementById("rnahw-wrapper")) {
  148. var wrapper = document.createElement('div');
  149. wrapper.id = 'rnahw-wrapper';
  150. while (document.body.firstChild instanceof Node) {
  151. wrapper.appendChild(document.body.firstChild);
  152. }
  153. document.body.appendChild(wrapper);
  154. }
  155. var width = ${getWidth(style)};
  156. ${updateSizeWithMessage('wrapper')}
  157. window.addEventListener('load', updateSize);
  158. window.addEventListener('resize', updateSize);
  159. ${domMutationObserveScript}
  160. ${Platform.OS === 'ios' ? makeScalePageToFit : ''}
  161. updateSize();
  162. `;
  163. }