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
JavaScript
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