react-native-signature-pad-v2
Version:
React Native wrapper around szimek's Canvas based Signature Pad
135 lines (112 loc) • 4.58 kB
JavaScript
import { ViewPropTypes } from "deprecated-react-native-prop-types";
import PropTypes from "prop-types";
import React, { Component } from "react";
import { StyleSheet } from "react-native";
import { WebView } from "react-native-webview";
import htmlContent from "./injectedHtml";
import injectedApplication from "./injectedJavaScript/application";
import injectedErrorHandler from "./injectedJavaScript/errorHandler";
import injectedExecuteNativeFunction from "./injectedJavaScript/executeNativeFunction";
import injectedSignaturePad from "./injectedJavaScript/signaturePad";
export default class SignaturePad extends Component {
static propTypes = {
onChange: PropTypes.func,
onError: PropTypes.func,
style: ViewPropTypes.style,
penColor: PropTypes.string,
dataURL: PropTypes.string,
};
static defaultProps = {
onChange: () => {},
onError: () => {},
style: {},
};
constructor(props) {
super(props);
const { backgroundColor } = StyleSheet.flatten(props.style);
var injectedJavaScript =
injectedExecuteNativeFunction +
injectedErrorHandler +
injectedSignaturePad +
injectedApplication(props.penColor, backgroundColor, props.dataURL);
var html = htmlContent(injectedJavaScript);
this.state = { base64DataUrl: props.dataURL || null };
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.
}
componentDidMount() {
this.setState({
source: this.source,
});
}
_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) => {};
onMessage = (event) => {
var base64DataUrl = JSON.parse(event.nativeEvent.data);
this._bridged_finishedStroke(base64DataUrl);
};
render = () => {
return (
<WebView
automaticallyAdjustContentInsets={false}
onNavigationStateChange={this._onNavigationChange}
onMessage={this.onMessage}
renderError={this._renderError}
renderLoading={this._renderLoading}
source={this.state.source}
javaScriptEnabled={true}
style={this.props.style}
/>
);
};
}