@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.
@@ -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
- // Create script to init hCaptcha
35
- var onLoadListeners = [];
36
- var apiScriptRequested = false; // Generate hCaptcha API Script
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.src = "".concat(domain, "/1/api.js?render=explicit&onload=hcaptchaOnLoad");
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 (!isApiReady) {
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 (!this.isReady()) {
281
- return;
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.0",
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 transpile"
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
- // Create script to init hCaptcha
5
- let onLoadListeners = [];
6
- let apiScriptRequested = false;
7
-
8
- // Generate hCaptcha API Script
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
- apiScriptRequested = true;
17
+ if (document.getElementById(SCRIPT_ID)) {
18
+ // API was already requested
19
+ return mountPromise;
20
+ }
21
+
11
22
  // Create global onload callback
12
- window.hcaptchaOnLoad = () => {
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.src = `${domain}/1/api.js?render=explicit&onload=hcaptchaOnLoad`;
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
- if (!isApiReady) { //Check if hCaptcha has already been loaded, if not create script tag and wait to render captcha
70
- if (apiScriptRequested) {
71
- return;
72
- }
73
-
74
- // Only create the script tag once, use a global variable to track
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
- const { captchaId } = this.state;
93
+ const { captchaId } = this.state;
97
94
 
98
- if (!this.isReady()) {
99
- return;
100
- }
95
+ if (!this.isReady()) {
96
+ return;
97
+ }
101
98
 
102
- // Reset any stored variables / timers when unmounting
103
- hcaptcha.reset(captchaId);
104
- hcaptcha.remove(captchaId);
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 (!this.isReady()) {
218
- return;
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