--- /dev/null
+import {AbstractControl, ValidationErrors} from '@angular/forms';\r
+\r
+export function inRangeValidator(in_range: number[]): ValidationErrors|null {\r
+ return (control: AbstractControl): ValidationErrors => {\r
+ const value = parseFloat(control.value);\r
+ if (isNaN(value) || value > in_range[1] || value < in_range[0]) {\r
+ control.setErrors({\r
+ in_range: true\r
+ });\r
+ return {\r
+ in_range: true\r
+ }\r
+ } else {\r
+ return null;\r
+ }\r
+ }\r
+}\r
+\r
+export function greaterOrEqualValidator(max: string): ValidationErrors|null {\r
+ return (control: AbstractControl): ValidationErrors => {\r
+ const value = parseFloat(control.value);\r
+ const maxValue: any = parseFloat(max);\r
+ if (!isNaN(maxValue) && (isNaN(value) || value < maxValue)) {\r
+ control.setErrors({\r
+ greater_or_equal: true\r
+ });\r
+ return {\r
+ greater_or_equal: true\r
+ }\r
+ } else {\r
+ return null;\r
+ }\r
+ }\r
+}\r
+\r
+export function lessOrEqualValidator(min: string): ValidationErrors|null {\r
+ return (control: AbstractControl): ValidationErrors => {\r
+ const value = parseFloat(control.value);\r
+ const minValue: any = parseFloat(min);\r
+ if (!isNaN(minValue) && (isNaN(value) || value > minValue)) {\r
+ control.setErrors({\r
+ less_or_equal: true\r
+ });\r
+ return {\r
+ less_or_equal: true\r
+ }\r
+ } else {\r
+ return null;\r
+ }\r
+ }\r
+}\r
+\r
+export function greaterThanValidator(max: string): ValidationErrors|null {\r
+ return (control: AbstractControl): ValidationErrors => {\r
+ const value = parseFloat(control.value);\r
+ const maxValue: any = parseFloat(max);\r
+ if (!isNaN(maxValue) && (isNaN(value) || value <= maxValue)) {\r
+ control.setErrors({\r
+ greater_than: true\r
+ });\r
+ return {\r
+ greater_than: true\r
+ }\r
+ } else {\r
+ return null;\r
+ }\r
+ }\r
+}\r
+\r
+export function lessThanValidator(min: string): ValidationErrors|null {\r
+ return (control: AbstractControl): ValidationErrors => {\r
+ const value = parseFloat(control.value);\r
+ const minValue: any = parseFloat(min);\r
+ if (!isNaN(minValue) && (isNaN(value) || value >= minValue)) {\r
+ control.setErrors({\r
+ less_than: true\r
+ });\r
+ return {\r
+ less_than: true\r
+ }\r
+ } else {\r
+ return null;\r
+ }\r
+ }\r
+}\r
+\r
+export function equalValidator(value: any): ValidationErrors|null {\r
+ return (control: AbstractControl): ValidationErrors => {\r
+ if (control.value != value) {\r
+ control.setErrors({\r
+ equal: true\r
+ });\r
+ return {\r
+ equal: true\r
+ }\r
+ } else {\r
+ return null;\r
+ }\r
+ }\r
+}\r
+\r
+export function lengthValidator(length: number): ValidationErrors|null {\r
+ return (control: AbstractControl): ValidationErrors => {\r
+ if (control.value && control.value.length !== length) {\r
+ control.setErrors({\r
+ length: true\r
+ });\r
+ return {\r
+ length: true\r
+ }\r
+ } else {\r
+ return null;\r
+ }\r
+ }\r
+}\r
+\r
+export function floatValidator(): ValidationErrors|null {\r
+ return (control: AbstractControl): ValidationErrors => {\r
+ let floatPattern = /^(-?\d+)(\.\d+)?$/;\r
+ if (control.value && !floatPattern.test(control.value)) {\r
+ control.setErrors({\r
+ float: true\r
+ });\r
+ return {\r
+ float: true\r
+ }\r
+ } else {\r
+ return null;\r
+ }\r
+ }\r
+}\r
+\r
+export function integerValidator(): ValidationErrors|null {\r
+ return (control: AbstractControl): ValidationErrors => {\r
+ let integerPattern = /^-?\d+$/;\r
+ if (control.value && !integerPattern.test(control.value)) {\r
+ control.setErrors({\r
+ integer: true\r
+ });\r
+ return {\r
+ integer: true\r
+ }\r
+ } else {\r
+ return null;\r
+ }\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+import {\r
+ Component, Input, forwardRef, SimpleChanges, ViewChild, OnChanges, Output, EventEmitter,\r
+ ElementRef\r
+} from '@angular/core';\r
+import {TranslateService} from '@ngx-translate/core';\r
+import {\r
+ ControlValueAccessor, NG_VALUE_ACCESSOR, NG_VALIDATORS, Validator,\r
+ AbstractControl, ValidationErrors\r
+} from '@angular/forms';\r
+import {\r
+ inRangeValidator, greaterOrEqualValidator, lessOrEqualValidator,\r
+ greaterThanValidator, lessThanValidator, equalValidator, lengthValidator, floatValidator, integerValidator\r
+} from './validators';\r
+import {isNullOrUndefined} from "util";\r
+\r
+const noop = () => {\r
+};\r
+\r
+export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {\r
+ provide: NG_VALUE_ACCESSOR,\r
+ useExisting: forwardRef(() => WfmTextInputComponent),\r
+ multi: true\r
+};\r
+\r
+export const CUSTOM_INPUT_VALIDATOR: any = {\r
+ provide: NG_VALIDATORS,\r
+ useExisting: forwardRef(() => WfmTextInputComponent),\r
+ multi: true\r
+};\r
+\r
+@Component({\r
+ selector: 'wfm-text-input',\r
+ template: `\r
+ <input type="text"\r
+ [disabled]="disabled" \r
+ [class]="inputClass"\r
+ [placeholder]="placeholder"\r
+ [required]="required"\r
+ [maxlength]="maxlength"\r
+ [minlength]="minlength"\r
+ [pattern]="pattern"\r
+ (focus)="onFocus()"\r
+ (blur)="onBlur()"\r
+ [(ngModel)]="value"\r
+ [ngModelOptions]="{standalone: true}"\r
+ #wfInput="ngModel"\r
+ />\r
+\r
+ <small [hidden]="!wfInput.valid || !hintLabel || !isHintLabelShow" class="hint-label">{{hintLabel}}</small>\r
+ <small [hidden]="!wfInput.errors?.required" class="text-danger">\r
+ {{ 'VALIDATE.REQUIRED' | translate }}\r
+ </small>\r
+ <small [hidden]="!wfInput.errors?.maxlength" class="text-danger">\r
+ {{ 'VALIDATE.MAX_LENGTH' | translate: {value: maxlength} }}\r
+ </small>\r
+ <small [hidden]="!wfInput.errors?.minlength" class="text-danger">\r
+ {{ 'VALIDATE.MIN_LENGTH' | translate: {value: minlength} }}\r
+ </small>\r
+ <small [hidden]="!wfInput.errors?.length" class="text-danger">\r
+ {{ 'VALIDATE.LENGTH' | translate: {value: length} }}\r
+ </small>\r
+ <small *ngIf="patternError" [hidden]="!wfInput.errors?.pattern" class="text-danger">\r
+ {{ patternError }}\r
+ </small>\r
+ <small *ngIf="!patternError && pattern === generalRules" [hidden]="!wfInput.errors?.pattern" class="text-danger">\r
+ {{ getCommonRuleMessage(minlength + '-' + maxlength) }}\r
+ </small>\r
+ <small [hidden]="!wfInput.errors?.greater_or_equal" class="text-danger">\r
+ {{ 'VALIDATE.GREATER_OR_EQUAL' | translate: {value: greater_or_equal} }}\r
+ </small>\r
+ <small [hidden]="!wfInput.errors?.less_or_equal" class="text-danger">\r
+ {{ 'VALIDATE.LESS_OR_EQUAL' | translate: {value: less_or_equal} }}\r
+ </small>\r
+ <small [hidden]="!wfInput.errors?.greater_than" class="text-danger">\r
+ {{ 'VALIDATE.GREATER_THAN' | translate: {value: greater_than} }}\r
+ </small>\r
+ <small [hidden]="!wfInput.errors?.less_than" class="text-danger">\r
+ {{ 'VALIDATE.LESS_THAN' | translate: {value: less_than} }}\r
+ </small>\r
+ <small [hidden]="!wfInput.errors?.in_range" class="text-danger">\r
+ {{ 'VALIDATE.IN_RANGE' | translate: {value: in_range} }}\r
+ </small>\r
+ <small [hidden]="!wfInput.errors?.equal" class="text-danger">\r
+ {{ 'VALIDATE.EQUAL' | translate: {value: equal} }}\r
+ </small>\r
+ <small [hidden]="!wfInput.errors?.float" class="text-danger">\r
+ {{ 'VALIDATE.FLOAT' | translate }}\r
+ </small>\r
+ <small [hidden]="!wfInput.errors?.integer" class="text-danger">\r
+ {{ 'VALIDATE.INTEGER' | translate }}\r
+ </small>\r
+ `,\r
+ styles: [`\r
+ .hint-label {\r
+ color:#7c868d;\r
+ }\r
+ input.ng-invalid {\r
+ border-color: #d9534f;\r
+ }\r
+ `],\r
+ providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR, CUSTOM_INPUT_VALIDATOR]\r
+})\r
+export class WfmTextInputComponent implements ControlValueAccessor, Validator, OnChanges {\r
+ @Input() public disabled: boolean;\r
+ @Input() public inputType = 'string';\r
+ @Input() public inputClass = 'form-control';\r
+ @Input() public placeholder = '';\r
+ @Input() public hintLabel: string;\r
+ @Input() public patternError: string;\r
+ @Input() public required = false;\r
+ @Input() public maxlength: number;\r
+ @Input() public minlength: number;\r
+ @Input() public pattern = '';\r
+ @Input() public greater_or_equal: string; // >=\r
+ @Input() public less_or_equal: string; // <=\r
+ @Input() public greater_than: string; // >\r
+ @Input() public less_than: string; // <\r
+ @Input() public length: number;\r
+ @Input() public equal: any;\r
+ @Input() public in_range: string;\r
+ @Input() public isFocus: boolean;\r
+ @Output() public blur: any = new EventEmitter();\r
+ @Output() public click: any = new EventEmitter();\r
+ @ViewChild('wfInput') public wfInput: any;\r
+\r
+ public isHintLabelShow = false;\r
+ private innerValue: any = '';\r
+ private onTouchedCallback: () => void = noop;\r
+ private onChangeCallback: (_: any) => void = noop;\r
+ private _validators: any = {};\r
+ public generalRules = '^(?![-_.])(?!\\d*$)[\\da-zA-Z-_.]*$';\r
+\r
+ constructor(public translate: TranslateService,\r
+ private elementRef: ElementRef) {\r
+\r
+ }\r
+\r
+ public ngOnChanges(changes: SimpleChanges): void {\r
+ this._createValidator(changes);\r
+ if (this.isFocus) {\r
+ this.elementRef.nativeElement.querySelector('input').focus();\r
+ }\r
+ }\r
+\r
+ // 动态创建Validator\r
+ private _createValidator(changes: SimpleChanges): void {\r
+ for (let change in changes) {\r
+ switch (change) {\r
+ case 'in_range':\r
+ if (!isNullOrUndefined(this.in_range)) {\r
+ this._validators.in_range = inRangeValidator(JSON.parse(this.in_range));\r
+ }\r
+ break;\r
+ case 'greater_or_equal':\r
+ if (!isNullOrUndefined(this.greater_or_equal)) {\r
+ this._validators.greater_or_equal = greaterOrEqualValidator(this.greater_or_equal);\r
+ }\r
+ break;\r
+ case 'less_or_equal':\r
+ if (!isNullOrUndefined(this.less_or_equal)) {\r
+ this._validators.less_or_equal = lessOrEqualValidator(this.less_or_equal);\r
+ }\r
+ break;\r
+ case 'greater_than':\r
+ if (!isNullOrUndefined(this.greater_than)) {\r
+ this._validators.greater_than = greaterThanValidator(this.greater_than);\r
+ }\r
+ break;\r
+ case 'less_than':\r
+ if (!isNullOrUndefined(this.less_than)) {\r
+ this._validators.less_than = lessThanValidator(this.less_than);\r
+ }\r
+ break;\r
+ case 'equal':\r
+ if (!isNullOrUndefined(this.equal)) {\r
+ this._validators.equal = equalValidator(this.equal);\r
+ }\r
+ break;\r
+ case 'length':\r
+ if (!isNullOrUndefined(this.length)) {\r
+ this._validators.length = lengthValidator(this.length);\r
+ }\r
+ break;\r
+ case 'inputType':\r
+ delete this._validators.float;\r
+ delete this._validators.integer;\r
+ if (this.inputType === 'float') {\r
+ this._validators.float = floatValidator();\r
+ } else if (this.inputType === 'integer') {\r
+ this._validators.integer = integerValidator();\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ // 执行控件验证\r
+ public validate(c: AbstractControl): ValidationErrors | null {\r
+ let errors: any;\r
+ for (let validatorName in this._validators) {\r
+ let validator = this._validators[validatorName];\r
+ if (validator) {\r
+ let errors = validator(c);\r
+ if (errors) {\r
+ return errors;\r
+ }\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+\r
+ public onFocus(): void {\r
+ if (this.isFocus) {\r
+ this.click.emit();\r
+ }\r
+ this.isHintLabelShow = true;\r
+ }\r
+\r
+ public onBlur(): void {\r
+ this.blur.emit();\r
+ this.isHintLabelShow = false;\r
+ this.onTouchedCallback();\r
+ }\r
+\r
+ get value(): any {\r
+ this.validate(this.wfInput.control);\r
+ return this.innerValue;\r
+ };\r
+\r
+ set value(value: any) {\r
+ if (value !== this.innerValue) {\r
+ this.innerValue = value;\r
+ this.onChangeCallback(value);\r
+ }\r
+ }\r
+\r
+ writeValue(value: any) {\r
+ if (value !== this.innerValue) {\r
+ this.innerValue = value;\r
+ }\r
+ }\r
+\r
+ registerOnChange(fn: any) {\r
+ this.onChangeCallback = fn;\r
+ }\r
+\r
+ registerOnTouched(fn: any) {\r
+ this.onTouchedCallback = fn;\r
+ }\r
+\r
+ public getCommonRuleMessage(length: any): string {\r
+ let message = this.translate.get('VALIDATE.FIRST_CHARACTER')['value'] + ', ' +\r
+ this.translate.get('VALIDATE.NOT_ALL_NUMBER')['value'] + ', ' +\r
+ this.translate.get('VALIDATE.CHARACTER_LIMIT', {value: '[0-9],[a-z],[A-Z],[_],[-],[.]'})['value'] + ', ' +\r
+ this.translate.get('VALIDATE.CHARACTER_LENGTH', {value: length})['value'];\r
+ return message;\r
+ }\r
+}\r