123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- 'use strict'
-
- import React, {
- Component,
- PropTypes
- } from 'react';
-
- import {
- findNodeHandle,
- requireNativeComponent,
- DeviceEventEmitter,
- Dimensions,
- Platform,
- UIManager,
- View,
- WebView
- } from 'react-native';
-
- const RCTAutoHeightWebView = requireNativeComponent('RCTAutoHeightWebView', AutoHeightWebView, { nativeOnly: { messagingEnabled: PropTypes.bool } });
-
- export default class AutoHeightWebView extends Component {
- constructor(props) {
- super(props);
- this.onMessage = this.onMessage.bind(this);
- if (IsBelowKitKat) {
- this.listenWebViewBridgeMessage = this.listenWebViewBridgeMessage.bind(this);
- }
- const initialScript = props.files ? this.appendFilesToHead(props.files, BaseScript) : BaseScript;
- this.state = {
- isChangingSource: false,
- height: 0,
- heightOffset: 0,
- script: initialScript
- };
- }
-
- componentWillMount() {
- if (IsBelowKitKat) {
- DeviceEventEmitter.addListener("webViewBridgeMessage", this.listenWebViewBridgeMessage);
- }
- }
-
- componentDidMount() {
- this.startInterval();
- }
-
- componentWillReceiveProps(nextProps) {
- // injectedJavaScript only works when webview reload (html changed)
- if (nextProps.html === this.props.html) {
- this.htmlHasChanged = false;
- return;
- }
- else {
- this.setState({
- isChangingSource: true,
- height: 0,
- heightOffset: 0
- });
- }
- let currentScript = BaseScript;
- if ((nextProps.files && !this.props.files) || (nextProps.files && this.props.files && JSON.stringify(nextProps.files) !== JSON.stringify(this.props.files))) {
- currentScript = this.appendFilesToHead(nextProps.files, BaseScript);
- }
- this.setState({ script: currentScript });
- }
-
- componentDidUpdate(prevProps, prevState) {
- // redisplay webview when changing source
- if (this.state.isChangingSource) {
- this.startInterval();
- this.setState({ isChangingSource: false });
- }
- }
-
- componentWillUnmount() {
- this.stopInterval();
- if (IsBelowKitKat) {
- DeviceEventEmitter.removeListener("webViewBridgeMessage", listenWebViewBridgeMessage);
- }
- }
-
- listenWebViewBridgeMessage(body) {
- this.onMessage(body.message);
- }
-
- postMessage(data) {
- UIManager.dispatchViewManagerCommand(
- findNodeHandle(this.webview),
- UIManager.RCTAutoHeightWebView.Commands.postMessage,
- [String(data)]
- );
- };
-
- sendToWebView(message) {
- UIManager.dispatchViewManagerCommand(
- findNodeHandle(this.webview),
- UIManager.RCTAutoHeightWebView.Commands.sendToWebView,
- [String(message)]
- );
- }
-
- startInterval() {
- this.finishInterval = false;
- this.interval = setInterval(() => {
- if (!this.finishInterval) {
- IsBelowKitKat ? this.sendToWebView('getBodyHeight') : this.postMessage('getBodyHeight');
- }
- }, 205);
- }
-
- stopInterval() {
- this.finishInterval = true;
- clearInterval(this.interval);
- }
-
- onMessage(e) {
- const height = parseInt(IsBelowKitKat ? e.nativeEvent.message : e.nativeEvent.data);
- if (height) {
- this.stopInterval();
- console.log(height);
- this.setState({
- heightOffset: this.props.heightOffset,
- height
- });
- if (this.props.onHeightUpdated) {
- this.props.onHeightUpdated(height);
- }
- }
- }
-
- appendFilesToHead(files, script) {
- if (!files) {
- return script;
- }
- for (let file of files) {
- script =
- `
- var link = document.createElement('link');
- link.rel = '` + file.rel + `';
- link.type = '` + file.type + `';
- link.href = '` + file.href + `';
- document.head.appendChild(link);
- `+ script;
- }
- return script;
- }
-
- render() {
- const source = this.props.enableBaseUrl ? {
- html: this.props.html,
- baseUrl: 'file:///android_asset/web/'
- } : { html: this.props.html };
- return (
- <View style={[{
- width: ScreenWidth,
- height: this.state.height + this.state.heightOffset
- }, this.props.style]}>
- {
- this.state.isChangingSource ? null :
- <RCTAutoHeightWebView
- ref={webview => this.webview = webview}
- style={{ flex: 1 }}
- javaScriptEnabled={true}
- injectedJavaScript={this.state.script + this.props.customScript}
- scrollEnabled={false}
- source={source}
- onChange={this.onMessage}
- onMessage={this.onMessage}
- messagingEnabled={true} />
- }
- </View>
- );
- }
- }
-
- AutoHeightWebView.propTypes = {
- ...WebView.propTypes,
- html: PropTypes.string,
- onHeightUpdated: PropTypes.func,
- customScript: PropTypes.string,
- // offset rn webview margin
- heightOffset: PropTypes.number,
- // baseUrl not work in android 4.3 or below version
- enableBaseUrl: PropTypes.bool,
- // works if set enableBaseUrl to true; add web/files... to android/app/src/assets/
- files: PropTypes.arrayOf(PropTypes.shape({
- href: PropTypes.string,
- type: PropTypes.string,
- rel: PropTypes.string
- }))
- }
-
- AutoHeightWebView.defaultProps = {
- enableBaseUrl: false,
- heightOffset: 20
- }
-
- const ScreenWidth = Dimensions.get('window').width;
-
- const IsBelowKitKat = Platform.Version < 19;
-
- const BaseScript =
- IsBelowKitKat ?
- `
- (function () {
- AutoHeightWebView.onMessage = function (message) {
- AutoHeightWebView.send(String(document.body.offsetHeight));
- };
- } ());
- ` :
- `
- ; (function () {
- document.addEventListener('message', function (e) {
- window.postMessage(String(document.body.offsetHeight));
- });
- } ());
- `;
|