From 035b0a449b240a2615cb0599ff242604a7864e83 Mon Sep 17 00:00:00 2001
From: jonaswinkler <17569239+jonaswinkler@users.noreply.github.com>
Date: Wed, 24 Feb 2021 18:00:26 +0100
Subject: [PATCH] use ng-bootstrap date selector, with proper
formatting/parsing according to the current locale #177
---
src-ui/src/app/app.module.ts | 14 +++--
.../input/date-time/date-time.component.html | 13 ----
.../input/date-time/date-time.component.ts | 61 -------------------
.../common/input/date/date.component.html | 15 +++++
.../date.component.scss} | 0
.../date.component.spec.ts} | 12 ++--
.../common/input/date/date.component.ts | 32 ++++++++++
.../document-detail.component.html | 2 +-
.../manage/settings/settings.component.ts | 9 +--
src-ui/src/app/services/settings.service.ts | 36 ++++++++---
src-ui/src/app/utils/ngb-date-adapter.ts | 23 +++++++
.../app/utils/ngb-date-parser-formatter.ts | 59 ++++++++++++++++++
12 files changed, 176 insertions(+), 100 deletions(-)
delete mode 100644 src-ui/src/app/components/common/input/date-time/date-time.component.html
delete mode 100644 src-ui/src/app/components/common/input/date-time/date-time.component.ts
create mode 100644 src-ui/src/app/components/common/input/date/date.component.html
rename src-ui/src/app/components/common/input/{date-time/date-time.component.scss => date/date.component.scss} (100%)
rename src-ui/src/app/components/common/input/{date-time/date-time.component.spec.ts => date/date.component.spec.ts} (55%)
create mode 100644 src-ui/src/app/components/common/input/date/date.component.ts
create mode 100644 src-ui/src/app/utils/ngb-date-adapter.ts
create mode 100644 src-ui/src/app/utils/ngb-date-parser-formatter.ts
diff --git a/src-ui/src/app/app.module.ts b/src-ui/src/app/app.module.ts
index 0773a9ace..9e0dc56de 100644
--- a/src-ui/src/app/app.module.ts
+++ b/src-ui/src/app/app.module.ts
@@ -3,7 +3,7 @@ import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
-import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
+import { NgbDateAdapter, NgbDateParserFormatter, NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { DocumentListComponent } from './components/document-list/document-list.component';
import { DocumentDetailComponent } from './components/document-detail/document-detail.component';
@@ -39,7 +39,6 @@ import { SelectComponent } from './components/common/input/select/select.compone
import { CheckComponent } from './components/common/input/check/check.component';
import { SaveViewConfigDialogComponent } from './components/document-list/save-view-config-dialog/save-view-config-dialog.component';
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
-import { DateTimeComponent } from './components/common/input/date-time/date-time.component';
import { TagsComponent } from './components/common/input/tags/tags.component';
import { SortableDirective } from './directives/sortable.directive';
import { CookieService } from 'ngx-cookie-service';
@@ -60,6 +59,9 @@ import { NgSelectModule } from '@ng-select/ng-select';
import { NumberComponent } from './components/common/input/number/number.component';
import { SafePipe } from './pipes/safe.pipe';
import { CustomDatePipe } from './pipes/custom-date.pipe';
+import { DateComponent } from './components/common/input/date/date.component';
+import { ISODateAdapter } from './utils/ngb-date-adapter';
+import { LocalizedDateParserFormatter } from './utils/ngb-date-parser-formatter';
import localeFr from '@angular/common/locales/fr';
import localeNl from '@angular/common/locales/nl';
@@ -106,7 +108,6 @@ registerLocaleData(localeEnGb)
SelectComponent,
CheckComponent,
SaveViewConfigDialogComponent,
- DateTimeComponent,
TagsComponent,
SortableDirective,
SavedViewWidgetComponent,
@@ -122,7 +123,8 @@ registerLocaleData(localeEnGb)
SelectDialogComponent,
NumberComponent,
SafePipe,
- CustomDatePipe
+ CustomDatePipe,
+ DateComponent
],
imports: [
BrowserModule,
@@ -144,7 +146,9 @@ registerLocaleData(localeEnGb)
multi: true
},
FilterPipe,
- DocumentTitlePipe
+ DocumentTitlePipe,
+ {provide: NgbDateAdapter, useClass: ISODateAdapter},
+ {provide: NgbDateParserFormatter, useClass: LocalizedDateParserFormatter}
],
bootstrap: [AppComponent]
})
diff --git a/src-ui/src/app/components/common/input/date-time/date-time.component.html b/src-ui/src/app/components/common/input/date-time/date-time.component.html
deleted file mode 100644
index 7c002db1b..000000000
--- a/src-ui/src/app/components/common/input/date-time/date-time.component.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/src-ui/src/app/components/common/input/date-time/date-time.component.ts b/src-ui/src/app/components/common/input/date-time/date-time.component.ts
deleted file mode 100644
index bce208ec8..000000000
--- a/src-ui/src/app/components/common/input/date-time/date-time.component.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-import { formatDate } from '@angular/common';
-import { Component, forwardRef, Input, OnInit } from '@angular/core';
-import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
-
-@Component({
- providers: [{
- provide: NG_VALUE_ACCESSOR,
- useExisting: forwardRef(() => DateTimeComponent),
- multi: true
- }],
- selector: 'app-input-date-time',
- templateUrl: './date-time.component.html',
- styleUrls: ['./date-time.component.scss']
-})
-export class DateTimeComponent implements OnInit,ControlValueAccessor {
-
- constructor() {
- }
-
- onChange = (newValue: any) => {};
-
- onTouched = () => {};
-
- writeValue(newValue: any): void {
- this.dateValue = formatDate(newValue, 'yyyy-MM-dd', "en-US")
- this.timeValue = formatDate(newValue, 'HH:mm:ss', 'en-US')
- }
- registerOnChange(fn: any): void {
- this.onChange = fn;
- }
- registerOnTouched(fn: any): void {
- this.onTouched = fn;
- }
- setDisabledState?(isDisabled: boolean): void {
- this.disabled = isDisabled;
- }
-
- @Input()
- titleDate: string = "Date"
-
- @Input()
- titleTime: string
-
- @Input()
- disabled: boolean = false
-
- @Input()
- hint: string
-
- timeValue
-
- dateValue
-
- ngOnInit(): void {
- }
-
- dateOrTimeChanged() {
- this.onChange(formatDate(this.dateValue + "T" + this.timeValue,"yyyy-MM-ddTHH:mm:ssZZZZZ", "en-us", "UTC"))
- }
-
-}
diff --git a/src-ui/src/app/components/common/input/date/date.component.html b/src-ui/src/app/components/common/input/date/date.component.html
new file mode 100644
index 000000000..ca9ccc040
--- /dev/null
+++ b/src-ui/src/app/components/common/input/date/date.component.html
@@ -0,0 +1,15 @@
+
diff --git a/src-ui/src/app/components/common/input/date-time/date-time.component.scss b/src-ui/src/app/components/common/input/date/date.component.scss
similarity index 100%
rename from src-ui/src/app/components/common/input/date-time/date-time.component.scss
rename to src-ui/src/app/components/common/input/date/date.component.scss
diff --git a/src-ui/src/app/components/common/input/date-time/date-time.component.spec.ts b/src-ui/src/app/components/common/input/date/date.component.spec.ts
similarity index 55%
rename from src-ui/src/app/components/common/input/date-time/date-time.component.spec.ts
rename to src-ui/src/app/components/common/input/date/date.component.spec.ts
index 0657768bd..ea92c7b30 100644
--- a/src-ui/src/app/components/common/input/date-time/date-time.component.spec.ts
+++ b/src-ui/src/app/components/common/input/date/date.component.spec.ts
@@ -1,20 +1,20 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
-import { DateTimeComponent } from './date-time.component';
+import { DateComponent } from './date.component';
-describe('DateTimeComponent', () => {
- let component: DateTimeComponent;
- let fixture: ComponentFixture;
+describe('DateComponent', () => {
+ let component: DateComponent;
+ let fixture: ComponentFixture;
beforeEach(async () => {
await TestBed.configureTestingModule({
- declarations: [ DateTimeComponent ]
+ declarations: [ DateComponent ]
})
.compileComponents();
});
beforeEach(() => {
- fixture = TestBed.createComponent(DateTimeComponent);
+ fixture = TestBed.createComponent(DateComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
diff --git a/src-ui/src/app/components/common/input/date/date.component.ts b/src-ui/src/app/components/common/input/date/date.component.ts
new file mode 100644
index 000000000..b3b863581
--- /dev/null
+++ b/src-ui/src/app/components/common/input/date/date.component.ts
@@ -0,0 +1,32 @@
+import { Component, forwardRef, Input, OnInit, ViewChild } from '@angular/core';
+import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
+import { NgbDateAdapter, NgbDateParserFormatter, NgbDatepickerContent } from '@ng-bootstrap/ng-bootstrap';
+import { SettingsService } from 'src/app/services/settings.service';
+import { v4 as uuidv4 } from 'uuid';
+import { AbstractInputComponent } from '../abstract-input';
+
+
+@Component({
+ providers: [{
+ provide: NG_VALUE_ACCESSOR,
+ useExisting: forwardRef(() => DateComponent),
+ multi: true
+ }],
+ selector: 'app-input-date',
+ templateUrl: './date.component.html',
+ styleUrls: ['./date.component.scss']
+})
+export class DateComponent extends AbstractInputComponent implements OnInit {
+
+ constructor(private settings: SettingsService) {
+ super()
+ }
+
+ ngOnInit(): void {
+ super.ngOnInit()
+ this.placeholder = this.settings.getLocalizedDateInputFormat()
+ }
+
+ placeholder: string
+
+}
diff --git a/src-ui/src/app/components/document-detail/document-detail.component.html b/src-ui/src/app/components/document-detail/document-detail.component.html
index 2814a1242..f9b87aee3 100644
--- a/src-ui/src/app/components/document-detail/document-detail.component.html
+++ b/src-ui/src/app/components/document-detail/document-detail.component.html
@@ -58,7 +58,7 @@
-
+
o.code == dateLocale)?.dateInputFormat || "yyyy-mm-dd"
+ }
+
get(key: string): any {
let setting = SETTINGS.find(s => s.key == key)
diff --git a/src-ui/src/app/utils/ngb-date-adapter.ts b/src-ui/src/app/utils/ngb-date-adapter.ts
new file mode 100644
index 000000000..19711319d
--- /dev/null
+++ b/src-ui/src/app/utils/ngb-date-adapter.ts
@@ -0,0 +1,23 @@
+import { Injectable } from "@angular/core";
+import { NgbDateAdapter, NgbDateStruct } from "@ng-bootstrap/ng-bootstrap";
+
+@Injectable()
+export class ISODateAdapter extends NgbDateAdapter {
+
+ fromModel(value: string | null): NgbDateStruct | null {
+ if (value) {
+ let date = new Date(value)
+ return {
+ day : date.getDate(),
+ month : date.getMonth() + 1,
+ year : date.getFullYear()
+ }
+ } else {
+ return null
+ }
+ }
+
+ toModel(date: NgbDateStruct | null): string | null {
+ return date ? new Date(date.year, date.month - 1, date.day).toISOString() : null
+ }
+}
diff --git a/src-ui/src/app/utils/ngb-date-parser-formatter.ts b/src-ui/src/app/utils/ngb-date-parser-formatter.ts
new file mode 100644
index 000000000..7d819a6bf
--- /dev/null
+++ b/src-ui/src/app/utils/ngb-date-parser-formatter.ts
@@ -0,0 +1,59 @@
+import { Injectable } from "@angular/core"
+import { NgbDateParserFormatter, NgbDateStruct } from "@ng-bootstrap/ng-bootstrap"
+import { SettingsService } from "../services/settings.service"
+
+@Injectable()
+export class LocalizedDateParserFormatter extends NgbDateParserFormatter {
+
+ constructor(private settings: SettingsService) {
+ super()
+ }
+
+ private getDateInputFormat() {
+ return this.settings.getLocalizedDateInputFormat()
+ }
+
+ /**
+ * This constructs a regular expression from a date input format which is then
+ * used to parse dates.
+ */
+ private getDateParseRegex() {
+ return new RegExp(
+ "^" + this.getDateInputFormat()
+ .replace('dd', '(?[0-9]+)')
+ .replace('mm', '(?[0-9]+)')
+ .replace('yyyy', '(?[0-9]+)')
+ .split('.').join('\\.\\s*') + "$" // allow whitespace(s) after dot (specific for German)
+ )
+ }
+
+ parse(value: string): NgbDateStruct | null {
+ let match = this.getDateParseRegex().exec(value)
+ if (match) {
+ let dateStruct = {
+ day: +match.groups.day,
+ month: +match.groups.month,
+ year: +match.groups.year
+ }
+ if (dateStruct.year <= (new Date().getFullYear() - 2000)) {
+ dateStruct.year += 2000
+ } else if (dateStruct.year < 100) {
+ dateStruct.year += 1900
+ }
+ return dateStruct
+ } else {
+ return null
+ }
+ }
+
+ format(date: NgbDateStruct | null): string {
+ if (date) {
+ return this.getDateInputFormat()
+ .replace('dd', date.day.toString().padStart(2, '0'))
+ .replace('mm', date.month.toString().padStart(2, '0'))
+ .replace('yyyy', date.year.toString().padStart(4, '0'))
+ } else {
+ return null
+ }
+ }
+}
\ No newline at end of file