@hcaptcha/react-hcaptcha 1.4.0 → 1.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.js +351 -0
- package/dist/esm/utils.js +14 -0
- package/dist/index.js +72 -51
- package/package.json +2 -2
- package/src/index.js +82 -49
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
|
|
2
|
+
import _inheritsLoose from "@babel/runtime/helpers/inheritsLoose";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { generateQuery } from "./utils.js";
|
|
5
|
+
var SCRIPT_ID = 'hcaptcha-api-script-id';
|
|
6
|
+
var HCAPTCHA_LOAD_FN_NAME = 'hcaptchaOnLoad'; // Prevent loading API script multiple times
|
|
7
|
+
|
|
8
|
+
var resolveFn;
|
|
9
|
+
var rejectFn;
|
|
10
|
+
var mountPromise = new Promise(function (resolve, reject) {
|
|
11
|
+
resolveFn = resolve;
|
|
12
|
+
rejectFn = reject;
|
|
13
|
+
}); // Generate hCaptcha API script
|
|
14
|
+
|
|
15
|
+
var mountCaptchaScript = function mountCaptchaScript(params) {
|
|
16
|
+
if (params === void 0) {
|
|
17
|
+
params = {};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (document.getElementById(SCRIPT_ID)) {
|
|
21
|
+
// API was already requested
|
|
22
|
+
return mountPromise;
|
|
23
|
+
} // Create global onload callback
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
window[HCAPTCHA_LOAD_FN_NAME] = resolveFn;
|
|
27
|
+
var domain = params.apihost || "https://js.hcaptcha.com";
|
|
28
|
+
delete params.apihost;
|
|
29
|
+
var script = document.createElement("script");
|
|
30
|
+
script.id = SCRIPT_ID;
|
|
31
|
+
script.src = domain + "/1/api.js?render=explicit&onload=" + HCAPTCHA_LOAD_FN_NAME;
|
|
32
|
+
script.async = true;
|
|
33
|
+
|
|
34
|
+
script.onerror = function (event) {
|
|
35
|
+
return rejectFn('script-error');
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
var query = generateQuery(params);
|
|
39
|
+
script.src += query !== "" ? "&" + query : "";
|
|
40
|
+
document.head.appendChild(script);
|
|
41
|
+
return mountPromise;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
45
|
+
_inheritsLoose(HCaptcha, _React$Component);
|
|
46
|
+
|
|
47
|
+
function HCaptcha(props) {
|
|
48
|
+
var _this;
|
|
49
|
+
|
|
50
|
+
_this = _React$Component.call(this, props) || this; // API Methods
|
|
51
|
+
|
|
52
|
+
_this.renderCaptcha = _this.renderCaptcha.bind(_assertThisInitialized(_this));
|
|
53
|
+
_this.resetCaptcha = _this.resetCaptcha.bind(_assertThisInitialized(_this));
|
|
54
|
+
_this.removeCaptcha = _this.removeCaptcha.bind(_assertThisInitialized(_this));
|
|
55
|
+
_this.isReady = _this.isReady.bind(_assertThisInitialized(_this)); // Event Handlers
|
|
56
|
+
|
|
57
|
+
_this.loadCaptcha = _this.loadCaptcha.bind(_assertThisInitialized(_this));
|
|
58
|
+
_this.handleOnLoad = _this.handleOnLoad.bind(_assertThisInitialized(_this));
|
|
59
|
+
_this.handleSubmit = _this.handleSubmit.bind(_assertThisInitialized(_this));
|
|
60
|
+
_this.handleExpire = _this.handleExpire.bind(_assertThisInitialized(_this));
|
|
61
|
+
_this.handleError = _this.handleError.bind(_assertThisInitialized(_this));
|
|
62
|
+
_this.handleOpen = _this.handleOpen.bind(_assertThisInitialized(_this));
|
|
63
|
+
_this.handleClose = _this.handleClose.bind(_assertThisInitialized(_this));
|
|
64
|
+
_this.handleChallengeExpired = _this.handleChallengeExpired.bind(_assertThisInitialized(_this));
|
|
65
|
+
var isApiReady = typeof hcaptcha !== 'undefined';
|
|
66
|
+
_this.ref = /*#__PURE__*/React.createRef();
|
|
67
|
+
_this.apiScriptRequested = false;
|
|
68
|
+
_this.state = {
|
|
69
|
+
isApiReady: isApiReady,
|
|
70
|
+
isRemoved: false,
|
|
71
|
+
elementId: props.id,
|
|
72
|
+
captchaId: ''
|
|
73
|
+
};
|
|
74
|
+
return _this;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
var _proto = HCaptcha.prototype;
|
|
78
|
+
|
|
79
|
+
_proto.componentDidMount = function componentDidMount() {
|
|
80
|
+
// Once captcha is mounted intialize hCaptcha - hCaptcha
|
|
81
|
+
var isApiReady = this.state.isApiReady;
|
|
82
|
+
/*
|
|
83
|
+
* Check if hCaptcha has already been loaded,
|
|
84
|
+
* If Yes, render the captcha
|
|
85
|
+
* If No, create script tag and wait to render the captcha
|
|
86
|
+
*/
|
|
87
|
+
|
|
88
|
+
if (isApiReady) {
|
|
89
|
+
this.renderCaptcha();
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
this.loadCaptcha();
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
_proto.componentWillUnmount = function componentWillUnmount() {
|
|
97
|
+
var captchaId = this.state.captchaId;
|
|
98
|
+
|
|
99
|
+
if (!this.isReady()) {
|
|
100
|
+
return;
|
|
101
|
+
} // Reset any stored variables / timers when unmounting
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
hcaptcha.reset(captchaId);
|
|
105
|
+
hcaptcha.remove(captchaId);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
_proto.shouldComponentUpdate = function shouldComponentUpdate(nextProps, nextState) {
|
|
109
|
+
// Prevent component re-rendering when these internal state variables are updated
|
|
110
|
+
if (this.state.isApiReady !== nextState.isApiReady || this.state.isRemoved !== nextState.isRemoved) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return true;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
_proto.componentDidUpdate = function componentDidUpdate(prevProps) {
|
|
118
|
+
var _this2 = this;
|
|
119
|
+
|
|
120
|
+
// Prop Keys that could change
|
|
121
|
+
var keys = ['sitekey', 'size', 'theme', 'tabindex', 'languageOverride', 'endpoint']; // See if any props changed during component update
|
|
122
|
+
|
|
123
|
+
var match = keys.every(function (key) {
|
|
124
|
+
return prevProps[key] === _this2.props[key];
|
|
125
|
+
}); // If they have changed, remove current captcha and render a new one
|
|
126
|
+
|
|
127
|
+
if (!match) {
|
|
128
|
+
this.removeCaptcha(function () {
|
|
129
|
+
_this2.renderCaptcha();
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
_proto.loadCaptcha = function loadCaptcha() {
|
|
135
|
+
if (this.apiScriptRequested) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
var _this$props = this.props,
|
|
140
|
+
apihost = _this$props.apihost,
|
|
141
|
+
assethost = _this$props.assethost,
|
|
142
|
+
endpoint = _this$props.endpoint,
|
|
143
|
+
host = _this$props.host,
|
|
144
|
+
imghost = _this$props.imghost,
|
|
145
|
+
hl = _this$props.languageOverride,
|
|
146
|
+
reCaptchaCompat = _this$props.reCaptchaCompat,
|
|
147
|
+
reportapi = _this$props.reportapi,
|
|
148
|
+
sentry = _this$props.sentry,
|
|
149
|
+
custom = _this$props.custom;
|
|
150
|
+
var mountParams = {
|
|
151
|
+
apihost: apihost,
|
|
152
|
+
assethost: assethost,
|
|
153
|
+
endpoint: endpoint,
|
|
154
|
+
hl: hl,
|
|
155
|
+
host: host,
|
|
156
|
+
imghost: imghost,
|
|
157
|
+
recaptchacompat: reCaptchaCompat === false ? "off" : null,
|
|
158
|
+
reportapi: reportapi,
|
|
159
|
+
sentry: sentry,
|
|
160
|
+
custom: custom
|
|
161
|
+
};
|
|
162
|
+
mountCaptchaScript(mountParams).then(this.handleOnLoad)["catch"](this.handleError);
|
|
163
|
+
this.apiScriptRequested = true;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
_proto.renderCaptcha = function renderCaptcha(onReady) {
|
|
167
|
+
var isApiReady = this.state.isApiReady;
|
|
168
|
+
if (!isApiReady) return;
|
|
169
|
+
var renderParams = Object.assign({
|
|
170
|
+
"open-callback": this.handleOpen,
|
|
171
|
+
"close-callback": this.handleClose,
|
|
172
|
+
"error-callback": this.handleError,
|
|
173
|
+
"chalexpired-callback": this.handleChallengeExpired,
|
|
174
|
+
"expired-callback": this.handleExpire,
|
|
175
|
+
"callback": this.handleSubmit
|
|
176
|
+
}, this.props, {
|
|
177
|
+
hl: this.props.hl || this.props.languageOverride,
|
|
178
|
+
languageOverride: undefined
|
|
179
|
+
}); //Render hCaptcha widget and provide necessary callbacks - hCaptcha
|
|
180
|
+
|
|
181
|
+
var captchaId = hcaptcha.render(this.ref.current, renderParams);
|
|
182
|
+
this.setState({
|
|
183
|
+
isRemoved: false,
|
|
184
|
+
captchaId: captchaId
|
|
185
|
+
}, function () {
|
|
186
|
+
onReady && onReady();
|
|
187
|
+
});
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
_proto.resetCaptcha = function resetCaptcha() {
|
|
191
|
+
var captchaId = this.state.captchaId;
|
|
192
|
+
|
|
193
|
+
if (!this.isReady()) {
|
|
194
|
+
return;
|
|
195
|
+
} // Reset captcha state, removes stored token and unticks checkbox
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
hcaptcha.reset(captchaId);
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
_proto.removeCaptcha = function removeCaptcha(callback) {
|
|
202
|
+
var captchaId = this.state.captchaId;
|
|
203
|
+
|
|
204
|
+
if (!this.isReady()) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
this.setState({
|
|
209
|
+
isRemoved: true
|
|
210
|
+
}, function () {
|
|
211
|
+
hcaptcha.remove(captchaId);
|
|
212
|
+
callback && callback();
|
|
213
|
+
});
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
_proto.handleOnLoad = function handleOnLoad() {
|
|
217
|
+
var _this3 = this;
|
|
218
|
+
|
|
219
|
+
this.setState({
|
|
220
|
+
isApiReady: true
|
|
221
|
+
}, function () {
|
|
222
|
+
// render captcha and wait for captcha id
|
|
223
|
+
_this3.renderCaptcha(function () {
|
|
224
|
+
// trigger onLoad if it exists
|
|
225
|
+
var onLoad = _this3.props.onLoad;
|
|
226
|
+
if (onLoad) onLoad();
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
_proto.handleSubmit = function handleSubmit(event) {
|
|
232
|
+
var onVerify = this.props.onVerify;
|
|
233
|
+
var _this$state = this.state,
|
|
234
|
+
isRemoved = _this$state.isRemoved,
|
|
235
|
+
captchaId = _this$state.captchaId;
|
|
236
|
+
if (typeof hcaptcha === 'undefined' || isRemoved) return;
|
|
237
|
+
var token = hcaptcha.getResponse(captchaId); //Get response token from hCaptcha widget
|
|
238
|
+
|
|
239
|
+
var ekey = hcaptcha.getRespKey(captchaId); //Get current challenge session id from hCaptcha widget
|
|
240
|
+
|
|
241
|
+
onVerify(token, ekey); //Dispatch event to verify user response
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
_proto.handleExpire = function handleExpire() {
|
|
245
|
+
var onExpire = this.props.onExpire;
|
|
246
|
+
var captchaId = this.state.captchaId;
|
|
247
|
+
|
|
248
|
+
if (!this.isReady()) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
hcaptcha.reset(captchaId); // If hCaptcha runs into error, reset captcha - hCaptcha
|
|
253
|
+
|
|
254
|
+
if (onExpire) onExpire();
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
_proto.handleError = function handleError(event) {
|
|
258
|
+
var onError = this.props.onError;
|
|
259
|
+
var captchaId = this.state.captchaId;
|
|
260
|
+
|
|
261
|
+
if (this.isReady()) {
|
|
262
|
+
// If hCaptcha runs into error, reset captcha - hCaptcha
|
|
263
|
+
hcaptcha.reset(captchaId);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (onError) onError(event);
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
_proto.isReady = function isReady() {
|
|
270
|
+
var _this$state2 = this.state,
|
|
271
|
+
isApiReady = _this$state2.isApiReady,
|
|
272
|
+
isRemoved = _this$state2.isRemoved;
|
|
273
|
+
return isApiReady && !isRemoved;
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
_proto.handleOpen = function handleOpen() {
|
|
277
|
+
if (!this.isReady() || !this.props.onOpen) {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
this.props.onOpen();
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
_proto.handleClose = function handleClose() {
|
|
285
|
+
if (!this.isReady() || !this.props.onClose) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
this.props.onClose();
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
_proto.handleChallengeExpired = function handleChallengeExpired() {
|
|
293
|
+
if (!this.isReady() || !this.props.onChalExpired) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
this.props.onChalExpired();
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
_proto.execute = function execute(opts) {
|
|
301
|
+
if (opts === void 0) {
|
|
302
|
+
opts = null;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
var captchaId = this.state.captchaId;
|
|
306
|
+
|
|
307
|
+
if (!this.isReady()) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (opts && typeof opts !== "object") {
|
|
312
|
+
opts = null;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return hcaptcha.execute(captchaId, opts);
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
_proto.setData = function setData(data) {
|
|
319
|
+
var captchaId = this.state.captchaId;
|
|
320
|
+
|
|
321
|
+
if (!this.isReady()) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (data && typeof data !== "object") {
|
|
326
|
+
data = null;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
hcaptcha.setData(captchaId, data);
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
_proto.getResponse = function getResponse() {
|
|
333
|
+
return hcaptcha.getResponse(this.state.captchaId);
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
_proto.getRespKey = function getRespKey() {
|
|
337
|
+
return hcaptcha.getRespKey(this.state.captchaId);
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
_proto.render = function render() {
|
|
341
|
+
var elementId = this.state.elementId;
|
|
342
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
343
|
+
ref: this.ref,
|
|
344
|
+
id: elementId
|
|
345
|
+
});
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
return HCaptcha;
|
|
349
|
+
}(React.Component);
|
|
350
|
+
|
|
351
|
+
export default HCaptcha;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
function generateQuery(params) {
|
|
2
|
+
return Object.entries(params).filter(function (_ref) {
|
|
3
|
+
var key = _ref[0],
|
|
4
|
+
value = _ref[1];
|
|
5
|
+
return value || value === false;
|
|
6
|
+
}).map(function (_ref2) {
|
|
7
|
+
var key = _ref2[0],
|
|
8
|
+
value = _ref2[1];
|
|
9
|
+
return encodeURIComponent(key) + "=" + encodeURIComponent(value);
|
|
10
|
+
}).join("&");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
;
|
|
14
|
+
export { generateQuery };
|
package/dist/index.js
CHANGED
|
@@ -31,30 +31,41 @@ function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflec
|
|
|
31
31
|
|
|
32
32
|
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
var
|
|
36
|
-
|
|
34
|
+
var SCRIPT_ID = 'hcaptcha-api-script-id';
|
|
35
|
+
var HCAPTCHA_LOAD_FN_NAME = 'hcaptchaOnLoad'; // Prevent loading API script multiple times
|
|
36
|
+
|
|
37
|
+
var resolveFn;
|
|
38
|
+
var rejectFn;
|
|
39
|
+
var mountPromise = new Promise(function (resolve, reject) {
|
|
40
|
+
resolveFn = resolve;
|
|
41
|
+
rejectFn = reject;
|
|
42
|
+
}); // Generate hCaptcha API script
|
|
37
43
|
|
|
38
44
|
var mountCaptchaScript = function mountCaptchaScript() {
|
|
39
45
|
var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
40
|
-
apiScriptRequested = true; // Create global onload callback
|
|
41
|
-
|
|
42
|
-
window.hcaptchaOnLoad = function () {
|
|
43
|
-
// Iterate over onload listeners, call each listener
|
|
44
|
-
onLoadListeners = onLoadListeners.filter(function (listener) {
|
|
45
|
-
listener();
|
|
46
|
-
return false;
|
|
47
|
-
});
|
|
48
|
-
};
|
|
49
46
|
|
|
47
|
+
if (document.getElementById(SCRIPT_ID)) {
|
|
48
|
+
// API was already requested
|
|
49
|
+
return mountPromise;
|
|
50
|
+
} // Create global onload callback
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
window[HCAPTCHA_LOAD_FN_NAME] = resolveFn;
|
|
50
54
|
var domain = params.apihost || "https://js.hcaptcha.com";
|
|
51
55
|
delete params.apihost;
|
|
52
56
|
var script = document.createElement("script");
|
|
53
|
-
script.
|
|
57
|
+
script.id = SCRIPT_ID;
|
|
58
|
+
script.src = "".concat(domain, "/1/api.js?render=explicit&onload=").concat(HCAPTCHA_LOAD_FN_NAME);
|
|
54
59
|
script.async = true;
|
|
60
|
+
|
|
61
|
+
script.onerror = function (event) {
|
|
62
|
+
return rejectFn('script-error');
|
|
63
|
+
};
|
|
64
|
+
|
|
55
65
|
var query = (0, _utils.generateQuery)(params);
|
|
56
66
|
script.src += query !== "" ? "&".concat(query) : "";
|
|
57
67
|
document.head.appendChild(script);
|
|
68
|
+
return mountPromise;
|
|
58
69
|
};
|
|
59
70
|
|
|
60
71
|
var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
@@ -73,6 +84,7 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
73
84
|
_this.removeCaptcha = _this.removeCaptcha.bind((0, _assertThisInitialized2["default"])(_this));
|
|
74
85
|
_this.isReady = _this.isReady.bind((0, _assertThisInitialized2["default"])(_this)); // Event Handlers
|
|
75
86
|
|
|
87
|
+
_this.loadCaptcha = _this.loadCaptcha.bind((0, _assertThisInitialized2["default"])(_this));
|
|
76
88
|
_this.handleOnLoad = _this.handleOnLoad.bind((0, _assertThisInitialized2["default"])(_this));
|
|
77
89
|
_this.handleSubmit = _this.handleSubmit.bind((0, _assertThisInitialized2["default"])(_this));
|
|
78
90
|
_this.handleExpire = _this.handleExpire.bind((0, _assertThisInitialized2["default"])(_this));
|
|
@@ -82,6 +94,7 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
82
94
|
_this.handleChallengeExpired = _this.handleChallengeExpired.bind((0, _assertThisInitialized2["default"])(_this));
|
|
83
95
|
var isApiReady = typeof hcaptcha !== 'undefined';
|
|
84
96
|
_this.ref = /*#__PURE__*/React.createRef();
|
|
97
|
+
_this.apiScriptRequested = false;
|
|
85
98
|
_this.state = {
|
|
86
99
|
isApiReady: isApiReady,
|
|
87
100
|
isRemoved: false,
|
|
@@ -94,44 +107,20 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
94
107
|
(0, _createClass2["default"])(HCaptcha, [{
|
|
95
108
|
key: "componentDidMount",
|
|
96
109
|
value: function componentDidMount() {
|
|
97
|
-
//Once captcha is mounted intialize hCaptcha - hCaptcha
|
|
98
|
-
var _this$props = this.props,
|
|
99
|
-
apihost = _this$props.apihost,
|
|
100
|
-
assethost = _this$props.assethost,
|
|
101
|
-
endpoint = _this$props.endpoint,
|
|
102
|
-
host = _this$props.host,
|
|
103
|
-
imghost = _this$props.imghost,
|
|
104
|
-
hl = _this$props.languageOverride,
|
|
105
|
-
reCaptchaCompat = _this$props.reCaptchaCompat,
|
|
106
|
-
reportapi = _this$props.reportapi,
|
|
107
|
-
sentry = _this$props.sentry,
|
|
108
|
-
custom = _this$props.custom;
|
|
110
|
+
// Once captcha is mounted intialize hCaptcha - hCaptcha
|
|
109
111
|
var isApiReady = this.state.isApiReady;
|
|
112
|
+
/*
|
|
113
|
+
* Check if hCaptcha has already been loaded,
|
|
114
|
+
* If Yes, render the captcha
|
|
115
|
+
* If No, create script tag and wait to render the captcha
|
|
116
|
+
*/
|
|
110
117
|
|
|
111
|
-
if (
|
|
112
|
-
//Check if hCaptcha has already been loaded, if not create script tag and wait to render captcha
|
|
113
|
-
if (apiScriptRequested) {
|
|
114
|
-
return;
|
|
115
|
-
} // Only create the script tag once, use a global variable to track
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
mountCaptchaScript({
|
|
119
|
-
apihost: apihost,
|
|
120
|
-
assethost: assethost,
|
|
121
|
-
endpoint: endpoint,
|
|
122
|
-
hl: hl,
|
|
123
|
-
host: host,
|
|
124
|
-
imghost: imghost,
|
|
125
|
-
recaptchacompat: reCaptchaCompat === false ? "off" : null,
|
|
126
|
-
reportapi: reportapi,
|
|
127
|
-
sentry: sentry,
|
|
128
|
-
custom: custom
|
|
129
|
-
}); // Add onload callback to global onload listeners
|
|
130
|
-
|
|
131
|
-
onLoadListeners.push(this.handleOnLoad);
|
|
132
|
-
} else {
|
|
118
|
+
if (isApiReady) {
|
|
133
119
|
this.renderCaptcha();
|
|
120
|
+
return;
|
|
134
121
|
}
|
|
122
|
+
|
|
123
|
+
this.loadCaptcha();
|
|
135
124
|
}
|
|
136
125
|
}, {
|
|
137
126
|
key: "componentWillUnmount",
|
|
@@ -174,6 +163,39 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
174
163
|
});
|
|
175
164
|
}
|
|
176
165
|
}
|
|
166
|
+
}, {
|
|
167
|
+
key: "loadCaptcha",
|
|
168
|
+
value: function loadCaptcha() {
|
|
169
|
+
if (this.apiScriptRequested) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
var _this$props = this.props,
|
|
174
|
+
apihost = _this$props.apihost,
|
|
175
|
+
assethost = _this$props.assethost,
|
|
176
|
+
endpoint = _this$props.endpoint,
|
|
177
|
+
host = _this$props.host,
|
|
178
|
+
imghost = _this$props.imghost,
|
|
179
|
+
hl = _this$props.languageOverride,
|
|
180
|
+
reCaptchaCompat = _this$props.reCaptchaCompat,
|
|
181
|
+
reportapi = _this$props.reportapi,
|
|
182
|
+
sentry = _this$props.sentry,
|
|
183
|
+
custom = _this$props.custom;
|
|
184
|
+
var mountParams = {
|
|
185
|
+
apihost: apihost,
|
|
186
|
+
assethost: assethost,
|
|
187
|
+
endpoint: endpoint,
|
|
188
|
+
hl: hl,
|
|
189
|
+
host: host,
|
|
190
|
+
imghost: imghost,
|
|
191
|
+
recaptchacompat: reCaptchaCompat === false ? "off" : null,
|
|
192
|
+
reportapi: reportapi,
|
|
193
|
+
sentry: sentry,
|
|
194
|
+
custom: custom
|
|
195
|
+
};
|
|
196
|
+
mountCaptchaScript(mountParams).then(this.handleOnLoad)["catch"](this.handleError);
|
|
197
|
+
this.apiScriptRequested = true;
|
|
198
|
+
}
|
|
177
199
|
}, {
|
|
178
200
|
key: "renderCaptcha",
|
|
179
201
|
value: function renderCaptcha(onReady) {
|
|
@@ -277,12 +299,11 @@ var HCaptcha = /*#__PURE__*/function (_React$Component) {
|
|
|
277
299
|
var onError = this.props.onError;
|
|
278
300
|
var captchaId = this.state.captchaId;
|
|
279
301
|
|
|
280
|
-
if (
|
|
281
|
-
|
|
302
|
+
if (this.isReady()) {
|
|
303
|
+
// If hCaptcha runs into error, reset captcha - hCaptcha
|
|
304
|
+
hcaptcha.reset(captchaId);
|
|
282
305
|
}
|
|
283
306
|
|
|
284
|
-
hcaptcha.reset(captchaId); // If hCaptcha runs into error, reset captcha - hCaptcha
|
|
285
|
-
|
|
286
307
|
if (onError) onError(event);
|
|
287
308
|
}
|
|
288
309
|
}, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hcaptcha/react-hcaptcha",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.3",
|
|
4
4
|
"types": "types/index.d.ts",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"prebuild": "rimraf dist",
|
|
19
19
|
"build": "npm run transpile && npm run build:esm",
|
|
20
20
|
"build:esm": "cross-env BABEL_ENV=esm babel src -d dist/esm --copy-files",
|
|
21
|
-
"prepublishOnly": "npm run
|
|
21
|
+
"prepublishOnly": "npm run build"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
24
|
"react": ">= 16.3.0",
|
package/src/index.js
CHANGED
|
@@ -1,34 +1,42 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { generateQuery } from "./utils.js";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
const SCRIPT_ID = 'hcaptcha-api-script-id';
|
|
5
|
+
const HCAPTCHA_LOAD_FN_NAME = 'hcaptchaOnLoad';
|
|
6
|
+
|
|
7
|
+
// Prevent loading API script multiple times
|
|
8
|
+
let resolveFn;
|
|
9
|
+
let rejectFn;
|
|
10
|
+
const mountPromise = new Promise((resolve, reject) => {
|
|
11
|
+
resolveFn = resolve;
|
|
12
|
+
rejectFn = reject;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
// Generate hCaptcha API script
|
|
9
16
|
const mountCaptchaScript = (params={}) => {
|
|
10
|
-
|
|
17
|
+
if (document.getElementById(SCRIPT_ID)) {
|
|
18
|
+
// API was already requested
|
|
19
|
+
return mountPromise;
|
|
20
|
+
}
|
|
21
|
+
|
|
11
22
|
// Create global onload callback
|
|
12
|
-
window
|
|
13
|
-
// Iterate over onload listeners, call each listener
|
|
14
|
-
onLoadListeners = onLoadListeners.filter(listener => {
|
|
15
|
-
listener();
|
|
16
|
-
return false;
|
|
17
|
-
});
|
|
18
|
-
};
|
|
23
|
+
window[HCAPTCHA_LOAD_FN_NAME] = resolveFn;
|
|
19
24
|
|
|
20
25
|
const domain = params.apihost || "https://js.hcaptcha.com";
|
|
21
26
|
delete params.apihost;
|
|
22
27
|
|
|
23
28
|
const script = document.createElement("script");
|
|
24
|
-
script.
|
|
29
|
+
script.id = SCRIPT_ID;
|
|
30
|
+
script.src = `${domain}/1/api.js?render=explicit&onload=${HCAPTCHA_LOAD_FN_NAME}`;
|
|
25
31
|
script.async = true;
|
|
32
|
+
script.onerror = (event) => rejectFn('script-error');
|
|
26
33
|
|
|
27
34
|
const query = generateQuery(params);
|
|
28
35
|
script.src += query !== ""? `&${query}` : "";
|
|
29
36
|
|
|
30
37
|
document.head.appendChild(script);
|
|
31
|
-
|
|
38
|
+
return mountPromise;
|
|
39
|
+
};
|
|
32
40
|
|
|
33
41
|
|
|
34
42
|
class HCaptcha extends React.Component {
|
|
@@ -42,6 +50,7 @@ class HCaptcha extends React.Component {
|
|
|
42
50
|
this.isReady = this.isReady.bind(this);
|
|
43
51
|
|
|
44
52
|
// Event Handlers
|
|
53
|
+
this.loadCaptcha = this.loadCaptcha.bind(this);
|
|
45
54
|
this.handleOnLoad = this.handleOnLoad.bind(this);
|
|
46
55
|
this.handleSubmit = this.handleSubmit.bind(this);
|
|
47
56
|
this.handleExpire = this.handleExpire.bind(this);
|
|
@@ -53,6 +62,7 @@ class HCaptcha extends React.Component {
|
|
|
53
62
|
const isApiReady = typeof hcaptcha !== 'undefined';
|
|
54
63
|
|
|
55
64
|
this.ref = React.createRef();
|
|
65
|
+
this.apiScriptRequested = false;
|
|
56
66
|
|
|
57
67
|
this.state = {
|
|
58
68
|
isApiReady,
|
|
@@ -62,46 +72,33 @@ class HCaptcha extends React.Component {
|
|
|
62
72
|
}
|
|
63
73
|
}
|
|
64
74
|
|
|
65
|
-
componentDidMount () { //Once captcha is mounted intialize hCaptcha - hCaptcha
|
|
66
|
-
const { apihost, assethost, endpoint, host, imghost, languageOverride:hl, reCaptchaCompat, reportapi, sentry, custom } = this.props;
|
|
75
|
+
componentDidMount () { // Once captcha is mounted intialize hCaptcha - hCaptcha
|
|
67
76
|
const { isApiReady } = this.state;
|
|
68
77
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
mountCaptchaScript({
|
|
76
|
-
apihost,
|
|
77
|
-
assethost,
|
|
78
|
-
endpoint,
|
|
79
|
-
hl,
|
|
80
|
-
host,
|
|
81
|
-
imghost,
|
|
82
|
-
recaptchacompat: reCaptchaCompat === false? "off" : null,
|
|
83
|
-
reportapi,
|
|
84
|
-
sentry,
|
|
85
|
-
custom
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
// Add onload callback to global onload listeners
|
|
89
|
-
onLoadListeners.push(this.handleOnLoad);
|
|
90
|
-
} else {
|
|
78
|
+
/*
|
|
79
|
+
* Check if hCaptcha has already been loaded,
|
|
80
|
+
* If Yes, render the captcha
|
|
81
|
+
* If No, create script tag and wait to render the captcha
|
|
82
|
+
*/
|
|
83
|
+
if (isApiReady) {
|
|
91
84
|
this.renderCaptcha();
|
|
85
|
+
|
|
86
|
+
return;
|
|
92
87
|
}
|
|
88
|
+
|
|
89
|
+
this.loadCaptcha();
|
|
93
90
|
}
|
|
94
91
|
|
|
95
92
|
componentWillUnmount() {
|
|
96
|
-
|
|
93
|
+
const { captchaId } = this.state;
|
|
97
94
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
95
|
+
if (!this.isReady()) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
101
98
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
99
|
+
// Reset any stored variables / timers when unmounting
|
|
100
|
+
hcaptcha.reset(captchaId);
|
|
101
|
+
hcaptcha.remove(captchaId);
|
|
105
102
|
}
|
|
106
103
|
|
|
107
104
|
shouldComponentUpdate(nextProps, nextState) {
|
|
@@ -127,6 +124,42 @@ class HCaptcha extends React.Component {
|
|
|
127
124
|
}
|
|
128
125
|
}
|
|
129
126
|
|
|
127
|
+
loadCaptcha() {
|
|
128
|
+
if (this.apiScriptRequested) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const {
|
|
133
|
+
apihost,
|
|
134
|
+
assethost,
|
|
135
|
+
endpoint,
|
|
136
|
+
host,
|
|
137
|
+
imghost,
|
|
138
|
+
languageOverride: hl,
|
|
139
|
+
reCaptchaCompat,
|
|
140
|
+
reportapi,
|
|
141
|
+
sentry,
|
|
142
|
+
custom
|
|
143
|
+
} = this.props;
|
|
144
|
+
const mountParams = {
|
|
145
|
+
apihost,
|
|
146
|
+
assethost,
|
|
147
|
+
endpoint,
|
|
148
|
+
hl,
|
|
149
|
+
host,
|
|
150
|
+
imghost,
|
|
151
|
+
recaptchacompat: reCaptchaCompat === false? "off" : null,
|
|
152
|
+
reportapi,
|
|
153
|
+
sentry,
|
|
154
|
+
custom
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
mountCaptchaScript(mountParams)
|
|
158
|
+
.then(this.handleOnLoad)
|
|
159
|
+
.catch(this.handleError);
|
|
160
|
+
this.apiScriptRequested = true;
|
|
161
|
+
}
|
|
162
|
+
|
|
130
163
|
renderCaptcha(onReady) {
|
|
131
164
|
const { isApiReady } = this.state;
|
|
132
165
|
if (!isApiReady) return;
|
|
@@ -214,11 +247,11 @@ class HCaptcha extends React.Component {
|
|
|
214
247
|
const { onError } = this.props;
|
|
215
248
|
const { captchaId } = this.state;
|
|
216
249
|
|
|
217
|
-
if (
|
|
218
|
-
|
|
250
|
+
if (this.isReady()) {
|
|
251
|
+
// If hCaptcha runs into error, reset captcha - hCaptcha
|
|
252
|
+
hcaptcha.reset(captchaId);
|
|
219
253
|
}
|
|
220
254
|
|
|
221
|
-
hcaptcha.reset(captchaId) // If hCaptcha runs into error, reset captcha - hCaptcha
|
|
222
255
|
if (onError) onError(event);
|
|
223
256
|
}
|
|
224
257
|
|