forked from archriss/react-native-display-html
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
157 lines (141 loc) · 4.98 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import React, { Component } from 'react';
import { View, WebView, Platform, ViewPropTypes } from 'react-native';
import PropTypes from 'prop-types';
import WebViewBridge from 'react-native-webview-bridge';
export default class DisplayHTML extends Component {
static propTypes () {
return {
htmlString: PropTypes.string.isRequired,
onMessage: PropTypes.func,
additionalScripts: PropTypes.array,
title: PropTypes.string,
style: ViewPropTypes ? ViewPropTypes.style : WebView.propTypes.style,
containerStyle: ViewPropTypes ? ViewPropTypes.style : View.propTypes.style,
HTMLStyles: PropTypes.string,
defaultHeight: PropTypes.number,
additionalHeight: PropTypes.number,
bodyClass: PropTypes.string
};
};
static defaultProps = {
title: `react-native-display-html-${Date.now()}`,
scrollEnabled: false,
defaultHeight: 100,
additionalHeight: 0,
containerStyle: {},
style: {},
bodyClass: ''
};
constructor (props) {
super(props);
this.state = {
height: props.defaultHeight + props.additionalHeight
};
this.onMessage = this.onMessage.bind(this);
this.additionalScripts = [this.heightScript];
if (props.additionalScripts && props.additionalScripts.length) {
this.additionalScripts = this.additionalScripts.concat(props.additionalScripts);
}
this._buildAdditionalScripts();
}
get HTMLSource () {
return `
<!DOCTYPE html>
<title>${this.props.title}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<html>${this.HTMLStyles}
<body class="${this.props.bodyClass}">
${this.props.htmlString}
</body>
</html>`;
}
get HTMLStyles () {
return this.props.HTMLStyles ? `<style>${this.props.HTMLStyles}</style>` : '';
}
get source () {
let source = { html: this.HTMLSource };
if (Platform.OS === 'android' && Platform.Version > 18) {
// Allows loading assets such as fonts from the webview.
// Setting a baseUrl prevents the HTML from rendering
// on Android < 4.4.
// See: https://github.com/facebook/react-native/issues/11753
// Potential fix: http://bit.ly/2jrH6RC
source.baseUrl = 'file:///android_asset/';
}
return source;
}
/**
* Checks regularly the height of the webview to update the webview
* accordingly.
* Note : this isn't transpiled and must be written in ES5 !
*/
heightScript () {
function updateHeight () {
var B = document.body;
var height;
if (typeof document.height !== 'undefined') {
height = document.height;
} else {
height = Math.max(B.scrollHeight, B.offsetHeight);
}
window.WebViewBridge.send(JSON.stringify({ height: height }));
}
if (window.WebViewBridge) {
updateHeight();
setInterval(updateHeight, 1000);
}
}
/**
* Little helper converting functions to plain strings to inject
* in the webview.
* @param {function} func
*/
_stringifyFunc (func) {
return `(${String(func)})();`;
}
/**
* Build a single large string with all scripts so it can be injected
* in the webview.
*/
_buildAdditionalScripts () {
this._injectedScripts = '';
this.additionalScripts.forEach((func) => {
this._injectedScripts += this._stringifyFunc(func);
});
}
/**
* Callback when the bridge sends a message back to react-native.
* It updates the webview's height if the payload contains the
* 'height' key. Else, it fires this.props.onMessage.
* @param {object} event
*/
onMessage (event) {
const { additionalHeight, onMessage } = this.props;
const eventData = JSON.parse(event);
const { height } = eventData;
if (height) {
let newHeight = height;
if (!this._additionalHeightInjected) {
newHeight += additionalHeight;
this._additionalHeightInjected = true;
}
this.setState({ height: newHeight });
} else {
return onMessage && onMessage(eventData);
}
}
render () {
const { style, containerStyle } = this.props;
return (
<View style={containerStyle}>
<WebViewBridge
{...this.props}
injectedJavaScript={this._injectedScripts}
style={[style, { height: this.state.height }]}
source={this.source}
onBridgeMessage={this.onMessage}
/>
</View>
);
}
}