Skip to content
This repository was archived by the owner on Aug 17, 2021. It is now read-only.

Commit 6617d58

Browse files
committed
Change service to serivce provider
Resolves #98 by changing the service to a service provider which allows the user to set default values for the site key, theme, stoken, size, and type. These defaults can be overridden by setting the values on individual instances of the directive. The key validation has been moved out of the directive and into the service since now the directive does not require a key (as it can use the default defined in the provider during the config by the user).
1 parent 4e8d274 commit 6617d58

File tree

3 files changed

+181
-91
lines changed

3 files changed

+181
-91
lines changed

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,35 @@ If you want to use a secure token pass it along with the site key as an html att
152152
Please note that you have to enrypt your token yourself with your private key upfront!
153153
To learn more about secure tokens and how to generate & encrypt them please refer to the [reCAPTCHA Docs](https://developers.google.com/recaptcha/docs/secure_token).
154154

155+
Service Provider
156+
----------------
157+
You can use the vcRecaptchaServiceProvider to configure the recaptcha service once in your application's config function.
158+
This is a convenient way to set your reCaptcha site key, theme, stoken, size, and type in one place instead of each vc-recaptcha directive element instance.
159+
The defaults defined in the service provider will be overrode by any values passed to the vc-recaptcha directive element for that instance.
160+
161+
```javascript
162+
myApp.config(function(vcRecaptchaServiceProvider){
163+
vcRecaptchaServiceProvider.setSiteKey('---- YOUR PUBLIC KEY GOES HERE ----')
164+
vcRecaptchaServiceProvider.setTheme('---- light or dark ----')
165+
vcRecaptchaServiceProvider.setStoken('--- YOUR GENERATED SECURE TOKEN ---')
166+
vcRecaptchaServiceProvider.setSize('---- compact or normal ----')
167+
vcRecaptchaServiceProvider.setType('---- audio or image ----')
168+
});
169+
```
170+
171+
You can also set all of the values at once.
172+
173+
```javascript
174+
myApp.config(function(vcRecaptchaServiceProvider){
175+
vcRecaptchaServiceProvider.setDefaults({
176+
key: '---- YOUR PUBLIC KEY GOES HERE ----',
177+
theme: '---- light or dark ----',
178+
stoken: '--- YOUR GENERATED SECURE TOKEN ---',
179+
size: '---- compact or normal ----',
180+
type: '---- audio or image ----'
181+
});
182+
```
183+
Note: any value omitted will be undefined, even if previously set.
155184
156185
Differences with the old reCaptcha
157186
----------------------------------

src/directive.js

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@
22
(function (ng) {
33
'use strict';
44

5-
function throwNoKeyException() {
6-
throw new Error('You need to set the "key" attribute to your public reCaptcha key. If you don\'t have a key, please get one from https://www.google.com/recaptcha/admin/create');
7-
}
8-
95
var app = ng.module('vcRecaptcha');
106

117
app.directive('vcRecaptcha', ['$document', '$timeout', 'vcRecaptchaService', function ($document, $timeout, vcRecaptcha) {
@@ -15,7 +11,7 @@
1511
require: "?^^form",
1612
scope: {
1713
response: '=?ngModel',
18-
key: '=',
14+
key: '=?',
1915
stoken: '=?',
2016
theme: '=?',
2117
size: '=?',
@@ -25,22 +21,10 @@
2521
onExpire: '&'
2622
},
2723
link: function (scope, elm, attrs, ctrl) {
28-
if (!attrs.hasOwnProperty('key')) {
29-
throwNoKeyException();
30-
}
31-
3224
scope.widgetId = null;
3325

3426
var sessionTimeout;
3527
var removeCreationListener = scope.$watch('key', function (key) {
36-
if (!key) {
37-
return;
38-
}
39-
40-
if (key.length !== 40) {
41-
throwNoKeyException();
42-
}
43-
4428
var callback = function (gRecaptchaResponse) {
4529
// Safe $apply
4630
$timeout(function () {
@@ -63,8 +47,10 @@
6347
}, 2 * 60 * 1000);
6448
};
6549

66-
vcRecaptcha.create(elm[0], key, callback, {
50+
vcRecaptcha.create(elm[0], {
6751

52+
callback: callback,
53+
key: key,
6854
stoken: scope.stoken || attrs.stoken || null,
6955
theme: scope.theme || attrs.theme || null,
7056
tabindex: scope.tabindex || attrs.tabindex || null,

src/service.js

Lines changed: 148 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -2,97 +2,172 @@
22
(function (ng) {
33
'use strict';
44

5+
function throwNoKeyException() {
6+
throw new Error('You need to set the "key" attribute to your public reCaptcha key. If you don\'t have a key, please get one from https://www.google.com/recaptcha/admin/create');
7+
}
8+
59
var app = ng.module('vcRecaptcha');
610

711
/**
812
* An angular service to wrap the reCaptcha API
913
*/
10-
app.service('vcRecaptchaService', ['$window', '$q', function ($window, $q) {
11-
var deferred = $q.defer(), promise = deferred.promise, recaptcha;
14+
app.provider('vcRecaptchaService', function(){
15+
var provider = this;
16+
var config = {};
17+
18+
/**
19+
* Sets the reCaptcha configuration values which will be used by default is not specified in a specific directive instance.
20+
*
21+
* @since 2.5.0
22+
* @param defaults object which overrides the current defaults object.
23+
*/
24+
provider.setDefaults = function(defaults){
25+
angular.copy(config, defaults);
26+
};
1227

13-
$window.vcRecaptchaApiLoadedCallback = $window.vcRecaptchaApiLoadedCallback || [];
28+
/**
29+
* Sets the reCaptcha key which will be used by default is not specified in a specific directive instance.
30+
*
31+
* @since 2.5.0
32+
* @param siteKey the reCaptcha public key (refer to the README file if you don't know what this is).
33+
*/
34+
provider.setSiteKey = function(siteKey){
35+
config.key = siteKey;
36+
};
1437

15-
var callback = function () {
16-
recaptcha = $window.grecaptcha;
38+
/**
39+
* Sets the reCaptcha theme which will be used by default is not specified in a specific directive instance.
40+
*
41+
* @since 2.5.0
42+
* @param theme The reCaptcha theme.
43+
*/
44+
provider.setTheme = function(theme){
45+
config.theme = theme;
46+
};
1747

18-
deferred.resolve(recaptcha);
48+
/**
49+
* Sets the reCaptcha stoken which will be used by default is not specified in a specific directive instance.
50+
*
51+
* @since 2.5.0
52+
* @param stoken The reCaptcha stoken.
53+
*/
54+
provider.setStoken = function(stoken){
55+
config.stoken = stoken;
1956
};
2057

21-
$window.vcRecaptchaApiLoadedCallback.push(callback);
58+
/**
59+
* Sets the reCaptcha size which will be used by default is not specified in a specific directive instance.
60+
*
61+
* @since 2.5.0
62+
* @param size The reCaptcha size.
63+
*/
64+
provider.setSize = function(size){
65+
config.size = size;
66+
};
2267

23-
$window.vcRecaptchaApiLoaded = function () {
24-
$window.vcRecaptchaApiLoadedCallback.forEach(function(callback) {
25-
callback();
26-
});
68+
/**
69+
* Sets the reCaptcha type which will be used by default is not specified in a specific directive instance.
70+
*
71+
* @since 2.5.0
72+
* @param type The reCaptcha type.
73+
*/
74+
provider.setType = function(type){
75+
config.type = type;
2776
};
2877

78+
provider.$get = ['$window', '$q', function ($window, $q) {
79+
var deferred = $q.defer(), promise = deferred.promise, recaptcha;
2980

30-
function getRecaptcha() {
31-
if (!!recaptcha) {
32-
return $q.when(recaptcha);
33-
}
81+
$window.vcRecaptchaApiLoadedCallback = $window.vcRecaptchaApiLoadedCallback || [];
3482

35-
return promise;
36-
}
83+
var callback = function () {
84+
recaptcha = $window.grecaptcha;
3785

38-
function validateRecaptchaInstance() {
39-
if (!recaptcha) {
40-
throw new Error('reCaptcha has not been loaded yet.');
41-
}
42-
}
43-
44-
45-
// Check if grecaptcha is not defined already.
46-
if (ng.isDefined($window.grecaptcha)) {
47-
callback();
48-
}
49-
50-
return {
51-
52-
/**
53-
* Creates a new reCaptcha object
54-
*
55-
* @param elm the DOM element where to put the captcha
56-
* @param key the recaptcha public key (refer to the README file if you don't know what this is)
57-
* @param fn a callback function to call when the captcha is resolved
58-
* @param conf the captcha object configuration
59-
*/
60-
create: function (elm, key, fn, conf) {
61-
conf.callback = fn;
62-
conf.sitekey = key;
63-
64-
return getRecaptcha().then(function (recaptcha) {
65-
return recaptcha.render(elm, conf);
86+
deferred.resolve(recaptcha);
87+
};
88+
89+
$window.vcRecaptchaApiLoadedCallback.push(callback);
90+
91+
$window.vcRecaptchaApiLoaded = function () {
92+
$window.vcRecaptchaApiLoadedCallback.forEach(function(callback) {
93+
callback();
6694
});
67-
},
68-
69-
/**
70-
* Reloads the reCaptcha
71-
*/
72-
reload: function (widgetId) {
73-
validateRecaptchaInstance();
74-
75-
// $log.info('Reloading captcha');
76-
recaptcha.reset(widgetId);
77-
78-
// reCaptcha will call the same callback provided to the
79-
// create function once this new captcha is resolved.
80-
},
81-
82-
/**
83-
* Gets the response from the reCaptcha widget.
84-
*
85-
* @see https://developers.google.com/recaptcha/docs/display#js_api
86-
*
87-
* @returns {String}
88-
*/
89-
getResponse: function (widgetId) {
90-
validateRecaptchaInstance();
91-
92-
return recaptcha.getResponse(widgetId);
95+
};
96+
97+
98+
function getRecaptcha() {
99+
if (!!recaptcha) {
100+
return $q.when(recaptcha);
101+
}
102+
103+
return promise;
104+
}
105+
106+
function validateRecaptchaInstance() {
107+
if (!recaptcha) {
108+
throw new Error('reCaptcha has not been loaded yet.');
109+
}
110+
}
111+
112+
113+
// Check if grecaptcha is not defined already.
114+
if (ng.isDefined($window.grecaptcha)) {
115+
callback();
93116
}
94-
};
95117

96-
}]);
118+
return {
119+
120+
/**
121+
* Creates a new reCaptcha object
122+
*
123+
* @param elm the DOM element where to put the captcha
124+
* @param conf the captcha object configuration
125+
* @throws NoKeyException if no key is provided in the provider config or the directive instance (via attribute)
126+
*/
127+
create: function (elm, conf) {
128+
129+
conf.key = conf.key || config.key;
130+
conf.theme = conf.theme || config.theme;
131+
conf.stoken = conf.stoken || config.stoken;
132+
conf.size = conf.size || config.size;
133+
conf.type = conf.type || config.type;
134+
135+
if (!conf.key || conf.key.length !== 40) {
136+
throwNoKeyException();
137+
}
138+
return getRecaptcha().then(function (recaptcha) {
139+
return recaptcha.render(elm, conf);
140+
});
141+
},
142+
143+
/**
144+
* Reloads the reCaptcha
145+
*/
146+
reload: function (widgetId) {
147+
validateRecaptchaInstance();
148+
149+
// $log.info('Reloading captcha');
150+
recaptcha.reset(widgetId);
151+
152+
// reCaptcha will call the same callback provided to the
153+
// create function once this new captcha is resolved.
154+
},
155+
156+
/**
157+
* Gets the response from the reCaptcha widget.
158+
*
159+
* @see https://developers.google.com/recaptcha/docs/display#js_api
160+
*
161+
* @returns {String}
162+
*/
163+
getResponse: function (widgetId) {
164+
validateRecaptchaInstance();
165+
166+
return recaptcha.getResponse(widgetId);
167+
}
168+
};
169+
170+
}];
171+
});
97172

98173
}(angular));

0 commit comments

Comments
 (0)