forked from kevinstumpf/react-native-signature-pad
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
132 lines (106 loc) · 4.17 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
'use strict';
import React, { Component } from 'react';
import {
View,
WebView,
StyleSheet,
} from 'react-native';
import PropTypes from 'prop-types';
import htmlContent from './injectedHtml';
import injectedSignaturePad from './injectedJavaScript/signaturePad';
import injectedApplication from './injectedJavaScript/application';
import injectedErrorHandler from './injectedJavaScript/errorHandler';
import injectedExecuteNativeFunction from './injectedJavaScript/executeNativeFunction';
class SignaturePad extends Component {
static propTypes = {
onChange: PropTypes.func,
onError: PropTypes.func,
style: View.propTypes.style,
penColor: PropTypes.string,
dataURL: PropTypes.string,
};
static defaultProps = {
onChange: () => {
},
onError: () => {
},
style: {}
};
constructor(props) {
super(props);
this.state = {base64DataUrl: props.dataURL || null};
const { backgroundColor } = StyleSheet.flatten(props.style);
var injectedJavaScript = injectedExecuteNativeFunction
+ injectedErrorHandler
+ injectedSignaturePad
+ injectedApplication(props.penColor, backgroundColor, props.dataURL);
var html = htmlContent(injectedJavaScript);
this.source = {html}; //We don't use WebView's injectedJavaScript because on Android, the WebView re-injects the JavaScript upon every url change. Given that we use url changes to communicate signature changes to the React Native app, the JS is re-injected every time a stroke is drawn.
}
_onNavigationChange = (args) => {
this._parseMessageFromWebViewNavigationChange(unescape(args.url));
};
_parseMessageFromWebViewNavigationChange = (newUrl) => {
//Example input:
//applewebdata://4985ECDA-4C2B-4E37-87ED-0070D14EB985#executeFunction=jsError&arguments=%7B%22message%22:%22ReferenceError:%20Can't%20find%20variable:%20WHADDUP%22,%22url%22:%22applewebdata://4985ECDA-4C2B-4E37-87ED-0070D14EB985%22,%22line%22:340,%22column%22:10%7D"
//All parameters to the native world are passed via a hash url where every parameter is passed as &[ParameterName]<-[Content]&
var hashUrlIndex = newUrl.lastIndexOf('#');
if(hashUrlIndex === -1) {
return;
}
var hashUrl = newUrl.substring(hashUrlIndex);
hashUrl = decodeURIComponent(hashUrl);
var regexFindAllSubmittedParameters = /&(.*?)&/g;
var parameters = {};
var parameterMatch = regexFindAllSubmittedParameters.exec(hashUrl);
if(!parameterMatch) {
return;
}
while(parameterMatch) {
var parameterPair = parameterMatch[1]; //For example executeFunction=jsError or arguments=...
var parameterPairSplit = parameterPair.split('<-');
if(parameterPairSplit.length === 2) {
parameters[parameterPairSplit[0]] = parameterPairSplit[1];
}
parameterMatch = regexFindAllSubmittedParameters.exec(hashUrl);
}
if(!this._attemptToExecuteNativeFunctionFromWebViewMessage(parameters)) {
logger.warn({parameters, hashUrl}, 'Received an unknown set of parameters from WebView');
}
};
_attemptToExecuteNativeFunctionFromWebViewMessage = (message) => {
if(message.executeFunction && message.arguments) {
var parsedArguments = JSON.parse(message.arguments);
var referencedFunction = this['_bridged_' + message.executeFunction];
if(typeof(referencedFunction) === 'function') {
referencedFunction.apply(this, [parsedArguments]);
return true;
}
}
return false;
};
_bridged_jsError = (args) => {
this.props.onError({details: args});
};
_bridged_finishedStroke = ({base64DataUrl}) => {
this.props.onChange({base64DataUrl});
this.setState({base64DataUrl});
};
_renderError = (args) => {
this.props.onError({details: args});
};
_renderLoading = (args) => {
};
render = () => {
return (
<WebView automaticallyAdjustContentInsets={false}
onNavigationStateChange={this._onNavigationChange}
renderError={this._renderError}
renderLoading={this._renderLoading}
source={this.source}
javaScriptEnabled={true}
style={this.props.style}/>
)
};
}
module.exports = SignaturePad;