├── .gitignore
├── .npmignore
├── .travis.yml
├── LICENSE.md
├── README.md
├── angular2-recaptcha.ts
├── index.ts
├── lib
├── captcha.component.ts
└── captcha.service.ts
├── package-lock.json
├── package.json
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | typings
3 | factories
4 |
5 |
6 | # misc
7 | *.log
8 | .idea
9 | *.d.ts
10 | *.js
11 | *.metadata.json
12 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | README.md
2 | tsconfig.json
3 | .npmignore
4 | .idea
5 | *.ts
6 | !*.d.ts
7 | factories
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 6
4 |
5 | os:
6 | - linux
7 |
8 | script: npm run prepare
9 |
10 | cache:
11 | directories: node_modules
12 |
13 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017 xmaestro
2 |
3 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
4 |
5 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Angular 2 : TypeScript component for Google reCaptcha 2
4 |
5 | This is just very simple Angular 2 component that implements Google [reCaptcha 2](https://www.google.com/recaptcha/intro/index.html).
6 |
7 | Installation
8 | --------------------------------------
9 |
10 | Install it from npm:
11 |
12 | ```bash
13 | npm install angular2-recaptcha
14 | ```
15 |
16 | Usage
17 | --------------------------------------
18 |
19 | ### SystemJS config
20 |
21 | ```js
22 | System.config({
23 | map: {
24 | 'angular2-recaptcha': 'node_modules/angular2-recaptcha'
25 | },
26 | packages: {
27 | app: {
28 | format: 'register',
29 | defaultExtension: 'js'
30 | },
31 | 'angular2-recaptcha': {defaultExtension: 'js', main:'index'}
32 | }
33 | });
34 | ```
35 |
36 | ### Module
37 |
38 | ```typescript
39 | ...
40 | import { ReCaptchaModule } from 'angular2-recaptcha';
41 | ...
42 | ```
43 |
44 | ```typescript
45 | ...
46 | @NgModule({
47 | imports: [...,ReCaptchaModule]
48 | })
49 | ...
50 | ```
51 |
52 | ### View
53 |
54 | Use in template like below
55 |
56 | ```html
57 |
58 | ```
59 |
60 | Where **site_key** is the Google reCaptcha public key. Optional parameters as follows:
61 | * **language** One of the ISO language values supported by Google: https://developers.google.com/recaptcha/docs/language Note that due to the design of the reCaptcha API, only the first component on a page can change the language from default English.
62 | * **theme** Either `light` (default) or `dark`.
63 | * **type** Either `image` (default) or `audio`.
64 | * **size** Either `normal` (default), `compact` or `invisible`.
65 | * **tabindex** Tabindex for navigation, default 0.
66 | * **global** If true, the reCaptcha script will be loaded from www.recaptcha.net instead of www.google.com
67 |
68 |
69 | ## Callback
70 |
71 | To catch the success callback, you will need to subscribe to the `captchaResponse` event. The response token will be passed in the `$event` parameter.
72 | To wait for component to be loaded subscribe to `loaded` event.
73 |
74 | ```html
75 |
76 | ```
77 |
78 | The event `captchaExpired` is triggered when the displayed image has expired. It does not have any event parameters.
79 |
80 | ## Methods
81 |
82 | To access the methods, use [@ViewChild](https://angular.io/docs/ts/latest/api/core/index/ViewChild-decorator.html).
83 |
84 | ### Import
85 | ```typescript
86 | import { ViewChild } from '@angular/core';
87 | import { ReCaptchaComponent } from 'angular2-recaptcha';
88 |
89 | export class RegisterComponent {
90 | @ViewChild(ReCaptchaComponent) captcha: ReCaptchaComponent;
91 | }
92 | ```
93 |
94 | ### Usage
95 | You can request a new captcha to be displayed:
96 | ```typescript
97 | this.captcha.reset();
98 | ```
99 |
100 | The previous response can be retrieved:
101 | ```typescript
102 | let token = this.captcha.getResponse();
103 | ```
104 |
--------------------------------------------------------------------------------
/angular2-recaptcha.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { ReCaptchaComponent } from "./lib/captcha.component";
3 | import { RECAPTCHA_SERVICE_PROVIDER } from "./lib/captcha.service";
4 |
5 | @NgModule({
6 | declarations: [ReCaptchaComponent],
7 | exports: [ReCaptchaComponent],
8 | providers: [RECAPTCHA_SERVICE_PROVIDER]
9 | })
10 | export class ReCaptchaModule {}
11 |
12 | export * from './lib/captcha.component';
13 |
--------------------------------------------------------------------------------
/index.ts:
--------------------------------------------------------------------------------
1 | export * from './angular2-recaptcha';
2 |
--------------------------------------------------------------------------------
/lib/captcha.component.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Component,
3 | OnInit,
4 | Input,
5 | Output,
6 | EventEmitter,
7 | NgZone,
8 | ViewChild, ElementRef, forwardRef
9 | } from '@angular/core';
10 | import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
11 | import { ReCaptchaService } from './captcha.service';
12 |
13 | @Component({
14 | selector: 're-captcha',
15 | template: '
',
16 | providers: [
17 | {
18 | provide: NG_VALUE_ACCESSOR,
19 | useExisting: forwardRef(() => ReCaptchaComponent),
20 | multi: true
21 | }
22 | ]
23 | })
24 | export class ReCaptchaComponent implements OnInit, ControlValueAccessor {
25 |
26 | @Input() site_key: string = null;
27 | @Input() theme = 'light';
28 | @Input() type = 'image';
29 | @Input() size = 'normal';
30 | @Input() tabindex = 0;
31 | @Input() badge = 'bottomright';
32 | /* Available languages: https://developers.google.com/recaptcha/docs/language */
33 | @Input() language: string = null;
34 | @Input() global: boolean = false;
35 |
36 | @Output() captchaResponse = new EventEmitter();
37 | @Output() captchaExpired = new EventEmitter();
38 | @Output() loaded = new EventEmitter();
39 |
40 | @ViewChild('target') targetRef: ElementRef;
41 | widgetId: any = null;
42 |
43 | onChange: Function = () => {};
44 | onTouched: Function = () => {};
45 |
46 | constructor(
47 | private _zone: NgZone,
48 | private _captchaService: ReCaptchaService
49 | ) {
50 | }
51 |
52 | ngOnInit() {
53 | this._captchaService.getReady(this.language, this.global)
54 | .subscribe((ready) => {
55 | if (!ready)
56 | return;
57 | // noinspection TypeScriptUnresolvedVariable,TypeScriptUnresolvedFunction
58 | this.widgetId = (window).grecaptcha.render(this.targetRef.nativeElement, {
59 | 'sitekey': this.site_key,
60 | 'badge': this.badge,
61 | 'theme': this.theme,
62 | 'type': this.type,
63 | 'size': this.size,
64 | 'tabindex': this.tabindex,
65 | 'callback': ((response: any) => this._zone.run(this.recaptchaCallback.bind(this, response))),
66 | 'expired-callback': (() => this._zone.run(this.recaptchaExpiredCallback.bind(this)))
67 | });
68 | setTimeout(() => {
69 | this.loaded.emit(true);
70 | }, 0);
71 | });
72 | }
73 |
74 | // noinspection JSUnusedGlobalSymbols
75 | public reset() {
76 | if (this.widgetId === null)
77 | return;
78 | // noinspection TypeScriptUnresolvedVariable
79 | this._zone.runOutsideAngular((window).grecaptcha.reset.bind(this.widgetId));
80 | this.onChange(null);
81 | }
82 |
83 | // noinspection JSUnusedGlobalSymbols
84 | public execute() {
85 | if (this.widgetId === null)
86 | return;
87 | // noinspection TypeScriptUnresolvedVariable
88 | (window).grecaptcha.execute(this.widgetId);
89 | }
90 |
91 | public getResponse(): string {
92 | if (this.widgetId === null)
93 | return null;
94 | // noinspection TypeScriptUnresolvedVariable
95 | return (window).grecaptcha.getResponse(this.widgetId);
96 | }
97 |
98 | writeValue(newValue: any): void {
99 | /* ignore it */
100 | }
101 |
102 | registerOnChange(fn: any): void {
103 | this.onChange = fn;
104 | }
105 |
106 | registerOnTouched(fn: any): void {
107 | this.onTouched = fn;
108 | }
109 |
110 | private recaptchaCallback(response: string) {
111 | this.onChange(response);
112 | this.onTouched();
113 | this.captchaResponse.emit(response);
114 | }
115 |
116 | private recaptchaExpiredCallback() {
117 | this.onChange(null);
118 | this.onTouched();
119 | this.captchaExpired.emit();
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/lib/captcha.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, NgZone, Optional, SkipSelf } from '@angular/core';
2 | import { BehaviorSubject, Observable } from 'rxjs';
3 |
4 | /*
5 | * Common service shared by all reCaptcha component instances
6 | * through dependency injection.
7 | * This service has the task of loading the reCaptcha API once for all.
8 | * Only the first instance of the component creates the service, subsequent
9 | * components will use the existing instance.
10 | *
11 | * As the language is passed to the