forked from EVOgeek/Vmeda.Online
		
	MOBILE-3565 components: Create input-errors, mark-required and recaptcha
This commit is contained in:
		
							parent
							
								
									51e220f497
								
							
						
					
					
						commit
						232669855a
					
				| @ -19,7 +19,11 @@ import { TranslateModule } from '@ngx-translate/core'; | ||||
| 
 | ||||
| import { CoreIconComponent } from './icon/icon'; | ||||
| import { CoreIframeComponent } from './iframe/iframe'; | ||||
| import { CoreInputErrorsComponent } from './input-errors/input-errors'; | ||||
| import { CoreLoadingComponent } from './loading/loading'; | ||||
| import { CoreMarkRequiredComponent } from './mark-required/mark-required'; | ||||
| import { CoreRecaptchaComponent } from './recaptcha/recaptcha'; | ||||
| import { CoreRecaptchaModalComponent } from './recaptcha/recaptchamodal'; | ||||
| import { CoreShowPasswordComponent } from './show-password/show-password'; | ||||
| import { CoreEmptyBoxComponent } from './empty-box/empty-box'; | ||||
| import { CoreDirectivesModule } from '@app/directives/directives.module'; | ||||
| @ -29,7 +33,11 @@ import { CorePipesModule } from '@app/pipes/pipes.module'; | ||||
|     declarations: [ | ||||
|         CoreIconComponent, | ||||
|         CoreIframeComponent, | ||||
|         CoreInputErrorsComponent, | ||||
|         CoreLoadingComponent, | ||||
|         CoreMarkRequiredComponent, | ||||
|         CoreRecaptchaComponent, | ||||
|         CoreRecaptchaModalComponent, | ||||
|         CoreShowPasswordComponent, | ||||
|         CoreEmptyBoxComponent, | ||||
|     ], | ||||
| @ -43,7 +51,11 @@ import { CorePipesModule } from '@app/pipes/pipes.module'; | ||||
|     exports: [ | ||||
|         CoreIconComponent, | ||||
|         CoreIframeComponent, | ||||
|         CoreInputErrorsComponent, | ||||
|         CoreLoadingComponent, | ||||
|         CoreMarkRequiredComponent, | ||||
|         CoreRecaptchaComponent, | ||||
|         CoreRecaptchaModalComponent, | ||||
|         CoreShowPasswordComponent, | ||||
|         CoreEmptyBoxComponent, | ||||
|     ], | ||||
|  | ||||
							
								
								
									
										16
									
								
								src/app/components/input-errors/core-input-errors.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/app/components/input-errors/core-input-errors.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| <div class="core-input-error-container" role="alert" *ngIf="(control && control.dirty && !control.valid) || errorText"> | ||||
|     <ng-container *ngIf="control && control.dirty && !control.valid"> | ||||
|         <ng-container *ngFor="let error of errorKeys"> | ||||
|             <div *ngIf="control.hasError(error)" class="core-input-error"> | ||||
|                 <span *ngIf="errorMessages[error]">{{errorMessages[error]}}</span> | ||||
|                 <span *ngIf="!errorMessages[error] && error == 'max' && control.errors.max"> | ||||
|                     {{ 'core.login.invalidvaluemax' | translate:{$a: control.errors.max.max} }} | ||||
|                 </span> | ||||
|                 <span *ngIf="!errorMessages[error] && error == 'min' && control.errors.min"> | ||||
|                     {{ 'core.login.invalidvaluemin' | translate:{$a: control.errors.min.min} }} | ||||
|                 </span> | ||||
|             </div> | ||||
|         </ng-container> | ||||
|     </ng-container> | ||||
|     <div *ngIf="errorText" class="core-input-error" aria-live="assertive">{{ errorText }}</div> | ||||
| </div> | ||||
							
								
								
									
										16
									
								
								src/app/components/input-errors/input-errors.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/app/components/input-errors/input-errors.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| :host { | ||||
|     width: 100%; | ||||
| 
 | ||||
|     .core-input-error-container { | ||||
|         .core-input-error { | ||||
|             padding: 4px; | ||||
|             color: var(--ion-color-danger); | ||||
|             font-size: 12px; | ||||
|             display: none; | ||||
| 
 | ||||
|             &:first-child { | ||||
|                 display: block; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										86
									
								
								src/app/components/input-errors/input-errors.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								src/app/components/input-errors/input-errors.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,86 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Component, Input, OnChanges, SimpleChange } from '@angular/core'; | ||||
| import { FormControl } from '@angular/forms'; | ||||
| import { Translate } from '@singletons/core.singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Component to show errors if an input isn't valid. | ||||
|  * | ||||
|  * @description | ||||
|  * The purpose of this component is to make easier and consistent the validation of forms. | ||||
|  * | ||||
|  * It should be applied next to the input element (ion-input, ion-select, ...). In case of ion-checkbox, it should be in another | ||||
|  * item, placing it in the same item as the checkbox will cause problems. | ||||
|  * | ||||
|  * Please notice that the inputs need to have a FormControl to make it work. That FormControl needs to be passed to this component. | ||||
|  * | ||||
|  * If this component is placed in the same ion-item as a ion-label or ion-input, then it should have the attribute "item-content", | ||||
|  * otherwise Ionic will remove it. | ||||
|  * | ||||
|  * Example usage: | ||||
|  * | ||||
|  * <ion-item text-wrap> | ||||
|  *     <ion-label stacked core-mark-required="true">{{ 'core.login.username' | translate }}</ion-label> | ||||
|  *     <ion-input type="text" name="username" formControlName="username"></ion-input> | ||||
|  *     <core-input-errors item-content [control]="myForm.controls.username" [errorMessages]="usernameErrors"></core-input-errors> | ||||
|  * </ion-item> | ||||
|  */ | ||||
| @Component({ | ||||
|     selector: 'core-input-errors', | ||||
|     templateUrl: 'core-input-errors.html', | ||||
|     styleUrls: ['input-errors.scss'], | ||||
| }) | ||||
| export class CoreInputErrorsComponent implements OnChanges { | ||||
| 
 | ||||
|     @Input() control?: FormControl; | ||||
|     @Input() errorMessages?: Record<string, string>; | ||||
|     @Input() errorText?: string; // Set other non automatic errors.
 | ||||
|     errorKeys: string[] = []; | ||||
| 
 | ||||
|     /** | ||||
|      * Initialize some common errors if they aren't set. | ||||
|      */ | ||||
|     protected initErrorMessages(): void { | ||||
|         this.errorMessages = this.errorMessages || {}; | ||||
| 
 | ||||
|         this.errorMessages.required = this.errorMessages.required || Translate.instance.instant('core.required'); | ||||
|         this.errorMessages.email = this.errorMessages.email || Translate.instance.instant('core.login.invalidemail'); | ||||
|         this.errorMessages.date = this.errorMessages.date || Translate.instance.instant('core.login.invaliddate'); | ||||
|         this.errorMessages.datetime = this.errorMessages.datetime || Translate.instance.instant('core.login.invaliddate'); | ||||
|         this.errorMessages.datetimelocal = this.errorMessages.datetimelocal || Translate.instance.instant('core.login.invaliddate'); | ||||
|         this.errorMessages.time = this.errorMessages.time || Translate.instance.instant('core.login.invalidtime'); | ||||
|         this.errorMessages.url = this.errorMessages.url || Translate.instance.instant('core.login.invalidurl'); | ||||
| 
 | ||||
|         // Set empty values by default, the default error messages will be built in the template when needed.
 | ||||
|         this.errorMessages.max = this.errorMessages.max || ''; | ||||
|         this.errorMessages.min = this.errorMessages.min || ''; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Component being changed. | ||||
|      */ | ||||
|     ngOnChanges(changes: { [name: string]: SimpleChange }): void { | ||||
|         if ((changes.control || changes.errorMessages) && this.control) { | ||||
|             this.initErrorMessages(); | ||||
| 
 | ||||
|             this.errorKeys = this.errorMessages ? Object.keys(this.errorMessages) : []; | ||||
|         } | ||||
|         if (changes.errorText) { | ||||
|             this.errorText = changes.errorText.currentValue; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										3
									
								
								src/app/components/mark-required/core-mark-required.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/app/components/mark-required/core-mark-required.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| <ng-content></ng-content> | ||||
| <ion-icon *ngIf="coreMarkRequired" class="core-input-required-asterisk" name="fas-asterisk" color="danger" [title]="requiredLabel"> | ||||
| </ion-icon> | ||||
							
								
								
									
										8
									
								
								src/app/components/mark-required/mark-required.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/app/components/mark-required/mark-required.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| :host { | ||||
|     .core-input-required-asterisk { | ||||
|         font-size: 8px; | ||||
|         --padding-start: 4px; | ||||
|         line-height: 100%; | ||||
|         vertical-align: top; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										78
									
								
								src/app/components/mark-required/mark-required.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/app/components/mark-required/mark-required.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,78 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Component, Input, OnInit, AfterViewInit, ElementRef } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreTextUtils } from '@services/utils/text'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { Translate } from '@singletons/core.singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Directive to add a red asterisk for required input fields. | ||||
|  * | ||||
|  * @description | ||||
|  * For forms with required and not required fields, it is recommended to use this directive to mark the required ones. | ||||
|  * | ||||
|  * This directive should be applied in the label. Example: | ||||
|  * | ||||
|  * <ion-label core-mark-required="{{field.required}}">{{ 'core.login.username' | translate }}</ion-label> | ||||
|  */ | ||||
| @Component({ | ||||
|     selector: '[core-mark-required]', | ||||
|     templateUrl: 'core-mark-required.html', | ||||
|     styleUrls: ['mark-required.scss'], | ||||
| }) | ||||
| export class CoreMarkRequiredComponent implements OnInit, AfterViewInit { | ||||
| 
 | ||||
|     // eslint-disable-next-line @angular-eslint/no-input-rename
 | ||||
|     @Input('core-mark-required') coreMarkRequired: boolean | string = true; | ||||
| 
 | ||||
|     protected element: HTMLElement; | ||||
|     requiredLabel?: string; | ||||
| 
 | ||||
|     constructor( | ||||
|         element: ElementRef, | ||||
|     ) { | ||||
|         this.element = element.nativeElement; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Component being initialized. | ||||
|      */ | ||||
|     ngOnInit(): void { | ||||
|         this.requiredLabel = Translate.instance.instant('core.required'); | ||||
|         this.coreMarkRequired = CoreUtils.instance.isTrueOrOne(this.coreMarkRequired); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Called after the view is initialized. | ||||
|      */ | ||||
|     ngAfterViewInit(): void { | ||||
|         if (this.coreMarkRequired) { | ||||
|             // Add the "required" to the aria-label.
 | ||||
|             const ariaLabel = this.element.getAttribute('aria-label') || | ||||
|                 CoreTextUtils.instance.cleanTags(this.element.innerHTML, true); | ||||
|             if (ariaLabel) { | ||||
|                 this.element.setAttribute('aria-label', ariaLabel + ' ' + this.requiredLabel); | ||||
|             } | ||||
|         } else { | ||||
|             // Remove the "required" from the aria-label.
 | ||||
|             const ariaLabel = this.element.getAttribute('aria-label'); | ||||
|             if (ariaLabel) { | ||||
|                 this.element.setAttribute('aria-label', ariaLabel.replace(' ' + this.requiredLabel, '')); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										13
									
								
								src/app/components/recaptcha/core-recaptcha.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/app/components/recaptcha/core-recaptcha.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| <!-- ReCAPTCHA V2 --> | ||||
| <div *ngIf="publicKey && siteUrl && model"> | ||||
|     <!-- A button to open the recaptcha modal. --> | ||||
|     <ion-button expand="block" color="light" class="ion-margin" *ngIf="!model[modelValueName]" (click)="answerRecaptcha()"> | ||||
|         {{ 'core.resourcedisplayopen' | translate }} | ||||
|     </ion-button> | ||||
|     <ion-item *ngIf="model[modelValueName]"> | ||||
|         <ion-label color="success">{{ 'core.answered' | translate }}</ion-label> | ||||
|     </ion-item> | ||||
|     <ion-item *ngIf="expired"> | ||||
|         <ion-label color="danger">{{ 'core.login.recaptchaexpired' | translate }}</ion-label> | ||||
|     </ion-item> | ||||
| </div> | ||||
							
								
								
									
										14
									
								
								src/app/components/recaptcha/core-recaptchamodal.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/app/components/recaptcha/core-recaptchamodal.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-title>{{ 'core.login.security_question' | translate }}</ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon slot="icon-only" name="fa-times"></ion-icon> | ||||
|             </ion-button> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <core-iframe [src]="recaptchaUrl" (loaded)="loaded($event)"></core-iframe> | ||||
| </ion-content> | ||||
							
								
								
									
										85
									
								
								src/app/components/recaptcha/recaptcha.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								src/app/components/recaptcha/recaptcha.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,85 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Component, Input, OnInit } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreLang } from '@services/lang'; | ||||
| import { CoreSites } from '@services/sites'; | ||||
| import { CoreTextUtils } from '@services/utils/text'; | ||||
| import { ModalController } from '@singletons/core.singletons'; | ||||
| import { CoreRecaptchaModalComponent } from './recaptchamodal'; | ||||
| 
 | ||||
| /** | ||||
|  * Component that allows answering a recaptcha. | ||||
|  */ | ||||
| @Component({ | ||||
|     selector: 'core-recaptcha', | ||||
|     templateUrl: 'core-recaptcha.html', | ||||
| }) | ||||
| export class CoreRecaptchaComponent implements OnInit { | ||||
| 
 | ||||
|     @Input() model?: Record<string, string>; // The model where to store the recaptcha response.
 | ||||
|     @Input() publicKey?: string; // The site public key.
 | ||||
|     @Input() modelValueName = 'recaptcharesponse'; // Name of the model property where to store the response.
 | ||||
|     @Input() siteUrl?: string; // The site URL. If not defined, current site.
 | ||||
| 
 | ||||
|     expired = false; | ||||
| 
 | ||||
|     protected lang?: string; | ||||
| 
 | ||||
|     constructor() { | ||||
|         this.initLang(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Component being initialized. | ||||
|      */ | ||||
|     ngOnInit(): void { | ||||
|         this.siteUrl = this.siteUrl || CoreSites.instance.getCurrentSite()?.getURL(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Initialize the lang property. | ||||
|      */ | ||||
|     protected async initLang(): Promise<void> { | ||||
|         this.lang = await CoreLang.instance.getCurrentLanguage(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Open the recaptcha modal. | ||||
|      */ | ||||
|     async answerRecaptcha(): Promise<void> { | ||||
|         // Set the iframe src. We use an iframe because reCaptcha V2 doesn't work with file:// protocol.
 | ||||
|         const src = CoreTextUtils.instance.concatenatePaths(this.siteUrl!, 'webservice/recaptcha.php?lang=' + this.lang); | ||||
| 
 | ||||
|         // Modal to answer the recaptcha.
 | ||||
|         // This is because the size of the recaptcha is dynamic, so it could cause problems if it was displayed inline.
 | ||||
| 
 | ||||
|         const modal = await ModalController.instance.create({ | ||||
|             component: CoreRecaptchaModalComponent, | ||||
|             cssClass: 'core-modal-fullscreen', | ||||
|             componentProps: { | ||||
|                 recaptchaUrl: src, | ||||
|             }, | ||||
|         }); | ||||
| 
 | ||||
|         await modal.present(); | ||||
| 
 | ||||
|         const result = await modal.onWillDismiss(); | ||||
| 
 | ||||
|         this.expired = result.data.expired; | ||||
|         this.model![this.modelValueName] = result.data.value; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										121
									
								
								src/app/components/recaptcha/recaptchamodal.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								src/app/components/recaptcha/recaptchamodal.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,121 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Component, Input, OnDestroy } from '@angular/core'; | ||||
| 
 | ||||
| import { ModalController } from '@singletons/core.singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Component to display a the recaptcha in a modal. | ||||
|  */ | ||||
| @Component({ | ||||
|     selector: 'core-recaptcha-modal', | ||||
|     templateUrl: 'core-recaptchamodal.html', | ||||
| }) | ||||
| export class CoreRecaptchaModalComponent implements OnDestroy { | ||||
| 
 | ||||
|     @Input() recaptchaUrl?: string; | ||||
| 
 | ||||
|     expired = false; | ||||
|     value = ''; | ||||
| 
 | ||||
|     protected messageListenerFunction: (event: MessageEvent) => Promise<void>; | ||||
| 
 | ||||
|     constructor() { | ||||
|         // Listen for messages from the iframe.
 | ||||
|         this.messageListenerFunction = this.onIframeMessage.bind(this); | ||||
|         window.addEventListener('message', this.messageListenerFunction); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Close modal. | ||||
|      */ | ||||
|     closeModal(): void { | ||||
|         ModalController.instance.dismiss({ | ||||
|             expired: this.expired, | ||||
|             value: this.value, | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * The iframe with the recaptcha was loaded. | ||||
|      * | ||||
|      * @param iframe Iframe element. | ||||
|      */ | ||||
|     loaded(iframe: HTMLIFrameElement): void { | ||||
|         // Search the iframe content.
 | ||||
|         const contentWindow = iframe?.contentWindow; | ||||
| 
 | ||||
|         if (contentWindow) { | ||||
|             try { | ||||
|                 // Set the callbacks we're interested in.
 | ||||
|                 contentWindow['recaptchacallback'] = this.onRecaptchaCallback.bind(this); | ||||
|                 contentWindow['recaptchaexpiredcallback'] = this.onRecaptchaExpiredCallback.bind(this); | ||||
|             } catch (error) { | ||||
|                 // Cannot access the window.
 | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Treat an iframe message event. | ||||
|      * | ||||
|      * @param event Event. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     protected async onIframeMessage(event: MessageEvent): Promise<void> { | ||||
|         if (!event.data || event.data.environment != 'moodleapp' || event.data.context != 'recaptcha') { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         switch (event.data.action) { | ||||
|             case 'callback': | ||||
|                 this.onRecaptchaCallback(event.data.value); | ||||
|                 break; | ||||
|             case 'expired': | ||||
|                 this.onRecaptchaExpiredCallback(); | ||||
|                 break; | ||||
| 
 | ||||
|             default: | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Recapcha callback called. | ||||
|      * | ||||
|      * @param value Value received. | ||||
|      */ | ||||
|     protected onRecaptchaCallback(value: string): void { | ||||
|         this.expired = false; | ||||
|         this.value = value; | ||||
|         this.closeModal(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Recapcha expired callback called. | ||||
|      */ | ||||
|     protected onRecaptchaExpiredCallback(): void { | ||||
|         this.expired = true; | ||||
|         this.value = ''; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Component destroyed. | ||||
|      */ | ||||
|     ngOnDestroy(): void { | ||||
|         window.removeEventListener('message', this.messageListenerFunction); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user