diff --git a/README.md b/README.md index aa90656..b560b55 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ Properties used to customise the rendering: | onErrored | func | *optional* callback when the challenge errored, most likely due to network issues. | | onExpired | func | *optional* callback when the challenge is expired and has to be redone by user. By default it will call the onChange with null to signify expired callback. | | sitekey | string | The API client key | +| data-action | string | Data-action may only contain only alphanumeric characters, slashes, and underscores. Data-action must not be user-specific. It is important to check the action returned in the verify response. | | size | enum | *optional* `compact`, `normal` or `invisible`. This allows you to change the size or do an invisible captcha | | stoken | string | *optional* set the stoken parameter, which allows the captcha to be used from different domains, see [reCAPTCHA secure-token] | | tabindex | number | *optional* The tabindex on the element *(__default:__ `0`)* @@ -66,6 +67,7 @@ The component instance also has some utility functions that can be called. These - need to call when using `"invisible"` reCAPTCHA - [example below](#invisible-recaptcha) - `executeAsync()` programmatically invoke the challenge and return a promise that resolves to the token or errors(if encountered). - alternative approach to `execute()` in combination with the `onChange()` prop - [example below](#invisible-recaptcha) +- `getValue()` *after* the user completes the reCAPTCHA challenge programmatically get the token response for the reCAPTCHA widget. Example: ```javascript diff --git a/clean.js b/clean.js new file mode 100644 index 0000000..683338f --- /dev/null +++ b/clean.js @@ -0,0 +1,31 @@ +/* eslint-disable no-unused-vars */ +/* eslint-env node */ +"use strict"; +var fs = require("fs"); + +function deleteFolderRecursive(path) { + if (fs.existsSync(path) && fs.lstatSync(path).isDirectory()) { + fs.readdirSync(path).forEach(function (file, index) { + var curPath = path + "/" + file; + + if (fs.lstatSync(curPath).isDirectory()) { + // recurse + deleteFolderRecursive(curPath); + } else { + // delete file + fs.unlinkSync(curPath); + } + }); + + console.log(`Deleting directory "${path}"...`); + fs.rmdirSync(path); + } +} + +console.log("Cleaning working tree..."); + +process.argv.forEach(function (val, index, array) { + deleteFolderRecursive("./" + val); +}); + +console.log("Successfully cleaned working tree!"); diff --git a/package.json b/package.json index ff30f29..53b2d78 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "lib": "lib/" }, "scripts": { - "build": "rm -rf lib && npm run build:cjs && npm run build:esm", + "build": "node clean.js lib && npm run build:cjs && npm run build:esm", "build:cjs": "babel src --out-dir lib", "build:esm": "cross-env BABEL_ENV=esm babel src --out-dir lib/esm", "prepare": "npm run build", diff --git a/react-google-recaptcha.code-workspace b/react-google-recaptcha.code-workspace new file mode 100644 index 0000000..876a149 --- /dev/null +++ b/react-google-recaptcha.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +} \ No newline at end of file diff --git a/src/recaptcha.js b/src/recaptcha.js index 63d9e7c..4baddba 100644 --- a/src/recaptcha.js +++ b/src/recaptcha.js @@ -99,8 +99,7 @@ export default class ReCAPTCHA extends React.Component { explicitRender() { const render = this.getCaptchaFunction("render"); if (render && this._widgetId === undefined) { - const wrapper = document.createElement("div"); - this._widgetId = render(wrapper, { + this._widgetId = render(this.captcha, { sitekey: this.props.sitekey, callback: this.handleChange, theme: this.props.theme, @@ -113,8 +112,8 @@ export default class ReCAPTCHA extends React.Component { hl: this.props.hl, badge: this.props.badge, isolated: this.props.isolated, + "data-action": this.props.dataAction, }); - this.captcha.appendChild(wrapper); } if (this._executeRequested && this.props.grecaptcha && this._widgetId !== undefined) { this._executeRequested = false; @@ -173,6 +172,7 @@ ReCAPTCHA.propTypes = { hl: PropTypes.string, badge: PropTypes.oneOf(["bottomright", "bottomleft", "inline"]), isolated: PropTypes.bool, + dataAction: PropTypes.string, }; ReCAPTCHA.defaultProps = { onChange: () => {}, diff --git a/test/recaptcha.spec.js b/test/recaptcha.spec.js index 80f1560..c4fda67 100644 --- a/test/recaptcha.spec.js +++ b/test/recaptcha.spec.js @@ -51,6 +51,26 @@ describe("ReCAPTCHA", () => { ReCaptchaRef.current.reset(); expect(grecaptchaMock.reset).toBeCalledWith(WIDGET_ID); }); + it("getValue, should call grecaptcha.getResponse with the widget id (for legacy reasons)", () => { + const WIDGET_ID = "someWidgetId"; + const grecaptchaMock = { + render() { + return WIDGET_ID; + }, + getResponse: jest.fn(), + }; + const ReCaptchaRef = React.createRef(); + render( + , + ); + ReCaptchaRef.current.getValue(); + expect(grecaptchaMock.getResponse).toBeCalledWith(WIDGET_ID); + }); it("execute, should call grecaptcha.execute with the widget id", () => { const WIDGET_ID = "someWidgetId"; const grecaptchaMock = {