Brak opisu

WebViewExample.js 11KB

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