UNPKG

moh-common-lib

Version:

A library of Angular components, services, and styles for B.C. Government Ministry of Health (MoH).

541 lines (534 loc) 37.8 kB
import { Injectable, Component, ViewChild, NgZone, ChangeDetectorRef, Output, Input, EventEmitter, Optional, Self, NgModule } from '@angular/core'; import { HttpClient, HttpClientModule } from '@angular/common/http'; import { NgControl, FormsModule } from '@angular/forms'; import { CommonModule } from '@angular/common'; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class CaptchaDataService { /** * @param {?} httpClient */ constructor(httpClient) { this.httpClient = httpClient; } // private http: Http) { } /** * @param {?} apiBaseUrl * @param {?} nonce * @return {?} */ fetchData(apiBaseUrl, nonce) { return this.httpClient .post(apiBaseUrl + '/captcha', { nonce: nonce }, { observe: 'response' }); } /** * @param {?} apiBaseUrl * @param {?} nonce * @param {?} answer * @param {?} encryptedAnswer * @return {?} */ verifyCaptcha(apiBaseUrl, nonce, answer, encryptedAnswer) { return this.httpClient .post(apiBaseUrl + '/verify/captcha', { nonce: nonce, answer: answer, validation: encryptedAnswer }, { observe: 'response' }); } /** * @param {?} apiBaseUrl * @param {?} validation * @param {?=} translation * @return {?} */ fetchAudio(apiBaseUrl, validation, translation) { /** @type {?} */ const payload = { validation: validation }; if (translation) { payload.translation = translation; } return this.httpClient .post(apiBaseUrl + '/captcha/audio', payload, { observe: 'response' }); } } CaptchaDataService.decorators = [ { type: Injectable } ]; /** @nocollapse */ CaptchaDataService.ctorParameters = () => [ { type: HttpClient } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * CAPTCHA can display a "required" error automatically when you programmaically * call `markAllInpusAsTouched()`. (\@see AbstractForm). In order to do this, * you must set: name, ngModel, and required. Otherwise, these fields are * optional. * * \@example * <common-captcha * [nonce]="application.uuid" * [apiBaseUrl]="captchaApiBaseUrl" * (onValidToken)="setToken($event)" * name='captcha' * ngModel * required> * </common-captcha> */ class CaptchaComponent { /** * @param {?} dataService * @param {?} cd * @param {?} ngZone * @param {?} controlDir */ constructor(dataService, cd, ngZone, controlDir) { this.dataService = dataService; this.cd = cd; this.ngZone = ngZone; this.controlDir = controlDir; // tslint:disable-next-line:no-output-on-prefix this.onValidToken = new EventEmitter(); this.language = 'en'; /** * Http error response for fetching a CAPTCHA image. */ this.errorFetchingImg = null; /** * Http error response for verifying user's answer. */ this.errorVerifyAnswer = null; this.validation = ''; this.audio = ''; this.answer = ''; this.fetchingAudioInProgress = false; this._onChange = (/** * @param {?} _ * @return {?} */ (_) => { }); this._onTouched = (/** * @return {?} */ () => { }); // tslint:disable-next-line:member-ordering this.translatedMessages = { playAudio: { en: 'Play Audio', zh: '播放声音', fr: 'Lecture audio', pa: 'ਆਡੀਓ ਚਲਾਓ', }, tryAnotherImg: { en: 'Try another image', zh: '换个图像', fr: 'Essayez une autre image', pa: 'ਕੋਈ ਹੋਰ ਚਿੱਤਰ ਅਜ਼ਮਾਓ', }, userPromptMessage: { en: 'Enter the text you either see in the box or you hear in the audio', zh: '请输入看到或听到的文字', fr: 'Entrez le texte que vous voyez dans la case ou que vous entendez dans le son', pa: 'ਉਹ ਟੈਕਸਟ ਦਾਖਲ ਕਰੋ ਜੋ ਤੁਸੀਂ ਬਕਸੇ ਵਿੱਚ ਦੇਖਦੇ ਹੋ ਜਾਂ ਤੁਸੀਂ ਆਡੀਓ ਵਿੱਚ ਸੁਣਦੇ ਹੋ', }, incorrectAnswer: { en: 'Incorrect answer, please try again.', zh: '答案不对请重试', fr: 'Mauvaise réponse, veuillez réessayer.', pa: 'ਗਲਤ ਜਵਾਬ, ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ.', }, successMessage: { en: 'You can submit your application now.', zh: '你现在可以提交申请了', fr: 'Vous pouvez soumettre votre candidature maintenant.', pa: 'ਤੁਸੀਂ ਆਪਣੀ ਅਰਜ਼ੀ ਹੁਣੇ ਪੇਸ਼ ਕਰ ਸਕਦੇ ਹੋ', }, correct: { en: 'Correct.', zh: '正确', fr: 'Correct.', pa: 'ਸਹੀ ਕਰੋ', }, loadingImage: { en: 'Loading CAPTCHA image', zh: '正在下载验证码', fr: 'Chargement de l\'image CAPTCHA', pa: 'ਕੈਪਟਚਾ ਚਿੱਤਰ ਲੋਡ ਕਰ ਰਿਹਾ ਹੈ', }, browserNotSupportAudio: { en: 'Your browser does not support the audio element.', zh: '你的浏览器不支持播音', fr: 'Votre navigateur ne supporte pas l\'élément audio.', pa: 'ਤੁਹਾਡਾ ਬ੍ਰਾਉਜ਼ਰ ਆਡੀਓ ਐਲੀਮੈਂਟ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦਾ.', }, verifyingAnswer: { en: 'Verifying your answer...', zh: '正在验证答案...', fr: 'Vérification de votre réponse ...', pa: 'ਤੁਹਾਡਾ ਜਵਾਬ ਤਸਦੀਕ ਕਰ ਰਿਹਾ ਹੈ ...', }, errorRetrievingImg: { en: 'Error happened while retrieving CAPTCHA image. Please {{Click Here}} to try again', zh: '验证码下载错误请{{点击这里}}重试', fr: 'Une erreur s\'est produite lors de la récupération de l\'image CAPTCHA. S\'il vous plaît {{Cliquez Ici}} pour réessayer', pa: 'ਕੈਪਟਚਾ ਚਿੱਤਰ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਦੇ ਸਮੇਂ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ. ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਲਈ {{ਇੱਥੇ ਕਲਿਕ ਕਰੋ}}', }, errorVerifyingAnswer: { en: 'Error happened while verifying your answer. Please {{Click Here}} to try again', zh: '验证答案过程发生错误请{{点击这里}}重试', fr: 'Une erreur s\'est produite lors de la vérification de votre réponse. S\'il vous plaît {{Cliquez Ici}} pour réessayer', pa: 'ਤੁਹਾਡਾ ਜਵਾਬ ਤਸਦੀਕ ਕਰਨ ਵੇਲੇ ਗਲਤੀ ਆਈ ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਲਈ {{ਇੱਥੇ ਕਲਿਕ ਕਰੋ}}', }, }; if (controlDir) { controlDir.valueAccessor = this; } } /** * @param {?} fn * @return {?} */ registerOnChange(fn) { this._onChange = fn; } /** * @param {?} fn * @return {?} */ registerOnTouched(fn) { this._onTouched = fn; } /** * @param {?} value * @return {?} */ writeValue(value) { this.answer = value; } /** * @return {?} */ onBlur() { this._onTouched(); } /** * @return {?} */ ngOnInit() { this.forceRefresh.bind(this); window['ca.bcgov.captchaRefresh'] = this.publicForceRefresh.bind(this); // if(!this.userPromptMessage){ // this.userPromptMessage = "Enter the text you either see in the box or you hear in the audio"; // } } /** * @return {?} */ ngAfterViewInit() { this.forceRefresh(); } /** * @param {?} changes * @return {?} */ ngOnChanges(changes) { // when changing language, if audio is empty then no need to refetch if (!changes.language || !this.audio || this.audio.length === 0) { if (!(changes.reloadCaptcha && (true === changes.reloadCaptcha.previousValue || false === changes.reloadCaptcha.previousValue) && (changes.reloadCaptcha.currentValue !== changes.reloadCaptcha.previousValue))) { return; } } this.getNewCaptcha(false); } /** * @return {?} */ forceRefresh() { this.getNewCaptcha(false); this.cd.detectChanges(); } /** * @return {?} */ publicForceRefresh() { this.ngZone.run((/** * @return {?} */ () => this.forceRefresh())); } /** * @param {?} event * @return {?} */ answerChanged(event) { if (this.answer.length < 6) { this.incorrectAnswer = null; } if (this.answer.length === 6) { this._onChange(event); // have response trigger _onChange for custom form control this.state = CAPTCHA_STATE.VERIFYING_ANSWER; this.incorrectAnswer = null; this.dataService.verifyCaptcha(this.apiBaseUrl, this.nonce, this.answer, this.validation).subscribe((/** * @param {?} response * @return {?} */ response => { /** @type {?} */ const payload = response.body; if (this.isValidPayload(payload)) { this.handleVerify(payload); } else { this.state = CAPTCHA_STATE.ERROR_VERIFY; this.errorVerifyAnswer = this.createErrorTextLine(response); } }), (/** * @param {?} error * @return {?} */ (error) => { this.state = CAPTCHA_STATE.ERROR_VERIFY; this.errorVerifyAnswer = this.createErrorTextLine(error); })); } } // Call the backend to see if our answer is correct /** * @private * @param {?} payload * @return {?} */ handleVerify(payload) { // There could be the rare change where an invalid payload response is received. if (payload.valid === true) { this.state = CAPTCHA_STATE.SUCCESS_VERIFY_ANSWER_CORRECT; this.onValidToken.emit(payload.jwt); // this.controlDir.errors.set } else { this.incorrectAnswer = true; this.answer = ''; this.audio = ''; // They failed - try a new one. this.getNewCaptcha(true); } } /** * Case where HTTP 200 response code is received by the payload is incorrect or corrupt. * The occurance of this type of case should be rare. * @private * @param {?} payload * @return {?} */ isValidPayload(payload) { // console.debug('Response payload: %o', payload); if (!payload) { console.error('payload cannot be null or undefined or 0'); return false; } else { /** @type {?} */ const hasValueProp = payload.hasOwnProperty('valid'); if (!hasValueProp) { console.error('payload must have its own property named \'valid\''); return false; } else { return true; } } } /** * @return {?} */ retryFetchCaptcha() { this.state = undefined; /** * wait for 0.5 seond before resubmitting */ setTimeout((/** * @return {?} */ () => { this.getNewCaptcha(false); }), 100); } /** * @return {?} */ playAudio() { if (this.audio && this.audio.length > 0) { this.audioElement.nativeElement.play(); } else { this.fetchAudio(true); } } /** * @private * @param {?=} playImmediately * @return {?} */ fetchAudio(playImmediately = false) { if (!this.fetchingAudioInProgress) { this.fetchingAudioInProgress = true; this.dataService.fetchAudio(this.apiBaseUrl, this.validation, this.language).subscribe((/** * @param {?} response * @return {?} */ (response) => { this.fetchingAudioInProgress = false; this.audio = response.body.audio; this.cd.detectChanges(); if (playImmediately) { this.audioElement.nativeElement.play(); } }), (/** * @param {?} error * @return {?} */ (error) => { this.fetchingAudioInProgress = false; this.cd.detectChanges(); })); } } /** * @param {?} errorCase * @return {?} */ getNewCaptcha(errorCase) { this.state = CAPTCHA_STATE.FETCHING_CAPTCHA_IMG; this.audio = ''; // Reset things if (!errorCase) { // Let them know they failed instead of wiping out the answer area // Contructing this form on page load/reload will have errorCase = false this.incorrectAnswer = null; } this.dataService.fetchData(this.apiBaseUrl, this.nonce).subscribe((/** * @param {?} response * @return {?} */ response => { this.state = CAPTCHA_STATE.SUCCESS_FETCH_IMG; /** @type {?} */ const payload = response.body; this.imageContainer.nativeElement.innerHTML = payload.captcha; this.validation = payload.validation; this.cd.detectChanges(); if (this.eagerFetchAudio === 'true') { this.fetchAudio(); } }), (/** * @param {?} error * @return {?} */ (error) => { this.state = CAPTCHA_STATE.ERROR_FETCH_IMG; this.errorFetchingImg = this.createErrorTextLine(error); this.cd.detectChanges(); })); } /** * @private * @param {?} error * @return {?} */ createErrorTextLine(error) { /** @type {?} */ let line = 'Error status: ' + error.status; if (error.statusText) { line = line + ', status text: ' + error.statusText; } return line; } } CaptchaComponent.decorators = [ { type: Component, args: [{ selector: 'common-captcha', template: "<div class=\"bcgov-captcha\">\r\n\r\n\r\n <svg class=\"defs\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\r\n <defs>\r\n <symbol id=\"icon-play-def\" viewBox=\"0 0 32 32\">\r\n <path d=\"M16 0c-8.837 0-16 7.163-16 16s7.163 16 16 16 16-7.163 16-16-7.163-16-16-16zM16 29c-7.18 0-13-5.82-13-13s5.82-13 13-13 13 5.82 13 13-5.82 13-13 13zM12 9l12 7-12 7z\"></path>\r\n </symbol>\r\n\r\n <symbol id=\"icon-loop-def\" viewBox=\"0 0 32 32\">\r\n <path d=\"M27.802 5.197c-2.925-3.194-7.13-5.197-11.803-5.197-8.837 0-16 7.163-16 16h3c0-7.18 5.82-13 13-13 3.844 0 7.298 1.669 9.678 4.322l-4.678 4.678h11v-11l-4.198 4.197z\"></path>\r\n <path d=\"M29 16c0 7.18-5.82 13-13 13-3.844 0-7.298-1.669-9.678-4.322l4.678-4.678h-11v11l4.197-4.197c2.925 3.194 7.13 5.197 11.803 5.197 8.837 0 16-7.163 16-16h-3z\"></path>\r\n </symbol>\r\n\r\n <symbol id=\"icon-check-def\" viewBox=\"0 0 24 24\">\r\n <path d=\"M9 16.172l10.594-10.594 1.406 1.406-12 12-5.578-5.578 1.406-1.406z\"></path>\r\n </symbol>\r\n\r\n <symbol id=\"icon-exclamation-triangle-def\" viewBox=\"0 0 28 28\">\r\n <path d=\"M16 21.484v-2.969c0-0.281-0.219-0.516-0.5-0.516h-3c-0.281 0-0.5 0.234-0.5 0.516v2.969c0 0.281 0.219 0.516 0.5 0.516h3c0.281 0 0.5-0.234 0.5-0.516zM15.969 15.641l0.281-7.172c0-0.094-0.047-0.219-0.156-0.297-0.094-0.078-0.234-0.172-0.375-0.172h-3.437c-0.141 0-0.281 0.094-0.375 0.172-0.109 0.078-0.156 0.234-0.156 0.328l0.266 7.141c0 0.203 0.234 0.359 0.531 0.359h2.891c0.281 0 0.516-0.156 0.531-0.359zM15.75 1.047l12 22c0.344 0.609 0.328 1.359-0.031 1.969s-1.016 0.984-1.719 0.984h-24c-0.703 0-1.359-0.375-1.719-0.984s-0.375-1.359-0.031-1.969l12-22c0.344-0.641 1.016-1.047 1.75-1.047s1.406 0.406 1.75 1.047z\"></path>\r\n </symbol>\r\n\r\n </defs>\r\n </svg>\r\n\r\n\r\n\r\n <form class=\"captcha-form\" #formRef=\"ngForm\">\r\n <div [ngClass]=\"{'has-error': !!incorrectAnswer}\">\r\n <div>\r\n\r\n <div class=\"spinner-box\" *ngIf=\"!state || state === 1\">\r\n <div>\r\n <svg class=\"captcha-spinner\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 100 100\" preserveAspectRatio=\"xMidYMid\"><g transform=\"rotate(0 50 50)\">\r\n <rect x=\"47\" y=\"22\" rx=\"9.4\" ry=\"4.4\" width=\"6\" height=\"16\" fill=\"#1d3f72\">\r\n <animate attributeName=\"opacity\" values=\"1;0\" times=\"0;1\" dur=\"1s\" begin=\"-0.8888888888888888s\" repeatCount=\"indefinite\"></animate>\r\n </rect>\r\n </g><g transform=\"rotate(40 50 50)\">\r\n <rect x=\"47\" y=\"22\" rx=\"9.4\" ry=\"4.4\" width=\"6\" height=\"16\" fill=\"#1d3f72\">\r\n <animate attributeName=\"opacity\" values=\"1;0\" times=\"0;1\" dur=\"1s\" begin=\"-0.7777777777777778s\" repeatCount=\"indefinite\"></animate>\r\n </rect>\r\n </g><g transform=\"rotate(80 50 50)\">\r\n <rect x=\"47\" y=\"22\" rx=\"9.4\" ry=\"4.4\" width=\"6\" height=\"16\" fill=\"#1d3f72\">\r\n <animate attributeName=\"opacity\" values=\"1;0\" times=\"0;1\" dur=\"1s\" begin=\"-0.6666666666666666s\" repeatCount=\"indefinite\"></animate>\r\n </rect>\r\n </g><g transform=\"rotate(120 50 50)\">\r\n <rect x=\"47\" y=\"22\" rx=\"9.4\" ry=\"4.4\" width=\"6\" height=\"16\" fill=\"#1d3f72\">\r\n <animate attributeName=\"opacity\" values=\"1;0\" times=\"0;1\" dur=\"1s\" begin=\"-0.5555555555555556s\" repeatCount=\"indefinite\"></animate>\r\n </rect>\r\n </g><g transform=\"rotate(160 50 50)\">\r\n <rect x=\"47\" y=\"22\" rx=\"9.4\" ry=\"4.4\" width=\"6\" height=\"16\" fill=\"#1d3f72\">\r\n <animate attributeName=\"opacity\" values=\"1;0\" times=\"0;1\" dur=\"1s\" begin=\"-0.4444444444444444s\" repeatCount=\"indefinite\"></animate>\r\n </rect>\r\n </g><g transform=\"rotate(200 50 50)\">\r\n <rect x=\"47\" y=\"22\" rx=\"9.4\" ry=\"4.4\" width=\"6\" height=\"16\" fill=\"#1d3f72\">\r\n <animate attributeName=\"opacity\" values=\"1;0\" times=\"0;1\" dur=\"1s\" begin=\"-0.3333333333333333s\" repeatCount=\"indefinite\"></animate>\r\n </rect>\r\n </g><g transform=\"rotate(240 50 50)\">\r\n <rect x=\"47\" y=\"22\" rx=\"9.4\" ry=\"4.4\" width=\"6\" height=\"16\" fill=\"#1d3f72\">\r\n <animate attributeName=\"opacity\" values=\"1;0\" times=\"0;1\" dur=\"1s\" begin=\"-0.2222222222222222s\" repeatCount=\"indefinite\"></animate>\r\n </rect>\r\n </g><g transform=\"rotate(280 50 50)\">\r\n <rect x=\"47\" y=\"22\" rx=\"9.4\" ry=\"4.4\" width=\"6\" height=\"16\" fill=\"#1d3f72\">\r\n <animate attributeName=\"opacity\" values=\"1;0\" times=\"0;1\" dur=\"1s\" begin=\"-0.1111111111111111s\" repeatCount=\"indefinite\"></animate>\r\n </rect>\r\n </g><g transform=\"rotate(320 50 50)\">\r\n <rect x=\"47\" y=\"22\" rx=\"9.4\" ry=\"4.4\" width=\"6\" height=\"16\" fill=\"#1d3f72\">\r\n <animate attributeName=\"opacity\" values=\"1;0\" times=\"0;1\" dur=\"1s\" begin=\"0s\" repeatCount=\"indefinite\"></animate>\r\n </rect>\r\n </g></svg>\r\n </div>\r\n <div>\r\n {{translatedMessages.loadingImage[language]}}\r\n </div>\r\n </div>\r\n\r\n <div [ngClass]=\"{'captcha-box-visible': state === 2, 'captcha-box-invisible': state !== 2}\">\r\n <div class=\"captcha-image-and-buttons-container\">\r\n <div #image class=\"captcha-image\"></div>\r\n <audio #audioElement *ngIf=\"audio && audio.length > 0\" id=\"audioElement\" [src]=\"audio\">\r\n {{translatedMessages.browserNotSupportAudio[language]}}\r\n </audio>\r\n <div class=\"captcha-buttons-container\">\r\n <button class=\"captcha-button play-audio-button\" href=\"javascript:void(0)\" (click)=\"playAudio()\" role=\"button\">\r\n <svg *ngIf=\"!fetchingAudioInProgress\" class=\"icon-play\"><use xlink:href=\"#icon-play-def\"></use></svg>\r\n\r\n <svg *ngIf=\"fetchingAudioInProgress\" class=\"audio-spinner\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 100 100\" preserveAspectRatio=\"xMidYMid\"><g transform=\"rotate(0 50 50)\">\r\n <rect x=\"45\" y=\"9\" rx=\"2.7\" ry=\"0.54\" width=\"10\" height=\"22\" fill=\"#fff\">\r\n <animate attributeName=\"opacity\" values=\"1;0\" times=\"0;1\" dur=\"1s\" begin=\"-0.8888888888888888s\" repeatCount=\"indefinite\"></animate>\r\n </rect>\r\n </g><g transform=\"rotate(40 50 50)\">\r\n <rect x=\"45\" y=\"9\" rx=\"2.7\" ry=\"0.54\" width=\"10\" height=\"22\" fill=\"#fff\">\r\n <animate attributeName=\"opacity\" values=\"1;0\" times=\"0;1\" dur=\"1s\" begin=\"-0.7777777777777778s\" repeatCount=\"indefinite\"></animate>\r\n </rect>\r\n </g><g transform=\"rotate(80 50 50)\">\r\n <rect x=\"45\" y=\"9\" rx=\"2.7\" ry=\"0.54\" width=\"10\" height=\"22\" fill=\"#fff\">\r\n <animate attributeName=\"opacity\" values=\"1;0\" times=\"0;1\" dur=\"1s\" begin=\"-0.6666666666666666s\" repeatCount=\"indefinite\"></animate>\r\n </rect>\r\n </g><g transform=\"rotate(120 50 50)\">\r\n <rect x=\"45\" y=\"9\" rx=\"2.7\" ry=\"0.54\" width=\"10\" height=\"22\" fill=\"#fff\">\r\n <animate attributeName=\"opacity\" values=\"1;0\" times=\"0;1\" dur=\"1s\" begin=\"-0.5555555555555556s\" repeatCount=\"indefinite\"></animate>\r\n </rect>\r\n </g><g transform=\"rotate(160 50 50)\">\r\n <rect x=\"45\" y=\"9\" rx=\"2.7\" ry=\"0.54\" width=\"10\" height=\"22\" fill=\"#fff\">\r\n <animate attributeName=\"opacity\" values=\"1;0\" times=\"0;1\" dur=\"1s\" begin=\"-0.4444444444444444s\" repeatCount=\"indefinite\"></animate>\r\n </rect>\r\n </g><g transform=\"rotate(200 50 50)\">\r\n <rect x=\"45\" y=\"9\" rx=\"2.7\" ry=\"0.54\" width=\"10\" height=\"22\" fill=\"#fff\">\r\n <animate attributeName=\"opacity\" values=\"1;0\" times=\"0;1\" dur=\"1s\" begin=\"-0.3333333333333333s\" repeatCount=\"indefinite\"></animate>\r\n </rect>\r\n </g><g transform=\"rotate(240 50 50)\">\r\n <rect x=\"45\" y=\"9\" rx=\"2.7\" ry=\"0.54\" width=\"10\" height=\"22\" fill=\"#fff\">\r\n <animate attributeName=\"opacity\" values=\"1;0\" times=\"0;1\" dur=\"1s\" begin=\"-0.2222222222222222s\" repeatCount=\"indefinite\"></animate>\r\n </rect>\r\n </g><g transform=\"rotate(280 50 50)\">\r\n <rect x=\"45\" y=\"9\" rx=\"2.7\" ry=\"0.54\" width=\"10\" height=\"22\" fill=\"#fff\">\r\n <animate attributeName=\"opacity\" values=\"1;0\" times=\"0;1\" dur=\"1s\" begin=\"-0.1111111111111111s\" repeatCount=\"indefinite\"></animate>\r\n </rect>\r\n </g><g transform=\"rotate(320 50 50)\">\r\n <rect x=\"45\" y=\"9\" rx=\"2.7\" ry=\"0.54\" width=\"10\" height=\"22\" fill=\"#fff\">\r\n <animate attributeName=\"opacity\" values=\"1;0\" times=\"0;1\" dur=\"1s\" begin=\"0s\" repeatCount=\"indefinite\"></animate>\r\n </rect>\r\n </g></svg>\r\n\r\n <span>{{translatedMessages.playAudio[language]}}</span>\r\n </button>\r\n\r\n <button class=\"captcha-button try-another-image\" href=\"javascript:void(0)\" (click)=\"retryFetchCaptcha()\" role=\"button\">\r\n <svg class=\"icon-loop icon-loop-def\"><use xlink:href=\"#icon-loop-def\"></use></svg>\r\n <span>{{translatedMessages.tryAnotherImg[language]}}</span>\r\n </button>\r\n </div>\r\n </div>\r\n <div class=\"captcha-input-container\">\r\n <label for=\"answer\">\r\n {{userPromptMessage || translatedMessages.userPromptMessage[language]}}\r\n <input id=\"answer\" type=\"text\"\r\n #userAnswerRef = \"ngModel\"\r\n [(ngModel)]=\"answer\"\r\n (input)=\"answerChanged($event)\"\r\n class=\"captcha-input\"\r\n (blur)='onBlur()'\r\n [ngClass]=\"{'captcha-wrong-answer': userAnswerRef.dirty && incorrectAnswer}\"\r\n name=\"answer\"\r\n maxlength=\"6\"\r\n required\r\n autocorrect=\"off\"\r\n autocomplete=\"off\"\r\n autocapitalize=\"none\"\r\n aria-required=\"true\">\r\n </label>\r\n </div>\r\n </div>\r\n <div>\r\n\r\n <div class=\"error-captcha\" *ngIf=\"state === 3\" role=\"alert\" aria-live=\"assertive\">\r\n <div>\r\n <svg class=\"icon-exclamation-triangle\"><use xlink:href=\"#icon-exclamation-triangle-def\"></use></svg>\r\n\r\n <span> {{translatedMessages.errorRetrievingImg[language].substring(0,translatedMessages.errorRetrievingImg[language].indexOf('{'))}}\r\n <button class=\"error-fetching-button captcha-button\" href=\"javascript:void(0)\" (click)=\"retryFetchCaptcha()\">{{translatedMessages.errorRetrievingImg[language].substring(translatedMessages.errorRetrievingImg[language].lastIndexOf('{')+1,translatedMessages.errorRetrievingImg[language].indexOf('}'))}}</button>\r\n {{translatedMessages.errorRetrievingImg[language].substring(translatedMessages.errorRetrievingImg[language].lastIndexOf('}')+1)}}\r\n </span>\r\n </div>\r\n\r\n <div>\r\n {{errorFetchingImg}}\r\n </div>\r\n </div>\r\n\r\n <div class=\"spinner-box\" *ngIf=\"state == 4\" role=\"alert\" aria-live=\"assertive\">\r\n <span>{{translatedMessages.verifyingAnswer[language]}}</span>\r\n </div>\r\n <div class=\"error-captcha\" *ngIf=\"state === 6\" role=\"alert\" aria-live=\"assertive\">\r\n <svg class=\"icon-exclamation-triangle\"><use xlink:href=\"#icon-exclamation-triangle-def\"></use></svg>\r\n <span>{{translatedMessages.errorVerifyingAnswer[language].substring(0,translatedMessages.errorVerifyingAnswer[language].indexOf('{'))}}\r\n <button class=\"error-verifying-button captcha-button\" href=\"javascript:void(0)\" (click)=\"retryFetchCaptcha()\">{{translatedMessages.errorVerifyingAnswer[language].substring(translatedMessages.errorVerifyingAnswer[language].lastIndexOf('{')+1,translatedMessages.errorVerifyingAnswer[language].indexOf('}'))}}</button>\r\n {{translatedMessages.errorVerifyingAnswer[language].substring(translatedMessages.errorVerifyingAnswer[language].lastIndexOf('}')+1)}}\r\n </span>\r\n <p>\r\n </p>\r\n </div>\r\n\r\n <div class=\"captcha-error\" *ngIf=\"incorrectAnswer === true\" role=\"alert\" aria-live=\"assertive\">\r\n {{translatedMessages.incorrectAnswer[language]}}\r\n </div>\r\n\r\n <div class=\"captcha-error\" *ngIf=\"state === 2 && !incorrectAnswer && controlDir?.touched && controlDir?.errors?.required\" role=\"alert\" aria-live=\"assertive\">\r\n Field is required.\r\n </div>\r\n </div>\r\n\r\n </div>\r\n </div>\r\n </form>\r\n\r\n <div class=\"confirm-correct-answer\" *ngIf=\"state === 5\" role=\"alert\" aria-live=\"assertive\">\r\n <svg class=\"icon-check\"><use xlink:href=\"#icon-check-def\"></use></svg>\r\n {{translatedMessages.correct[language]}} <span>{{successMessage || translatedMessages.successMessage[language]}}</span>\r\n </div>\r\n</div>\r\n", styles: [".bcgov-captcha{text-align:left}.bcgov-captcha .confirm-correct-answer{display:block;color:green}.bcgov-captcha .confirm-correct-answer i{color:green}.bcgov-captcha .spinner-box{height:60px;margin:2px 10px 6px;padding:5px 10px 5px 18px;display:flex;align-items:center}.bcgov-captcha .error-captcha{margin-left:10px}.bcgov-captcha .error-captcha svg{color:#ff8c00}.bcgov-captcha .error-captcha p{margin-left:32px}.bcgov-captcha .captcha-box-visible{display:block}.bcgov-captcha .captcha-box-invisible{display:none}.bcgov-captcha .captcha-image{display:inline-block;border:1px solid gray;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;margin-bottom:4px}.bcgov-captcha .play-audio-button{margin-bottom:3px}.bcgov-captcha .has-error{border-color:#dc3545}.bcgov-captcha .has-error:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.bcgov-captcha input[type=text]{display:block;margin:0;width:100%;font-size:20px;box-shadow:none;border-radius:none;padding:6px;border:1px solid #ccc;transition:box-shadow .3s,border .3s}.bcgov-captcha input[type=text]:focus{border:1px solid #fff;box-shadow:0 0 1px 1px #2196f3;outline:0}.bcgov-captcha input[type=text].captcha-wrong-answer{border:1px solid #a94442}.bcgov-captcha .captcha-error{color:#a94442}.bcgov-captcha .icon-check,.bcgov-captcha .icon-exclamation-triangle,.bcgov-captcha .icon-loop,.bcgov-captcha .icon-play{display:inline-block;width:1rem;height:1rem;stroke-width:0;stroke:currentColor;fill:currentColor}.bcgov-captcha .spinner{-webkit-animation:1.4s linear infinite rotator;animation:1.4s linear infinite rotator}@-webkit-keyframes rotator{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}}@keyframes rotator{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}}.bcgov-captcha .path{stroke-dasharray:187;stroke-dashoffset:0;-webkit-transform-origin:center;transform-origin:center;-webkit-animation:1.4s ease-in-out infinite dash,5.6s ease-in-out infinite colors;animation:1.4s ease-in-out infinite dash,5.6s ease-in-out infinite colors}@-webkit-keyframes colors{0%{stroke:#9e9e9e}25%{stroke:#757575}50%{stroke:#616161}75%{stroke:#424242}100%{stroke:#212121}}@keyframes colors{0%{stroke:#9e9e9e}25%{stroke:#757575}50%{stroke:#616161}75%{stroke:#424242}100%{stroke:#212121}}@-webkit-keyframes dash{0%{stroke-dashoffset:187}50%{stroke-dashoffset:46.75;-webkit-transform:rotate(135deg);transform:rotate(135deg)}100%{stroke-dashoffset:187;-webkit-transform:rotate(450deg);transform:rotate(450deg)}}@keyframes dash{0%{stroke-dashoffset:187}50%{stroke-dashoffset:46.75;-webkit-transform:rotate(135deg);transform:rotate(135deg)}100%{stroke-dashoffset:187;-webkit-transform:rotate(450deg);transform:rotate(450deg)}}.bcgov-captcha .captcha-button{background-color:#036;border:none;border-radius:4px;color:#fff;padding:5px 10px;text-align:center;text-decoration:none;font-size:10px;font-family:BCSans,'Noto Sans',Verdana,Arial,sans-serif;font-weight:700;letter-spacing:1px;cursor:pointer;box-sizing:border-box;justify-content:center;align-items:center;display:flex}.bcgov-captcha .captcha-button.error-fetching-button,.bcgov-captcha .captcha-button.error-verifying-button{display:inline-block}.bcgov-captcha .captcha-button:hover{text-decoration:underline;opacity:.8}.bcgov-captcha .captcha-button:focus{outline:#3b99fc solid 4px;outline-offset:1px}.bcgov-captcha .captcha-button:active{opacity:1}.bcgov-captcha .captcha-input-container{max-width:420px}.bcgov-captcha .captcha-input-container>label{text-align:left}.bcgov-captcha .captcha-buttons-container{display:flex;flex-direction:column;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;justify-content:space-between;margin-bottom:4px}.bcgov-captcha .captcha-buttons-container>button{height:28px}.bcgov-captcha .captcha-buttons-container>button>span{margin-left:4px}.bcgov-captcha .captcha-form{display:flex;flex-direction:column}.bcgov-captcha .captcha-image-and-buttons-container{display:flex;flex-direction:column;flex-flow:wrap;justify-content:space-between;max-width:315px}.bcgov-captcha .defs{width:0;height:0;overflow:hidden}.bcgov-captcha .audio-spinner{display:inline-block;width:15px;height:15px;stroke-width:0;stroke:currentColor;fill:currentColor}.bcgov-captcha .captcha-spinner{display:inline-block;width:50px;height:50px;stroke-width:0;stroke:currentColor;fill:currentColor}"] }] } ]; /** @nocollapse */ CaptchaComponent.ctorParameters = () => [ { type: CaptchaDataService }, { type: ChangeDetectorRef }, { type: NgZone }, { type: NgControl, decorators: [{ type: Optional }, { type: Self }] } ]; CaptchaComponent.propDecorators = { imageContainer: [{ type: ViewChild, args: ['image',] }], audioElement: [{ type: ViewChild, args: ['audioElement',] }], apiBaseUrl: [{ type: Input, args: ['apiBaseUrl',] }], nonce: [{ type: Input, args: ['nonce',] }], onValidToken: [{ type: Output }], successMessage: [{ type: Input, args: ['successMessage',] }], eagerFetchAudio: [{ type: Input, args: ['eagerFetchAudio',] }], language: [{ type: Input, args: ['language',] }], userPromptMessage: [{ type: Input, args: ['userPromptMessage',] }] }; /** @enum {number} */ const CAPTCHA_STATE = { FETCHING_CAPTCHA_IMG: 1, SUCCESS_FETCH_IMG: 2, ERROR_FETCH_IMG: 3, VERIFYING_ANSWER: 4, SUCCESS_VERIFY_ANSWER_CORRECT: 5, // http error during verification call. ERROR_VERIFY: 6, }; CAPTCHA_STATE[CAPTCHA_STATE.FETCHING_CAPTCHA_IMG] = 'FETCHING_CAPTCHA_IMG'; CAPTCHA_STATE[CAPTCHA_STATE.SUCCESS_FETCH_IMG] = 'SUCCESS_FETCH_IMG'; CAPTCHA_STATE[CAPTCHA_STATE.ERROR_FETCH_IMG] = 'ERROR_FETCH_IMG'; CAPTCHA_STATE[CAPTCHA_STATE.VERIFYING_ANSWER] = 'VERIFYING_ANSWER'; CAPTCHA_STATE[CAPTCHA_STATE.SUCCESS_VERIFY_ANSWER_CORRECT] = 'SUCCESS_VERIFY_ANSWER_CORRECT'; CAPTCHA_STATE[CAPTCHA_STATE.ERROR_VERIFY] = 'ERROR_VERIFY'; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ class CaptchaModule { /** * @return {?} */ static forRoot() { return { ngModule: CaptchaModule, providers: [CaptchaDataService] }; } } CaptchaModule.decorators = [ { type: NgModule, args: [{ declarations: [ CaptchaComponent ], imports: [ HttpClientModule, CommonModule, FormsModule ], providers: [ CaptchaDataService ], exports: [ CaptchaComponent ], },] } ]; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ export { CaptchaModule, CaptchaDataService as ɵb, CaptchaComponent as ɵa }; //# sourceMappingURL=moh-common-lib-captcha.js.map