From 8261a4ea8091c27b61ac581a852e2e18283b3cdd Mon Sep 17 00:00:00 2001 From: YuanHu Date: Tue, 27 Mar 2018 17:33:22 +0800 Subject: Include paletx components Include paletx components to WF Designer UI. Issue-ID: SDC-1130,SDC-1131 Change-Id: Iad06b2dde8fc98d03a0e3633e829b686d75cafd0 Signed-off-by: YuanHu --- .../paletx/plx-text-input/text-input.component.ts | 765 +++++++++++++++++++++ 1 file changed, 765 insertions(+) create mode 100644 sdc-workflow-designer-ui/src/app/paletx/plx-text-input/text-input.component.ts (limited to 'sdc-workflow-designer-ui/src/app/paletx/plx-text-input/text-input.component.ts') diff --git a/sdc-workflow-designer-ui/src/app/paletx/plx-text-input/text-input.component.ts b/sdc-workflow-designer-ui/src/app/paletx/plx-text-input/text-input.component.ts new file mode 100644 index 00000000..9b5a01e9 --- /dev/null +++ b/sdc-workflow-designer-ui/src/app/paletx/plx-text-input/text-input.component.ts @@ -0,0 +1,765 @@ +import {AfterContentInit, Component, ElementRef, EventEmitter, forwardRef, HostBinding, HostListener, Input, OnInit, Output, Renderer2, ViewChild} from '@angular/core'; +import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'; +import {Observable} from 'rxjs/Observable'; + +import {BooleanFieldValue} from '../core/boolean-field-value'; +import {NumberWrapperParseFloat} from '../core/number-wrapper-parse'; +import {UUID} from '../core/uuid'; + +const noop = () => {}; + +export const PX_TEXT_INPUT_CONTROL_VALUE_ACCESSOR: any = { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => PlxTextInputComponent), + multi: true +}; + +@Component({ + selector: 'plx-text-input', + templateUrl: 'text-input.html', + styleUrls: ['text-input.less'], + host: {'style': 'display: inline-block;'}, + providers: [PX_TEXT_INPUT_CONTROL_VALUE_ACCESSOR] +}) + +export class PlxTextInputComponent implements ControlValueAccessor, OnInit, + AfterContentInit { + private _focused: boolean = false; + private _value: any = ''; + /** Callback registered via registerOnTouched (ControlValueAccessor) */ + private _onTouchedCallback: () => void = noop; + /** Callback registered via registerOnChange (ControlValueAccessor) */ + private _onChangeCallback: (_: any) => void = noop; + + /** Readonly properties. */ + get empty() { + return this._value === null || this._value === ''; + } + get inputId(): string { + return `${this.id}`; + } + get isShowHintLabel() { + return this._focused && this.hintLabel !== null; + } + get inputType() { + return this.type === 'number' ? 'text' : this.type; + } + + @Input() id: string = `plx-input-${UUID.UUID()}`; + @Input() name: string = null; + @Input() hintLabel: string = null; + @Input() lang: string = 'zh'; + @Input() @BooleanFieldValue() disabled: boolean = false; + + @Input() numberShowSpinner = true; + @Input() max: string|number = null; + @Input() maxLength: number = 64; + @Input() min: string|number = null; + @Input() minLength: number = null; + @Input() placeholder: string = ''; + @Input() @BooleanFieldValue() readOnly: boolean = false; + @Input() @BooleanFieldValue() required: boolean = false; + @Input() @BooleanFieldValue() notShowOption: boolean = true; + @Input() type: string = 'text'; + @Input() tabIndex: number = null; + @Input() pattern: string = null; + + @Input() @BooleanFieldValue() shortInput: boolean = false; + @Input() unit: string = null; + @Input() unitOptions: string[] = null; + @Input() prefix: string = null; + @Input() suffixList: string[] = null; + + // @Input() precision: number = 0; + @Input() step: number = 1; + @Input() width: string = '400px'; + @Input() unitWidth: string = '45px'; + @Input() unitOptionWidth: string = '84px'; + @Input() prefixWidth: string = '70px'; + @Input() historyList: string[]; + + @Input() prefixOptions: string[] = []; + @Input() prefixOptionWidth: string = '84px'; + + @Input() @BooleanFieldValue() passwordSwitch: boolean = false; + + @ViewChild('input') inputViewChild: ElementRef; + @ViewChild('inputOutter') pxTextInputElement: ElementRef; + + @HostBinding('class.input-invalid') selectClass: boolean = true; + + isDisabledUp: boolean = false; + isDisabledDown: boolean = false; + displayDataList: string[]; + currentPrecision: number = 0; + keyPattern: RegExp = /[0-9\-]/; + langPattern: RegExp = + /[a-zA-Z]|[\u4e00-\u9fa5]|[\uff08\uff09\u300a\u300b\u2014\u2014\uff1a\uff1b\uff0c\u201c\u201d\u2018\u2019\+\=\{\}\u3001\u3002\u3010\u3011\<\>\uff01\uff1f\/\|]/g; + timer: any; + optionalLabel: string = null; + hasSelection = false; + _precision: number = 0; + displayValue: any; + + isOpenDataList: boolean = false; + dataListClicked: boolean = false; + isOpenSuffixList: boolean = false; + suffixListClicked: boolean = false; + + showUnit: string; + isShowUnitOption: boolean = false; + unitOptionClicked: boolean = false; + + prefixOptionClicked: boolean = false; + isShowPrefixOption = false; + showPrefix: string; + showPassword: boolean = false; + tooltipText: string; + tooltipTexts = { + 'zh': { + 'true': '隐藏', + 'false': '显示', + }, + 'en': { + 'true': 'hidden', + 'false': 'show', + } + }; + isPwdSwithHover: boolean = false; + isPwdSwithClick: boolean = false; + + _autoFocus: boolean = false; + @Input() + set autoFocus(value: boolean) { + this._autoFocus = value; + + const that = this; + if (this._autoFocus) { + setTimeout(() => { + that.inputViewChild.nativeElement.focus(); + }, 0); + } + } + get autoFocus() { + return this._autoFocus; + } + + @Input() + set precision(value: string) { + this._precision = parseInt(value); + } + get precision() { + return this._value; + } + + get inputWidth() { + if (this.prefixOptions && this.prefixOptions.length > 0) { + if (this.unitOptions && this.unitOptions.length > 0) { + return `calc(${this.width} - ${this.prefixOptionWidth} - ${this.unitOptionWidth})`; + } else if (this.unit !== null) { + return `calc(${this.width} - ${this.prefixOptionWidth} - ${this.unitWidth})`; + } else { + return `calc(${this.width} - ${this.prefixOptionWidth})`; + } + } + + if (this.unit !== null && this.prefix !== null) { + return `calc(${this.width} - ${this.unitWidth} - ${this.prefixWidth})`; + } + + if (this.unit !== null) { + return `calc(${this.width} - ${this.unitWidth})`; + } + + if (!!this.unitOptions && this.unitOptions.length !== 0 && + this.prefix !== null) { + return `calc(${this.width} - ${this.unitOptionWidth} - ${ + this.prefixWidth + })`; + } + + if (!!this.unitOptions && this.unitOptions.length !== 0) { + return `calc(${this.width} - ${this.unitOptionWidth})`; + } + if (this.prefix !== null) { + return `calc(${this.width} - ${this.prefixWidth})`; + } + return this.width; + } + + + get hasUnit() { + return this.unit !== null; + } + get hasUnitOption() { + return this.showUnit !== undefined; + } + get hasPrefix() { + return this.prefix !== null; + } + get hasPrefixOption() { + return this.prefixOptions && this.prefixOptions.length > 0; + } + get isFocus() { + return this._focused; + } + + private _blurEmitter: EventEmitter = + new EventEmitter(); + private _focusEmitter: EventEmitter = + new EventEmitter(); + private click = new EventEmitter(); + private unitChange = new EventEmitter(); + @Output() public prefixChange = new EventEmitter(); + + @Output('blur') + get onBlur(): Observable { + return this._blurEmitter.asObservable(); + } + + @Output('focus') + get onFocus(): Observable { + return this._focusEmitter.asObservable(); + } + + @HostListener('focus') + onHostFocus() { + this.renderer.addClass(this.el.nativeElement, 'input-focus'); + this.renderer.removeClass(this.el.nativeElement, 'input-blur'); + } + + @HostListener('blur') + onHostBlur() { + this.renderer.addClass(this.el.nativeElement, 'input-blur'); + this.renderer.removeClass(this.el.nativeElement, 'input-focus'); + } + + @Input() + set value(v: any) { + v = this.filterZhChar(v); + v = this._convertValueForInputType(v); + if (v !== this._value) { + this._value = v; + if (this.type === 'number') { + if (this._value === '') { + this._onChangeCallback(null); + } else if (isNaN(this._value)) { + this._onChangeCallback(this._value); + } else { + this._onChangeCallback(NumberWrapperParseFloat(this._value)); + } + } else { + this._onChangeCallback(this._value); + } + } + } + get value(): any { + return this._value; + } + + constructor( + private el: ElementRef, private renderer: Renderer2) {} + + ngOnInit() { + if (this.shortInput) { + this.width = '120px'; + this.unitWidth = '40px'; + this.prefixWidth = '40px'; + } + this.translateLabel(); + + if (!!this.unitOptions && this.unitOptions.length !== 0) { + this.showUnit = this.unitOptions[0]; + } + + if (!!this.prefixOptions && this.prefixOptions.length !== 0) { + this.showPrefix = this.prefixOptions[0]; + } + } + + ngAfterContentInit() { + if (this.pxTextInputElement) { + Array.from(this.pxTextInputElement.nativeElement.childNodes) + .forEach((node: HTMLElement) => { + if (node.nodeType === 3) { + this.pxTextInputElement.nativeElement.removeChild(node); + } + }); + } + } + private translateLabel() { + if (this.lang === 'zh') { + this.optionalLabel = '(可选)'; + } else { + this.optionalLabel = '(Optional)'; + } + } + + _handleFocus(event: FocusEvent) { + this._focused = true; + this._focusEmitter.emit(event); + } + + _handleBlur(event: FocusEvent) { + this._focused = false; + this._onTouchedCallback(); + this._blurEmitter.emit(event); + } + + _checkValueLimit(value: any) { + if (this.type === 'number') { + if ((value === '' || value === undefined || value === null) && + !this.required) { + return ''; + } else if ( + this.min !== null && + NumberWrapperParseFloat(value) < NumberWrapperParseFloat(this.min)) { + return this.min; + } else if ( + this.max !== null && + NumberWrapperParseFloat(value) > NumberWrapperParseFloat(this.max)) { + return this.max; + } else { + return value; + } + } + return value; + } + + _checkValue() { + this.value = this._checkValueLimit(this.value); + this.displayValue = this.value; + } + + _handleChange(event: Event) { + this.value = (event.target).value; + this._onTouchedCallback(); + } + + openDataList() { + this.dataListClicked = true; + if (this.historyList) { + if (this.value) { + this.filterOption(this.value); + } else { + this.displayDataList = this.historyList; + if (!this.isOpenDataList) { + this.isOpenDataList = true; + } + } + } + } + + _handleClick(event: Event) { + if (this.isShowUnitOption) { + this.isShowUnitOption = false; + } + this.click.emit(event); + + if (this.historyList) { + this.openDataList(); + } + } + + _handleSelect(event: Event) { // 输入框文本被选中时处理 + if (!this.hasSelection) { + this.hasSelection = true; + } + } + deleteSelection() { // 删除选中文本, + document.getSelection().deleteFromDocument(); + this.hasSelection = false; + } + + _onWindowClick(event: Event) { + if (this.historyList) { + if (!this.dataListClicked) { + this.isOpenDataList = false; + } + this.dataListClicked = false; + } + + if (this.suffixList) { + if (!this.suffixListClicked) { + this.isOpenSuffixList = false; + } + this.suffixListClicked = false; + } + + if (this.unitOptions) { + if (!this.unitOptionClicked) { + this.isShowUnitOption = false; + } + this.unitOptionClicked = false; + } + + if (this.prefixOptions) { + if (!this.prefixOptionClicked) { + this.isShowPrefixOption = false; + } + this.prefixOptionClicked = false; + } + } + + _showPrefixOption(event: Event) { + this.isShowPrefixOption = !this.isShowPrefixOption; + this.prefixOptionClicked = true; + } + + _showUnitOption(event: Event) { + this.isShowUnitOption = !this.isShowUnitOption; + this.unitOptionClicked = true; + } + + _setUnit(unitValue: string) { + this.unitOptionClicked = true; + this.showUnit = unitValue; + this.unitChange.emit(unitValue); + this.isShowUnitOption = false; + } + + _setPrefix(value: string) { + if (value !== this.showPrefix) { + this.showPrefix = value; + this.prefixChange.emit(value); + } + this.prefixOptionClicked = true; + this.isShowPrefixOption = false; + } + + filterOption(value: any) { + this.displayDataList = []; + this.displayDataList = this.historyList.filter((data: string) => { + return data.toLowerCase().indexOf(value.toLowerCase()) > -1; + }); + + this.isOpenDataList = this.displayDataList.length !== 0; + } + + concatValueAndSuffix(value: string) { + const that = this; + that.displayDataList = []; + let mark = '@'; + if (value === '') { + that.displayDataList = []; + } else if (value.trim().toLowerCase().indexOf(mark) === -1) { + that.displayDataList.push(value); + that.suffixList.map((item: string) => { + let tempValue = value + mark + item; + that.displayDataList.push(tempValue); + }); + } else { + that.suffixList.map((item: string) => { + let tempValue = value.split(mark)[0] + mark + item; + that.displayDataList.push(tempValue); + }); + that.displayDataList = that.displayDataList.filter((item: string) => { + return item.trim().toLowerCase().indexOf(value) > -1; + }); + } + + that.isOpenSuffixList = that.displayDataList.length !== 0; + } + + _handleInput(event: any) { + let inputValue = event.target.value.trim().toLowerCase(); + + if (this.historyList) { + this.filterOption(inputValue); + } + + if (this.suffixList) { + this.concatValueAndSuffix(inputValue); + } + } + + chooseInputData(data: any) { + this.displayValue = data; + this.value = data; + + this.isOpenDataList = false; + this.dataListClicked = true; + this.isOpenSuffixList = false; + this.suffixListClicked = true; + } + + writeValue(value: any) { + this.displayValue = this._checkValueLimit(value); + this._value = this.displayValue; + } + + registerOnChange(fn: any) { + this._onChangeCallback = fn; + } + + registerOnTouched(fn: any) { + this._onTouchedCallback = fn; + } + + private getConvertValue(v: any) { + this.currentPrecision = v.toString().split('.')[1].length; + if (this.currentPrecision === 0) { // 输入小数点,但小数位数为0时 + return v; + } + if (this.currentPrecision < + this._precision) { // 输入小数点,且小数位数不为0 + return this.toFixed(v, this.currentPrecision); + } else { + return this.toFixed(v, this._precision); + } + } + + private filterZhChar(v: any) { + if (this.type === 'number') { + let reg = /[^0-9.-]/; + while (reg.test(v)) { + v = v.replace(reg, ''); + } + } + return v; + } + + private _convertValueForInputType(v: any): any { + switch (this.type) { + case 'number': { + if (v === '' || v === '-') { + return v; + } + + if (v.toString().indexOf('.') === -1) { // 整数 + return this.toFixed(v, 0); + } else { + return this.getConvertValue(v); + } + } + default: + return v; + } + } + + private toFixed(value: number, precision: number) { + return Number(value).toFixed(precision); + } + + repeat(interval: number, dir: number) { + let i = interval || 500; + + this.clearTimer(); + this.timer = setTimeout(() => { + this.repeat(40, dir); + }, i); + + this.spin(dir); + } + + clearTimer() { + if (this.timer) { + clearInterval(this.timer); + } + } + + spin(dir: number) { + let step = this.step * dir; + let currentValue = this._convertValueForInputType(this.value) || 0; + + this.value = Number(currentValue) + step; + + if (this.maxLength !== null && + this.value.toString().length > this.maxLength) { + this.value = currentValue; + } + + if (this.min !== null && this.value <= NumberWrapperParseFloat(this.min)) { + this.value = this.min; + this.isDisabledDown = true; + } + + if (this.max !== null && this.value >= NumberWrapperParseFloat(this.max)) { + this.value = this.max; + this.isDisabledUp = true; + } + this.displayValue = this.value; + this._onChangeCallback(NumberWrapperParseFloat(this.value)); + } + + onUpButtonMousedown(event: Event, input: HTMLInputElement) { + if (!this.disabled && this.type === 'number') { + input.focus(); + this.repeat(null, 1); + event.preventDefault(); + } + } + + onUpButtonMouseup(event: Event) { + if (!this.disabled) { + this.clearTimer(); + } + } + + onUpButtonMouseleave(event: Event) { + if (!this.disabled) { + this.clearTimer(); + } + } + + onDownButtonMousedown(event: Event, input: HTMLInputElement) { + if (!this.disabled && this.type === 'number') { + input.focus(); + this.repeat(null, -1); + event.preventDefault(); + } + } + + onDownButtonMouseup(event: Event) { + if (!this.disabled) { + this.clearTimer(); + } + } + + onDownButtonMouseleave(event: Event) { + if (!this.disabled) { + this.clearTimer(); + } + } + + onInputKeydown(event: KeyboardEvent) { + if (this.type === 'number') { + if (event.which === 229) { + event.preventDefault(); + return; + } else if (event.which === 38) { + this.spin(1); + event.preventDefault(); + } else if (event.which === 40) { + this.spin(-1); + event.preventDefault(); + } + } + } + onInputKeyPress(event: KeyboardEvent) { + let inputChar = String.fromCharCode(event.charCode); + if (this.type === 'number') { + if (event.which === 8) { + return; + } + + // if (!this.isValueLimit()) { + // this.handleSelection(event); + // } + + if (inputChar === '-' && this.min !== null && + NumberWrapperParseFloat(this.min) >= 0) { + event.preventDefault(); + return; + } + if (this.isIllegalNumberInputChar(event) || + this.isIllegalIntergerInput(inputChar)) { + event.preventDefault(); + return; + } + if (this.isIllegalFloatInput( + inputChar)) { // 当该函数返回true时,执行两种情景 + this.handleSelection(event); + } + if (this.hasSelection) { // 文本被选中,执行文本替换 + this.deleteSelection(); + } + } + } + + private handleSelection(event: any) { + if (this.hasSelection) { // 文本被选中,执行文本替换 + this.deleteSelection(); + } else { // 无选中文本,阻止非法输入 + event.preventDefault(); + } + } + // private isValueLimit() { + // if (this.min !== null && NumberWrapperParseFloat(this.value) !== 0 && + // this.value <= NumberWrapperParseFloat(this.min)) { + // return false; + // } + // if (this.max !== null && NumberWrapperParseFloat(this.value) !== 0 && + // this.value >= NumberWrapperParseFloat(this.max)) { + // return false; + // } + // return true; + // } + + private isIllegalNumberInputChar(event: KeyboardEvent) { + /* 8:backspace, 46:. */ + return !this.keyPattern.test(String.fromCharCode(event.charCode)) && + event.which !== 46 && event.which !== 0; + } + + private isIllegalIntergerInput(inputChar: string) { + return this._precision === 0 && + (inputChar === '.' || + (this._value && this._value && this._value.toString().length > 0 && + inputChar === '-')); + } + + private isIllegalFloatInput(inputChar: string) { + return this._precision > 0 && this._value && + ((this._value.toString().length > 0 && inputChar === '-') || + ((this._value.toString() === '' || + this._value.toString().indexOf('.') > 0) && + inputChar === '.') || + (this._value.toString().indexOf('.') > 0 && + this._value.toString().split('.')[1].length === this._precision)); + } + + onInput(event: Event, inputValue: string) { + this.value = inputValue; + } + + //处理鼠标经过上下箭头时,样式设置 + isEmptyValue() { + if (this.value === undefined || this.value === null || this.value === '') { + return true; + } + return false; + } + + isDisabledUpCaret() { + if (this.isEmptyValue()) { + return true; + } else if ( + this.max !== null && + (NumberWrapperParseFloat(this.value) >= + NumberWrapperParseFloat(this.max))) { + return true; + } + return false; + } + + isDisabledDownCaret() { + if (this.isEmptyValue()) { + return true; + } else if ( + this.min !== null && + (NumberWrapperParseFloat(this.value) <= + NumberWrapperParseFloat(this.min))) { + return true; + } + return false; + } + + _handleMouseEnterUp() { + this.isDisabledUp = this.isDisabledUpCaret(); + } + + _handleMouseEnterDown() { + this.isDisabledDown = this.isDisabledDownCaret(); + } + + public switch(): void { + this.showPassword = !this.showPassword; + this.showPassword?this.inputViewChild.nativeElement.type = + 'text':this.inputViewChild.nativeElement.type = 'password'; + } + + private setPasswordTooltip(): void { + this.tooltipTexts[this.lang][this.showPassword.toString()] + } +} -- cgit 1.2.3-korg