diff --git a/frontend/src/app/shared/components/fields/edit/field-types/date-edit-field/date-edit-field.component.ts b/frontend/src/app/shared/components/fields/edit/field-types/date-edit-field/date-edit-field.component.ts index d30c5a9b2c..facc2df44b 100644 --- a/frontend/src/app/shared/components/fields/edit/field-types/date-edit-field/date-edit-field.component.ts +++ b/frontend/src/app/shared/components/fields/edit/field-types/date-edit-field/date-edit-field.component.ts @@ -39,6 +39,8 @@ import { TimezoneService } from 'core-app/core/datetime/timezone.service'; tabindex="-1" (changed)="onValueSelected($event)" (canceled)="onCancel()" + (blurred)="submit($event)" + (enterPressed)="submit($event)" [initialDate]="formatter(value)" [required]="required" [disabled]="inFlight" @@ -52,27 +54,31 @@ export class DateEditFieldComponent extends EditFieldComponent implements OnInit @InjectField() opModalService:OpModalService; - ngOnInit() { + ngOnInit():void { super.ngOnInit(); } - public onValueSelected(data:string) { + public onValueSelected(data:string):void { this.value = this.parser(data); - this.handler.handleUserSubmit(); } - public onCancel() { + public submit(data:string):void { + this.onValueSelected(data); + void this.handler.handleUserSubmit(); + } + + public onCancel():void { this.handler.handleUserCancel(); } - public parser(data:any) { + public parser(data:string):string|null { if (moment(data, 'YYYY-MM-DD', true).isValid()) { return data; } return null; } - public formatter(data:any) { + public formatter(data:string):string|null { if (moment(data, 'YYYY-MM-DD', true).isValid()) { const d = this.timezoneService.parseDate(data); return this.timezoneService.formattedISODate(d); diff --git a/frontend/src/app/shared/components/op-date-picker/date-picker.directive.ts b/frontend/src/app/shared/components/op-date-picker/date-picker.directive.ts index 15dc97062a..f5df244d91 100644 --- a/frontend/src/app/shared/components/op-date-picker/date-picker.directive.ts +++ b/frontend/src/app/shared/components/op-date-picker/date-picker.directive.ts @@ -97,12 +97,16 @@ export abstract class AbstractDatePickerDirective extends UntilDestroyedMixin im } closeOnOutsideClick(event:MouseEvent):void { - if (!(event.relatedTarget - && this.datePickerInstance.datepickerInstance.calendarContainer.contains(event.relatedTarget as HTMLElement))) { + if (this.isOutsideClick(event)) { this.close(); } } + isOutsideClick(event:MouseEvent):boolean { + return (!(event.relatedTarget + && this.datePickerInstance.datepickerInstance.calendarContainer.contains(event.relatedTarget as HTMLElement))); + } + close():void { this.datePickerInstance.hide(); } diff --git a/frontend/src/app/shared/components/op-date-picker/op-single-date-picker/op-single-date-picker.component.html b/frontend/src/app/shared/components/op-date-picker/op-single-date-picker/op-single-date-picker.component.html index c6ad9cdf3a..59e92be5c4 100644 --- a/frontend/src/app/shared/components/op-date-picker/op-single-date-picker/op-single-date-picker.component.html +++ b/frontend/src/app/shared/components/op-date-picker/op-single-date-picker/op-single-date-picker.component.html @@ -8,8 +8,9 @@ [required]="required" [disabled]="disabled" (click)="openOnClick()" + (keydown.enter)="enterPressed.emit(dateValue)" (keydown.escape)="close()" - (blur)="closeOnOutsideClick($event)" (input)="onInputChange()" + (blur)="onBlurred($event)" type="text" > diff --git a/frontend/src/app/shared/components/op-date-picker/op-single-date-picker/op-single-date-picker.component.ts b/frontend/src/app/shared/components/op-date-picker/op-single-date-picker/op-single-date-picker.component.ts index 575bdfbda5..f38203605f 100644 --- a/frontend/src/app/shared/components/op-date-picker/op-single-date-picker/op-single-date-picker.component.ts +++ b/frontend/src/app/shared/components/op-date-picker/op-single-date-picker/op-single-date-picker.component.ts @@ -26,7 +26,12 @@ // See COPYRIGHT and LICENSE files for more details. //++ -import { Component, Input, Output } from '@angular/core'; +import { + Component, + EventEmitter, + Input, + Output, +} from '@angular/core'; import { Instance } from 'flatpickr/dist/types/instance'; import { KeyCodes } from 'core-app/shared/helpers/keyCodes.enum'; import { DatePicker } from 'core-app/shared/components/op-date-picker/datepicker'; @@ -42,16 +47,33 @@ import { componentDestroyed } from '@w11k/ngx-componentdestroyed'; export class OpSingleDatePickerComponent extends AbstractDatePickerDirective { @Output() public changed = new DebouncedEventEmitter(componentDestroyed(this)); + @Output() public blurred = new EventEmitter(); + + @Output() public enterPressed = new EventEmitter(); + @Input() public initialDate = ''; onInputChange():void { if (this.inputIsValidDate()) { this.changed.emit(this.currentValue); - } else { - this.changed.emit(''); } } + onBlurred(event:MouseEvent):void { + if (this.isOutsideClick(event)) { + this.close(); + this.blurred.emit(this.currentValue); + } + } + + get dateValue():string { + if (this.inputIsValidDate()) { + return this.currentValue; + } + + return ''; + } + protected inputIsValidDate():boolean { return (/\d{4}-\d{2}-\d{2}/.exec(this.currentValue)) !== null; } diff --git a/spec/features/work_packages/details/custom_fields/custom_field_spec.rb b/spec/features/work_packages/details/custom_fields/custom_field_spec.rb index de9963c7a8..312d68414f 100644 --- a/spec/features/work_packages/details/custom_fields/custom_field_spec.rb +++ b/spec/features/work_packages/details/custom_fields/custom_field_spec.rb @@ -253,7 +253,7 @@ describe 'custom field inplace editor', js: true do expect(work_package.custom_value_for(custom_field.id).formatted_value).to eq '03/30/2021' field.activate! - field.clear + field.clear with_backspace: true field.submit_by_enter field.expect_state_text '-'