UNPKG

5.17 kBJavaScriptView Raw
1/********************************************
2 * WebViewQuillViewer.js
3 * A Delta viewer suitable for viewing output from a Quill.js
4 * editor. The Delta format is discussed here: https://quilljs.com/docs/delta/
5 * This component is useful for applications that must avoid using native code
6 *
7 */
8import React from 'react';
9import { View, ActivityIndicator, StyleSheet, WebView, Platform } from 'react-native';
10import PropTypes from 'prop-types';
11import renderIf from 'render-if';
12import { Asset } from 'expo';
13// path to the file that the webview will load
14const INDEX_FILE_PATH = `./assets/dist/reactQuillViewer-index.html`;
15const INDEX_FILE_ASSET_URI = Asset.fromModule(require(INDEX_FILE_PATH)).uri;
16const MESSAGE_PREFIX = 'react-native-webview-quilljs';
17
18export default class WebViewQuillViewer extends React.Component {
19 constructor() {
20 super();
21 this.webview = null;
22 this.state = {
23 webViewNotLoaded: true, // flag to show activity indicator
24 };
25 }
26
27 createWebViewRef = (webview) => {
28 this.webview = webview;
29 };
30
31 handleMessage = (event) => {
32 let msgData;
33 try {
34 msgData = JSON.parse(event.nativeEvent.data);
35 if (msgData.hasOwnProperty('prefix') && msgData.prefix === MESSAGE_PREFIX) {
36 // console.log(`WebViewQuillEditor: received message ${msgData.type}`);
37 this.sendMessage('MESSAGE_ACKNOWLEDGED');
38 // console.log(`WebViewQuillEditor: sent MESSAGE_ACKNOWLEDGED`);
39
40 switch (msgData.type) {
41 case 'VIEWER_LOADED':
42 this.viewerLoaded();
43 break;
44 case 'VIEWER_SENT':
45 this.props.getViewerCallback(msgData.payload.viewer);
46 break;
47 default:
48 console.warn(`WebViewQuillViewer Error: Unhandled message type received "${msgData.type}"`);
49 }
50 }
51 } catch (err) {
52 console.warn(err);
53 return;
54 }
55 };
56
57 onWebViewLoaded = () => {
58 console.log('Webview loaded');
59 this.setState({ webViewNotLoaded: false });
60 this.sendMessage('LOAD_VIEWER');
61 if (this.props.hasOwnProperty('backgroundColor')) {
62 this.sendMessage('SET_BACKGROUND_COLOR', {
63 backgroundColor: this.props.backgroundColor
64 });
65 };
66 if(this.props.hasOwnProperty('onLoad')){
67 this.props.onLoad();
68 }
69 if(this.props.hasOwnProperty('getViewerCallback')){
70 this.sendMessage('SEND_VIEWER');
71 }
72 };
73
74 viewerLoaded = () => {
75 // send the content to the viewer if we have it
76 if (this.props.hasOwnProperty('contentToDisplay')) {
77 console.log(this.props.contentToDisplay);
78 this.sendMessage('SET_CONTENTS', {
79 ops: this.props.contentToDisplay
80 });
81 }
82 if (this.props.hasOwnProperty('htmlContentToDisplay')) {
83 this.sendMessage('SET_HTML_CONTENTS', {
84 html: this.props.htmlContentToDisplay
85 });
86 }
87 };
88
89 sendContentToViewer = (delta) => {
90 this.sendMessage('SET_CONTENTS', {
91 ops: delta.ops
92 });
93 };
94
95 sendMessage = (type, payload) => {
96 // only send message when webview is loaded
97 if (this.webview) {
98 console.log(`WebViewQuillViewer: sending message ${type}`);
99 this.webview.postMessage(
100 JSON.stringify({
101 prefix: MESSAGE_PREFIX,
102 type,
103 payload
104 }),
105 '*'
106 );
107 }
108 };
109
110 showLoadingIndicator = () => {
111 return (
112 <View style={styles.activityOverlayStyle}>
113 <View style={styles.activityIndicatorContainer}>
114 <ActivityIndicator size="large" animating={this.state.webViewNotLoaded} color="green" />
115 </View>
116 </View>
117 );
118 };
119
120 onError = (error) => {
121 Alert.alert('WebView onError', error, [ { text: 'OK', onPress: () => console.log('OK Pressed') } ]);
122 };
123
124 renderError = (error) => {
125 Alert.alert('WebView renderError', error, [ { text: 'OK', onPress: () => console.log('OK Pressed') } ]);
126 };
127
128 render = () => {
129 return (
130 <View
131 style={{
132 flex: 1,
133 }}
134 >
135 <WebView
136 style={{ ...StyleSheet.absoluteFillObject }}
137 ref={this.createWebViewRef}
138 source={
139 Platform.OS === 'ios'
140 ? require('./assets/dist/reactQuillViewer-index.html')
141 : { uri: INDEX_FILE_ASSET_URI }
142 }
143 onLoadEnd={this.onWebViewLoaded}
144 onMessage={this.handleMessage}
145 startInLoadingState={true}
146 renderLoading={this.showLoadingIndicator}
147 renderError={this.renderError}
148 javaScriptEnabled={true}
149 onError={this.onError}
150 scalesPageToFit={false}
151 mixedContentMode={'always'}
152 />
153 </View>
154 );
155 };
156}
157
158WebViewQuillViewer.propTypes = {
159 backgroundColor: PropTypes.string,
160 onLoad: PropTypes.func
161};
162
163// Specifies the default values for props:
164WebViewQuillViewer.defaultProps = {
165 theme: 'bubble'
166};
167
168const styles = StyleSheet.create({
169 activityOverlayStyle: {
170 ...StyleSheet.absoluteFillObject,
171 marginHorizontal: 20,
172 marginVertical: 60,
173 display: 'flex',
174 justifyContent: 'center',
175 alignContent: 'center',
176 borderRadius: 5
177 },
178 activityIndicatorContainer: {
179 backgroundColor: 'white',
180 padding: 10,
181 borderRadius: 50,
182 alignSelf: 'center',
183 shadowColor: '#000000',
184 shadowOffset: {
185 width: 0,
186 height: 3
187 },
188 shadowRadius: 5,
189 shadowOpacity: 1.0
190 }
191});