From 068112460945cf6a48ebec9757640838ca2586ba Mon Sep 17 00:00:00 2001 From: "chen.yang" Date: Tue, 20 Dec 2016 19:32:45 +0800 Subject: [PATCH 1/2] add renderLoading callback to CrosswalkWebview --- index.android.js | 116 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 106 insertions(+), 10 deletions(-) diff --git a/index.android.js b/index.android.js index bb459c2..ccfaa57 100644 --- a/index.android.js +++ b/index.android.js @@ -1,7 +1,7 @@ 'use strict'; import React, { PropTypes } from 'react'; -import ReactNative, { requireNativeComponent, View } from 'react-native'; +import ReactNative, { requireNativeComponent, View, ActivityIndicator, StyleSheet } from 'react-native'; var { addons: { PureRenderMixin }, @@ -12,6 +12,20 @@ var resolveAssetSource = require('react-native/Libraries/Image/resolveAssetSourc var WEBVIEW_REF = 'crosswalkWebView'; +const WebViewState = { + IDLE: 'IDLE', + LOADING: 'LOADING', + ERROR: 'ERROR', +}; + +var defaultRenderLoading = () => ( + + + +); + var CrosswalkWebView = React.createClass({ mixins: [PureRenderMixin], statics: { JSNavigationScheme }, @@ -30,14 +44,52 @@ var CrosswalkWebView = React.createClass({ PropTypes.number, // used internally by React packager ]), url: PropTypes.string, + renderError: PropTypes.func, + renderLoading: PropTypes.func, + onLoad: PropTypes.func, + onLoadEnd: PropTypes.func, + startInLoadingState: PropTypes.bool, // force WebView to show loadingView on first load ...View.propTypes }, + getInitialState () { + return { + viewState: WebViewState.IDLE, + lastErrorEvent: null, + startInLoadingState: true, + }; + }, getDefaultProps () { - return { - localhost: false - }; + return { + localhost: false + }; + }, + componentWillMount() { + if (this.props.startInLoadingState) { + this.setState({viewState: WebViewState.LOADING}); + } }, render () { + var otherView = null; + + if (this.state.viewState === WebViewState.LOADING) { + otherView = (this.props.renderLoading || defaultRenderLoading)(); + } else if (this.state.viewState === WebViewState.ERROR) { + var errorEvent = this.state.lastErrorEvent; + otherView = this.props.renderError && this.props.renderError( + errorEvent.url, + errorEvent.errorNumber, + errorEvent.errorMessage); + } else if (this.state.viewState !== WebViewState.IDLE) { + console.error('WebView invalid state encountered: ' + this.state.loading); + } + + var webViewStyles = [styles.container, this.props.style]; + if (this.state.viewState === WebViewState.LOADING || + this.state.viewState === WebViewState.ERROR) { + // if we're in either LOADING or ERROR states, don't show the webView + webViewStyles.push(styles.hidden); + } + var source = this.props.source || {}; if (this.props.url) { source.uri = this.props.url; @@ -46,28 +98,54 @@ var CrosswalkWebView = React.createClass({ onCrosswalkWebViewNavigationStateChange: this.onNavigationStateChange, onCrosswalkWebViewError: this.onError }); - return ( + var webView = + style={webViewStyles} + />; + + return ( + + {webView} + {otherView} + ); }, getWebViewHandle () { return ReactNative.findNodeHandle(this.refs[WEBVIEW_REF]); }, onNavigationStateChange (event) { + if (event.nativeEvent && !event.nativeEvent.loading) { + this._onLoadingFinish(event); + } + var { onNavigationStateChange } = this.props; if (onNavigationStateChange) { onNavigationStateChange(event.nativeEvent); } }, onError (event) { - var { onError } = this.props; - if (onError) { - onError(event.nativeEvent); - } + this._onLoadingFinish(event); + + var {onError, onLoadEnd} = this.props; + onError && onError(event.nativeEvent); + onLoadEnd && onLoadEnd(event); + console.warn('Encountered an error loading page', event.nativeEvent); + + this.setState({ + lastErrorEvent: event.nativeEvent, + viewState: WebViewState.ERROR + }); + }, + _onLoadingFinish (event) { + var {onLoad, onLoadEnd} = this.props; + onLoad && onLoad(event); + onLoadEnd && onLoadEnd(event); + this.setState({ + viewState: WebViewState.IDLE, + }); }, goBack () { UIManager.dispatchViewManagerCommand( @@ -92,6 +170,24 @@ var CrosswalkWebView = React.createClass({ } }); +var styles = StyleSheet.create({ + container: { + flex: 1, + }, + hidden: { + height: 0, + flex: 0, // disable 'flex:1' when hiding a View + }, + loadingView: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + }, + loadingProgressBar: { + height: 20, + }, +}); + var NativeCrosswalkWebView = requireNativeComponent('CrosswalkWebView', CrosswalkWebView); export default CrosswalkWebView; From 034aaf97369bbdba9ee93c932411b94e5a6df226 Mon Sep 17 00:00:00 2001 From: "chen.yang" Date: Wed, 21 Dec 2016 13:48:55 +0800 Subject: [PATCH 2/2] add renderError support --- index.android.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/index.android.js b/index.android.js index ccfaa57..84a236f 100644 --- a/index.android.js +++ b/index.android.js @@ -118,7 +118,9 @@ var CrosswalkWebView = React.createClass({ }, onNavigationStateChange (event) { if (event.nativeEvent && !event.nativeEvent.loading) { - this._onLoadingFinish(event); + if (this.state.viewState !== WebViewState.ERROR) { + this._onLoadingFinish(event); + } } var { onNavigationStateChange } = this.props;