No Description

WebViewExample.js 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. /**
  2. * Copyright (c) 2018-present, Infinite Red, Inc.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. *
  7. * @format
  8. * @flow
  9. */
  10. 'use strict';
  11. var React = require('react');
  12. var ReactNative = require('react-native');
  13. var {
  14. StyleSheet,
  15. Text,
  16. TextInput,
  17. TouchableWithoutFeedback,
  18. TouchableOpacity,
  19. View,
  20. WebView,
  21. } = ReactNative;
  22. var HEADER = '#3b5998';
  23. var BGWASH = 'rgba(255,255,255,0.8)';
  24. var DISABLED_WASH = 'rgba(255,255,255,0.25)';
  25. var TEXT_INPUT_REF = 'urlInput';
  26. var WEBVIEW_REF = 'webview';
  27. var DEFAULT_URL = 'https://m.facebook.com';
  28. const FILE_SYSTEM_ORIGIN_WHITE_LIST = ['file://*', 'http://*', 'https://*'];
  29. class WebViewExample extends React.Component<{}, $FlowFixMeState> {
  30. state = {
  31. url: DEFAULT_URL,
  32. status: 'No Page Loaded',
  33. backButtonEnabled: false,
  34. forwardButtonEnabled: false,
  35. loading: true,
  36. scalesPageToFit: true,
  37. };
  38. inputText = '';
  39. handleTextInputChange = event => {
  40. var url = event.nativeEvent.text;
  41. if (!/^[a-zA-Z-_]+:/.test(url)) {
  42. url = 'http://' + url;
  43. }
  44. this.inputText = url;
  45. };
  46. render() {
  47. this.inputText = this.state.url;
  48. return (
  49. <View style={[styles.container]}>
  50. <View style={[styles.addressBarRow]}>
  51. <TouchableOpacity
  52. onPress={this.goBack}
  53. style={
  54. this.state.backButtonEnabled
  55. ? styles.navButton
  56. : styles.disabledButton
  57. }>
  58. <Text>{'<'}</Text>
  59. </TouchableOpacity>
  60. <TouchableOpacity
  61. onPress={this.goForward}
  62. style={
  63. this.state.forwardButtonEnabled
  64. ? styles.navButton
  65. : styles.disabledButton
  66. }>
  67. <Text>{'>'}</Text>
  68. </TouchableOpacity>
  69. <TextInput
  70. ref={TEXT_INPUT_REF}
  71. autoCapitalize="none"
  72. defaultValue={this.state.url}
  73. onSubmitEditing={this.onSubmitEditing}
  74. onChange={this.handleTextInputChange}
  75. clearButtonMode="while-editing"
  76. style={styles.addressBarTextInput}
  77. />
  78. <TouchableOpacity onPress={this.pressGoButton}>
  79. <View style={styles.goButton}>
  80. <Text>Go!</Text>
  81. </View>
  82. </TouchableOpacity>
  83. </View>
  84. <WebView
  85. ref={WEBVIEW_REF}
  86. automaticallyAdjustContentInsets={false}
  87. style={styles.webView}
  88. source={{ uri: this.state.url }}
  89. javaScriptEnabled={true}
  90. domStorageEnabled={true}
  91. decelerationRate="normal"
  92. onNavigationStateChange={this.onNavigationStateChange}
  93. onShouldStartLoadWithRequest={this.onShouldStartLoadWithRequest}
  94. startInLoadingState={true}
  95. scalesPageToFit={this.state.scalesPageToFit}
  96. />
  97. <View style={styles.statusBar}>
  98. <Text style={styles.statusBarText}>{this.state.status}</Text>
  99. </View>
  100. </View>
  101. );
  102. }
  103. goBack = () => {
  104. this.refs[WEBVIEW_REF].goBack();
  105. };
  106. goForward = () => {
  107. this.refs[WEBVIEW_REF].goForward();
  108. };
  109. reload = () => {
  110. this.refs[WEBVIEW_REF].reload();
  111. };
  112. onShouldStartLoadWithRequest = event => {
  113. // Implement any custom loading logic here, don't forget to return!
  114. return true;
  115. };
  116. onNavigationStateChange = navState => {
  117. this.setState({
  118. backButtonEnabled: navState.canGoBack,
  119. forwardButtonEnabled: navState.canGoForward,
  120. url: navState.url,
  121. status: navState.title,
  122. loading: navState.loading,
  123. scalesPageToFit: true,
  124. });
  125. };
  126. onSubmitEditing = event => {
  127. this.pressGoButton();
  128. };
  129. pressGoButton = () => {
  130. var url = this.inputText.toLowerCase();
  131. if (url === this.state.url) {
  132. this.reload();
  133. } else {
  134. this.setState({
  135. url: url,
  136. });
  137. }
  138. // dismiss keyboard
  139. this.refs[TEXT_INPUT_REF].blur();
  140. };
  141. }
  142. class Button extends React.Component<$FlowFixMeProps> {
  143. _handlePress = () => {
  144. if (this.props.enabled !== false && this.props.onPress) {
  145. this.props.onPress();
  146. }
  147. };
  148. render() {
  149. return (
  150. <TouchableWithoutFeedback onPress={this._handlePress}>
  151. <View style={styles.button}>
  152. <Text>{this.props.text}</Text>
  153. </View>
  154. </TouchableWithoutFeedback>
  155. );
  156. }
  157. }
  158. class ScaledWebView extends React.Component<{}, $FlowFixMeState> {
  159. state = {
  160. scalingEnabled: true,
  161. };
  162. render() {
  163. return (
  164. <View>
  165. <WebView
  166. style={{
  167. backgroundColor: BGWASH,
  168. height: 200,
  169. }}
  170. source={{ uri: 'https://facebook.github.io/react/' }}
  171. scalesPageToFit={this.state.scalingEnabled}
  172. />
  173. <View style={styles.buttons}>
  174. {this.state.scalingEnabled ? (
  175. <Button
  176. text="Scaling:ON"
  177. enabled={true}
  178. onPress={() => this.setState({ scalingEnabled: false })}
  179. />
  180. ) : (
  181. <Button
  182. text="Scaling:OFF"
  183. enabled={true}
  184. onPress={() => this.setState({ scalingEnabled: true })}
  185. />
  186. )}
  187. </View>
  188. </View>
  189. );
  190. }
  191. }
  192. class MessagingTest extends React.Component<{}, $FlowFixMeState> {
  193. webview = null;
  194. state = {
  195. messagesReceivedFromWebView: 0,
  196. message: '',
  197. };
  198. onMessage = e =>
  199. this.setState({
  200. messagesReceivedFromWebView: this.state.messagesReceivedFromWebView + 1,
  201. message: e.nativeEvent.data,
  202. });
  203. postMessage = () => {
  204. if (this.webview) {
  205. this.webview.postMessage('"Hello" from React Native!');
  206. }
  207. };
  208. render(): React.Node {
  209. const { messagesReceivedFromWebView, message } = this.state;
  210. return (
  211. <View style={[styles.container, { height: 200 }]}>
  212. <View style={styles.container}>
  213. <Text>
  214. Messages received from web view: {messagesReceivedFromWebView}
  215. </Text>
  216. <Text>{message || '(No message)'}</Text>
  217. <View style={styles.buttons}>
  218. <Button
  219. text="Send Message to Web View"
  220. enabled
  221. onPress={this.postMessage}
  222. />
  223. </View>
  224. </View>
  225. <View style={styles.container}>
  226. <WebView
  227. ref={webview => {
  228. this.webview = webview;
  229. }}
  230. style={{
  231. backgroundColor: BGWASH,
  232. height: 100,
  233. }}
  234. originWhitelist={FILE_SYSTEM_ORIGIN_WHITE_LIST}
  235. source={require('./messagingtest.html')}
  236. onMessage={this.onMessage}
  237. />
  238. </View>
  239. </View>
  240. );
  241. }
  242. }
  243. class InjectJS extends React.Component<{}> {
  244. webview = null;
  245. injectJS = () => {
  246. const script = 'document.write("Injected JS ")';
  247. if (this.webview) {
  248. this.webview.injectJavaScript(script);
  249. }
  250. };
  251. render() {
  252. return (
  253. <View>
  254. <WebView
  255. ref={webview => {
  256. this.webview = webview;
  257. }}
  258. style={{
  259. backgroundColor: BGWASH,
  260. height: 300,
  261. }}
  262. source={{ uri: 'https://www.facebook.com' }}
  263. scalesPageToFit={true}
  264. />
  265. <View style={styles.buttons}>
  266. <Button text="Inject JS" enabled onPress={this.injectJS} />
  267. </View>
  268. </View>
  269. );
  270. }
  271. }
  272. var styles = StyleSheet.create({
  273. container: {
  274. flex: 1,
  275. backgroundColor: HEADER,
  276. },
  277. addressBarRow: {
  278. flexDirection: 'row',
  279. padding: 8,
  280. },
  281. webView: {
  282. backgroundColor: BGWASH,
  283. height: 350,
  284. },
  285. addressBarTextInput: {
  286. backgroundColor: BGWASH,
  287. borderColor: 'transparent',
  288. borderRadius: 3,
  289. borderWidth: 1,
  290. height: 24,
  291. paddingLeft: 10,
  292. paddingTop: 3,
  293. paddingBottom: 3,
  294. flex: 1,
  295. fontSize: 14,
  296. },
  297. navButton: {
  298. width: 20,
  299. padding: 3,
  300. marginRight: 3,
  301. alignItems: 'center',
  302. justifyContent: 'center',
  303. backgroundColor: BGWASH,
  304. borderColor: 'transparent',
  305. borderRadius: 3,
  306. },
  307. disabledButton: {
  308. width: 20,
  309. padding: 3,
  310. marginRight: 3,
  311. alignItems: 'center',
  312. justifyContent: 'center',
  313. backgroundColor: DISABLED_WASH,
  314. borderColor: 'transparent',
  315. borderRadius: 3,
  316. },
  317. goButton: {
  318. height: 24,
  319. padding: 3,
  320. marginLeft: 8,
  321. alignItems: 'center',
  322. backgroundColor: BGWASH,
  323. borderColor: 'transparent',
  324. borderRadius: 3,
  325. alignSelf: 'stretch',
  326. },
  327. statusBar: {
  328. flexDirection: 'row',
  329. alignItems: 'center',
  330. paddingLeft: 5,
  331. height: 22,
  332. },
  333. statusBarText: {
  334. color: 'white',
  335. fontSize: 13,
  336. },
  337. spinner: {
  338. width: 20,
  339. marginRight: 6,
  340. },
  341. buttons: {
  342. flexDirection: 'row',
  343. height: 30,
  344. backgroundColor: 'black',
  345. alignItems: 'center',
  346. justifyContent: 'space-between',
  347. },
  348. button: {
  349. flex: 0.5,
  350. width: 0,
  351. margin: 5,
  352. borderColor: 'gray',
  353. borderWidth: 1,
  354. backgroundColor: 'gray',
  355. },
  356. });
  357. const HTML = `
  358. <!DOCTYPE html>\n
  359. <html>
  360. <head>
  361. <title>Hello Static World</title>
  362. <meta http-equiv="content-type" content="text/html; charset=utf-8">
  363. <meta name="viewport" content="width=320, user-scalable=no">
  364. <style type="text/css">
  365. body {
  366. margin: 0;
  367. padding: 0;
  368. font: 62.5% arial, sans-serif;
  369. background: #ccc;
  370. }
  371. h1 {
  372. padding: 45px;
  373. margin: 0;
  374. text-align: center;
  375. color: #33f;
  376. }
  377. </style>
  378. </head>
  379. <body>
  380. <h1>Hello Static World</h1>
  381. </body>
  382. </html>
  383. `;
  384. exports.displayName = (undefined: ?string);
  385. exports.title = '<WebView>';
  386. exports.description = 'Base component to display web content';
  387. exports.examples = [
  388. {
  389. title: 'Simple Browser',
  390. render(): React.Element<any> {
  391. return <WebViewExample />;
  392. },
  393. },
  394. {
  395. title: 'Scale Page to Fit',
  396. render(): React.Element<any> {
  397. return <ScaledWebView />;
  398. },
  399. },
  400. {
  401. title: 'Bundled HTML',
  402. render(): React.Element<any> {
  403. return (
  404. <WebView
  405. style={{
  406. backgroundColor: BGWASH,
  407. height: 100,
  408. }}
  409. originWhitelist={FILE_SYSTEM_ORIGIN_WHITE_LIST}
  410. source={require('./helloworld.html')}
  411. scalesPageToFit={true}
  412. />
  413. );
  414. },
  415. },
  416. {
  417. title: 'Static HTML',
  418. render(): React.Element<any> {
  419. return (
  420. <WebView
  421. style={{
  422. backgroundColor: BGWASH,
  423. height: 100,
  424. }}
  425. source={{ html: HTML }}
  426. scalesPageToFit={true}
  427. />
  428. );
  429. },
  430. },
  431. {
  432. title: 'POST Test',
  433. render(): React.Element<any> {
  434. return (
  435. <WebView
  436. style={{
  437. backgroundColor: BGWASH,
  438. height: 100,
  439. }}
  440. source={{
  441. uri: 'http://www.posttestserver.com/post.php',
  442. method: 'POST',
  443. body: 'foo=bar&bar=foo',
  444. }}
  445. scalesPageToFit={false}
  446. />
  447. );
  448. },
  449. },
  450. {
  451. title: 'Messaging Test',
  452. render(): React.Element<any> {
  453. return <MessagingTest />;
  454. },
  455. },
  456. {
  457. title: 'Inject JavaScript',
  458. render(): React.Element<any> {
  459. return <InjectJS />;
  460. },
  461. },
  462. ];