From 43d40b3ab8fbdd37216729a3c9356d284154c806 Mon Sep 17 00:00:00 2001 From: Evan Sharp Date: Fri, 5 Feb 2016 21:25:10 -0500 Subject: [PATCH 1/2] Use recaptcha expired called Resolves #57 by using recaptcha's expired-callback instead of a hard-coded 2 min timeout --- src/directive.js | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/src/directive.js b/src/directive.js index 0237f4a..38b281e 100644 --- a/src/directive.js +++ b/src/directive.js @@ -31,7 +31,6 @@ scope.widgetId = null; - var sessionTimeout; var removeCreationListener = scope.$watch('key', function (key) { if (!key) { return; @@ -51,16 +50,6 @@ // Notify about the response availability scope.onSuccess({response: gRecaptchaResponse, widgetId: scope.widgetId}); }); - - // captcha session lasts 2 mins after set. - sessionTimeout = $timeout(function (){ - if(ctrl){ - ctrl.$setValidity('recaptcha',false); - } - scope.response = ""; - // Notify about the response availability - scope.onExpire({widgetId: scope.widgetId}); - }, 2 * 60 * 1000); }; vcRecaptcha.create(elm[0], key, callback, { @@ -68,7 +57,8 @@ stoken: scope.stoken || attrs.stoken || null, theme: scope.theme || attrs.theme || null, tabindex: scope.tabindex || attrs.tabindex || null, - size: scope.size || attrs.size || null + size: scope.size || attrs.size || null, + 'expired-callback': expired }).then(function (widgetId) { // The widget has been created @@ -91,14 +81,19 @@ // reset the validity of the form if we were removed ctrl.$setValidity('recaptcha', null); } - if (sessionTimeout) { - // don't trigger the session timeout if we are no longer active - $timeout.cancel(sessionTimeout); - sessionTimeout = null; - } + cleanup(); } + function expired(){ + if(ctrl){ + ctrl.$setValidity('recaptcha',false); + } + scope.response = ""; + // Notify about the response availability + scope.onExpire({widgetId: scope.widgetId}); + } + function cleanup(){ // removes elements reCaptcha added. angular.element($document[0].querySelectorAll('.pls-container')).parent().remove(); From 4a8eb7e855bac8d65f7fb46cd03a10db05150d48 Mon Sep 17 00:00:00 2001 From: Evan Sharp Date: Fri, 5 Feb 2016 22:03:44 -0500 Subject: [PATCH 2/2] Add required to opt out of validation Resolves #96 by adding and documenting the required attribute. When require is `false` or is a scoped variable which is `false`, the form validation will be removed. This is opt out to prevent a breaking change and usually the validation is preferred. --- README.md | 7 +++++++ src/directive.js | 25 ++++++++++++++++--------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index ec20096..93ef286 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,13 @@ var app = angular.module('myApp', ['vcRecaptcha']); Here, the `key` attribute is passed to the directive's scope, so you can use either a property in your scope or just a hardcoded string. Be careful to use your public key, not your private one. +Form Validation +--------------- +**By default**, if placed in a [form](https://docs.angularjs.org/api/ng/directive/form) using [formControl](https://docs.angularjs.org/api/ng/type/form.FormController) the captcha will need to be checked for the form to be valid. +If the captcha is not checked (if the user has not checked the box or the check has expired) the form will be marked as invalid. The validation key is `recaptcha`. +You can **opt out** of this feature by setting the `required` attribute to `false` or a scoped variable +that will evaluate to `false`. Any other value, or omitting the attribute will opt in to this feature. + Response Validation ------------------- diff --git a/src/directive.js b/src/directive.js index 38b281e..7ac0a58 100644 --- a/src/directive.js +++ b/src/directive.js @@ -20,6 +20,7 @@ theme: '=?', size: '=?', tabindex: '=?', + required: '=?', onCreate: '&', onSuccess: '&', onExpire: '&' @@ -31,6 +32,10 @@ scope.widgetId = null; + if(ctrl && angular.isDefined(attrs.required)){ + scope.$watch('required', validate); + } + var removeCreationListener = scope.$watch('key', function (key) { if (!key) { return; @@ -43,10 +48,9 @@ var callback = function (gRecaptchaResponse) { // Safe $apply $timeout(function () { - if(ctrl){ - ctrl.$setValidity('recaptcha',true); - } scope.response = gRecaptchaResponse; + validate(); + // Notify about the response availability scope.onSuccess({response: gRecaptchaResponse, widgetId: scope.widgetId}); }); @@ -62,9 +66,7 @@ }).then(function (widgetId) { // The widget has been created - if(ctrl){ - ctrl.$setValidity('recaptcha',false); - } + validate(); scope.widgetId = widgetId; scope.onCreate({widgetId: widgetId}); @@ -86,14 +88,19 @@ } function expired(){ - if(ctrl){ - ctrl.$setValidity('recaptcha',false); - } scope.response = ""; + validate(); + // Notify about the response availability scope.onExpire({widgetId: scope.widgetId}); } + function validate(){ + if(ctrl){ + ctrl.$setValidity('recaptcha', scope.required === false ? null : Boolean(scope.response)); + } + } + function cleanup(){ // removes elements reCaptcha added. angular.element($document[0].querySelectorAll('.pls-container')).parent().remove();