ngx-slider-recaptcha
Version:
Angular slider with reCAPTCHA verification
507 lines (495 loc) • 37.5 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, InjectionToken, EventEmitter, TemplateRef, Component, Inject, ViewChild, Input, Output, HostListener, NgModule } from '@angular/core';
import { of } from 'rxjs';
import * as i1 from '@angular/common';
import { CommonModule } from '@angular/common';
const DEFAULT_SLIDER_RECAPTCHA_CONFIG = {
width: 300,
height: 200,
puzzleSize: 45,
puzzleRadius: 10,
toleranceOffset: 5,
maxRetryAttempts: 3,
allowRefresh: false,
allowResponsiveWidth: false,
disabled: false,
primaryColor: '#0083c1',
errorColor: '#c4161c',
successColor: '#52ccba',
textColor: '#4b4b4b',
sliderContainerBackgroundColor: '#f7f9fa',
sliderContainerBorderColor: '#e6e8eb',
borderRadius: 4,
loadingText: 'Loading...',
instructionText: 'Slide to complete the puzzle',
};
class DefaultNgxSliderRecaptchaImageService {
getSliderImage() {
return of(`assets/images/ngx-slider-recaptcha-${Math.floor(Math.random() * 5)}.jpg`);
}
}
DefaultNgxSliderRecaptchaImageService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: DefaultNgxSliderRecaptchaImageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
DefaultNgxSliderRecaptchaImageService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: DefaultNgxSliderRecaptchaImageService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: DefaultNgxSliderRecaptchaImageService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}] });
class DefaultNgxSliderRecaptchaVerificationService {
verify(verificationRequest) {
var _a;
if (!((_a = verificationRequest === null || verificationRequest === void 0 ? void 0 : verificationRequest.sliderMovements) === null || _a === void 0 ? void 0 : _a.length)) {
return of({
success: false,
message: 'No slider movement detected. Please try again.'
});
}
const { sliderMovements, puzzleBlockPosition, puzzlePosition, toleranceOffset: offset } = verificationRequest;
const averageMovement = sliderMovements.reduce((sum, value) => sum + value, 0) / sliderMovements.length;
const movementDeviation = Math.sqrt(sliderMovements.reduce((sum, value) => sum + Math.pow(value - averageMovement, 2), 0) / sliderMovements.length);
const isVerified = movementDeviation !== 0;
const isSpliced = Math.abs(puzzleBlockPosition - puzzlePosition) < (offset !== null && offset !== void 0 ? offset : 0);
const response = {
success: isSpliced && isVerified,
message: isSpliced && isVerified ? 'Verification successful' : 'Verification failed',
};
return of(response);
}
}
DefaultNgxSliderRecaptchaVerificationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: DefaultNgxSliderRecaptchaVerificationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
DefaultNgxSliderRecaptchaVerificationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: DefaultNgxSliderRecaptchaVerificationService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: DefaultNgxSliderRecaptchaVerificationService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}] });
const NGX_SLIDER_RECAPTCHA_IMAGE_SERVICE_TOKEN = new InjectionToken('NgxSliderRecaptchaImageService');
const NGX_SLIDER_RECAPTCHA_CONFIG_TOKEN = new InjectionToken('NgxSliderRecaptchaConfig');
const NGX_SLIDER_RECAPTCHA_VERIFICATION_SERVICE_TOKEN = new InjectionToken('NgxSliderRecaptchaVerificationService');
class NgxSliderRecaptchaComponent {
constructor(renderer, cdr, globalSliderConfig, verifier, imageRetriever) {
this.renderer = renderer;
this.cdr = cdr;
this.globalSliderConfig = globalSliderConfig;
this.verifier = verifier;
this.imageRetriever = imageRetriever;
this.disabled = false;
this.onVerified = new EventEmitter();
this.onRefresh = new EventEmitter();
this.onError = new EventEmitter();
this._sliderText = '';
this._sliderOffsetX = 0;
this._blockOffsetX = 0;
this._maskWidth = 0;
this._isSliderDragging = false;
this._isVerifying = false;
this._verificationStatus = 'none';
this.dragStartX = 0;
this.dragStartY = 0;
this.puzzleX = 0;
this.puzzleY = 0;
this.loadCount = 0;
this.sliderMovements = [];
this.isUsingIE = window.navigator.userAgent.includes('Trident');
this.SLIDER_CONTAINER_MARGIN = 7;
}
ngOnInit() {
this._sliderConfig = Object.assign(Object.assign(Object.assign({}, this._sliderConfig), this.globalSliderConfig), DEFAULT_SLIDER_RECAPTCHA_CONFIG);
}
ngAfterViewInit() {
if (!this.ctx || !this.blockCtx) {
this.initializeCaptcha();
}
}
ngOnChanges(changes) {
var _a;
if ((_a = changes['config']) === null || _a === void 0 ? void 0 : _a.currentValue) {
this._sliderConfig = Object.assign(Object.assign(Object.assign({}, this._sliderConfig), this.globalSliderConfig), this.config);
this._sliderText = this.sliderConfig.instructionText;
this.initializeStyles();
this.cdr.detectChanges();
}
}
reset() {
setTimeout(() => {
this._maskWidth = 0;
this._sliderOffsetX = 0;
this._blockOffsetX = 0;
this.sliderMovements = [];
this._verificationStatus = 'none';
this._sliderText = this.sliderConfig.loadingText;
this.initializeCaptcha();
this.cdr.detectChanges();
}, 500);
}
refresh() {
this.reset();
this.onRefresh.emit();
}
isTemplate(input) {
return input instanceof TemplateRef;
}
get isSliderDragging() {
return this._isSliderDragging;
}
get isVerifying() {
return this._isVerifying;
}
get sliderText() {
return this._sliderText;
}
get verificationStatus() {
return this._verificationStatus;
}
get maskWidth() {
return this._maskWidth;
}
get sliderOffsetX() {
return this._sliderOffsetX;
}
get blockOffsetX() {
return this._blockOffsetX;
}
get sliderConfig() {
return this._sliderConfig;
}
get isDisabled() {
var _a, _b;
return (_b = (_a = this.disabled) !== null && _a !== void 0 ? _a : this.sliderConfig.disabled) !== null && _b !== void 0 ? _b : false;
}
onDragStart(event) {
const target = event.target;
if (this.isVerifying || !this.slider.nativeElement.contains(target)) {
return;
}
this._isSliderDragging = true;
this.initializeDragStartCoordinates(event);
}
onDragMove(event) {
if (this.isVerifying || !this._isSliderDragging)
return;
const { x, y } = this.extractEventCoordinates(event);
const { width, puzzleSize } = this.sliderConfig;
let deltaX = x - this.dragStartX;
let deltaY = y - this.dragStartY;
if (deltaX < 0 || deltaX + puzzleSize > width)
return;
this._sliderOffsetX = (deltaX - 1);
this._maskWidth = (deltaX + 4);
this._blockOffsetX = (width - this.sliderConfig.puzzleSize - 20) / (width - puzzleSize) * deltaX;
this.sliderMovements.push(Math.round(deltaY));
}
onDragEnd(event) {
if (this.isVerifying || !this._isSliderDragging)
return;
this._isSliderDragging = false;
const { x } = this.extractEventCoordinates(event);
if (x === this.dragStartX)
return;
const verificationRequest = {
sliderMovements: this.sliderMovements,
puzzleBlockPosition: this.blockOffsetX,
puzzlePosition: this.puzzleX,
toleranceOffset: this.sliderConfig.toleranceOffset
};
this._isVerifying = true;
this.verifier.verify(verificationRequest).subscribe({
next: (response) => {
this._isVerifying = false;
if (response.success) {
this._verificationStatus = 'success';
this.onVerified.emit(response);
}
else {
this._verificationStatus = 'fail';
this.onError.emit("Verification failed");
setTimeout(() => this.reset(), 1000);
}
},
error: (error) => {
this._isVerifying = false;
this.onError.emit(error);
setTimeout(() => this.reset(), 1000);
}
});
}
initializeCanvasDimensions() {
const { width, height, puzzleSize } = this.sliderConfig;
const sliderContainerHeight = (puzzleSize !== null && puzzleSize !== void 0 ? puzzleSize : 0) + this.SLIDER_CONTAINER_MARGIN;
const adjustedHeight = (height !== null && height !== void 0 ? height : 0) - sliderContainerHeight;
[this.canvas.nativeElement, this.block.nativeElement].forEach(element => {
this.renderer.setAttribute(element, 'width', width.toString());
this.renderer.setAttribute(element, 'height', adjustedHeight.toString());
});
}
initializeCanvasContexts() {
this.initializeCanvasDimensions();
this.ctx = this.canvas.nativeElement.getContext('2d', { willReadFrequently: true });
this.blockCtx = this.block.nativeElement.getContext('2d', { willReadFrequently: true });
if (!this.ctx || !this.blockCtx) {
throw new Error("Failed to initialize canvas contexts");
}
}
initializeCaptcha() {
this.resetCanvas();
this.initializeStyles();
this.initializeCanvasContexts();
this.renderPuzzle();
}
renderPuzzle() {
let img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = () => this.configurePuzzleImage(img);
img.onerror = () => this.retryImageLoad(img);
this.fetchImageSource(img);
this._sliderText = this.sliderConfig.loadingText;
this.cdr.detectChanges();
}
configurePuzzleImage(img) {
const { width, puzzleSize, puzzleRadius, instructionText } = this.sliderConfig;
let puzzleBlockWidth = puzzleSize + puzzleRadius * 2 + 3;
const { width: canvasWidth, height: canvasHeight } = this.canvas.nativeElement;
this.puzzleX = this.generateRandomNumber(puzzleBlockWidth + 10, canvasWidth - (puzzleBlockWidth + 10));
this.puzzleY = this.generateRandomNumber(10 + puzzleRadius * 2, canvasHeight - (puzzleBlockWidth + 10));
this.drawPuzzlePieceShape(this.ctx, 'fill');
this.drawPuzzlePieceShape(this.blockCtx, 'clip');
this.ctx.drawImage(img, 0, 0, width, canvasHeight);
this.blockCtx.drawImage(img, 0, 0, width, canvasHeight);
const yOffset = this.puzzleY - puzzleRadius * 2 - 1;
const imageData = this.blockCtx.getImageData(this.puzzleX - 3, yOffset, puzzleBlockWidth, puzzleBlockWidth);
this.renderer.setAttribute(this.block.nativeElement, 'width', puzzleBlockWidth.toString());
this.renderer.setAttribute(this.block.nativeElement, 'height', canvasHeight.toString());
this.blockCtx.putImageData(imageData, 0, yOffset + 1);
this._sliderText = instructionText;
this.cdr.detectChanges();
}
retryImageLoad(img) {
this.loadCount++;
if (this.loadCount <= this.sliderConfig.maxRetryAttempts) {
this.renderPuzzle();
}
else {
img.src = this.loadFallbackImage();
}
}
fetchImageSource(img) {
this.imageRetriever.getSliderImage().subscribe({
next: (image) => img.src = image,
error: (error) => this.onError.emit(error)
});
}
loadFallbackImage() {
return `assets/images/ngx-slider-recaptcha-${Math.floor(Math.random() * 4)}.jpg`;
}
drawPuzzlePieceShape(ctx, operation) {
const { puzzleSize: size, puzzleRadius: radius } = this.sliderConfig;
const { PI } = Math;
const { puzzleX, puzzleY } = this;
ctx.beginPath();
ctx.moveTo(puzzleX, puzzleY);
ctx.arc(puzzleX + size / 2, puzzleY - radius + 2, radius, 0.72 * PI, 2.26 * PI);
ctx.lineTo(puzzleX + size, puzzleY);
ctx.arc(puzzleX + size + radius - 2, puzzleY + size / 2, radius, 1.21 * PI, 2.78 * PI);
ctx.lineTo(puzzleX + size, puzzleY + size);
ctx.lineTo(puzzleX, puzzleY + size);
ctx.arc(puzzleX + radius - 2, puzzleY + size / 2, radius + 0.4, 2.76 * PI, 1.24 * PI, true);
ctx.lineTo(puzzleX, puzzleY);
ctx.lineWidth = 2;
ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
ctx.strokeStyle = 'rgba(255, 255, 255, 0.7)';
ctx.stroke();
ctx[operation]();
ctx.globalCompositeOperation = this.isUsingIE ? 'xor' : 'destination-over';
}
generateRandomNumber(start, end) {
return Math.round(Math.random() * (end - start) + start);
}
;
resetCanvas() {
var _a, _b;
const { width, height } = this.canvas.nativeElement;
(_a = this.ctx) === null || _a === void 0 ? void 0 : _a.clearRect(0, 0, width, height);
(_b = this.blockCtx) === null || _b === void 0 ? void 0 : _b.clearRect(0, 0, width, height);
}
extractEventCoordinates(event) {
if (event instanceof MouseEvent) {
return { x: event.clientX, y: event.clientY };
}
else {
return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
}
}
initializeDragStartCoordinates(event) {
const { x, y } = this.extractEventCoordinates(event);
this.dragStartX = x;
this.dragStartY = y;
}
initializeStyles() {
if (this.sliderConfig.allowResponsiveWidth) {
this._sliderConfig = Object.assign(Object.assign({}, this._sliderConfig), { width: this.captchaContainer.nativeElement.offsetWidth });
}
const { width, height, primaryColor, successColor, errorColor, textColor, sliderContainerBackgroundColor: containerBackgroundColor, sliderContainerBorderColor: containerBorderColor, borderRadius: commonBorderRadius, puzzleSize } = this.sliderConfig;
this.setStyle('--recaptcha-container-width', `${width}px`);
this.setStyle('--recaptcha-container-height', `${height}px`);
this.setStyle('--recaptcha-canvas-width', `${width}px`);
this.setStyle('--recaptcha-canvas-height', `${(height - (puzzleSize + this.SLIDER_CONTAINER_MARGIN))}px`);
this.setStyle('--recaptcha-primary-color', primaryColor);
this.setStyle('--recaptcha-error-color', errorColor);
this.setStyle('--recaptcha-success-color', successColor);
this.setStyle('--recaptcha-text-color', textColor);
this.setStyle('--recaptcha-container-background-color', containerBackgroundColor);
this.setStyle('--recaptcha-container-border-color', containerBorderColor);
this.setStyle('--recaptcha-common-border-radius', `${commonBorderRadius}px`);
this.setStyle('--recaptcha-slider-container-height', `${puzzleSize}px`);
this.setStyle('--recaptcha-slider-mask-primary-color', this.hexToRgba(primaryColor, 0.3));
this.setStyle('--recaptcha-slider-mask-success-color', this.hexToRgba(successColor, 0.3));
this.setStyle('--recaptcha-slider-mask-error-color', this.hexToRgba(errorColor, 0.3));
}
setStyle(property, value) {
document.documentElement.style.setProperty(property, value);
}
hexToRgba(hex, opacity) {
const sanitizedHex = hex === null || hex === void 0 ? void 0 : hex.replace(/^#/, '');
const [radius, g, b] = [0, 2, 4].map((start) => parseInt(sanitizedHex.slice(start, start + 2), 16));
return `rgba(${radius}, ${g}, ${b}, ${opacity})`;
}
}
NgxSliderRecaptchaComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgxSliderRecaptchaComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: NGX_SLIDER_RECAPTCHA_CONFIG_TOKEN }, { token: NGX_SLIDER_RECAPTCHA_VERIFICATION_SERVICE_TOKEN }, { token: NGX_SLIDER_RECAPTCHA_IMAGE_SERVICE_TOKEN }], target: i0.ɵɵFactoryTarget.Component });
NgxSliderRecaptchaComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: NgxSliderRecaptchaComponent, isStandalone: true, selector: "ngx-slider-recaptcha", inputs: { config: "config", disabled: "disabled", sliderContent: "sliderContent", successContent: "successContent", failContent: "failContent" }, outputs: { onVerified: "onVerified", onRefresh: "onRefresh", onError: "onError" }, host: { listeners: { "document:mousedown": "onDragStart($event)", "document:touchstart": "onDragStart($event)", "document:mousemove": "onDragMove($event)", "document:touchmove": "onDragMove($event)", "document:mouseup": "onDragEnd($event)", "document:touchend": "onDragEnd($event)" } }, viewQueries: [{ propertyName: "canvas", first: true, predicate: ["canvas"], descendants: true, static: true }, { propertyName: "block", first: true, predicate: ["block"], descendants: true, static: true }, { propertyName: "captchaContainer", first: true, predicate: ["captchaContainer"], descendants: true, static: true }, { propertyName: "slider", first: true, predicate: ["slider"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div #captchaContainer class=\"captcha-container\">\r\n <canvas #canvas class=\"canvas\"></canvas>\r\n <canvas #block class=\"block\" [style.left.px]=\"blockOffsetX\"></canvas>\r\n <div class=\"slider-container\" [class.active]=\"isSliderDragging\" [class.success]=\"verificationStatus === 'success'\"\r\n [class.fail]=\"verificationStatus === 'fail'\">\r\n <div class=\"slider-mask\" [style.width.px]=\"maskWidth\">\r\n <div #slider class=\"slider\" [style.left.px]=\"sliderOffsetX\">\r\n <ng-container *ngIf=\"verificationStatus === 'none'\">\r\n <ng-container *ngIf=\"sliderContent; else defaultTemplate\">\r\n <ng-container *ngIf=\"isTemplate(sliderContent); else sliderContentStringTemplate\">\r\n <ng-container *ngTemplateOutlet=\"sliderContent\"></ng-container>\r\n </ng-container>\r\n <ng-template #sliderContentStringTemplate>\r\n {{ sliderContent }}\r\n </ng-template>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"verificationStatus === 'success'\">\r\n <ng-container *ngIf=\"successContent; else defaultTemplate\">\r\n <ng-container *ngIf=\"isTemplate(successContent); else successContentStringTemplate\">\r\n <ng-container *ngTemplateOutlet=\"successContent\"></ng-container>\r\n </ng-container>\r\n <ng-template #successContentStringTemplate>\r\n {{ successContent }}\r\n </ng-template>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"verificationStatus === 'fail'\">\r\n <ng-container *ngIf=\"failContent; else defaultTemplate\">\r\n <ng-container *ngIf=\"isTemplate(failContent); else failContentStringTemplate\">\r\n <ng-container *ngTemplateOutlet=\"failContent\"></ng-container>\r\n </ng-container>\r\n <ng-template #failContentStringTemplate>\r\n {{ sliderContent }}\r\n </ng-template>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-template #defaultTemplate>\r\n <span class=\"slider-icon\"></span>\r\n </ng-template>\r\n </div>\r\n </div>\r\n <span class=\"slider-text\" *ngIf=\"!isVerifying\">{{ sliderText }}</span>\r\n </div>\r\n <i *ngIf=\"sliderConfig.allowRefresh\" class=\"refresh-icon\" (click)=\"refresh()\"></i>\r\n <div class=\"disable-wrapper\" *ngIf=\"isDisabled || isVerifying\"></div>\r\n</div>", styles: ["@charset \"UTF-8\";.captcha-container{display:flex;flex-direction:column;position:relative}.canvas{width:var(--recaptcha-canvas-width);height:var(--recaptcha-canvas-height);border:1px solid #ccc;border-radius:3px}.block{position:absolute;left:0;top:0}.slider-container{position:relative;display:flex;justify-content:center;align-items:center;margin-top:5px;height:var(--recaptcha-slider-container-height);width:var(--recaptcha-canvas-width);border:1px solid var(--recaptcha-container-border-color);background:var(--recaptcha-container-background-color);border-radius:var(--recaptcha-common-border-radius);box-shadow:inset 0 0 5px #00000026}.slider-container .slider-text{position:relative;color:var(--recaptcha-text-color);white-space:nowrap;text-overflow:ellipsis;overflow:hidden;padding-left:calc(var(--recaptcha-slider-container-height) + 10px);padding-right:10px}.slider-container .slider-mask{position:absolute;left:0;top:0;height:var(--recaptcha-slider-container-height);width:var(--recaptcha-slider-container-height);border:1px solid transparent;border-right:0;transform:translate(-1px,-1px);border-radius:calc(var(--recaptcha-common-border-radius) - 1px)}.slider-container .slider-icon:before{content:\"\\2794\"}.slider-container.active .slider-text,.slider-container.success .slider-text,.slider-container.fail .slider-text{display:none}.slider{position:absolute;top:0;left:0;width:var(--recaptcha-slider-container-height);height:var(--recaptcha-slider-container-height);max-width:var(--recaptcha-slider-container-height);max-height:var(--recaptcha-slider-container-height);background:#fff;box-shadow:0 0 3px #0000004d;cursor:pointer;border-radius:calc(var(--recaptcha-common-border-radius) - 1px);display:flex;align-items:center;justify-content:center;border:1px solid #fff;transform:translateY(-1px)}.slider:hover{background:var(--recaptcha-primary-color);color:#fff;border:1px solid var(--recaptcha-primary-color)}.slider:hover .slider-icon{background-position:0 -13px;color:#fff}.active .slider{top:-1px;border:1px solid var(--recaptcha-primary-color);background-color:var(--recaptcha-primary-color);color:#fff;transform:translateY(0)}.active .slider-mask{border-color:var(--recaptcha-primary-color);background:var(--recaptcha-slider-mask-primary-color)}.success .slider{top:-1px;border:1px solid var(--recaptcha-success-color);background-color:var(--recaptcha-success-color);color:#fff;transform:translateY(0)}.success .slider-mask{border-color:var(--recaptcha-success-color);background-color:#d2f4ef}.success .slider-icon:before{content:\"\\2713\"}.fail .slider{top:-1px;border:1px solid var(--recaptcha-error-color);background-color:var(--recaptcha-error-color);color:#fff;transform:translateY(0)}.fail .slider-mask{border-color:var(--recaptcha-error-color);background-color:var(--recaptcha-slider-mask-error-color)}.fail .slider-icon:before{content:\"\\2715\"}.refresh-icon{position:absolute;right:6px;top:6px;cursor:pointer;color:#ffffff4d;font-size:1rem;z-index:5;transition:color .3s linear}.refresh-icon:before{content:\"\\27f3\"}.refresh-icon:hover{color:#fff}.disable-wrapper{position:absolute;cursor:not-allowed;z-index:9999;width:var(--recaptcha-container-width);height:var(--recaptcha-container-height);background-color:#e1e1e14d}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgxSliderRecaptchaComponent, decorators: [{
type: Component,
args: [{ standalone: true, selector: 'ngx-slider-recaptcha', imports: [CommonModule], template: "<div #captchaContainer class=\"captcha-container\">\r\n <canvas #canvas class=\"canvas\"></canvas>\r\n <canvas #block class=\"block\" [style.left.px]=\"blockOffsetX\"></canvas>\r\n <div class=\"slider-container\" [class.active]=\"isSliderDragging\" [class.success]=\"verificationStatus === 'success'\"\r\n [class.fail]=\"verificationStatus === 'fail'\">\r\n <div class=\"slider-mask\" [style.width.px]=\"maskWidth\">\r\n <div #slider class=\"slider\" [style.left.px]=\"sliderOffsetX\">\r\n <ng-container *ngIf=\"verificationStatus === 'none'\">\r\n <ng-container *ngIf=\"sliderContent; else defaultTemplate\">\r\n <ng-container *ngIf=\"isTemplate(sliderContent); else sliderContentStringTemplate\">\r\n <ng-container *ngTemplateOutlet=\"sliderContent\"></ng-container>\r\n </ng-container>\r\n <ng-template #sliderContentStringTemplate>\r\n {{ sliderContent }}\r\n </ng-template>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"verificationStatus === 'success'\">\r\n <ng-container *ngIf=\"successContent; else defaultTemplate\">\r\n <ng-container *ngIf=\"isTemplate(successContent); else successContentStringTemplate\">\r\n <ng-container *ngTemplateOutlet=\"successContent\"></ng-container>\r\n </ng-container>\r\n <ng-template #successContentStringTemplate>\r\n {{ successContent }}\r\n </ng-template>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"verificationStatus === 'fail'\">\r\n <ng-container *ngIf=\"failContent; else defaultTemplate\">\r\n <ng-container *ngIf=\"isTemplate(failContent); else failContentStringTemplate\">\r\n <ng-container *ngTemplateOutlet=\"failContent\"></ng-container>\r\n </ng-container>\r\n <ng-template #failContentStringTemplate>\r\n {{ sliderContent }}\r\n </ng-template>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-template #defaultTemplate>\r\n <span class=\"slider-icon\"></span>\r\n </ng-template>\r\n </div>\r\n </div>\r\n <span class=\"slider-text\" *ngIf=\"!isVerifying\">{{ sliderText }}</span>\r\n </div>\r\n <i *ngIf=\"sliderConfig.allowRefresh\" class=\"refresh-icon\" (click)=\"refresh()\"></i>\r\n <div class=\"disable-wrapper\" *ngIf=\"isDisabled || isVerifying\"></div>\r\n</div>", styles: ["@charset \"UTF-8\";.captcha-container{display:flex;flex-direction:column;position:relative}.canvas{width:var(--recaptcha-canvas-width);height:var(--recaptcha-canvas-height);border:1px solid #ccc;border-radius:3px}.block{position:absolute;left:0;top:0}.slider-container{position:relative;display:flex;justify-content:center;align-items:center;margin-top:5px;height:var(--recaptcha-slider-container-height);width:var(--recaptcha-canvas-width);border:1px solid var(--recaptcha-container-border-color);background:var(--recaptcha-container-background-color);border-radius:var(--recaptcha-common-border-radius);box-shadow:inset 0 0 5px #00000026}.slider-container .slider-text{position:relative;color:var(--recaptcha-text-color);white-space:nowrap;text-overflow:ellipsis;overflow:hidden;padding-left:calc(var(--recaptcha-slider-container-height) + 10px);padding-right:10px}.slider-container .slider-mask{position:absolute;left:0;top:0;height:var(--recaptcha-slider-container-height);width:var(--recaptcha-slider-container-height);border:1px solid transparent;border-right:0;transform:translate(-1px,-1px);border-radius:calc(var(--recaptcha-common-border-radius) - 1px)}.slider-container .slider-icon:before{content:\"\\2794\"}.slider-container.active .slider-text,.slider-container.success .slider-text,.slider-container.fail .slider-text{display:none}.slider{position:absolute;top:0;left:0;width:var(--recaptcha-slider-container-height);height:var(--recaptcha-slider-container-height);max-width:var(--recaptcha-slider-container-height);max-height:var(--recaptcha-slider-container-height);background:#fff;box-shadow:0 0 3px #0000004d;cursor:pointer;border-radius:calc(var(--recaptcha-common-border-radius) - 1px);display:flex;align-items:center;justify-content:center;border:1px solid #fff;transform:translateY(-1px)}.slider:hover{background:var(--recaptcha-primary-color);color:#fff;border:1px solid var(--recaptcha-primary-color)}.slider:hover .slider-icon{background-position:0 -13px;color:#fff}.active .slider{top:-1px;border:1px solid var(--recaptcha-primary-color);background-color:var(--recaptcha-primary-color);color:#fff;transform:translateY(0)}.active .slider-mask{border-color:var(--recaptcha-primary-color);background:var(--recaptcha-slider-mask-primary-color)}.success .slider{top:-1px;border:1px solid var(--recaptcha-success-color);background-color:var(--recaptcha-success-color);color:#fff;transform:translateY(0)}.success .slider-mask{border-color:var(--recaptcha-success-color);background-color:#d2f4ef}.success .slider-icon:before{content:\"\\2713\"}.fail .slider{top:-1px;border:1px solid var(--recaptcha-error-color);background-color:var(--recaptcha-error-color);color:#fff;transform:translateY(0)}.fail .slider-mask{border-color:var(--recaptcha-error-color);background-color:var(--recaptcha-slider-mask-error-color)}.fail .slider-icon:before{content:\"\\2715\"}.refresh-icon{position:absolute;right:6px;top:6px;cursor:pointer;color:#ffffff4d;font-size:1rem;z-index:5;transition:color .3s linear}.refresh-icon:before{content:\"\\27f3\"}.refresh-icon:hover{color:#fff}.disable-wrapper{position:absolute;cursor:not-allowed;z-index:9999;width:var(--recaptcha-container-width);height:var(--recaptcha-container-height);background-color:#e1e1e14d}\n"] }]
}], ctorParameters: function () {
return [{ type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
type: Inject,
args: [NGX_SLIDER_RECAPTCHA_CONFIG_TOKEN]
}] }, { type: undefined, decorators: [{
type: Inject,
args: [NGX_SLIDER_RECAPTCHA_VERIFICATION_SERVICE_TOKEN]
}] }, { type: undefined, decorators: [{
type: Inject,
args: [NGX_SLIDER_RECAPTCHA_IMAGE_SERVICE_TOKEN]
}] }];
}, propDecorators: { canvas: [{
type: ViewChild,
args: ['canvas', { static: true }]
}], block: [{
type: ViewChild,
args: ['block', { static: true }]
}], captchaContainer: [{
type: ViewChild,
args: ['captchaContainer', { static: true }]
}], slider: [{
type: ViewChild,
args: ['slider', { static: true }]
}], config: [{
type: Input
}], disabled: [{
type: Input
}], sliderContent: [{
type: Input
}], successContent: [{
type: Input
}], failContent: [{
type: Input
}], onVerified: [{
type: Output
}], onRefresh: [{
type: Output
}], onError: [{
type: Output
}], onDragStart: [{
type: HostListener,
args: ['document:mousedown', ['$event']]
}, {
type: HostListener,
args: ['document:touchstart', ['$event']]
}], onDragMove: [{
type: HostListener,
args: ['document:mousemove', ['$event']]
}, {
type: HostListener,
args: ['document:touchmove', ['$event']]
}], onDragEnd: [{
type: HostListener,
args: ['document:mouseup', ['$event']]
}, {
type: HostListener,
args: ['document:touchend', ['$event']]
}] } });
class NgxSliderRecaptchaModule {
static forRoot(options = {}) {
const { sliderConfig = DEFAULT_SLIDER_RECAPTCHA_CONFIG, verificationService = DefaultNgxSliderRecaptchaVerificationService, imageRetrievalService = DefaultNgxSliderRecaptchaImageService } = options;
return {
ngModule: NgxSliderRecaptchaModule,
providers: [
{
provide: NGX_SLIDER_RECAPTCHA_CONFIG_TOKEN,
useValue: sliderConfig
},
{
provide: NGX_SLIDER_RECAPTCHA_VERIFICATION_SERVICE_TOKEN,
useClass: verificationService
},
{
provide: NGX_SLIDER_RECAPTCHA_IMAGE_SERVICE_TOKEN,
useClass: imageRetrievalService
}
]
};
}
}
NgxSliderRecaptchaModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgxSliderRecaptchaModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
NgxSliderRecaptchaModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: NgxSliderRecaptchaModule, imports: [CommonModule,
NgxSliderRecaptchaComponent], exports: [NgxSliderRecaptchaComponent] });
NgxSliderRecaptchaModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgxSliderRecaptchaModule, providers: [
{
provide: NGX_SLIDER_RECAPTCHA_CONFIG_TOKEN,
useValue: DEFAULT_SLIDER_RECAPTCHA_CONFIG
},
{
provide: NGX_SLIDER_RECAPTCHA_VERIFICATION_SERVICE_TOKEN,
useClass: DefaultNgxSliderRecaptchaVerificationService
},
{
provide: NGX_SLIDER_RECAPTCHA_IMAGE_SERVICE_TOKEN,
useClass: DefaultNgxSliderRecaptchaImageService
}
], imports: [CommonModule,
NgxSliderRecaptchaComponent] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgxSliderRecaptchaModule, decorators: [{
type: NgModule,
args: [{
imports: [
CommonModule,
NgxSliderRecaptchaComponent
],
exports: [
NgxSliderRecaptchaComponent
],
providers: [
{
provide: NGX_SLIDER_RECAPTCHA_CONFIG_TOKEN,
useValue: DEFAULT_SLIDER_RECAPTCHA_CONFIG
},
{
provide: NGX_SLIDER_RECAPTCHA_VERIFICATION_SERVICE_TOKEN,
useClass: DefaultNgxSliderRecaptchaVerificationService
},
{
provide: NGX_SLIDER_RECAPTCHA_IMAGE_SERVICE_TOKEN,
useClass: DefaultNgxSliderRecaptchaImageService
}
]
}]
}] });
/*
* Public API Surface of ngx-slider-recaptcha
*/
/**
* Generated bundle index. Do not edit.
*/
export { DEFAULT_SLIDER_RECAPTCHA_CONFIG, DefaultNgxSliderRecaptchaImageService, DefaultNgxSliderRecaptchaVerificationService, NGX_SLIDER_RECAPTCHA_CONFIG_TOKEN, NGX_SLIDER_RECAPTCHA_IMAGE_SERVICE_TOKEN, NGX_SLIDER_RECAPTCHA_VERIFICATION_SERVICE_TOKEN, NgxSliderRecaptchaComponent, NgxSliderRecaptchaModule };
//# sourceMappingURL=ngx-slider-recaptcha.mjs.map