UNPKG

primeng

Version:

PrimeNG is a premium UI library for Angular featuring a rich set of 90+ components, a theme designer, various theme alternatives such as Material, Bootstrap, Tailwind, premium templates and professional support. In addition, it integrates with PrimeBlock,

253 lines (249 loc) 9.69 kB
import { DOCUMENT, isPlatformBrowser } from '@angular/common'; import * as i0 from '@angular/core'; import { forwardRef, input, booleanAttribute, output, inject, PLATFORM_ID, ElementRef, effect, Directive, NgModule } from '@angular/core'; import { NG_VALIDATORS } from '@angular/forms'; import { isAndroid, getBrowser } from '@primeuix/utils'; const KEYFILTER_VALIDATOR = { provide: NG_VALIDATORS, useExisting: forwardRef(() => KeyFilter), multi: true }; const DEFAULT_MASKS = { pint: /^[\d]*$/, int: /^[-]?[\d]*$/, pnum: /^[\d\.]*$/, money: /^[\d\.\s,]*$/, num: /^[-]?[\d\.]*$/, hex: /^[0-9a-f]*$/i, email: /^[a-z0-9_\.\-@]*$/i, alpha: /^[a-z_]*$/i, alphanum: /^[a-z0-9_]*$/i }; const KEYS = { TAB: 9, RETURN: 13, ESC: 27, BACKSPACE: 8, DELETE: 46 }; const SAFARI_KEYS = { 63234: 37, // left 63235: 39, // right 63232: 38, // up 63233: 40, // down 63276: 33, // page up 63277: 34, // page down 63272: 46, // delete 63273: 36, // home 63275: 35 // end }; /** * KeyFilter Directive is a built-in feature of InputText to restrict user input based on a regular expression. * @group Components */ class KeyFilter { /** * When enabled, instead of blocking keys, input is validated internally to test against the regular expression. * @group Props */ pValidateOnly = input(false, { ...(ngDevMode ? { debugName: "pValidateOnly" } : /* istanbul ignore next */ {}), transform: booleanAttribute }); /** * Sets the pattern for key filtering. * @group Props */ pattern = input(undefined, { ...(ngDevMode ? { debugName: "pattern" } : /* istanbul ignore next */ {}), alias: 'pKeyFilter' }); /** * Emits a value whenever the ngModel of the component changes. * @param {(string | number)} modelValue - Custom model change event. * @group Emits */ ngModelChange = output(); regex = /./; isAndroid; lastValue; document = inject(DOCUMENT); platformId = inject(PLATFORM_ID); el = inject(ElementRef); constructor() { if (isPlatformBrowser(this.platformId)) { this.isAndroid = isAndroid(); } else { this.isAndroid = false; } effect(() => { const _pattern = this.pattern(); if (_pattern instanceof RegExp) { this.regex = _pattern; } else if (_pattern && _pattern in DEFAULT_MASKS) { this.regex = DEFAULT_MASKS[_pattern]; } else { this.regex = /./; } }); } isNavKeyPress(e) { let k = e.keyCode; k = getBrowser().safari ? SAFARI_KEYS[k] || k : k; return (k >= 33 && k <= 40) || k == KEYS.RETURN || k == KEYS.TAB || k == KEYS.ESC; } isSpecialKey(e) { let k = e.keyCode || e.charCode; return k == 9 || k == 13 || k == 27 || k == 16 || k == 17 || (k >= 18 && k <= 20) || (getBrowser().opera && !e.shiftKey && (k == 8 || (k >= 33 && k <= 35) || (k >= 36 && k <= 39) || (k >= 44 && k <= 45))); } getKey(e) { let k = e.keyCode || e.charCode; return getBrowser().safari ? SAFARI_KEYS[k] || k : k; } getCharCode(e) { return e.charCode || e.keyCode || e.which; } findDelta(value, prevValue) { let delta = ''; for (let i = 0; i < value.length; i++) { let str = value.substr(0, i) + value.substr(i + value.length - prevValue.length); if (str === prevValue) delta = value.substr(i, value.length - prevValue.length); } return delta; } isValidChar(c) { return this.regex.test(c); } isValidString(str) { for (let i = 0; i < str.length; i++) { if (!this.isValidChar(str.substr(i, 1))) { return false; } } return true; } onInput(e) { if (this.isAndroid && !this.pValidateOnly()) { let val = this.el.nativeElement.value; let lastVal = this.lastValue || ''; let inserted = this.findDelta(val, lastVal); let removed = this.findDelta(lastVal, val); let pasted = inserted.length > 1 || (!inserted && !removed); if (pasted) { if (!this.isValidString(val)) { this.el.nativeElement.value = lastVal; this.ngModelChange.emit(lastVal); } } else if (!removed) { if (!this.isValidChar(inserted)) { this.el.nativeElement.value = lastVal; this.ngModelChange.emit(lastVal); } } val = this.el.nativeElement.value; if (this.isValidString(val)) { this.lastValue = val; } } } onKeyPress(e) { if (this.isAndroid || this.pValidateOnly()) { return; } let browser = getBrowser(); let k = this.getKey(e); if (browser.mozilla && (e.ctrlKey || e.altKey)) { return; } else if (k == 17 || k == 18) { return; } // Enter key if (k == 13) { return; } let c = this.getCharCode(e); let cc = String.fromCharCode(c); let ok = true; if (!browser.mozilla && (this.isSpecialKey(e) || !cc)) { return; } let existingValue = this.el.nativeElement.value || ''; let combinedValue = existingValue + cc; ok = this.regex.test(combinedValue); if (!ok) { e.preventDefault(); } } onPaste(e) { let clipboardData = e.clipboardData; // Fallback for older browsers if (!clipboardData && this.document.defaultView) { const windowClipboard = this.document.defaultView.clipboardData; if (windowClipboard) { clipboardData = { getData: (_format) => windowClipboard.getData('text') }; } } if (clipboardData) { let pattern = /\{[0-9]+\}/; const pastedText = clipboardData.getData('text'); if (pattern.test(this.regex.toString())) { if (!this.regex.test(pastedText)) { e.preventDefault(); return; } } else { for (let char of pastedText.toString()) { if (!this.regex.test(char)) { e.preventDefault(); return; } } } } } validate(_c) { if (this.pValidateOnly()) { let value = this.el.nativeElement.value; if (value && !this.regex.test(value)) { return { validatePattern: false }; } } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: KeyFilter, deps: [], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.6", type: KeyFilter, isStandalone: true, selector: "[pKeyFilter]", inputs: { pValidateOnly: { classPropertyName: "pValidateOnly", publicName: "pValidateOnly", isSignal: true, isRequired: false, transformFunction: null }, pattern: { classPropertyName: "pattern", publicName: "pKeyFilter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { ngModelChange: "ngModelChange" }, host: { listeners: { "input": "onInput($event)", "keypress": "onKeyPress($event)", "paste": "onPaste($event)" } }, providers: [KEYFILTER_VALIDATOR], ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: KeyFilter, decorators: [{ type: Directive, args: [{ selector: '[pKeyFilter]', standalone: true, providers: [KEYFILTER_VALIDATOR], host: { '(input)': 'onInput($event)', '(keypress)': 'onKeyPress($event)', '(paste)': 'onPaste($event)' } }] }], ctorParameters: () => [], propDecorators: { pValidateOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "pValidateOnly", required: false }] }], pattern: [{ type: i0.Input, args: [{ isSignal: true, alias: "pKeyFilter", required: false }] }], ngModelChange: [{ type: i0.Output, args: ["ngModelChange"] }] } }); class KeyFilterModule { static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: KeyFilterModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "22.0.6", ngImport: i0, type: KeyFilterModule, imports: [KeyFilter], exports: [KeyFilter] }); static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: KeyFilterModule }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: KeyFilterModule, decorators: [{ type: NgModule, args: [{ imports: [KeyFilter], exports: [KeyFilter] }] }] }); /** * Generated bundle index. Do not edit. */ export { KEYFILTER_VALIDATOR, KeyFilter, KeyFilterModule }; //# sourceMappingURL=primeng-keyfilter.mjs.map