Files

234 lines
6.1 KiB
JavaScript
Raw Permalink Normal View History

2016-02-10 14:04:21 -05:00
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* Copyright (c) 2016-present, Ali Najafizadeh
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule WebViewBridge
*/
'use strict';
var React = require('react-native');
var invariant = require('invariant');
var keyMirror = require('keymirror');
var merge = require('merge');
var resolveAssetSource = require('react-native/Libraries/Image/resolveAssetSource');
2016-02-10 14:04:21 -05:00
var {
ReactNativeViewAttributes,
UIManager,
EdgeInsetsPropType,
StyleSheet,
Text,
View,
2016-02-16 10:29:44 +01:00
WebView,
2016-02-10 14:04:21 -05:00
requireNativeComponent,
PropTypes,
2016-02-11 16:13:50 -05:00
DeviceEventEmitter,
2016-02-10 14:04:21 -05:00
NativeModules: {
WebViewBridgeManager
}
} = React;
var RCT_WEBVIEWBRIDGE_REF = 'webviewbridge';
var WebViewBridgeState = keyMirror({
IDLE: null,
LOADING: null,
ERROR: null,
});
/**
* Renders a native WebView.
*/
var WebViewBridge = React.createClass({
propTypes: {
2016-02-16 10:29:44 +01:00
...WebView.propTypes,
2016-02-10 14:04:21 -05:00
/**
* Will be called once the message is being sent from webview
*/
onBridgeMessage: PropTypes.func,
},
getInitialState: function() {
return {
viewState: WebViewBridgeState.IDLE,
lastErrorEvent: null,
startInLoadingState: true,
};
},
componentWillMount: function() {
2016-02-24 13:24:39 -05:00
DeviceEventEmitter.addListener("webViewBridgeMessage", (body) => {
2016-02-11 16:13:50 -05:00
const { onBridgeMessage } = this.props;
2016-02-24 13:24:39 -05:00
const message = body.message;
if (onBridgeMessage) {
onBridgeMessage(message);
}
2016-02-11 16:13:50 -05:00
});
2016-02-10 14:04:21 -05:00
if (this.props.startInLoadingState) {
this.setState({viewState: WebViewBridgeState.LOADING});
}
},
render: function() {
var otherView = null;
if (this.state.viewState === WebViewBridgeState.LOADING) {
otherView = this.props.renderLoading && this.props.renderLoading();
} else if (this.state.viewState === WebViewBridgeState.ERROR) {
var errorEvent = this.state.lastErrorEvent;
otherView = this.props.renderError && this.props.renderError(
errorEvent.domain,
errorEvent.code,
errorEvent.description);
} else if (this.state.viewState !== WebViewBridgeState.IDLE) {
console.error('RCTWebViewBridge invalid state encountered: ' + this.state.loading);
}
var webViewStyles = [styles.container, this.props.style];
if (this.state.viewState === WebViewBridgeState.LOADING ||
this.state.viewState === WebViewBridgeState.ERROR) {
// if we're in either LOADING or ERROR states, don't show the webView
webViewStyles.push(styles.hidden);
}
var {javaScriptEnabled, domStorageEnabled} = this.props;
if (this.props.javaScriptEnabledAndroid) {
console.warn('javaScriptEnabledAndroid is deprecated. Use javaScriptEnabled instead');
javaScriptEnabled = this.props.javaScriptEnabledAndroid;
}
if (this.props.domStorageEnabledAndroid) {
console.warn('domStorageEnabledAndroid is deprecated. Use domStorageEnabled instead');
domStorageEnabled = this.props.domStorageEnabledAndroid;
}
2016-03-02 20:24:15 +05:30
let {source, ...props} = {...this.props};
2016-02-10 14:04:21 -05:00
var webView =
<RCTWebViewBridge
ref={RCT_WEBVIEWBRIDGE_REF}
key="webViewKey"
2016-02-27 12:37:01 -05:00
{...props}
2016-03-02 20:24:15 +05:30
source={resolveAssetSource(source)}
2016-02-10 14:04:21 -05:00
style={webViewStyles}
onLoadingStart={this.onLoadingStart}
onLoadingFinish={this.onLoadingFinish}
onLoadingError={this.onLoadingError}
/>;
return (
<View style={styles.container}>
{webView}
{otherView}
</View>
);
},
goForward: function() {
UIManager.dispatchViewManagerCommand(
this.getWebViewBridgeHandle(),
UIManager.RCTWebViewBridge.Commands.goForward,
null
);
},
goBack: function() {
UIManager.dispatchViewManagerCommand(
this.getWebViewBridgeHandle(),
UIManager.RCTWebViewBridge.Commands.goBack,
null
);
},
reload: function() {
UIManager.dispatchViewManagerCommand(
this.getWebViewBridgeHandle(),
UIManager.RCTWebViewBridge.Commands.reload,
null
);
},
sendToBridge: function (message: string) {
2016-02-11 16:13:50 -05:00
UIManager.dispatchViewManagerCommand(
this.getWebViewBridgeHandle(),
UIManager.RCTWebViewBridge.Commands.sendToBridge,
[message]
);
},
injectBridgeScript: function () {
UIManager.dispatchViewManagerCommand(
this.getWebViewBridgeHandle(),
UIManager.RCTWebViewBridge.Commands.injectBridgeScript,
null
);
2016-02-10 14:04:21 -05:00
},
/**
* We return an event with a bunch of fields including:
* url, title, loading, canGoBack, canGoForward
*/
updateNavigationState: function(event) {
if (this.props.onNavigationStateChange) {
this.props.onNavigationStateChange(event.nativeEvent);
}
},
getWebViewBridgeHandle: function() {
return React.findNodeHandle(this.refs[RCT_WEBVIEWBRIDGE_REF]);
},
onLoadingStart: function(event) {
2016-02-11 16:13:50 -05:00
this.injectBridgeScript();
2016-02-10 14:04:21 -05:00
var onLoadStart = this.props.onLoadStart;
onLoadStart && onLoadStart(event);
this.updateNavigationState(event);
},
onLoadingError: function(event) {
event.persist(); // persist this event because we need to store it
var {onError, onLoadEnd} = this.props;
onError && onError(event);
onLoadEnd && onLoadEnd(event);
console.error('Encountered an error loading page', event.nativeEvent);
this.setState({
lastErrorEvent: event.nativeEvent,
viewState: WebViewBridgeState.ERROR
});
},
onLoadingFinish: function(event) {
var {onLoad, onLoadEnd} = this.props;
onLoad && onLoad(event);
onLoadEnd && onLoadEnd(event);
this.setState({
viewState: WebViewBridgeState.IDLE,
});
this.updateNavigationState(event);
},
});
var RCTWebViewBridge = requireNativeComponent('RCTWebViewBridge', WebViewBridge);
var styles = StyleSheet.create({
container: {
flex: 1,
},
hidden: {
height: 0,
flex: 0, // disable 'flex:1' when hiding a View
},
});
module.exports = WebViewBridge;