11'use strict' ;
22
3- import React , { Component , PropTypes } from 'react' ;
3+ import React , { Component } from 'react' ;
4+ import { PropTypes } from 'prop-types' ;
45import {
5- View ,
6- WebView ,
7- StyleSheet ,
6+ View ,
7+ WebView ,
8+ StyleSheet ,
89} from 'react-native' ;
910
1011import htmlContent from './injectedHtml' ;
@@ -14,173 +15,175 @@ import injectedErrorHandler from './injectedJavaScript/errorHandler';
1415import injectedExecuteNativeFunction from './injectedJavaScript/executeNativeFunction' ;
1516
1617class SignaturePad extends Component {
17- static propTypes = {
18- onChange : PropTypes . func ,
19- onError : PropTypes . func ,
20- style : View . propTypes . style ,
21- penColor : PropTypes . string ,
22- dataURL : PropTypes . string ,
23- height : PropTypes . number ,
24- width : PropTypes . number ,
25- penMinWidth : PropTypes . number ,
26- penMaxWidth : PropTypes . number ,
27- useFont : PropTypes . bool ,
28- name : PropTypes . string ,
29- fontStyle : PropTypes . string ,
30- } ;
31-
32- static defaultProps = {
33- onChange : ( ) => { } ,
34- onError : ( ) => { } ,
35- style : { } ,
36- useFont : false
37- } ;
38-
39- constructor ( props ) {
40- super ( props ) ;
41- var escapedName = props . name . replace ( / " / , `\\"` ) ;
42- this . state = { base64DataUrl : props . dataURL || null , name : escapedName } ;
43- const { backgroundColor } = StyleSheet . flatten ( props . style ) ;
44- var injectedJavaScript = injectedExecuteNativeFunction
45- + injectedErrorHandler
46- + injectedSignaturePad
47- + injectedApplication (
48- props . penColor ,
49- backgroundColor ,
50- props . dataURL ,
51- props . penMinWidth ,
52- props . penMaxWidth ,
53- props . useFont ,
54- escapedName ,
55- props . height ,
56- props . width
57- ) ;
58- var html = htmlContent ( injectedJavaScript , props . fontStyle ) ;
59- this . source = { html } ;
60- // We don't use WebView's injectedJavaScript because on Android,
61- // the WebView re-injects the JavaScript upon every url change.
62- // Given that we use url changes to communicate signature changes to the
63- // React Native app, the JS is re-injected every time a stroke is drawn.
64- }
65-
66- componentWillReceiveProps = ( nextProps ) => {
67- if ( this . props . useFont && this . state . name !== nextProps . name ) {
68- var escapedName = nextProps . name . replace ( / " / , `\\"` ) ;
69- this . setState ( { name : escapedName } ) ;
70-
71- const { backgroundColor } = StyleSheet . flatten ( this . props . style ) ;
72- var injectedJavaScript = injectedExecuteNativeFunction
73- + injectedErrorHandler
74- + injectedSignaturePad
75- + injectedApplication (
76- this . props . penColor ,
77- backgroundColor ,
78- this . props . dataURL ,
79- this . props . penMinWidth ,
80- this . props . penMaxWidth ,
81- this . props . useFont ,
82- escapedName ,
83- this . props . height ,
84- this . props . width
85- ) ;
86- var html = htmlContent ( injectedJavaScript , this . props . fontStyle ) ;
87- this . source = { html } ;
88- }
89- } ;
90-
91- _onNavigationChange = ( args ) => {
92- this . _parseMessageFromWebViewNavigationChange ( unescape ( args . url ) ) ;
93- } ;
94-
95- _parseMessageFromWebViewNavigationChange = ( newUrl ) => {
96- // Example input:
97- // 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"
98- // All parameters to the native world are passed via a hash url where
99- // every parameter is passed as &[ParameterName]<-[Content]&
100- var hashUrlIndex = newUrl . lastIndexOf ( '#' ) ;
101- if ( hashUrlIndex === - 1 ) {
102- return ;
18+ static propTypes = {
19+ onChange : PropTypes . func ,
20+ onError : PropTypes . func ,
21+ style : View . propTypes . style ,
22+ penColor : PropTypes . string ,
23+ dataURL : PropTypes . string ,
24+ height : PropTypes . number ,
25+ width : PropTypes . number ,
26+ penMinWidth : PropTypes . number ,
27+ penMaxWidth : PropTypes . number ,
28+ useFont : PropTypes . bool ,
29+ name : PropTypes . string ,
30+ fontStyle : PropTypes . string ,
31+ } ;
32+
33+ static defaultProps = {
34+ onChange : ( ) => {
35+ } ,
36+ onError : ( ) => {
37+ } ,
38+ style : { } ,
39+ useFont : false
40+ } ;
41+
42+ constructor ( props ) {
43+ super ( props ) ;
44+ var escapedName = props . name . replace ( / " / , `\\"` ) ;
45+ this . state = { base64DataUrl : props . dataURL || null , name : escapedName } ;
46+ const { backgroundColor} = StyleSheet . flatten ( props . style ) ;
47+ var injectedJavaScript = injectedExecuteNativeFunction
48+ + injectedErrorHandler
49+ + injectedSignaturePad
50+ + injectedApplication (
51+ props . penColor ,
52+ backgroundColor ,
53+ props . dataURL ,
54+ props . penMinWidth ,
55+ props . penMaxWidth ,
56+ props . useFont ,
57+ escapedName ,
58+ props . height ,
59+ props . width
60+ ) ;
61+ var html = htmlContent ( injectedJavaScript , props . fontStyle ) ;
62+ this . source = { html} ;
63+ // We don't use WebView's injectedJavaScript because on Android,
64+ // the WebView re-injects the JavaScript upon every url change.
65+ // Given that we use url changes to communicate signature changes to the
66+ // React Native app, the JS is re-injected every time a stroke is drawn.
10367 }
10468
105- var hashUrl = newUrl . substring ( hashUrlIndex ) ;
106- hashUrl = decodeURIComponent ( hashUrl ) ;
107- var regexFindAllSubmittedParameters = / & ( .* ?) & / g;
108-
109- var parameters = { } ;
110- var parameterMatch = regexFindAllSubmittedParameters . exec ( hashUrl ) ;
111- if ( ! parameterMatch ) {
112- return ;
113- }
114-
115- while ( parameterMatch ) {
116- var parameterPair = parameterMatch [ 1 ] ; //For example executeFunction=jsError or arguments=...
117-
118- var parameterPairSplit = parameterPair . split ( '<-' ) ;
119- if ( parameterPairSplit . length === 2 ) {
120- parameters [ parameterPairSplit [ 0 ] ] = parameterPairSplit [ 1 ] ;
121- }
122-
123- parameterMatch = regexFindAllSubmittedParameters . exec ( hashUrl ) ;
69+ componentWillReceiveProps = ( nextProps ) => {
70+ if ( this . props . useFont && this . state . name !== nextProps . name ) {
71+ var escapedName = nextProps . name . replace ( / " / , `\\"` ) ;
72+ this . setState ( { name : escapedName } ) ;
73+
74+ const { backgroundColor} = StyleSheet . flatten ( this . props . style ) ;
75+ var injectedJavaScript = injectedExecuteNativeFunction
76+ + injectedErrorHandler
77+ + injectedSignaturePad
78+ + injectedApplication (
79+ this . props . penColor ,
80+ backgroundColor ,
81+ this . props . dataURL ,
82+ this . props . penMinWidth ,
83+ this . props . penMaxWidth ,
84+ this . props . useFont ,
85+ escapedName ,
86+ this . props . height ,
87+ this . props . width
88+ ) ;
89+ var html = htmlContent ( injectedJavaScript , this . props . fontStyle ) ;
90+ this . source = { html} ;
91+ }
92+ } ;
93+
94+ _onNavigationChange = ( args ) => {
95+ this . _parseMessageFromWebViewNavigationChange ( unescape ( args . url ) ) ;
96+ } ;
97+
98+ _parseMessageFromWebViewNavigationChange = ( newUrl ) => {
99+ // Example input:
100+ // 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"
101+ // All parameters to the native world are passed via a hash url where
102+ // every parameter is passed as &[ParameterName]<-[Content]&
103+ var hashUrlIndex = newUrl . lastIndexOf ( '#' ) ;
104+ if ( hashUrlIndex === - 1 ) {
105+ return ;
106+ }
107+
108+ var hashUrl = newUrl . substring ( hashUrlIndex ) ;
109+ hashUrl = decodeURIComponent ( hashUrl ) ;
110+ var regexFindAllSubmittedParameters = / & ( .* ?) & / g;
111+
112+ var parameters = { } ;
113+ var parameterMatch = regexFindAllSubmittedParameters . exec ( hashUrl ) ;
114+ if ( ! parameterMatch ) {
115+ return ;
116+ }
117+
118+ while ( parameterMatch ) {
119+ var parameterPair = parameterMatch [ 1 ] ; //For example executeFunction=jsError or arguments=...
120+
121+ var parameterPairSplit = parameterPair . split ( '<-' ) ;
122+ if ( parameterPairSplit . length === 2 ) {
123+ parameters [ parameterPairSplit [ 0 ] ] = parameterPairSplit [ 1 ] ;
124+ }
125+
126+ parameterMatch = regexFindAllSubmittedParameters . exec ( hashUrl ) ;
127+ }
128+
129+ if ( ! this . _attemptToExecuteNativeFunctionFromWebViewMessage ( parameters ) ) {
130+ logger . warn (
131+ { parameters, hashUrl} ,
132+ 'Received an unknown set of parameters from WebView'
133+ ) ;
134+ }
135+ } ;
136+
137+ _attemptToExecuteNativeFunctionFromWebViewMessage = ( message ) => {
138+ if ( message . executeFunction && message . arguments ) {
139+ var parsedArguments = JSON . parse ( message . arguments ) ;
140+
141+ var referencedFunction = this [ '_bridged_' + message . executeFunction ] ;
142+ if ( typeof ( referencedFunction ) === 'function' ) {
143+ referencedFunction . apply ( this , [ parsedArguments ] ) ;
144+ return true ;
145+ }
146+ }
147+
148+ return false ;
149+ } ;
150+
151+ _bridged_jsError = ( args ) => {
152+ this . props . onError ( { details : args } ) ;
153+ } ;
154+
155+ _bridged_finishedStroke = ( { base64DataUrl} ) => {
156+ this . props . onChange ( { base64DataUrl} ) ;
157+ this . setState ( { base64DataUrl} ) ;
158+ } ;
159+
160+ _renderError = ( args ) => {
161+ this . props . onError ( { details : args } ) ;
162+ } ;
163+
164+ _renderLoading = ( args ) => {
165+ } ;
166+
167+ _onMessage = ( event ) => {
168+ var base64DataUrl = JSON . parse ( event . nativeEvent . data ) ;
169+ this . _bridged_finishedStroke ( base64DataUrl ) ;
124170 }
125171
126- if ( ! this . _attemptToExecuteNativeFunctionFromWebViewMessage ( parameters ) ) {
127- logger . warn (
128- { parameters, hashUrl } ,
129- 'Received an unknown set of parameters from WebView'
130- ) ;
131- }
132- } ;
133-
134- _attemptToExecuteNativeFunctionFromWebViewMessage = ( message ) => {
135- if ( message . executeFunction && message . arguments ) {
136- var parsedArguments = JSON . parse ( message . arguments ) ;
137-
138- var referencedFunction = this [ '_bridged_' + message . executeFunction ] ;
139- if ( typeof ( referencedFunction ) === 'function' ) {
140- referencedFunction . apply ( this , [ parsedArguments ] ) ;
141- return true ;
142- }
143- }
144-
145- return false ;
146- } ;
147-
148- _bridged_jsError = ( args ) => {
149- this . props . onError ( { details : args } ) ;
150- } ;
151-
152- _bridged_finishedStroke = ( { base64DataUrl } ) => {
153- this . props . onChange ( { base64DataUrl } ) ;
154- this . setState ( { base64DataUrl } ) ;
155- } ;
156-
157- _renderError = ( args ) => {
158- this . props . onError ( { details : args } ) ;
159- } ;
160-
161- _renderLoading = ( args ) => {
162- } ;
163-
164- _onMessage = ( event ) => {
165- var base64DataUrl = JSON . parse ( event . nativeEvent . data ) ;
166- this . _bridged_finishedStroke ( base64DataUrl ) ;
167- }
168-
169- render = ( ) => {
170- return (
171- < WebView
172- automaticallyAdjustContentInsets = { false }
173- onNavigationStateChange = { this . _onNavigationChange }
174- onMessage = { this . _onMessage }
175- renderError = { this . _renderError }
176- renderLoading = { this . _renderLoading }
177- source = { this . source }
178- scrollEnabled = { false }
179- javaScriptEnabled = { true }
180- style = { this . props . style }
181- />
182- ) ;
183- } ;
172+ render = ( ) => {
173+ return (
174+ < WebView
175+ automaticallyAdjustContentInsets = { false }
176+ onNavigationStateChange = { this . _onNavigationChange }
177+ onMessage = { this . _onMessage }
178+ renderError = { this . _renderError }
179+ renderLoading = { this . _renderLoading }
180+ source = { this . source }
181+ scrollEnabled = { false }
182+ javaScriptEnabled = { true }
183+ style = { this . props . style }
184+ />
185+ ) ;
186+ } ;
184187}
185188
186189module . exports = SignaturePad ;
0 commit comments