diff --git a/README.md b/README.md index 62333fe..a69a12c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,69 @@ -angular-re-captcha -================== +# angular-re-captcha [![Bower version][bower-image]][bower-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][coveralls-image]][coveralls-url] -google recaptcha service for angularjs +> Integrate [reCAPTCHA](http://www.google.com/recaptcha) into angularjs with form validation support. + +## Install + +Install via bower: + +```shell +bower install angular-re-captcha --save +``` +Include the file into your application: + +```html + +``` + +### Usage Example +Your can [have a look at the example](example/example.html). Basically you have to add reCAPTCHA to your dependencies, configure your key. + +```javascript +angular.module('myApp', ['reCAPTCHA']) + .config(function (reCAPTCHAProvider) { + // required: please use your own key :) + reCAPTCHAProvider.setPublicKey('---KEY---'); + + // optional: gets passed into the Recaptcha.create call + reCAPTCHAProvider.setOptions({ + theme: 'clean' + }); + }); +``` +and use the directive within a form. Make sure to set a ng-model + +```html +
+
+ +
+``` + +## API + +### reCAPTCHAProvider + +#### reCAPTCHAProvider.setPublicKey() +Type: `function` +Default: `null` + +Sets the PublicKey + +#### reCAPTCHAProvider.setOptions() +Type: `function` +Default: `null` + +Sets the options, that get passed into the Recaptcha.create call. Here are a list of the [available options](https://developers.google.com/recaptcha/docs/customization) + +## License + +[MIT License](http://en.wikipedia.org/wiki/MIT_License) + +[bower-url]: http://badge.fury.io/bo/angular-recaptcha +[bower-image]: https://badge.fury.io/bo/angular-re-captcha.png + +[travis-url]: http://travis-ci.org/mllrsohn/angular-re-captcha +[travis-image]: https://secure.travis-ci.org/mllrsohn/angular-re-captcha.png?branch=master + +[coveralls-url]: https://coveralls.io/r/mllrsohn/angular-re-captcha +[coveralls-image]: https://coveralls.io/repos/mllrsohn/angular-re-captcha/badge.png \ No newline at end of file diff --git a/angular-re-captcha.js b/angular-re-captcha.js index 4fdb8d9..a44e57b 100644 --- a/angular-re-captcha.js +++ b/angular-re-captcha.js @@ -70,40 +70,36 @@ angular.module('reCAPTCHA', []).provider('reCAPTCHA', function() { }, link: function(scope, element, attrs, controller) { var name = attrs.name || 'reCaptcha'; - scope.clear = function(getChallenge) { + scope.clear = function() { scope.ngModel = { response: '', challenge: false }; - if (getChallenge) { - $timeout(function() { - scope.ngModel.challenge = reCAPTCHA.challenge(); - }, 200); - } + $timeout(function () { + scope.ngModel.challenge = reCAPTCHA.challenge(); + }); }; - // Reset on Start - scope.clear(); - controller.$setValidity(name, false); - // Create reCAPTCHA reCAPTCHA.create(element[0], function() { - scope.$apply(function() { - scope.ngModel.challenge = reCAPTCHA.challenge(); - }); + // Reset on Start + scope.clear(); + controller.$setValidity(name, false); + // Watch for changes to setValidity scope.$watch('ngModel.response', function(response) { controller.$setValidity(name, (response.length === 0 ? false : true)); }); + // Attach model and click handler $compile(angular.element(document.querySelector('input#recaptcha_response_field')).attr('ng-model', 'ngModel.response'))(scope); - $compile(angular.element(document.querySelector('a#recaptcha_reload_btn')).attr('ng-click', 'clear(true)'))(scope); + $compile(angular.element(document.querySelector('a#recaptcha_reload_btn')).attr('ng-click', 'clear()'))(scope); }); // Destroy Element - element.on('$destroy', reCAPTCHA.destroy); + scope.$on('$destroy', reCAPTCHA.destroy); } }; }]); \ No newline at end of file diff --git a/example/example.html b/example/example.html index b37549a..0c78a1e 100644 --- a/example/example.html +++ b/example/example.html @@ -53,8 +53,9 @@

Debug output

theme: 'clean' }); }) - .controller('AppCtrl', function ($scope) { + .controller('AppCtrl', function ($scope, reCAPTCHA) { $scope.user = {}; + $scope.register = function () { if($scope.registerForm.$valid) { $scope.showdialog = true; diff --git a/test/unit/directives/recaptcha.js b/test/unit/directives/recaptcha.js index 10f5350..f66bd61 100644 --- a/test/unit/directives/recaptcha.js +++ b/test/unit/directives/recaptcha.js @@ -1,12 +1,46 @@ 'use strict'; describe('Directive - reCAPTCHA', function() { + var expect = chai.expect, + elm, scope, ctrl, + testKey = '6LfyK-0SAAAAAAl6V9jBGQgPxemtrpIZ-SPDPd-n', + parentFormCtrl, + mockHTML = 'regenerate'; - beforeEach(module('reCAPTCHA')); + beforeEach(function() { + module('reCAPTCHA', function(reCAPTCHAProvider) { + reCAPTCHAProvider.setPublicKey(testKey); + }); - it('should add inactive class when inactive attribute is present and set to true', inject(function($compile, $rootScope) { + window.Recaptcha = { + create: function (key, element, options) { + angular.element(element).html(mockHTML); + options.callback(); + }, + get_response: sinon.spy(), + get_challenge: function () { + return 'test'; + }, + destroy: sinon.spy() + }; + inject(function($rootScope, $compile, $controller, $timeout) { + elm = angular.element('
'); + scope = $rootScope; + $compile(elm)(scope); + scope.$digest(); + $timeout.flush(); + }); + }); - })); + it('should call clear and set the value', function() { + expect(scope.captcha.response).to.equal(''); + expect(scope.captcha.challenge).to.equal('test'); + }); + + it('should call destory', function() { + scope.$destroy(); + expect(window.Recaptcha.destroy.called).to.be.true; + }); }); \ No newline at end of file