UNPKG

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