123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- 'use strict';
-
- import React, { PureComponent } from 'react';
-
- import { Animated, Dimensions, StyleSheet, WebView } from 'react-native';
-
- import { androidPropTypes } from './propTypes.js';
-
- import Immutable from 'immutable';
-
- import { handleSizeUpdated, domMutationObserveScript } from './common.js';
-
- export default class AutoHeightWebView extends PureComponent {
- static propTypes = androidPropTypes;
-
- static defaultProps = {
- scalesPageToFit: true,
- enableBaseUrl: false,
- enableAnimation: true,
- animationDuration: 555,
- heightOffset: 20
- };
-
- constructor(props) {
- super(props);
- props.enableAnimation && (this.opacityAnimatedValue = new Animated.Value(0));
- this.state = {
- isChangingSource: false,
- height: 0,
- heightOffset: 0,
- script: baseScript
- };
- }
-
- componentDidMount() {
- this.startInterval();
- }
-
- componentWillReceiveProps(nextProps) {
- // injectedJavaScript only works when webView reload (source changed)
- if (Immutable.is(Immutable.fromJS(this.props.source), Immutable.fromJS(nextProps.source))) {
- return;
- } else {
- this.setState(
- {
- isChangingSource: true,
- height: 0,
- heightOffset: 0
- },
- () => {
- this.startInterval();
- this.setState({ isChangingSource: false });
- }
- );
- }
- this.setState({ script: baseScript });
- }
-
- componentWillUnmount() {
- this.stopInterval();
- }
-
- startInterval() {
- this.finishInterval = false;
- this.interval = setInterval(() => !this.finishInterval && this.webView.postMessage('getBodyHeight'), 205);
- }
-
- stopInterval() {
- this.finishInterval = true;
- clearInterval(this.interval);
- }
-
- onMessage = event => {
- const height = parseInt(event.nativeEvent.data);
- if (height && height !== this.state.height) {
- const { enableAnimation, animationDuration, heightOffset, onSizeUpdated, style } = this.props;
- enableAnimation && this.opacityAnimatedValue.setValue(0);
- this.stopInterval();
- this.setState(
- {
- heightOffset,
- height
- },
- () => {
- const currentWidth = Object.assign(styles.container, style).width;
- enableAnimation
- ? Animated.timing(this.opacityAnimatedValue, {
- toValue: 1,
- duration: animationDuration
- }).start(() => handleSizeUpdated(height, currentWidth, onSizeUpdated))
- : handleSizeUpdated(height, currentWidth, onSizeUpdated);
- }
- );
- }
- const { onMessage } = this.props;
- onMessage && onMessage(event);
- };
-
- getWebView = webView => (this.webView = webView);
-
- render() {
- const { height, script, isChangingSource, heightOffset } = this.state;
- const {
- thirdPartyCookiesEnabled,
- domStorageEnabled,
- userAgent,
- geolocationEnabled,
- allowUniversalAccessFromFileURLs,
- mixedContentMode,
- onNavigationStateChange,
- renderError,
- originWhitelist,
- mediaPlaybackRequiresUserAction,
- scalesPageToFit,
- enableAnimation,
- source,
- customScript,
- style,
- enableBaseUrl,
- onError,
- onLoad,
- onLoadStart,
- onLoadEnd
- } = this.props;
- let webViewSource = source;
- if (enableBaseUrl) {
- webViewSource = Object.assign({}, source, {
- baseUrl: 'file:///android_asset/web/'
- });
- }
- return (
- <Animated.View
- style={[
- styles.container,
- {
- opacity: enableAnimation ? this.opacityAnimatedValue : 1,
- height: height + heightOffset
- },
- style
- ]}
- >
- {isChangingSource ? null : (
- <WebView
- onNavigationStateChange={onNavigationStateChange}
- domStorageEnabled={domStorageEnabled}
- thirdPartyCookiesEnabled={thirdPartyCookiesEnabled}
- userAgent={userAgent}
- geolocationEnabled={geolocationEnabled}
- allowUniversalAccessFromFileURLs={allowUniversalAccessFromFileURLs}
- mixedContentMode={mixedContentMode}
- renderError={renderError}
- mediaPlaybackRequiresUserAction={mediaPlaybackRequiresUserAction}
- originWhitelist={originWhitelist}
- ref={this.getWebView}
- onMessage={this.onMessage}
- onError={onError}
- onLoad={onLoad}
- onLoadStart={onLoadStart}
- onLoadEnd={onLoadEnd}
- style={styles.webView}
- scalesPageToFit={scalesPageToFit}
- javaScriptEnabled={true}
- injectedJavaScript={script + customScript}
- source={webViewSource}
- messagingEnabled={true}
- />
- )}
- </Animated.View>
- );
- }
- }
-
- const screenWidth = Dimensions.get('window').width;
-
- const styles = StyleSheet.create({
- container: {
- height: 50,
- width: screenWidth,
- backgroundColor: 'transparent'
- },
- webView: {
- flex: 1,
- backgroundColor: 'transparent'
- }
- });
-
- const baseScript = `
- ; (function () {
- document.addEventListener('message', function (e) {
- window.postMessage(String(document.body.offsetHeight));
- });
- ${domMutationObserveScript}
- } ());
- `;
|