mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-19 17:14:57 +00:00
228 lines
7.3 KiB
TypeScript
228 lines
7.3 KiB
TypeScript
/*!
|
|
* @license
|
|
* Copyright 2016 Alfresco Software, Ltd.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/* tslint:disable:component-selector */
|
|
|
|
import {
|
|
Directive,
|
|
ElementRef,
|
|
forwardRef,
|
|
HostListener,
|
|
Input,
|
|
OnChanges,
|
|
Renderer,
|
|
SimpleChanges
|
|
} from '@angular/core';
|
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
|
|
export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {
|
|
provide: NG_VALUE_ACCESSOR,
|
|
useExisting: forwardRef(() => InputMaskDirective),
|
|
multi: true
|
|
};
|
|
|
|
@Directive({
|
|
selector: '[textMask]',
|
|
providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR]
|
|
})
|
|
export class InputMaskDirective implements OnChanges, ControlValueAccessor {
|
|
|
|
@Input('textMask') inputMask: {
|
|
mask: '',
|
|
isReversed: false
|
|
};
|
|
|
|
private translationMask = {
|
|
'0': { pattern: /\d/ },
|
|
'9': { pattern: /\d/, optional: true },
|
|
'#': { pattern: /\d/, recursive: true },
|
|
'A': { pattern: /[a-zA-Z0-9]/ },
|
|
'S': { pattern: /[a-zA-Z]/ }
|
|
};
|
|
|
|
private byPassKeys = [9, 16, 17, 18, 36, 37, 38, 39, 40, 91];
|
|
private value;
|
|
private invalidCharacters = [];
|
|
|
|
constructor(private el: ElementRef, private render: Renderer) {
|
|
}
|
|
|
|
_onChange = (_: any) => {
|
|
}
|
|
|
|
_onTouched = () => {
|
|
}
|
|
|
|
@HostListener('input', ['$event'])
|
|
@HostListener('keyup', ['$event']) onTextInput(event: KeyboardEvent) {
|
|
if (this.inputMask && this.inputMask.mask) {
|
|
this.maskValue(this.el.nativeElement.value, this.el.nativeElement.selectionStart,
|
|
this.inputMask.mask, this.inputMask.isReversed, event.keyCode);
|
|
} else {
|
|
this._onChange(this.el.nativeElement.value);
|
|
}
|
|
}
|
|
|
|
ngOnChanges(changes: SimpleChanges) {
|
|
if (changes['inputMask'] && changes['inputMask'].currentValue['mask']) {
|
|
this.inputMask = changes['inputMask'].currentValue;
|
|
}
|
|
}
|
|
|
|
writeValue(value: any) {
|
|
this.el.nativeElement.value = value;
|
|
}
|
|
|
|
registerOnChange(fn: any) {
|
|
this._onChange = fn;
|
|
}
|
|
|
|
registerOnTouched(fn: () => any): void {
|
|
this._onTouched = fn;
|
|
}
|
|
|
|
private maskValue(actualValue, startCaret, maskToApply, isMaskReversed, keyCode) {
|
|
if (this.byPassKeys.indexOf(keyCode) === -1) {
|
|
let value = this.getMasked(false, actualValue, maskToApply, isMaskReversed);
|
|
let calculatedCaret = this.calculateCaretPosition(startCaret, actualValue, keyCode);
|
|
this.render.setElementAttribute(this.el.nativeElement, 'value', value);
|
|
this.el.nativeElement.value = value;
|
|
this.setValue(value);
|
|
this._onChange(value);
|
|
this.setCaretPosition(calculatedCaret);
|
|
}
|
|
}
|
|
|
|
private setCaretPosition(caretPosition) {
|
|
this.el.nativeElement.moveStart = caretPosition;
|
|
this.el.nativeElement.moveEnd = caretPosition;
|
|
}
|
|
|
|
calculateCaretPosition(caretPosition, newValue, keyCode) {
|
|
let newValueLength = newValue.length;
|
|
let oldValue = this.getValue() || '';
|
|
let oldValueLength = oldValue.length;
|
|
|
|
if (keyCode === 8 && oldValue !== newValue) {
|
|
caretPosition = caretPosition - (newValue.slice(0, caretPosition).length - oldValue.slice(0, caretPosition).length);
|
|
} else if (oldValue !== newValue) {
|
|
if (caretPosition >= oldValueLength) {
|
|
caretPosition = newValueLength;
|
|
} else {
|
|
caretPosition = caretPosition + (newValue.slice(0, caretPosition).length - oldValue.slice(0, caretPosition).length);
|
|
}
|
|
}
|
|
return caretPosition;
|
|
}
|
|
|
|
getMasked(skipMaskChars, val, mask, isReversed = false) {
|
|
let buf = [],
|
|
value = val,
|
|
maskIndex = 0,
|
|
maskLen = mask.length,
|
|
valueIndex = 0,
|
|
valueLength = value.length,
|
|
offset = 1,
|
|
addMethod = 'push',
|
|
resetPos = -1,
|
|
lastMaskChar,
|
|
lastUntranslatedMaskChar,
|
|
check;
|
|
|
|
if (isReversed) {
|
|
addMethod = 'unshift';
|
|
offset = -1;
|
|
lastMaskChar = 0;
|
|
maskIndex = maskLen - 1;
|
|
valueIndex = valueLength - 1;
|
|
} else {
|
|
lastMaskChar = maskLen - 1;
|
|
}
|
|
check = this.isToCheck(isReversed, maskIndex, maskLen, valueIndex, valueLength);
|
|
while (check) {
|
|
let maskDigit = mask.charAt(maskIndex),
|
|
valDigit = value.charAt(valueIndex),
|
|
translation = this.translationMask[maskDigit];
|
|
|
|
if (translation) {
|
|
if (valDigit.match(translation.pattern)) {
|
|
buf[addMethod](valDigit);
|
|
if (translation.recursive) {
|
|
if (resetPos === -1) {
|
|
resetPos = maskIndex;
|
|
} else if (maskIndex === lastMaskChar) {
|
|
maskIndex = resetPos - offset;
|
|
}
|
|
if (lastMaskChar === resetPos) {
|
|
maskIndex -= offset;
|
|
}
|
|
}
|
|
maskIndex += offset;
|
|
} else if (valDigit === lastUntranslatedMaskChar) {
|
|
lastUntranslatedMaskChar = undefined;
|
|
} else if (translation.optional) {
|
|
maskIndex += offset;
|
|
valueIndex -= offset;
|
|
} else {
|
|
this.invalidCharacters.push({
|
|
index: valueIndex,
|
|
digit: valDigit,
|
|
translated: translation.pattern
|
|
});
|
|
}
|
|
valueIndex += offset;
|
|
} else {
|
|
if (!skipMaskChars) {
|
|
buf[addMethod](maskDigit);
|
|
}
|
|
if (valDigit === maskDigit) {
|
|
valueIndex += offset;
|
|
} else {
|
|
lastUntranslatedMaskChar = maskDigit;
|
|
}
|
|
maskIndex += offset;
|
|
}
|
|
check = this.isToCheck(isReversed, maskIndex, maskLen, valueIndex, valueLength);
|
|
}
|
|
|
|
let lastMaskCharDigit = mask.charAt(lastMaskChar);
|
|
if (maskLen === valueLength + 1 && !this.translationMask[lastMaskCharDigit]) {
|
|
buf.push(lastMaskCharDigit);
|
|
}
|
|
|
|
return buf.join('');
|
|
}
|
|
|
|
private isToCheck(isReversed, maskIndex, maskLen, valueIndex, valueLength) {
|
|
let check = false;
|
|
if (isReversed) {
|
|
check = (maskIndex > -1) && (valueIndex > -1);
|
|
} else {
|
|
check = (maskIndex < maskLen) && (valueIndex < valueLength);
|
|
}
|
|
return check;
|
|
}
|
|
|
|
private setValue(value) {
|
|
this.value = value;
|
|
}
|
|
|
|
private getValue() {
|
|
return this.value;
|
|
}
|
|
}
|