UNPKG

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