Skip to content

Commit 170a642

Browse files
authored
Merge pull request dozoisch#34 from ptondereau/invisible-feature
Add invisible props and execute method
2 parents cbfe092 + b2e5296 commit 170a642

File tree

8 files changed

+91
-45
lines changed

8 files changed

+91
-45
lines changed

.editorconfig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# EditorConfig is awesome: http://EditorConfig.org
2+
3+
# top-most EditorConfig file
4+
root = true
5+
6+
# Unix-style newlines with a newline ending every file
7+
[*]
8+
end_of_line = lf
9+
insert_final_newline = true
10+
11+
[*.js]
12+
charset = utf-8
13+
indent_style = space
14+
indent_size = 2
15+
16+
[{package.json,.travis.yml}]
17+
indent_style = space
18+
indent_size = 2

.eslintrc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"comma-dangle": [2, "always-multiline"],
1616
"comma-spacing": 1,
1717
"key-spacing": 0,
18+
"indent": ["error", 2],
1819
"no-mixed-spaces-and-tabs": 2,
1920
"no-multiple-empty-lines": [1, { "max": 1}],
2021
"no-underscore-dangle": 0,
@@ -31,7 +32,8 @@
3132
"react/prop-types": 1,
3233
"react/react-in-jsx-scope": 1,
3334
"react/self-closing-comp": 1,
34-
"react/wrap-multilines": 1,
35+
"react/jsx-wrap-multilines": 1,
36+
"semi": ["error", "always"],
3537
"strict": [1, "never"]
3638
}
3739
}

karma.conf.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ module.exports = function (config) {
4242

4343
autoWatch: true,
4444

45-
browsers: [ isCI ? "PhantomJS" : "Chrome" ],
45+
browsers: [isCI ? "PhantomJS" : "Chrome"],
4646

4747
captureTimeout: 60000,
4848
browserNoActivityTimeout: 30000,

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"scripts": {
1010
"build": "rm -rf lib && babel src --out-dir lib",
1111
"lint": "eslint ./",
12+
"lint:fix": "eslint ./ --fix",
1213
"test": "karma start --single-run",
1314
"test-watch": "karma start",
1415
"patch": "release patch --run",
@@ -49,9 +50,9 @@
4950
"babel-runtime": "^6.0.0",
5051
"chai": "^3.5.0",
5152
"es5-shim": "^4.5.0",
52-
"eslint": "~1.6.0",
53-
"eslint-config-defaults": "~7.0.1",
54-
"eslint-plugin-react": "~3.5.1",
53+
"eslint": "^3.17.1",
54+
"eslint-config-defaults": "^9.0.0",
55+
"eslint-plugin-react": "^6.10.0",
5556
"karma": "~0.13.9",
5657
"karma-chai": "~0.1.0",
5758
"karma-chrome-launcher": "~0.2.0",

src/recaptcha-wrapper.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ import makeAsyncScriptLoader from "react-async-script";
33

44
const callbackName = "onloadcallback";
55
const lang = typeof window !== "undefined" && (window.recaptchaOptions && window.recaptchaOptions.lang) ?
6-
"&hl=" + window.recaptchaOptions.lang :
6+
`&hl=${window.recaptchaOptions.lang}` :
77
"";
88
const URL = `https://www.google.com/recaptcha/api.js?onload=${callbackName}&render=explicit${lang}`;
99
const globalName = "grecaptcha";
1010

1111
export default makeAsyncScriptLoader(ReCAPTCHA, URL, {
12-
callbackName: callbackName,
13-
globalName: globalName,
14-
exposeFuncs: ["getValue", "reset"],
12+
callbackName,
13+
globalName,
14+
exposeFuncs: ["getValue", "reset", "execute"],
1515
});

src/recaptcha.js

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ const ReCAPTCHA = React.createClass({
1010
type: PropTypes.oneOf(["image", "audio"]),
1111
tabindex: PropTypes.number,
1212
onExpired: PropTypes.func,
13-
size: PropTypes.oneOf(["compact", "normal"]),
13+
size: PropTypes.oneOf(["compact", "normal", "invisible"]),
1414
stoken: PropTypes.string,
1515
},
1616

17-
getInitialState() {
17+
getInitialState () {
1818
return {};
1919
},
2020

21-
getDefaultProps() {
21+
getDefaultProps () {
2222
return {
2323
theme: "light",
2424
type: "image",
@@ -27,30 +27,39 @@ const ReCAPTCHA = React.createClass({
2727
};
2828
},
2929

30-
getValue() {
30+
getValue () {
3131
if (this.props.grecaptcha && this.state.widgetId !== undefined) {
3232
return this.props.grecaptcha.getResponse(this.state.widgetId);
3333
}
3434
return null;
3535
},
3636

37-
reset() {
37+
execute () {
38+
const { grecaptcha } = this.props;
39+
const { widgetId } = this.state;
40+
41+
if (grecaptcha && widgetId !== undefined) {
42+
return grecaptcha.execute(widgetId);
43+
}
44+
},
45+
46+
reset () {
3847
if (this.props.grecaptcha && this.state.widgetId !== undefined) {
3948
this.props.grecaptcha.reset(this.state.widgetId);
4049
}
4150
},
4251

43-
handleExpired() {
52+
handleExpired () {
4453
if (this.props.onExpired) {
4554
this.props.onExpired();
4655
} else if (this.props.onChange) {
4756
this.props.onChange(null);
4857
}
4958
},
5059

51-
explicitRender(cb) {
60+
explicitRender (cb) {
5261
if (this.props.grecaptcha && this.state.widgetId === undefined) {
53-
let id = this.props.grecaptcha.render(this.refs.captcha, {
62+
const id = this.props.grecaptcha.render(this.refs.captcha, {
5463
sitekey: this.props.sitekey,
5564
callback: this.props.onChange,
5665
theme: this.props.theme,
@@ -66,15 +75,15 @@ const ReCAPTCHA = React.createClass({
6675
}
6776
},
6877

69-
componentDidMount() {
78+
componentDidMount () {
7079
this.explicitRender();
7180
},
7281

73-
componentDidUpdate() {
82+
componentDidUpdate () {
7483
this.explicitRender();
7584
},
7685

77-
render() {
86+
render () {
7887
// consume properties owned by the reCATPCHA, pass the rest to the div so the user can style it.
7988
/* eslint-disable no-unused-vars */
8089
const { sitekey, onChange, theme, type, tabindex, onExpired, size, stoken, grecaptcha, ...childProps } = this.props;

test/recaptcha-spec.js

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,72 @@
11
import React from "react";
22
import ReactDOM from "react-dom";
33
import ReactTestUtils from "react-addons-test-utils";
4-
import ReCAPTCHA from "../src/recaptcha";
4+
import ReCAPTCHA from "../src/recaptcha"; // eslint-disable-line no-unused-vars
55

66
describe("ReCAPTCHA", () => {
77
it("Rendered Component should be a div", () => {
8-
let instance = ReactTestUtils.renderIntoDocument(
9-
<ReCAPTCHA sitekey="xxx" />
10-
);
8+
const instance = ReactTestUtils.renderIntoDocument(
9+
<ReCAPTCHA sitekey="xxx" />,
10+
);
1111
assert.equal(ReactDOM.findDOMNode(instance).nodeName, "DIV");
1212
});
1313
it("Rendered Component should contained passed props", () => {
14-
let props = {
14+
const props = {
1515
className: "TheClassName",
1616
id: "superdefinedId",
1717
};
18-
let instance = ReactTestUtils.renderIntoDocument(
19-
<ReCAPTCHA sitekey="xxx" {...props} />
20-
);
18+
const instance = ReactTestUtils.renderIntoDocument(
19+
<ReCAPTCHA sitekey="xxx" {...props} />,
20+
);
2121
assert.equal(ReactDOM.findDOMNode(instance).id, props.id);
2222
assert.match(ReactDOM.findDOMNode(instance).className, new RegExp(props.className));
2323
});
2424

2525
it("should call grecaptcha.render, when it is already loaded", (done) => {
26-
let grecaptchaMock = {
27-
render(node, options) {
26+
const grecaptchaMock = {
27+
render (node, options) {
2828
assert.isNotNull(node);
2929
assert.equal(options.sitekey, "xxx");
3030
done();
3131
},
3232
};
33-
let instance = ReactTestUtils.renderIntoDocument(
34-
<ReCAPTCHA sitekey="xxx" grecaptcha={grecaptchaMock} />
35-
);
33+
const instance = ReactTestUtils.renderIntoDocument(
34+
<ReCAPTCHA sitekey="xxx" grecaptcha={grecaptchaMock} />,
35+
);
3636
assert.ok(instance);
3737
});
3838
it("reset, should call grecaptcha.reset with the widget id", (done) => {
39-
let grecaptchaMock = {
40-
render() {
39+
const grecaptchaMock = {
40+
render () {
4141
return "someWidgetId";
4242
},
4343

44-
reset(widgetId) {
44+
reset (widgetId) {
4545
assert.isNotNull(widgetId);
4646
done();
4747
},
4848
};
49-
let instance = ReactTestUtils.renderIntoDocument(
50-
<ReCAPTCHA sitekey="xxx" grecaptcha={grecaptchaMock} />
51-
);
49+
const instance = ReactTestUtils.renderIntoDocument(
50+
<ReCAPTCHA sitekey="xxx" grecaptcha={grecaptchaMock} />,
51+
);
5252
instance.reset();
5353
});
54+
it("execute, should call grecaptcha.execute with the widget id", (done) => {
55+
const grecaptchaMock = {
56+
render () {
57+
return "someWidgetId";
58+
},
59+
60+
execute (widgetId) {
61+
assert.isNotNull(widgetId);
62+
done();
63+
},
64+
};
65+
const instance = ReactTestUtils.renderIntoDocument(
66+
<ReCAPTCHA sitekey="xxx" size="invisible" grecaptcha={grecaptchaMock} />,
67+
);
68+
instance.execute();
69+
});
5470
describe("Expired", () => {
5571
it("should call onChange with null when response is expired");
5672
it("should call onExpired when response is expired");

test/recaptcha-wrapper-spec.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import React from "react";
22
import ReactTestUtils from "react-addons-test-utils";
3-
import ReCAPTCHA from "../src/recaptcha-wrapper";
3+
import ReCAPTCHA from "../src/recaptcha-wrapper"; // eslint-disable-line no-unused-vars
44

55
const VALUE = "some value";
66
const WIDGET_ID = "someWidgetId";
77

8-
let grecaptchaMock = {
9-
render(node, options) {
8+
const grecaptchaMock = {
9+
render (node, options) {
1010
assert.ok(node, options);
1111
return WIDGET_ID;
1212
},
1313

14-
getResponse(widgetId) {
14+
getResponse (widgetId) {
1515
assert.equal(widgetId, WIDGET_ID);
1616
return VALUE;
1717
},
@@ -22,8 +22,8 @@ describe("ReCAPTCHAWrapper", () => {
2222
window.grecaptcha = grecaptchaMock;
2323
});
2424
it("should proxy functions", () => {
25-
let instance = ReactTestUtils.renderIntoDocument(
26-
<ReCAPTCHA sitekey="xxx"/>
25+
const instance = ReactTestUtils.renderIntoDocument(
26+
<ReCAPTCHA sitekey="xxx" />,
2727
);
2828
assert.ok(instance);
2929
assert.equal(instance.getValue(), VALUE);

0 commit comments

Comments
 (0)