| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514 |
- import * as i0 from '@angular/core';
- import { InjectionToken, PLATFORM_ID, Injectable, Inject, Optional, EventEmitter, Component, Input, HostBinding, Output, NgModule, forwardRef, Directive, HostListener } from '@angular/core';
- import { isPlatformBrowser } from '@angular/common';
- import { of, BehaviorSubject, Subject } from 'rxjs';
- import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
- const RECAPTCHA_LANGUAGE = new InjectionToken("recaptcha-language");
- const RECAPTCHA_BASE_URL = new InjectionToken("recaptcha-base-url");
- const RECAPTCHA_NONCE = new InjectionToken("recaptcha-nonce-tag");
- const RECAPTCHA_SETTINGS = new InjectionToken("recaptcha-settings");
- const RECAPTCHA_V3_SITE_KEY = new InjectionToken("recaptcha-v3-site-key");
- function loadScript(renderMode, onLoaded, urlParams, url, nonce) {
- window.ng2recaptchaloaded = () => {
- onLoaded(grecaptcha);
- };
- const script = document.createElement("script");
- script.innerHTML = "";
- const baseUrl = url || "https://www.google.com/recaptcha/api.js";
- script.src = `${baseUrl}?render=${renderMode}&onload=ng2recaptchaloaded${urlParams}`;
- if (nonce) {
- script.nonce = nonce;
- }
- script.async = true;
- script.defer = true;
- document.head.appendChild(script);
- }
- const loader = { loadScript };
- class RecaptchaLoaderService {
- /**
- * @internal
- * @nocollapse
- */
- static { this.ready = null; }
- constructor(
- // eslint-disable-next-line @typescript-eslint/ban-types
- platformId, language, baseUrl, nonce, v3SiteKey) {
- this.platformId = platformId;
- this.language = language;
- this.baseUrl = baseUrl;
- this.nonce = nonce;
- this.v3SiteKey = v3SiteKey;
- this.init();
- this.ready = isPlatformBrowser(this.platformId) ? RecaptchaLoaderService.ready.asObservable() : of();
- }
- /** @internal */
- init() {
- if (RecaptchaLoaderService.ready) {
- return;
- }
- if (isPlatformBrowser(this.platformId)) {
- const subject = new BehaviorSubject(null);
- RecaptchaLoaderService.ready = subject;
- const langParam = this.language ? "&hl=" + this.language : "";
- const renderMode = this.v3SiteKey || "explicit";
- loader.loadScript(renderMode, (grecaptcha) => subject.next(grecaptcha), langParam, this.baseUrl, this.nonce);
- }
- }
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaLoaderService, deps: [{ token: PLATFORM_ID }, { token: RECAPTCHA_LANGUAGE, optional: true }, { token: RECAPTCHA_BASE_URL, optional: true }, { token: RECAPTCHA_NONCE, optional: true }, { token: RECAPTCHA_V3_SITE_KEY, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaLoaderService }); }
- }
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaLoaderService, decorators: [{
- type: Injectable
- }], ctorParameters: function () { return [{ type: Object, decorators: [{
- type: Inject,
- args: [PLATFORM_ID]
- }] }, { type: undefined, decorators: [{
- type: Optional
- }, {
- type: Inject,
- args: [RECAPTCHA_LANGUAGE]
- }] }, { type: undefined, decorators: [{
- type: Optional
- }, {
- type: Inject,
- args: [RECAPTCHA_BASE_URL]
- }] }, { type: undefined, decorators: [{
- type: Optional
- }, {
- type: Inject,
- args: [RECAPTCHA_NONCE]
- }] }, { type: undefined, decorators: [{
- type: Optional
- }, {
- type: Inject,
- args: [RECAPTCHA_V3_SITE_KEY]
- }] }]; } });
- let nextId = 0;
- class RecaptchaComponent {
- constructor(elementRef, loader, zone, settings) {
- this.elementRef = elementRef;
- this.loader = loader;
- this.zone = zone;
- this.id = `ngrecaptcha-${nextId++}`;
- this.errorMode = "default";
- this.resolved = new EventEmitter();
- /**
- * @deprecated `(error) output will be removed in the next major version. Use (errored) instead
- */
- // eslint-disable-next-line @angular-eslint/no-output-native
- this.error = new EventEmitter();
- this.errored = new EventEmitter();
- if (settings) {
- this.siteKey = settings.siteKey;
- this.theme = settings.theme;
- this.type = settings.type;
- this.size = settings.size;
- this.badge = settings.badge;
- }
- }
- ngAfterViewInit() {
- this.subscription = this.loader.ready.subscribe((grecaptcha) => {
- if (grecaptcha != null && grecaptcha.render instanceof Function) {
- this.grecaptcha = grecaptcha;
- this.renderRecaptcha();
- }
- });
- }
- ngOnDestroy() {
- // reset the captcha to ensure it does not leave anything behind
- // after the component is no longer needed
- this.grecaptchaReset();
- if (this.subscription) {
- this.subscription.unsubscribe();
- }
- }
- /**
- * Executes the invisible recaptcha.
- * Does nothing if component's size is not set to "invisible".
- */
- execute() {
- if (this.size !== "invisible") {
- return;
- }
- if (this.widget != null) {
- void this.grecaptcha.execute(this.widget);
- }
- else {
- // delay execution of recaptcha until it actually renders
- this.executeRequested = true;
- }
- }
- reset() {
- if (this.widget != null) {
- if (this.grecaptcha.getResponse(this.widget)) {
- // Only emit an event in case if something would actually change.
- // That way we do not trigger "touching" of the control if someone does a "reset"
- // on a non-resolved captcha.
- this.resolved.emit(null);
- }
- this.grecaptchaReset();
- }
- }
- /**
- * ⚠️ Warning! Use this property at your own risk!
- *
- * While this member is `public`, it is not a part of the component's public API.
- * The semantic versioning guarantees _will not be honored_! Thus, you might find that this property behavior changes in incompatible ways in minor or even patch releases.
- * You are **strongly advised** against using this property.
- * Instead, use more idiomatic ways to get reCAPTCHA value, such as `resolved` EventEmitter, or form-bound methods (ngModel, formControl, and the likes).å
- */
- get __unsafe_widgetValue() {
- return this.widget != null ? this.grecaptcha.getResponse(this.widget) : null;
- }
- /** @internal */
- expired() {
- this.resolved.emit(null);
- }
- /** @internal */
- onError(args) {
- this.error.emit(args);
- this.errored.emit(args);
- }
- /** @internal */
- captchaResponseCallback(response) {
- this.resolved.emit(response);
- }
- /** @internal */
- grecaptchaReset() {
- if (this.widget != null) {
- this.zone.runOutsideAngular(() => this.grecaptcha.reset(this.widget));
- }
- }
- /** @internal */
- renderRecaptcha() {
- // This `any` can be removed after @types/grecaptcha get updated
- const renderOptions = {
- badge: this.badge,
- callback: (response) => {
- this.zone.run(() => this.captchaResponseCallback(response));
- },
- "expired-callback": () => {
- this.zone.run(() => this.expired());
- },
- sitekey: this.siteKey,
- size: this.size,
- tabindex: this.tabIndex,
- theme: this.theme,
- type: this.type,
- };
- if (this.errorMode === "handled") {
- renderOptions["error-callback"] = (...args) => {
- this.zone.run(() => this.onError(args));
- };
- }
- this.widget = this.grecaptcha.render(this.elementRef.nativeElement, renderOptions);
- if (this.executeRequested === true) {
- this.executeRequested = false;
- this.execute();
- }
- }
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaComponent, deps: [{ token: i0.ElementRef }, { token: RecaptchaLoaderService }, { token: i0.NgZone }, { token: RECAPTCHA_SETTINGS, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.1", type: RecaptchaComponent, selector: "re-captcha", inputs: { id: "id", siteKey: "siteKey", theme: "theme", type: "type", size: "size", tabIndex: "tabIndex", badge: "badge", errorMode: "errorMode" }, outputs: { resolved: "resolved", error: "error", errored: "errored" }, host: { properties: { "attr.id": "this.id" } }, exportAs: ["reCaptcha"], ngImport: i0, template: ``, isInline: true }); }
- }
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaComponent, decorators: [{
- type: Component,
- args: [{
- exportAs: "reCaptcha",
- selector: "re-captcha",
- template: ``,
- }]
- }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: RecaptchaLoaderService }, { type: i0.NgZone }, { type: undefined, decorators: [{
- type: Optional
- }, {
- type: Inject,
- args: [RECAPTCHA_SETTINGS]
- }] }]; }, propDecorators: { id: [{
- type: Input
- }, {
- type: HostBinding,
- args: ["attr.id"]
- }], siteKey: [{
- type: Input
- }], theme: [{
- type: Input
- }], type: [{
- type: Input
- }], size: [{
- type: Input
- }], tabIndex: [{
- type: Input
- }], badge: [{
- type: Input
- }], errorMode: [{
- type: Input
- }], resolved: [{
- type: Output
- }], error: [{
- type: Output
- }], errored: [{
- type: Output
- }] } });
- class RecaptchaCommonModule {
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaCommonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaCommonModule, declarations: [RecaptchaComponent], exports: [RecaptchaComponent] }); }
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaCommonModule }); }
- }
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaCommonModule, decorators: [{
- type: NgModule,
- args: [{
- declarations: [RecaptchaComponent],
- exports: [RecaptchaComponent],
- }]
- }] });
- class RecaptchaModule {
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaModule, imports: [RecaptchaCommonModule], exports: [RecaptchaComponent] }); }
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaModule, providers: [RecaptchaLoaderService], imports: [RecaptchaCommonModule] }); }
- }
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaModule, decorators: [{
- type: NgModule,
- args: [{
- exports: [RecaptchaComponent],
- imports: [RecaptchaCommonModule],
- providers: [RecaptchaLoaderService],
- }]
- }] });
- /**
- * The main service for working with reCAPTCHA v3 APIs.
- *
- * Use the `execute` method for executing a single action, and
- * `onExecute` observable for listening to all actions at once.
- */
- class ReCaptchaV3Service {
- constructor(zone, siteKey,
- // eslint-disable-next-line @typescript-eslint/ban-types
- platformId, baseUrl, nonce, language) {
- /** @internal */
- this.onLoadComplete = (grecaptcha) => {
- this.grecaptcha = grecaptcha;
- if (this.actionBacklog && this.actionBacklog.length > 0) {
- this.actionBacklog.forEach(([action, subject]) => this.executeActionWithSubject(action, subject));
- this.actionBacklog = undefined;
- }
- };
- this.zone = zone;
- this.isBrowser = isPlatformBrowser(platformId);
- this.siteKey = siteKey;
- this.nonce = nonce;
- this.language = language;
- this.baseUrl = baseUrl;
- this.init();
- }
- get onExecute() {
- if (!this.onExecuteSubject) {
- this.onExecuteSubject = new Subject();
- this.onExecuteObservable = this.onExecuteSubject.asObservable();
- }
- return this.onExecuteObservable;
- }
- get onExecuteError() {
- if (!this.onExecuteErrorSubject) {
- this.onExecuteErrorSubject = new Subject();
- this.onExecuteErrorObservable = this.onExecuteErrorSubject.asObservable();
- }
- return this.onExecuteErrorObservable;
- }
- /**
- * Executes the provided `action` with reCAPTCHA v3 API.
- * Use the emitted token value for verification purposes on the backend.
- *
- * For more information about reCAPTCHA v3 actions and tokens refer to the official documentation at
- * https://developers.google.com/recaptcha/docs/v3.
- *
- * @param {string} action the action to execute
- * @returns {Observable<string>} an `Observable` that will emit the reCAPTCHA v3 string `token` value whenever ready.
- * The returned `Observable` completes immediately after emitting a value.
- */
- execute(action) {
- const subject = new Subject();
- if (this.isBrowser) {
- if (!this.grecaptcha) {
- if (!this.actionBacklog) {
- this.actionBacklog = [];
- }
- this.actionBacklog.push([action, subject]);
- }
- else {
- this.executeActionWithSubject(action, subject);
- }
- }
- return subject.asObservable();
- }
- /** @internal */
- executeActionWithSubject(action, subject) {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- const onError = (error) => {
- this.zone.run(() => {
- subject.error(error);
- if (this.onExecuteErrorSubject) {
- // We don't know any better at this point, unfortunately, so have to resort to `any`
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
- this.onExecuteErrorSubject.next({ action, error });
- }
- });
- };
- this.zone.runOutsideAngular(() => {
- try {
- this.grecaptcha.execute(this.siteKey, { action }).then((token) => {
- this.zone.run(() => {
- subject.next(token);
- subject.complete();
- if (this.onExecuteSubject) {
- this.onExecuteSubject.next({ action, token });
- }
- });
- }, onError);
- }
- catch (e) {
- onError(e);
- }
- });
- }
- /** @internal */
- init() {
- if (this.isBrowser) {
- if ("grecaptcha" in window) {
- this.grecaptcha = grecaptcha;
- }
- else {
- const langParam = this.language ? "&hl=" + this.language : "";
- loader.loadScript(this.siteKey, this.onLoadComplete, langParam, this.baseUrl, this.nonce);
- }
- }
- }
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: ReCaptchaV3Service, deps: [{ token: i0.NgZone }, { token: RECAPTCHA_V3_SITE_KEY }, { token: PLATFORM_ID }, { token: RECAPTCHA_BASE_URL, optional: true }, { token: RECAPTCHA_NONCE, optional: true }, { token: RECAPTCHA_LANGUAGE, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: ReCaptchaV3Service }); }
- }
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: ReCaptchaV3Service, decorators: [{
- type: Injectable
- }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: undefined, decorators: [{
- type: Inject,
- args: [RECAPTCHA_V3_SITE_KEY]
- }] }, { type: Object, decorators: [{
- type: Inject,
- args: [PLATFORM_ID]
- }] }, { type: undefined, decorators: [{
- type: Optional
- }, {
- type: Inject,
- args: [RECAPTCHA_BASE_URL]
- }] }, { type: undefined, decorators: [{
- type: Optional
- }, {
- type: Inject,
- args: [RECAPTCHA_NONCE]
- }] }, { type: undefined, decorators: [{
- type: Optional
- }, {
- type: Inject,
- args: [RECAPTCHA_LANGUAGE]
- }] }]; } });
- class RecaptchaV3Module {
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaV3Module, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaV3Module }); }
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaV3Module, providers: [ReCaptchaV3Service] }); }
- }
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaV3Module, decorators: [{
- type: NgModule,
- args: [{
- providers: [ReCaptchaV3Service],
- }]
- }] });
- class RecaptchaValueAccessorDirective {
- constructor(host) {
- this.host = host;
- this.requiresControllerReset = false;
- }
- writeValue(value) {
- if (!value) {
- this.host.reset();
- }
- else {
- // In this case, it is most likely that a form controller has requested to write a specific value into the component.
- // This isn't really a supported case - reCAPTCHA values are single-use, and, in a sense, readonly.
- // What this means is that the form controller has recaptcha control state of X, while reCAPTCHA itself can't "restore"
- // to that state. In order to make form controller aware of this discrepancy, and to fix the said misalignment,
- // we'll be telling the controller to "reset" the value back to null.
- if (this.host.__unsafe_widgetValue !== value && Boolean(this.host.__unsafe_widgetValue) === false) {
- this.requiresControllerReset = true;
- }
- }
- }
- registerOnChange(fn) {
- this.onChange = fn;
- if (this.requiresControllerReset) {
- this.requiresControllerReset = false;
- this.onChange(null);
- }
- }
- registerOnTouched(fn) {
- this.onTouched = fn;
- }
- onResolve($event) {
- if (this.onChange) {
- this.onChange($event);
- }
- if (this.onTouched) {
- this.onTouched();
- }
- }
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaValueAccessorDirective, deps: [{ token: RecaptchaComponent }], target: i0.ɵɵFactoryTarget.Directive }); }
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.0.1", type: RecaptchaValueAccessorDirective, selector: "re-captcha[formControlName],re-captcha[formControl],re-captcha[ngModel]", host: { listeners: { "resolved": "onResolve($event)" } }, providers: [
- {
- multi: true,
- provide: NG_VALUE_ACCESSOR,
- useExisting: forwardRef(() => RecaptchaValueAccessorDirective),
- },
- ], ngImport: i0 }); }
- }
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaValueAccessorDirective, decorators: [{
- type: Directive,
- args: [{
- providers: [
- {
- multi: true,
- provide: NG_VALUE_ACCESSOR,
- useExisting: forwardRef(() => RecaptchaValueAccessorDirective),
- },
- ],
- selector: "re-captcha[formControlName],re-captcha[formControl],re-captcha[ngModel]",
- }]
- }], ctorParameters: function () { return [{ type: RecaptchaComponent }]; }, propDecorators: { onResolve: [{
- type: HostListener,
- args: ["resolved", ["$event"]]
- }] } });
- class RecaptchaFormsModule {
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaFormsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaFormsModule, declarations: [RecaptchaValueAccessorDirective], imports: [FormsModule, RecaptchaCommonModule], exports: [RecaptchaValueAccessorDirective] }); }
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaFormsModule, imports: [FormsModule, RecaptchaCommonModule] }); }
- }
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.1", ngImport: i0, type: RecaptchaFormsModule, decorators: [{
- type: NgModule,
- args: [{
- declarations: [RecaptchaValueAccessorDirective],
- exports: [RecaptchaValueAccessorDirective],
- imports: [FormsModule, RecaptchaCommonModule],
- }]
- }] });
- /**
- * Generated bundle index. Do not edit.
- */
- export { RECAPTCHA_BASE_URL, RECAPTCHA_LANGUAGE, RECAPTCHA_NONCE, RECAPTCHA_SETTINGS, RECAPTCHA_V3_SITE_KEY, ReCaptchaV3Service, RecaptchaComponent, RecaptchaFormsModule, RecaptchaLoaderService, RecaptchaModule, RecaptchaV3Module, RecaptchaValueAccessorDirective };
- //# sourceMappingURL=ng-recaptcha.mjs.map
|