From 3c9b4cc31e41a4bce106a6441ce6c32afd6c8319 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Tue, 25 Feb 2020 13:28:50 +0100 Subject: [PATCH 01/60] feature (value): add component for date value --- package-lock.json | 113 +++++++++++------- package.json | 4 +- projects/knora-ui/package.json | 4 +- .../display-edit/display-edit.component.html | 2 + .../date-value/date-value.component.html | 9 ++ .../date-value/date-value.component.scss | 0 .../date-value/date-value.component.spec.ts | 25 ++++ .../values/date-value/date-value.component.ts | 112 +++++++++++++++++ .../jdndatepicker.directive.spec.ts | 8 ++ .../jdndatepicker.directive.ts | 16 +++ .../knora-ui/src/lib/viewer/viewer.module.ts | 22 ++-- src/app/app.component.html | 8 ++ src/app/app.component.ts | 18 ++- src/app/app.module.ts | 4 +- yalc.lock | 2 +- 15 files changed, 284 insertions(+), 63 deletions(-) create mode 100644 projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html create mode 100644 projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.scss create mode 100644 projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts create mode 100644 projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts create mode 100644 projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.spec.ts create mode 100644 projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts diff --git a/package-lock.json b/package-lock.json index 02a651680..49387cfc7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -131,6 +131,14 @@ "tslib": "1.10.0", "typescript": "3.5.3", "webpack-sources": "1.4.3" + }, + "dependencies": { + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + } } }, "@angular-devkit/build-webpack": { @@ -2172,9 +2180,9 @@ } }, "@types/selenium-webdriver": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.16.tgz", - "integrity": "sha512-lMC2G0ItF2xv4UCiwbJGbnJlIuUixHrioOhNGHSCsYCJ8l4t9hMCUimCytvFv7qy6AfSzRxhRHoGa+UqaqwyeA==", + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.17.tgz", + "integrity": "sha512-tGomyEuzSC1H28y2zlW6XPCaDaXFaD6soTdb4GNdmte2qfHtrKqhy0ZFs4r/1hpazCfEZqeTSRLvSasmEx89uw==", "dev": true }, "@types/source-list-map": { @@ -2453,9 +2461,9 @@ } }, "ajv": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.11.0.tgz", - "integrity": "sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", + "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -3747,9 +3755,9 @@ "dev": true }, "compare-versions": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.5.1.tgz", - "integrity": "sha512-9fGPIB7C6AyM18CJJBHt5EnCZDG3oiTJYy0NjfIAGjKpzv0tkxWko7TNQHF5ymqm7IH03tqmeuBxtvD+Izh6mg==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", + "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", "dev": true }, "component-bind": { @@ -4622,9 +4630,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.349", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.349.tgz", - "integrity": "sha512-uEb2zs6EJ6OZIqaMsCSliYVgzE/f7/s1fLWqtvRtHg/v5KBF2xds974fUnyatfxIDgkqzQVwFtam5KExqywx0Q==", + "version": "1.3.360", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.360.tgz", + "integrity": "sha512-RE1pv2sjQiDRRN1nI0fJ0eQHZ9le4oobu16OArnwEUV5ycAU5SNjFyvzjZ1gPUAqBa2Ud1XagtW8j3ZXfHuQHA==", "dev": true }, "elliptic": { @@ -5265,9 +5273,9 @@ "dev": true }, "figures": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", - "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dev": true, "requires": { "escape-string-regexp": "^1.0.5" @@ -5384,9 +5392,9 @@ } }, "make-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.0.tgz", - "integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.2.tgz", + "integrity": "sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w==", "dev": true, "requires": { "semver": "^6.0.0" @@ -6303,9 +6311,9 @@ "dev": true }, "ipaddr.js": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", - "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true }, "is-absolute-url": { @@ -6832,6 +6840,19 @@ "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=", "dev": true }, + "jdnconvertiblecalendar": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/jdnconvertiblecalendar/-/jdnconvertiblecalendar-0.0.5.tgz", + "integrity": "sha512-/yBqMepJNHxy+yS4Llt0KQPsHGkMi1FVwcE77cpiJZh2RwoNyGBXOwFz4Am5FNZYBF3oiL39FMzHRwwf6yl6xg==" + }, + "jdnconvertiblecalendardateadapter": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/jdnconvertiblecalendardateadapter/-/jdnconvertiblecalendardateadapter-0.0.10.tgz", + "integrity": "sha512-qqbWdSe5owgGtRu24QV64IvR4zeE0icnVnRF9eC1Gz+L6wPmOpjPfUfkj+Hs/z14KK0/ADTl7HcslYbO0N2vtw==", + "requires": { + "tslib": "^1.9.0" + } + }, "jest-worker": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", @@ -8013,9 +8034,9 @@ } }, "make-error": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", - "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, "make-fetch-happen": { @@ -8605,9 +8626,9 @@ } }, "node-releases": { - "version": "1.1.49", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.49.tgz", - "integrity": "sha512-xH8t0LS0disN0mtRCh+eByxFPie+msJUBL/lJDBuap53QGiYPa9joh83K4pCZgWJ+2L4b9h88vCVdXQ60NO2bg==", + "version": "1.1.50", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.50.tgz", + "integrity": "sha512-lgAmPv9eYZ0bGwUYAKlr8MG6K4CvWliWqnkcT2P8mMAgVrH3lqfBPorFlxiG1pHQnqmavJZ9vbMXUTNyMLbrgQ==", "dev": true, "requires": { "semver": "^6.3.0" @@ -8716,9 +8737,9 @@ } }, "npm-registry-fetch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.2.tgz", - "integrity": "sha512-Z0IFtPEozNdeZRPh3aHHxdG+ZRpzcbQaJLthsm3VhNf6DScicTFRHZzK82u8RsJUsUHkX+QH/zcB/5pmd20H4A==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.3.tgz", + "integrity": "sha512-WGvUx0lkKFhu9MbiGFuT9nG2NpfQ+4dCJwRwwtK2HK5izJEvwDxMeUyqbuMS7N/OkpVCqDorV6rO5E4V9F8lJw==", "dev": true, "requires": { "JSONStream": "^1.3.4", @@ -9434,9 +9455,9 @@ } }, "postcss-value-parser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz", - "integrity": "sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.3.tgz", + "integrity": "sha512-N7h4pG+Nnu5BEIzyeaaIYWs0LI5XC40OrRh5L60z0QjFsqGWcHcbkBvpe1WYpcIS9yQ8sOi/vIPt1ejQCrMVrg==", "dev": true }, "prepend-http": { @@ -9650,13 +9671,13 @@ } }, "proxy-addr": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", - "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", "dev": true, "requires": { "forwarded": "~0.1.2", - "ipaddr.js": "1.9.0" + "ipaddr.js": "1.9.1" } }, "prr": { @@ -10090,9 +10111,9 @@ "dev": true }, "regjsparser": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.2.tgz", - "integrity": "sha512-E9ghzUtoLwDekPT0DYCp+c4h+bvuUpe6rRHCTYn6eGoqj1LgKXxT6I0Il4WbjhQkOghzi/V+y03bPKvbllL93Q==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.3.tgz", + "integrity": "sha512-8uZvYbnfAtEm9Ab8NTb3hdLwL4g/LQzEYP7Xs27T96abJCCE2d6r3cPZPQEsLKy0vRSGVNG+/zVGtLr86HQduA==", "dev": true, "requires": { "jsesc": "~0.5.0" @@ -11177,9 +11198,9 @@ }, "dependencies": { "readable-stream": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.5.0.tgz", - "integrity": "sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -11796,9 +11817,9 @@ "dev": true }, "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.0.tgz", + "integrity": "sha512-BmndXUtiTn/VDDrJzQE7Mm22Ix3PxgLltW9bSNLoeCY31gnG2OPx0QqJnuc9oMIKioYrz487i6K9o4Pdn0j+Kg==" }, "tslint": { "version": "5.15.0", diff --git a/package.json b/package.json index 72c7407cc..23c165b33 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,9 @@ "@knora/api": "file:.yalc/@knora/api", "rxjs": "~6.4.0", "tslib": "^1.10.0", - "zone.js": "~0.9.1" + "zone.js": "~0.9.1", + "jdnconvertiblecalendar": "^0.0.5", + "jdnconvertiblecalendardateadapter": "^0.0.10" }, "devDependencies": { "@angular-devkit/build-angular": "~0.803.20", diff --git a/projects/knora-ui/package.json b/projects/knora-ui/package.json index b70fc88f7..823d727d5 100644 --- a/projects/knora-ui/package.json +++ b/projects/knora-ui/package.json @@ -6,6 +6,8 @@ "@angular/core": "^8.2.14", "@angular/material": "^8.2.3", "@angular/cdk": "^8.2.3", - "@knora/api": "file:.yalc/@knora/api" + "@knora/api": "file:.yalc/@knora/api", + "jdnconvertiblecalendar": "^0.0.5", + "jdnconvertiblecalendardateadapter": "^0.0.10" } } diff --git a/projects/knora-ui/src/lib/viewer/operations/display-edit/display-edit.component.html b/projects/knora-ui/src/lib/viewer/operations/display-edit/display-edit.component.html index b8daf19db..13803aaae 100644 --- a/projects/knora-ui/src/lib/viewer/operations/display-edit/display-edit.component.html +++ b/projects/knora-ui/src/lib/viewer/operations/display-edit/display-edit.component.html @@ -6,6 +6,8 @@ + + Unsupported datatype
diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html new file mode 100644 index 000000000..d370674c0 --- /dev/null +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.scss b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts new file mode 100644 index 000000000..ea5ac8e5d --- /dev/null +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DateValueComponent } from './date-value.component'; + +describe('DateValueComponent', () => { + let component: DateValueComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ DateValueComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DateValueComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts new file mode 100644 index 000000000..99ea5b25c --- /dev/null +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts @@ -0,0 +1,112 @@ +import {Component, Inject, Input, OnChanges, OnDestroy, OnInit, SimpleChanges} from '@angular/core'; +import { + CreateDateValue, + CreateIntValue, + KnoraDate, + KnoraPeriod, + ReadDateValue, + ReadIntValue, + UpdateDateValue, + UpdateIntValue +} from '@knora/api'; +import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms'; +import {Subscription} from 'rxjs'; +import {CustomRegex} from '../custom-regex'; +import {BaseValueComponent} from '../base-value.component'; + +@Component({ + selector: 'kui-date-value', + templateUrl: './date-value.component.html', + styleUrls: ['./date-value.component.scss'] +}) +export class DateValueComponent extends BaseValueComponent implements OnInit, OnChanges, OnDestroy { + + @Input() displayValue?: ReadDateValue; + + valueFormControl: FormControl; + commentFormControl: FormControl; + + form: FormGroup; + + valueChangesSubscription: Subscription; + + customValidators = []; + + constructor(@Inject(FormBuilder) private fb: FormBuilder) { + super(); + } + + getInitValue(): KnoraDate | KnoraPeriod | null { + if (this.displayValue !== undefined) { + return this.displayValue.date; + } else { + return null; + } + } + + ngOnInit() { + // initialize form control elements + this.valueFormControl = new FormControl(null); + + this.commentFormControl = new FormControl(null); + + // subscribe to any change on the comment and recheck validity + this.valueChangesSubscription = this.commentFormControl.valueChanges.subscribe( + data => { + this.valueFormControl.updateValueAndValidity(); + } + ); + + this.form = this.fb.group({ + dateValue: this.valueFormControl, + comment: this.commentFormControl + }); + + this.resetFormControl(); + } + + ngOnChanges(changes: SimpleChanges): void { + this.resetFormControl(); + } + + // unsubscribe when the object is destroyed to prevent memory leaks + ngOnDestroy(): void { + this.unsubscribeFromValueChanges(); + } + + getNewValue(): CreateDateValue | false { + if (this.mode !== 'create' || !this.form.valid) { + return false; + } + + const newDateValue = new CreateDateValue(); + + // newDateValue.int = this.valueFormControl.value; + + if (this.commentFormControl.value !== null && this.commentFormControl.value !== '') { + newDateValue.valueHasComment = this.commentFormControl.value; + } + + return newDateValue; + } + + getUpdatedValue(): UpdateDateValue | false { + if (this.mode !== 'update' || !this.form.valid) { + return false; + } + + const updatedDateValue = new UpdateDateValue(); + + updatedDateValue.id = this.displayValue.id; + + // updatedDateValue.int = this.valueFormControl.value; + + // add the submitted comment to updatedIntValue only if user has added a comment + if (this.commentFormControl.value !== null && this.commentFormControl.value !== '') { + updatedDateValue.valueHasComment = this.commentFormControl.value; + } + + return updatedDateValue; + } + +} diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.spec.ts new file mode 100644 index 000000000..500e78c47 --- /dev/null +++ b/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.spec.ts @@ -0,0 +1,8 @@ +import { JDNDatepickerDirective } from './jdndatepicker.directive'; + +describe('JDNDatepickerDirective', () => { + it('should create an instance', () => { + //const directive = new JDNDatepickerDirective(); + //expect(directive).toBeTruthy(); + }); +}); diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts b/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts new file mode 100644 index 000000000..4e0a4f7fb --- /dev/null +++ b/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts @@ -0,0 +1,16 @@ +import {Directive} from '@angular/core'; +import {DateAdapter, MAT_DATE_LOCALE} from '@angular/material'; +import {JDNConvertibleCalendar} from 'jdnconvertiblecalendar'; +import {JDNConvertibleCalendarDateAdapter} from 'jdnconvertiblecalendardateadapter'; + +@Directive({ + selector: 'kuiJDNDatepicker', + providers: [{provide: DateAdapter, useClass: JDNConvertibleCalendarDateAdapter, deps: [MAT_DATE_LOCALE]}] +}) +export class JDNDatepickerDirective { + + constructor(private adapter: DateAdapter) { + console.log(this.adapter) + } + +} diff --git a/projects/knora-ui/src/lib/viewer/viewer.module.ts b/projects/knora-ui/src/lib/viewer/viewer.module.ts index d28965d6f..409b2297a 100644 --- a/projects/knora-ui/src/lib/viewer/viewer.module.ts +++ b/projects/knora-ui/src/lib/viewer/viewer.module.ts @@ -4,23 +4,29 @@ import {ReactiveFormsModule} from '@angular/forms'; import {MatInputModule} from '@angular/material/input'; import {MatCheckboxModule} from '@angular/material/checkbox'; import {CommonModule} from '@angular/common'; -import { IntValueComponent } from './values/int-value/int-value.component'; -import { DisplayEditComponent } from './operations/display-edit/display-edit.component'; -import { BooleanValueComponent } from './values/boolean-value/boolean-value.component'; -import { DecimalValueComponent } from './values/decimal-value/decimal-value.component'; -import { UriValueComponent } from './values/uri-value/uri-value.component'; +import {IntValueComponent} from './values/int-value/int-value.component'; +import {DisplayEditComponent} from './operations/display-edit/display-edit.component'; +import {BooleanValueComponent} from './values/boolean-value/boolean-value.component'; +import {DecimalValueComponent} from './values/decimal-value/decimal-value.component'; +import {UriValueComponent} from './values/uri-value/uri-value.component'; import {IntervalValueComponent} from './values/interval-value/interval-value.component'; import {IntervalInputComponent} from './values/interval-value/interval-input/interval-input.component'; +import {DateValueComponent} from './values/date-value/date-value.component'; +import {MatDatepickerModule} from '@angular/material'; +import {MatJDNConvertibleCalendarDateAdapterModule} from 'jdnconvertiblecalendardateadapter'; +import { JDNDatepickerDirective } from './values/date-value/jdn-datepicker-directive/jdndatepicker.directive'; @NgModule({ - declarations: [TextValueAsStringComponent, IntValueComponent, DisplayEditComponent, BooleanValueComponent, DecimalValueComponent, UriValueComponent, IntervalValueComponent, IntervalInputComponent], + declarations: [TextValueAsStringComponent, IntValueComponent, DisplayEditComponent, BooleanValueComponent, DecimalValueComponent, UriValueComponent, IntervalValueComponent, IntervalInputComponent, DateValueComponent, JDNDatepickerDirective], imports: [ CommonModule, ReactiveFormsModule, MatInputModule, - MatCheckboxModule + MatCheckboxModule, + MatDatepickerModule, + MatJDNConvertibleCalendarDateAdapterModule ], - exports: [TextValueAsStringComponent, IntValueComponent, DisplayEditComponent, BooleanValueComponent, DecimalValueComponent, UriValueComponent, IntervalValueComponent] + exports: [TextValueAsStringComponent, IntValueComponent, DisplayEditComponent, BooleanValueComponent, DecimalValueComponent, UriValueComponent, IntervalValueComponent, DateValueComponent, JDNDatepickerDirective] }) export class ViewerModule { } diff --git a/src/app/app.component.html b/src/app/app.component.html index 2c6c41133..f80ef2fea 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,3 +1,11 @@ +
diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 2f3ed3190..7042ea9af 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,4 +1,4 @@ -import {AfterViewInit, Component, Inject, OnInit, ViewChild} from '@angular/core'; +import {AfterViewInit, Component, Inject, OnInit, QueryList, ViewChild, ViewChildren} from '@angular/core'; import {ApiResponseData, KnoraApiConnection, LoginResponse, ReadResource, ReadValue} from '@knora/api'; import {mergeMap} from 'rxjs/operators'; import {DisplayEditComponent} from 'knora-ui/lib/viewer/operations/display-edit/display-edit.component'; @@ -9,13 +9,14 @@ import {KnoraApiConnectionToken} from 'knora-ui'; templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) -export class AppComponent implements OnInit { - @ViewChild('displayEdit', {static: false}) displayEditComponent: DisplayEditComponent; +export class AppComponent implements OnInit, AfterViewInit { + @ViewChildren('displayEdit') displayEditComponents: QueryList; title = 'knora-ui-ng-lib'; testthing: ReadResource; testValue: ReadValue; + properties: string[]; constructor(@Inject(KnoraApiConnectionToken) private knoraApiConnection: KnoraApiConnection) { } @@ -31,11 +32,18 @@ export class AppComponent implements OnInit { ).subscribe( (resource: ReadResource) => { this.testthing = resource; - // console.log(this.testthing); - this.testValue = this.testthing.getValues('http://0.0.0.0:3333/ontology/0001/anything/v2#hasInterval')[0]; + + this.properties = Object.keys(this.testthing.properties); + console.log(this.testthing); + this.testValue = this.testthing.getValues('http://0.0.0.0:3333/ontology/0001/anything/v2#hasDate')[0]; + console.log(this.testValue); } ); } + ngAfterViewInit(): void { + console.log(this.displayEditComponents); + } + } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index e15d50713..cf20c6beb 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -6,6 +6,7 @@ import { AppComponent } from './app.component'; import { KnoraApiConfigToken, KnoraApiConnectionToken, KuiConfigToken, ViewerModule} from 'knora-ui'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {AppInitService} from './app-init.service'; +import {MatJDNConvertibleCalendarDateAdapterModule} from 'jdnconvertiblecalendardateadapter'; export function initializeApp(appInitService: AppInitService) { return (): Promise => { @@ -21,7 +22,8 @@ export function initializeApp(appInitService: AppInitService) { BrowserModule, BrowserAnimationsModule, AppRoutingModule, - ViewerModule + ViewerModule, + MatJDNConvertibleCalendarDateAdapterModule ], providers: [ AppInitService, diff --git a/yalc.lock b/yalc.lock index 21bd1b0c0..0a01af5c3 100644 --- a/yalc.lock +++ b/yalc.lock @@ -2,7 +2,7 @@ "version": "v1", "packages": { "@knora/api": { - "signature": "cbf63807338d8cbc462923ad349eb3b4", + "signature": "d13352b37d1c81a041bdcbd0e77d7b23", "file": true } } From 6d6f3d2a1ef6566ae1589846698e918d3875db84 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Tue, 25 Feb 2020 15:34:01 +0100 Subject: [PATCH 02/60] feature (value): add component for date input --- .../date-input/date-input.component.html | 7 + .../date-input/date-input.component.scss | 0 .../date-input/date-input.component.spec.ts | 25 +++ .../date-input/date-input.component.ts | 201 ++++++++++++++++++ .../date-value/date-value.component.html | 6 +- .../values/date-value/date-value.component.ts | 13 +- .../jdndatepicker.directive.ts | 1 - .../interval-input.component.ts | 2 +- .../knora-ui/src/lib/viewer/viewer.module.ts | 3 +- 9 files changed, 251 insertions(+), 7 deletions(-) create mode 100644 projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html create mode 100644 projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.scss create mode 100644 projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts create mode 100644 projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html new file mode 100644 index 000000000..4bc0051aa --- /dev/null +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html @@ -0,0 +1,7 @@ +
+ + + + + +
diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.scss b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts new file mode 100644 index 000000000..2c9749dc4 --- /dev/null +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DateInputComponent } from './date-input.component'; + +describe('DateInputComponent', () => { + let component: DateInputComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ DateInputComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DateInputComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts new file mode 100644 index 000000000..1eeb02fa7 --- /dev/null +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts @@ -0,0 +1,201 @@ +import {Component, DoCheck, ElementRef, HostBinding, Input, OnDestroy, Optional, Self} from '@angular/core'; +import {ControlValueAccessor, FormBuilder, FormControl, FormGroup, FormGroupDirective, NgControl, NgForm, Validators} from '@angular/forms'; +import {MatFormFieldControl} from '@angular/material/form-field'; +import {KnoraDate, KnoraPeriod} from '@knora/api'; +import {CanUpdateErrorState, CanUpdateErrorStateCtor, ErrorStateMatcher, mixinErrorState} from '@angular/material/core'; +import {Subject} from 'rxjs'; +import {coerceBooleanProperty} from '@angular/cdk/coercion'; +import {FocusMonitor} from '@angular/cdk/a11y'; +import {JDNConvertibleCalendarModule} from 'jdnconvertiblecalendar/dist/src/JDNConvertibleCalendar'; +import GregorianCalendarDate = JDNConvertibleCalendarModule.GregorianCalendarDate; +import CalendarPeriod = JDNConvertibleCalendarModule.CalendarPeriod; +import {CalendarDate} from 'jdnconvertiblecalendar'; + +/** Error when invalid control is dirty, touched, or submitted. */ +export class DateInputErrorStateMatcher implements ErrorStateMatcher { + isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { + const isSubmitted = form && form.submitted; + return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted)); + } +} + +class MatInputBase { + constructor(public _defaultErrorStateMatcher: ErrorStateMatcher, + public _parentForm: NgForm, + public _parentFormGroup: FormGroupDirective, + public ngControl: NgControl) {} +} +const _MatInputMixinBase: CanUpdateErrorStateCtor & typeof MatInputBase = + mixinErrorState(MatInputBase); + +@Component({ + selector: 'kui-date-input', + templateUrl: './date-input.component.html', + styleUrls: ['./date-input.component.scss'], + providers: [{provide: MatFormFieldControl, useExisting: DateInputComponent}] +}) +export class DateInputComponent extends _MatInputMixinBase implements ControlValueAccessor, MatFormFieldControl, DoCheck, CanUpdateErrorState, OnDestroy { + + static nextId = 0; + + form: FormGroup; + stateChanges = new Subject(); + @HostBinding() id = `kui-date-input-${DateInputComponent.nextId++}`; + focused = false; + errorState = false; + controlType = 'kui-date-input'; + matcher = new DateInputErrorStateMatcher(); + + onChange = (_: any) => {}; + onTouched = () => {}; + + get empty() { + const userInput = this.form.value; + return !userInput.start && !userInput.end; + } + + @HostBinding('class.floating') + get shouldLabelFloat() { + return this.focused || !this.empty; + } + + @Input() + get required() { + return this._required; + } + + set required(req) { + this._required = coerceBooleanProperty(req); + this.stateChanges.next(); + } + + private _required = false; + + @Input() + get disabled(): boolean { + return this._disabled; + } + + set disabled(value: boolean) { + this._disabled = coerceBooleanProperty(value); + this._disabled ? this.form.disable() : this.form.enable(); + this.stateChanges.next(); + } + + private _disabled = false; + + @Input() + get placeholder() { + return this._placeholder; + } + + set placeholder(plh) { + this._placeholder = plh; + this.stateChanges.next(); + } + + private _placeholder: string; + + @Input() readonly = false; + + @HostBinding('attr.aria-describedby') describedBy = ''; + + setDescribedByIds(ids: string[]) { + this.describedBy = ids.join(' '); + } + + @Input() + get value(): KnoraDate | KnoraPeriod | null { + const userInput = this.form.value; + if (userInput.datestring !== null) { + return new KnoraDate('GREGORIAN', 'CE', 20, 1, 1); + } + return null; + } + + set value(date: KnoraDate | KnoraPeriod | null) { + console.log(date); + if (date !== null) { + if (date instanceof KnoraDate) { + console.log('single date'); + // single date + // set correct calendar + const calendarDate = new CalendarDate(date.year, date.month, date.day); + this.form.setValue({date: new GregorianCalendarDate(new CalendarPeriod(calendarDate, calendarDate))}); + } else { + // period + console.log('period'); + this.form.setValue({date: null}); + } + } else { + this.form.setValue({date: null}); + } + this.stateChanges.next(); + } + + @Input() errorStateMatcher: ErrorStateMatcher; + + constructor(fb: FormBuilder, + @Optional() @Self() public ngControl: NgControl, + private fm: FocusMonitor, + private elRef: ElementRef, + @Optional() _parentForm: NgForm, + @Optional() _parentFormGroup: FormGroupDirective, + _defaultErrorStateMatcher: ErrorStateMatcher) { + + super(_defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl); + + + + this.form = fb.group({ + date: [null, Validators.required] + }); + + + fm.monitor(elRef.nativeElement, true).subscribe(origin => { + this.focused = !!origin; + this.stateChanges.next(); + }); + + if (this.ngControl != null) { + this.ngControl.valueAccessor = this; + } + } + + ngDoCheck() { + if (this.ngControl) { + this.updateErrorState(); + } + } + + ngOnDestroy() { + this.stateChanges.complete(); + } + + onContainerClick(event: MouseEvent) { + if ((event.target as Element).tagName.toLowerCase() != 'input') { + this.elRef.nativeElement.querySelector('input').focus(); + } + } + + writeValue(date: KnoraDate | KnoraPeriod | null): void { + this.value = date; + } + + registerOnChange(fn: any): void { + this.onChange = fn; + } + + registerOnTouched(fn: any): void { + this.onTouched = fn; + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + } + + _handleInput(): void { + this.onChange(this.value); + } + +} diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html index d370674c0..2820447ab 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html @@ -1,8 +1,8 @@ - - - + + +
diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts index 99ea5b25c..35ce02865 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts @@ -9,10 +9,19 @@ import { UpdateDateValue, UpdateIntValue } from '@knora/api'; -import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms'; +import {FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm, Validators} from '@angular/forms'; import {Subscription} from 'rxjs'; import {CustomRegex} from '../custom-regex'; import {BaseValueComponent} from '../base-value.component'; +import {ErrorStateMatcher} from '@angular/material'; + +/** Error when invalid control is dirty, touched, or submitted. */ +export class IntervalErrorStateMatcher implements ErrorStateMatcher { + isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { + const isSubmitted = form && form.submitted; + return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted)); + } +} @Component({ selector: 'kui-date-value', @@ -32,6 +41,8 @@ export class DateValueComponent extends BaseValueComponent implements OnInit, On customValidators = []; + matcher = new IntervalErrorStateMatcher(); + constructor(@Inject(FormBuilder) private fb: FormBuilder) { super(); } diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts b/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts index 4e0a4f7fb..a7b7e122c 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts @@ -10,7 +10,6 @@ import {JDNConvertibleCalendarDateAdapter} from 'jdnconvertiblecalendardateadapt export class JDNDatepickerDirective { constructor(private adapter: DateAdapter) { - console.log(this.adapter) } } diff --git a/projects/knora-ui/src/lib/viewer/values/interval-value/interval-input/interval-input.component.ts b/projects/knora-ui/src/lib/viewer/values/interval-value/interval-input/interval-input.component.ts index f06044ca6..a206334da 100644 --- a/projects/knora-ui/src/lib/viewer/values/interval-value/interval-input/interval-input.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/interval-value/interval-input/interval-input.component.ts @@ -41,7 +41,7 @@ const _MatInputMixinBase: CanUpdateErrorStateCtor & typeof MatInputBase = selector: 'kui-interval-input', templateUrl: './interval-input.component.html', styleUrls: ['./interval-input.component.scss'], - providers: [{provide: MatFormFieldControl, useExisting: IntervalInputComponent}], + providers: [{provide: MatFormFieldControl, useExisting: IntervalInputComponent}] }) export class IntervalInputComponent extends _MatInputMixinBase implements ControlValueAccessor, MatFormFieldControl, DoCheck, CanUpdateErrorState, OnDestroy { static nextId = 0; diff --git a/projects/knora-ui/src/lib/viewer/viewer.module.ts b/projects/knora-ui/src/lib/viewer/viewer.module.ts index 409b2297a..c2b7bb1de 100644 --- a/projects/knora-ui/src/lib/viewer/viewer.module.ts +++ b/projects/knora-ui/src/lib/viewer/viewer.module.ts @@ -15,9 +15,10 @@ import {DateValueComponent} from './values/date-value/date-value.component'; import {MatDatepickerModule} from '@angular/material'; import {MatJDNConvertibleCalendarDateAdapterModule} from 'jdnconvertiblecalendardateadapter'; import { JDNDatepickerDirective } from './values/date-value/jdn-datepicker-directive/jdndatepicker.directive'; +import { DateInputComponent } from './values/date-value/date-input/date-input.component'; @NgModule({ - declarations: [TextValueAsStringComponent, IntValueComponent, DisplayEditComponent, BooleanValueComponent, DecimalValueComponent, UriValueComponent, IntervalValueComponent, IntervalInputComponent, DateValueComponent, JDNDatepickerDirective], + declarations: [TextValueAsStringComponent, IntValueComponent, DisplayEditComponent, BooleanValueComponent, DecimalValueComponent, UriValueComponent, IntervalValueComponent, IntervalInputComponent, DateValueComponent, JDNDatepickerDirective, DateInputComponent], imports: [ CommonModule, ReactiveFormsModule, From 932968550248e46d0c7990bad6538e4f10f739a0 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Wed, 26 Feb 2020 08:52:16 +0100 Subject: [PATCH 03/60] feature (value): write updated date to Knora --- .../date-input/date-input.component.html | 2 +- .../date-input/date-input.component.ts | 9 +++---- .../values/date-value/date-value.component.ts | 26 +++++++++---------- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html index 4bc0051aa..02ef06622 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html @@ -1,6 +1,6 @@
- + diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts index 1eeb02fa7..0fb99fc27 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts @@ -107,24 +107,21 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal @Input() get value(): KnoraDate | KnoraPeriod | null { const userInput = this.form.value; - if (userInput.datestring !== null) { - return new KnoraDate('GREGORIAN', 'CE', 20, 1, 1); + if (userInput.date !== null) { + return new KnoraDate(userInput.date.calendarName.toUpperCase(), 'CE', userInput.date.calendarStart.year, userInput.date.calendarStart.month, userInput.date.calendarStart.day); } return null; } set value(date: KnoraDate | KnoraPeriod | null) { - console.log(date); if (date !== null) { if (date instanceof KnoraDate) { - console.log('single date'); // single date - // set correct calendar + // TODO: set correct calendar const calendarDate = new CalendarDate(date.year, date.month, date.day); this.form.setValue({date: new GregorianCalendarDate(new CalendarPeriod(calendarDate, calendarDate))}); } else { // period - console.log('period'); this.form.setValue({date: null}); } } else { diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts index 35ce02865..514ae5ae5 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts @@ -1,17 +1,7 @@ import {Component, Inject, Input, OnChanges, OnDestroy, OnInit, SimpleChanges} from '@angular/core'; -import { - CreateDateValue, - CreateIntValue, - KnoraDate, - KnoraPeriod, - ReadDateValue, - ReadIntValue, - UpdateDateValue, - UpdateIntValue -} from '@knora/api'; -import {FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm, Validators} from '@angular/forms'; +import {CreateDateValue, KnoraDate, KnoraPeriod, ReadDateValue, UpdateDateValue} from '@knora/api'; +import {FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm} from '@angular/forms'; import {Subscription} from 'rxjs'; -import {CustomRegex} from '../custom-regex'; import {BaseValueComponent} from '../base-value.component'; import {ErrorStateMatcher} from '@angular/material'; @@ -110,7 +100,17 @@ export class DateValueComponent extends BaseValueComponent implements OnInit, On updatedDateValue.id = this.displayValue.id; - // updatedDateValue.int = this.valueFormControl.value; + console.log(this.valueFormControl.value) + + updatedDateValue.calendar = (this.valueFormControl.value as KnoraDate).calendar; + updatedDateValue.startEra = (this.valueFormControl.value as KnoraDate).era; + updatedDateValue.startDay = (this.valueFormControl.value as KnoraDate).day; + updatedDateValue.startMonth = (this.valueFormControl.value as KnoraDate).month; + updatedDateValue.startYear = (this.valueFormControl.value as KnoraDate).year; + updatedDateValue.endEra = updatedDateValue.startEra; + updatedDateValue.endDay = updatedDateValue.startDay; + updatedDateValue.endMonth = updatedDateValue.startMonth; + updatedDateValue.endYear = updatedDateValue.startYear; // add the submitted comment to updatedIntValue only if user has added a comment if (this.commentFormControl.value !== null && this.commentFormControl.value !== '') { From fc972750432abbbba95bffda3294f4d66b0ad344 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Wed, 26 Feb 2020 14:59:10 +0100 Subject: [PATCH 04/60] feature (value): handle single dates and periods correctly --- .../date-input/date-input.component.html | 11 +++- .../date-input/date-input.component.ts | 60 +++++++++++++++---- .../values/date-value/date-value.component.ts | 48 +++++++++++---- 3 files changed, 92 insertions(+), 27 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html index 02ef06622..e13fd7dce 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html @@ -1,7 +1,12 @@
- - - + + + + + + + +
diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts index 0fb99fc27..c6b1c792e 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts @@ -7,9 +7,9 @@ import {Subject} from 'rxjs'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; import {FocusMonitor} from '@angular/cdk/a11y'; import {JDNConvertibleCalendarModule} from 'jdnconvertiblecalendar/dist/src/JDNConvertibleCalendar'; +import {CalendarDate} from 'jdnconvertiblecalendar'; import GregorianCalendarDate = JDNConvertibleCalendarModule.GregorianCalendarDate; import CalendarPeriod = JDNConvertibleCalendarModule.CalendarPeriod; -import {CalendarDate} from 'jdnconvertiblecalendar'; /** Error when invalid control is dirty, touched, or submitted. */ export class DateInputErrorStateMatcher implements ErrorStateMatcher { @@ -23,8 +23,10 @@ class MatInputBase { constructor(public _defaultErrorStateMatcher: ErrorStateMatcher, public _parentForm: NgForm, public _parentFormGroup: FormGroupDirective, - public ngControl: NgControl) {} + public ngControl: NgControl) { + } } + const _MatInputMixinBase: CanUpdateErrorStateCtor & typeof MatInputBase = mixinErrorState(MatInputBase); @@ -46,8 +48,12 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal controlType = 'kui-date-input'; matcher = new DateInputErrorStateMatcher(); - onChange = (_: any) => {}; - onTouched = () => {}; + period: boolean; + + onChange = (_: any) => { + }; + onTouched = () => { + }; get empty() { const userInput = this.form.value; @@ -107,25 +113,53 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal @Input() get value(): KnoraDate | KnoraPeriod | null { const userInput = this.form.value; - if (userInput.date !== null) { - return new KnoraDate(userInput.date.calendarName.toUpperCase(), 'CE', userInput.date.calendarStart.year, userInput.date.calendarStart.month, userInput.date.calendarStart.day); + if (!this.period) { + // single date + if (userInput.dateStart !== null) { + return new KnoraDate(userInput.dateStart.calendarName.toUpperCase(), 'CE', userInput.dateStart.calendarStart.year, userInput.dateStart.calendarStart.month, userInput.dateStart.calendarStart.day); + } else { + return null; + } + } else { + // period + if (userInput.dateStart !== null && userInput.dateEnd !== null) { + const start = new KnoraDate(userInput.dateStart.calendarName.toUpperCase(), 'CE', userInput.dateStart.calendarStart.year, userInput.dateStart.calendarStart.month, userInput.dateStart.calendarStart.day); + const end = new KnoraDate(userInput.dateEnd.calendarName.toUpperCase(), 'CE', userInput.dateEnd.calendarStart.year, userInput.dateEnd.calendarStart.month, userInput.dateEnd.calendarStart.day); + return new KnoraPeriod(start, end); + } else { + return null; + } } - return null; } - set value(date: KnoraDate | KnoraPeriod | null) { + set value(date: KnoraDate | KnoraPeriod | null) { if (date !== null) { if (date instanceof KnoraDate) { // single date // TODO: set correct calendar const calendarDate = new CalendarDate(date.year, date.month, date.day); - this.form.setValue({date: new GregorianCalendarDate(new CalendarPeriod(calendarDate, calendarDate))}); + this.form.setValue({ + dateStart: new GregorianCalendarDate(new CalendarPeriod(calendarDate, calendarDate)), + dateEnd: null + }); + this.period = false; } else { // period - this.form.setValue({date: null}); + const period = (date as KnoraPeriod); + const calendarDateStart = new CalendarDate(period.start.year, period.start.month, period.start.day); + const calendarDateEnd = new CalendarDate(period.end.year, period.end.month, period.end.day); + + this.form.setValue({ + dateStart: new GregorianCalendarDate(new CalendarPeriod(calendarDateStart, calendarDateStart)), + dateEnd: new GregorianCalendarDate(new CalendarPeriod(calendarDateEnd, calendarDateEnd)) + }); + + this.period = true; } } else { - this.form.setValue({date: null}); + this.form.setValue({dateStart: null, dateEnd: null}); + + this.period = false; } this.stateChanges.next(); } @@ -143,9 +177,9 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal super(_defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl); - this.form = fb.group({ - date: [null, Validators.required] + dateStart: [null, Validators.required], + dateEnd: [null] }); diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts index 514ae5ae5..242f5e842 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts @@ -100,17 +100,43 @@ export class DateValueComponent extends BaseValueComponent implements OnInit, On updatedDateValue.id = this.displayValue.id; - console.log(this.valueFormControl.value) - - updatedDateValue.calendar = (this.valueFormControl.value as KnoraDate).calendar; - updatedDateValue.startEra = (this.valueFormControl.value as KnoraDate).era; - updatedDateValue.startDay = (this.valueFormControl.value as KnoraDate).day; - updatedDateValue.startMonth = (this.valueFormControl.value as KnoraDate).month; - updatedDateValue.startYear = (this.valueFormControl.value as KnoraDate).year; - updatedDateValue.endEra = updatedDateValue.startEra; - updatedDateValue.endDay = updatedDateValue.startDay; - updatedDateValue.endMonth = updatedDateValue.startMonth; - updatedDateValue.endYear = updatedDateValue.startYear; + console.log(this.valueFormControl.value); + + const dateOrPeriod = this.valueFormControl.value; + + if (dateOrPeriod instanceof KnoraDate) { + + updatedDateValue.calendar = dateOrPeriod.calendar; + updatedDateValue.startEra = dateOrPeriod.era; + updatedDateValue.startDay = dateOrPeriod.day; + updatedDateValue.startMonth = dateOrPeriod.month; + updatedDateValue.startYear = dateOrPeriod.year; + + // TODO: handle precision correctly + + updatedDateValue.endEra = updatedDateValue.startEra; + updatedDateValue.endDay = updatedDateValue.startDay; + updatedDateValue.endMonth = updatedDateValue.startMonth; + updatedDateValue.endYear = updatedDateValue.startYear; + + } else if (dateOrPeriod instanceof KnoraPeriod) { + + updatedDateValue.calendar = dateOrPeriod.start.calendar; + + updatedDateValue.startEra = dateOrPeriod.start.era; + updatedDateValue.startDay = dateOrPeriod.start.day; + updatedDateValue.startMonth = dateOrPeriod.start.month; + updatedDateValue.startYear = dateOrPeriod.start.year; + + updatedDateValue.endEra = dateOrPeriod.end.era; + updatedDateValue.endDay = dateOrPeriod.end.day; + updatedDateValue.endMonth = dateOrPeriod.end.month; + updatedDateValue.endYear = dateOrPeriod.start.year; + + } else { + return false; + } + // add the submitted comment to updatedIntValue only if user has added a comment if (this.commentFormControl.value !== null && this.commentFormControl.value !== '') { From f304cda8374d452687960de6ef8e6dbf49d60af5 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Wed, 26 Feb 2020 18:21:04 +0100 Subject: [PATCH 05/60] feature (value): try to determine active calendar dynamically --- package.json | 6 +++--- .../date-value/date-input/date-input.component.html | 10 +++++++--- .../jdndatepicker.directive.ts | 12 ++++++++---- projects/knora-ui/src/lib/viewer/viewer.module.ts | 4 ++-- src/app/app.module.ts | 11 ++++++----- yalc.lock | 5 +++++ 6 files changed, 31 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 23c165b33..d27250226 100644 --- a/package.json +++ b/package.json @@ -24,11 +24,11 @@ "@angular/platform-browser-dynamic": "~8.2.14", "@angular/router": "~8.2.14", "@knora/api": "file:.yalc/@knora/api", + "jdnconvertiblecalendar": "^0.0.5", + "jdnconvertiblecalendardateadapter": "file:.yalc/jdnconvertiblecalendardateadapter", "rxjs": "~6.4.0", "tslib": "^1.10.0", - "zone.js": "~0.9.1", - "jdnconvertiblecalendar": "^0.0.5", - "jdnconvertiblecalendardateadapter": "^0.0.10" + "zone.js": "~0.9.1" }, "devDependencies": { "@angular-devkit/build-angular": "~0.803.20", diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html index e13fd7dce..3c8b278b8 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html @@ -1,12 +1,16 @@
+ + - - - + + + + +
diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts b/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts index a7b7e122c..ba5d84165 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts @@ -1,15 +1,19 @@ -import {Directive} from '@angular/core'; +import {Directive, Host, Inject} from '@angular/core'; import {DateAdapter, MAT_DATE_LOCALE} from '@angular/material'; import {JDNConvertibleCalendar} from 'jdnconvertiblecalendar'; -import {JDNConvertibleCalendarDateAdapter} from 'jdnconvertiblecalendardateadapter'; +import {ACTIVE_CALENDAR, JDNConvertibleCalendarDateAdapter} from 'jdnconvertiblecalendardateadapter'; +import {DateInputComponent} from '../date-input/date-input.component'; @Directive({ selector: 'kuiJDNDatepicker', - providers: [{provide: DateAdapter, useClass: JDNConvertibleCalendarDateAdapter, deps: [MAT_DATE_LOCALE]}] + providers: [ + {provide: DateAdapter, useClass: JDNConvertibleCalendarDateAdapter, deps: [MAT_DATE_LOCALE, ACTIVE_CALENDAR]}, + {provide: ACTIVE_CALENDAR, useValue: 'Gregorian'} + ] }) export class JDNDatepickerDirective { - constructor(private adapter: DateAdapter) { + constructor(@Host() dateInput: DateInputComponent, @Inject(ACTIVE_CALENDAR) activeCalendar, private adapter: DateAdapter) { } } diff --git a/projects/knora-ui/src/lib/viewer/viewer.module.ts b/projects/knora-ui/src/lib/viewer/viewer.module.ts index c2b7bb1de..e72bccb3b 100644 --- a/projects/knora-ui/src/lib/viewer/viewer.module.ts +++ b/projects/knora-ui/src/lib/viewer/viewer.module.ts @@ -14,8 +14,8 @@ import {IntervalInputComponent} from './values/interval-value/interval-input/int import {DateValueComponent} from './values/date-value/date-value.component'; import {MatDatepickerModule} from '@angular/material'; import {MatJDNConvertibleCalendarDateAdapterModule} from 'jdnconvertiblecalendardateadapter'; -import { JDNDatepickerDirective } from './values/date-value/jdn-datepicker-directive/jdndatepicker.directive'; -import { DateInputComponent } from './values/date-value/date-input/date-input.component'; +import {JDNDatepickerDirective} from './values/date-value/jdn-datepicker-directive/jdndatepicker.directive'; +import {DateInputComponent} from './values/date-value/date-input/date-input.component'; @NgModule({ declarations: [TextValueAsStringComponent, IntValueComponent, DisplayEditComponent, BooleanValueComponent, DecimalValueComponent, UriValueComponent, IntervalValueComponent, IntervalInputComponent, DateValueComponent, JDNDatepickerDirective, DateInputComponent], diff --git a/src/app/app.module.ts b/src/app/app.module.ts index cf20c6beb..2f447160b 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,9 +1,9 @@ -import { BrowserModule } from '@angular/platform-browser'; +import {BrowserModule} from '@angular/platform-browser'; import {APP_INITIALIZER, NgModule} from '@angular/core'; -import { AppRoutingModule } from './app-routing.module'; -import { AppComponent } from './app.component'; -import { KnoraApiConfigToken, KnoraApiConnectionToken, KuiConfigToken, ViewerModule} from 'knora-ui'; +import {AppRoutingModule} from './app-routing.module'; +import {AppComponent} from './app.component'; +import {KnoraApiConfigToken, KnoraApiConnectionToken, KuiConfigToken, ViewerModule} from 'knora-ui'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {AppInitService} from './app-init.service'; import {MatJDNConvertibleCalendarDateAdapterModule} from 'jdnconvertiblecalendardateadapter'; @@ -48,4 +48,5 @@ export function initializeApp(appInitService: AppInitService) { ], bootstrap: [AppComponent] }) -export class AppModule { } +export class AppModule { +} diff --git a/yalc.lock b/yalc.lock index 0a01af5c3..cf4b27d2c 100644 --- a/yalc.lock +++ b/yalc.lock @@ -4,6 +4,11 @@ "@knora/api": { "signature": "d13352b37d1c81a041bdcbd0e77d7b23", "file": true + }, + "jdnconvertiblecalendardateadapter": { + "signature": "73c2e9dc367482a2aebc91e7215366b3", + "file": true, + "replaced": "^0.0.10" } } } \ No newline at end of file From 051e9897e29795a4ed890c5d0a243b7b9a2021c8 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Tue, 10 Mar 2020 10:06:03 +0100 Subject: [PATCH 06/60] feature (value): set active calendar via directive (ongoing) --- package-lock.json | 4 +--- .../date-input/date-input.component.html | 8 +++---- .../date-input/date-input.component.ts | 12 +++++++++++ .../jdndatepicker.directive.ts | 21 ++++++++++++++----- yalc.lock | 2 +- 5 files changed, 34 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 49387cfc7..2da843c48 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6846,9 +6846,7 @@ "integrity": "sha512-/yBqMepJNHxy+yS4Llt0KQPsHGkMi1FVwcE77cpiJZh2RwoNyGBXOwFz4Am5FNZYBF3oiL39FMzHRwwf6yl6xg==" }, "jdnconvertiblecalendardateadapter": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/jdnconvertiblecalendardateadapter/-/jdnconvertiblecalendardateadapter-0.0.10.tgz", - "integrity": "sha512-qqbWdSe5owgGtRu24QV64IvR4zeE0icnVnRF9eC1Gz+L6wPmOpjPfUfkj+Hs/z14KK0/ADTl7HcslYbO0N2vtw==", + "version": "file:.yalc/jdnconvertiblecalendardateadapter", "requires": { "tslib": "^1.9.0" } diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html index 3c8b278b8..54c5fe300 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html @@ -1,16 +1,16 @@
- + - + - + - +
diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts index c6b1c792e..a2f021f73 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts @@ -49,6 +49,8 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal matcher = new DateInputErrorStateMatcher(); period: boolean; + startCalendarName = 'Gregorian'; + endCalendarName?; onChange = (_: any) => { }; @@ -138,11 +140,17 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal // single date // TODO: set correct calendar const calendarDate = new CalendarDate(date.year, date.month, date.day); + + // determine calendar + + this.form.setValue({ dateStart: new GregorianCalendarDate(new CalendarPeriod(calendarDate, calendarDate)), dateEnd: null }); this.period = false; + this.startCalendarName = this.form.controls.dateStart.value.calendarName; + this.endCalendarName = undefined; } else { // period const period = (date as KnoraPeriod); @@ -155,11 +163,15 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal }); this.period = true; + this.startCalendarName = this.form.controls.dateStart.value.calendarName; + this.endCalendarName = this.form.controls.dateEnd.value.calendarName; } } else { this.form.setValue({dateStart: null, dateEnd: null}); this.period = false; + this.startCalendarName = 'Gregorian'; + this.endCalendarName = undefined; } this.stateChanges.next(); } diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts b/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts index ba5d84165..d78ea3ab4 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts @@ -1,19 +1,30 @@ -import {Directive, Host, Inject} from '@angular/core'; +import {Directive, Host, Inject, Input, OnChanges} from '@angular/core'; import {DateAdapter, MAT_DATE_LOCALE} from '@angular/material'; import {JDNConvertibleCalendar} from 'jdnconvertiblecalendar'; import {ACTIVE_CALENDAR, JDNConvertibleCalendarDateAdapter} from 'jdnconvertiblecalendardateadapter'; import {DateInputComponent} from '../date-input/date-input.component'; +import {BehaviorSubject} from 'rxjs'; + +export function makeCalendarToken() { + return new BehaviorSubject('Gregorian'); +} @Directive({ - selector: 'kuiJDNDatepicker', + selector: 'kui-jdn-datepicker', providers: [ {provide: DateAdapter, useClass: JDNConvertibleCalendarDateAdapter, deps: [MAT_DATE_LOCALE, ACTIVE_CALENDAR]}, - {provide: ACTIVE_CALENDAR, useValue: 'Gregorian'} + {provide: ACTIVE_CALENDAR, useFactory: makeCalendarToken} ] }) -export class JDNDatepickerDirective { +export class JDNDatepickerDirective implements OnChanges { + + @Input() activeCalendar: 'Gregorian' | 'Julian' | 'Islamic'; + + constructor(@Host() dateInput: DateInputComponent, @Inject(ACTIVE_CALENDAR) private activeCalendarToken, private adapter: DateAdapter) { + } - constructor(@Host() dateInput: DateInputComponent, @Inject(ACTIVE_CALENDAR) activeCalendar, private adapter: DateAdapter) { + ngOnChanges(): void { + this.activeCalendarToken.next(this.activeCalendar); } } diff --git a/yalc.lock b/yalc.lock index cf4b27d2c..85addae7b 100644 --- a/yalc.lock +++ b/yalc.lock @@ -6,7 +6,7 @@ "file": true }, "jdnconvertiblecalendardateadapter": { - "signature": "73c2e9dc367482a2aebc91e7215366b3", + "signature": "bf9fbb4f18b1687cfade543bd6dc4eeb", "file": true, "replaced": "^0.0.10" } From 2752ae1b81132c3cd247d0e988e1482aa1525c49 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Tue, 10 Mar 2020 10:45:29 +0100 Subject: [PATCH 07/60] feature (values): add calendar header --- .../calendar-header.component.html | 1 + .../calendar-header.component.scss | 6 ++ .../calendar-header.component.spec.ts | 25 ++++++ .../calendar-header.component.ts | 80 +++++++++++++++++++ .../date-input/date-input.component.html | 4 +- .../date-input/date-input.component.ts | 15 +++- .../knora-ui/src/lib/viewer/viewer.module.ts | 8 +- 7 files changed, 133 insertions(+), 6 deletions(-) create mode 100644 projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.html create mode 100644 projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.scss create mode 100644 projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts create mode 100644 projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.ts diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.html new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.html @@ -0,0 +1 @@ + diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.scss b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.scss new file mode 100644 index 000000000..2bea1c416 --- /dev/null +++ b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.scss @@ -0,0 +1,6 @@ +:host { + .mat-select.kui-calendar-header { + margin: 16px 16px 0 16px !important; + width: calc(100% - 32px) !important; + } +} diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts new file mode 100644 index 000000000..454343c29 --- /dev/null +++ b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CalendarHeaderComponent } from './calendar-header.component'; + +describe('CalendarHeaderComponent', () => { + let component: CalendarHeaderComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CalendarHeaderComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CalendarHeaderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.ts new file mode 100644 index 000000000..823f30f62 --- /dev/null +++ b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.ts @@ -0,0 +1,80 @@ +/** Custom header component containing a calendar format switcher */ +import {JDNConvertibleCalendarDateAdapter} from 'jdnconvertiblecalendardateadapter'; +import {FormBuilder, FormGroup, Validators} from '@angular/forms'; +import {JDNConvertibleCalendar} from 'jdnconvertiblecalendar'; +import {MatCalendar, MatDatepickerContent} from '@angular/material/datepicker'; +import {DateAdapter} from '@angular/material/core'; +import {Component, Host, Inject, OnInit} from '@angular/core'; + +@Component({ + selector: 'kui-calendar-header', + template: ` + + {{cal}} + + + `, + styleUrls: ['./calendar-header.component.scss'] +}) +export class CalendarHeaderComponent implements OnInit { + constructor(@Host() private _calendar: MatCalendar, + private _dateAdapter: DateAdapter, + private _datepickerContent: MatDatepickerContent, + @Inject(FormBuilder) private fb: FormBuilder) { + } + + form: FormGroup; + + // a list of supported calendars (Gregorian and Julian) + supportedCalendarFormats = ['Gregorian', 'Julian']; + + // the currently active calendar + activeFormat; + + ngOnInit() { + + // get the currently active calendar format from the date adapter + if (this._dateAdapter instanceof JDNConvertibleCalendarDateAdapter) { + this.activeFormat = this._dateAdapter.activeCalendar; + } else { + console.log('date adapter is expected to be an instance of JDNConvertibleCalendarDateAdapter'); + } + + // build a form for the calendar format selection + this.form = this.fb.group({ + calendar: [this.activeFormat, Validators.required] + }); + + // do the conversion when the user selects another calendar format + this.form.valueChanges.subscribe((data) => { + // pass the target calendar format to the conversion method + this.convertDate(data.calendar); + }); + + } + + /** + * Converts the date into the target format. + * + * @param calendar the target calendar format. + */ + convertDate(calendar: 'Gregorian' | 'Julian') { + + if (this._dateAdapter instanceof JDNConvertibleCalendarDateAdapter) { + + // convert the date into the target calendar format + const convertedDate = this._dateAdapter.convertCalendar(this._calendar.activeDate, calendar); + + // set the new date + this._calendar.activeDate = convertedDate; + + // select the new date in the datepicker UI + this._datepickerContent.datepicker.select(convertedDate); + + // update view after calendar format conversion + this._calendar.updateTodaysDate(); + } else { + console.log('date adapter is expected to be an instance of JDNConvertibleCalendarDateAdapter'); + } + } +} diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html index 54c5fe300..260f9ced5 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html @@ -3,14 +3,14 @@ - + - +
diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts index a2f021f73..143b68dfd 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts @@ -7,9 +7,10 @@ import {Subject} from 'rxjs'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; import {FocusMonitor} from '@angular/cdk/a11y'; import {JDNConvertibleCalendarModule} from 'jdnconvertiblecalendar/dist/src/JDNConvertibleCalendar'; -import {CalendarDate} from 'jdnconvertiblecalendar'; +import {CalendarDate, JulianCalendarDate} from 'jdnconvertiblecalendar'; import GregorianCalendarDate = JDNConvertibleCalendarModule.GregorianCalendarDate; import CalendarPeriod = JDNConvertibleCalendarModule.CalendarPeriod; +import {CalendarHeaderComponent} from '../calendar-header/calendar-header.component'; /** Error when invalid control is dirty, touched, or submitted. */ export class DateInputErrorStateMatcher implements ErrorStateMatcher { @@ -48,6 +49,7 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal controlType = 'kui-date-input'; matcher = new DateInputErrorStateMatcher(); + calendarHeaderComponent = CalendarHeaderComponent; period: boolean; startCalendarName = 'Gregorian'; endCalendarName?; @@ -140,12 +142,19 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal // single date // TODO: set correct calendar const calendarDate = new CalendarDate(date.year, date.month, date.day); + let startDate; // determine calendar - + if (date.calendar === 'GREGORIAN') { + startDate = new GregorianCalendarDate(new CalendarPeriod(calendarDate, calendarDate)); + } else if (date.calendar === 'JULIAN') { + startDate = new JulianCalendarDate(new CalendarPeriod(calendarDate, calendarDate)); + } else { + throw new Error('Unsupported calendar: ' + date.calendar); + } this.form.setValue({ - dateStart: new GregorianCalendarDate(new CalendarPeriod(calendarDate, calendarDate)), + dateStart: startDate, dateEnd: null }); this.period = false; diff --git a/projects/knora-ui/src/lib/viewer/viewer.module.ts b/projects/knora-ui/src/lib/viewer/viewer.module.ts index e72bccb3b..26e08f697 100644 --- a/projects/knora-ui/src/lib/viewer/viewer.module.ts +++ b/projects/knora-ui/src/lib/viewer/viewer.module.ts @@ -16,17 +16,23 @@ import {MatDatepickerModule} from '@angular/material'; import {MatJDNConvertibleCalendarDateAdapterModule} from 'jdnconvertiblecalendardateadapter'; import {JDNDatepickerDirective} from './values/date-value/jdn-datepicker-directive/jdndatepicker.directive'; import {DateInputComponent} from './values/date-value/date-input/date-input.component'; +import { CalendarHeaderComponent } from './values/date-value/calendar-header/calendar-header.component'; +import {MatOptionModule} from "@angular/material/core"; +import {MatSelectModule} from "@angular/material/select"; @NgModule({ - declarations: [TextValueAsStringComponent, IntValueComponent, DisplayEditComponent, BooleanValueComponent, DecimalValueComponent, UriValueComponent, IntervalValueComponent, IntervalInputComponent, DateValueComponent, JDNDatepickerDirective, DateInputComponent], + declarations: [TextValueAsStringComponent, IntValueComponent, DisplayEditComponent, BooleanValueComponent, DecimalValueComponent, UriValueComponent, IntervalValueComponent, IntervalInputComponent, DateValueComponent, JDNDatepickerDirective, DateInputComponent, CalendarHeaderComponent], imports: [ CommonModule, ReactiveFormsModule, MatInputModule, MatCheckboxModule, + MatOptionModule, + MatSelectModule, MatDatepickerModule, MatJDNConvertibleCalendarDateAdapterModule ], + entryComponents: [CalendarHeaderComponent], exports: [TextValueAsStringComponent, IntValueComponent, DisplayEditComponent, BooleanValueComponent, DecimalValueComponent, UriValueComponent, IntervalValueComponent, DateValueComponent, JDNDatepickerDirective] }) export class ViewerModule { From 3e3cd54e555fe3ec9a4cb599384977af66bd7ddd Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Tue, 10 Mar 2020 10:48:38 +0100 Subject: [PATCH 08/60] refactor (values): rename variable --- .../date-value/calendar-header/calendar-header.component.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.ts index 823f30f62..16b82f23b 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.ts @@ -29,20 +29,20 @@ export class CalendarHeaderComponent implements OnInit { supportedCalendarFormats = ['Gregorian', 'Julian']; // the currently active calendar - activeFormat; + activeCal; ngOnInit() { // get the currently active calendar format from the date adapter if (this._dateAdapter instanceof JDNConvertibleCalendarDateAdapter) { - this.activeFormat = this._dateAdapter.activeCalendar; + this.activeCal = this._dateAdapter.activeCalendar; } else { console.log('date adapter is expected to be an instance of JDNConvertibleCalendarDateAdapter'); } // build a form for the calendar format selection this.form = this.fb.group({ - calendar: [this.activeFormat, Validators.required] + calendar: [this.activeCal, Validators.required] }); // do the conversion when the user selects another calendar format From b8463c3b2038f2c6e71c4b86fe0a55994d062a37 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Mon, 16 Mar 2020 11:10:48 +0100 Subject: [PATCH 09/60] refactor (value): unify use of jdndatepicker directive --- .../date-input/date-input.component.html | 8 ++-- .../jdndatepicker.directive.spec.ts | 2 +- .../jdndatepicker.directive.ts | 6 +-- .../jdndatepicker.directive.spec.ts | 8 ---- .../jdndatepicker.directive.ts | 15 -------- .../time-input/time-input.component.html | 2 + .../time-input/time-input.component.spec.ts | 37 +++++++++++-------- .../knora-ui/src/lib/viewer/viewer.module.ts | 9 ++--- 8 files changed, 36 insertions(+), 51 deletions(-) delete mode 100644 projects/knora-ui/src/lib/viewer/values/time-value/jdn-datepicker-directive/jdndatepicker.directive.spec.ts delete mode 100644 projects/knora-ui/src/lib/viewer/values/time-value/jdn-datepicker-directive/jdndatepicker.directive.ts diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html index 5ca37a874..260f9ced5 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html @@ -1,16 +1,16 @@
- + - + - + - +
diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.spec.ts index 2fbdebc2c..500e78c47 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.spec.ts @@ -1,4 +1,4 @@ -import { JDNDatepickerDirectiveComplex } from './jdndatepicker.directive'; +import { JDNDatepickerDirective } from './jdndatepicker.directive'; describe('JDNDatepickerDirective', () => { it('should create an instance', () => { diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts b/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts index 6d854971b..aa1777c92 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts @@ -10,17 +10,17 @@ export function makeCalendarToken() { } @Directive({ - selector: 'kui-jdn-datepicker-complex', + selector: 'kui-jdn-datepicker', providers: [ {provide: DateAdapter, useClass: JDNConvertibleCalendarDateAdapter, deps: [MAT_DATE_LOCALE, ACTIVE_CALENDAR]}, {provide: ACTIVE_CALENDAR, useFactory: makeCalendarToken} ] }) -export class JDNDatepickerDirectiveComplex implements OnChanges { +export class JDNDatepickerDirective implements OnChanges { @Input() activeCalendar: 'Gregorian' | 'Julian' | 'Islamic'; - constructor(@Host() dateInput: DateInputComponent, @Inject(ACTIVE_CALENDAR) private activeCalendarToken, private adapter: DateAdapter) { + constructor(@Inject(ACTIVE_CALENDAR) private activeCalendarToken, private adapter: DateAdapter) { } ngOnChanges(): void { diff --git a/projects/knora-ui/src/lib/viewer/values/time-value/jdn-datepicker-directive/jdndatepicker.directive.spec.ts b/projects/knora-ui/src/lib/viewer/values/time-value/jdn-datepicker-directive/jdndatepicker.directive.spec.ts deleted file mode 100644 index a33c2f0b3..000000000 --- a/projects/knora-ui/src/lib/viewer/values/time-value/jdn-datepicker-directive/jdndatepicker.directive.spec.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { JDNDatepickerDirective } from './jdndatepicker.directive'; - -describe('JDNDatepickerDirective', () => { - it('should create an instance', () => { - //const directive = new JDNDatepickerDirective(); - //expect(directive).toBeTruthy(); - }); -}); \ No newline at end of file diff --git a/projects/knora-ui/src/lib/viewer/values/time-value/jdn-datepicker-directive/jdndatepicker.directive.ts b/projects/knora-ui/src/lib/viewer/values/time-value/jdn-datepicker-directive/jdndatepicker.directive.ts deleted file mode 100644 index 44c50d4d5..000000000 --- a/projects/knora-ui/src/lib/viewer/values/time-value/jdn-datepicker-directive/jdndatepicker.directive.ts +++ /dev/null @@ -1,15 +0,0 @@ -import {Directive} from '@angular/core'; -import {DateAdapter, MAT_DATE_LOCALE} from '@angular/material'; -import {JDNConvertibleCalendar} from 'jdnconvertiblecalendar'; -import {JDNConvertibleCalendarDateAdapter} from 'jdnconvertiblecalendardateadapter'; - -@Directive({ - selector: 'kuiJDNDatepicker', - providers: [{provide: DateAdapter, useClass: JDNConvertibleCalendarDateAdapter, deps: [MAT_DATE_LOCALE]}] -}) -export class JDNDatepickerDirective { - - constructor(private adapter: DateAdapter) { - } - -} \ No newline at end of file diff --git a/projects/knora-ui/src/lib/viewer/values/time-value/time-input/time-input.component.html b/projects/knora-ui/src/lib/viewer/values/time-value/time-input/time-input.component.html index 13620d0ae..07bc2cc12 100644 --- a/projects/knora-ui/src/lib/viewer/values/time-value/time-input/time-input.component.html +++ b/projects/knora-ui/src/lib/viewer/values/time-value/time-input/time-input.component.html @@ -1,8 +1,10 @@
+ + diff --git a/projects/knora-ui/src/lib/viewer/values/time-value/time-input/time-input.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/time-value/time-input/time-input.component.spec.ts index 076e6b79e..aa7f9800e 100644 --- a/projects/knora-ui/src/lib/viewer/values/time-value/time-input/time-input.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/time-value/time-input/time-input.component.spec.ts @@ -1,14 +1,15 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; -import { TimeInputComponent, DateTime } from './time-input.component'; -import { Component, OnInit, ViewChild, DebugElement } from '@angular/core'; -import { FormGroup, FormBuilder, ReactiveFormsModule } from '@angular/forms'; -import { MatFormFieldModule, MatInputModule } from '@angular/material'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { By } from '@angular/platform-browser'; -import { MatDatepickerModule } from '@angular/material/datepicker' -import { GregorianCalendarDate, CalendarPeriod, CalendarDate } from 'jdnconvertiblecalendar'; -import { MatJDNConvertibleCalendarDateAdapterModule } from 'jdnconvertiblecalendardateadapter'; +import {TimeInputComponent, DateTime} from './time-input.component'; +import {Component, OnInit, ViewChild, DebugElement} from '@angular/core'; +import {FormGroup, FormBuilder, ReactiveFormsModule} from '@angular/forms'; +import {MatFormFieldModule, MatInputModule} from '@angular/material'; +import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; +import {By} from '@angular/platform-browser'; +import {MatDatepickerModule} from '@angular/material/datepicker' +import {GregorianCalendarDate, CalendarPeriod, CalendarDate} from 'jdnconvertiblecalendar'; +import {MatJDNConvertibleCalendarDateAdapterModule} from 'jdnconvertiblecalendardateadapter'; +import {JDNDatepickerDirective} from "../../date-value/jdn-datepicker-directive/jdndatepicker.directive"; /** @@ -54,8 +55,14 @@ describe('TimeInputComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ReactiveFormsModule, MatFormFieldModule, MatInputModule, MatDatepickerModule, MatJDNConvertibleCalendarDateAdapterModule, BrowserAnimationsModule], - declarations: [TimeInputComponent, TestHostComponent] + imports: [ + ReactiveFormsModule, + MatFormFieldModule, + MatInputModule, + MatDatepickerModule, + MatJDNConvertibleCalendarDateAdapterModule, + BrowserAnimationsModule], + declarations: [TimeInputComponent, TestHostComponent, JDNDatepickerDirective] }) .compileComponents(); })); @@ -84,7 +91,7 @@ describe('TimeInputComponent', () => { it('should initialize the date correctly', () => { expect(dateInputNativeElement.value).toEqual('06-08-2019'); - + expect(timeInputNativeElement.value).toEqual('14:00'); }); @@ -127,7 +134,7 @@ describe('TimeInputComponent', () => { expect(dateTime.date.toCalendarPeriod().periodStart.month).toEqual(10); expect(dateTime.date.toCalendarPeriod().periodStart.day).toEqual(10); - expect (dateTime.time).toEqual('12:00'); + expect(dateTime.time).toEqual('12:00'); }); -}); \ No newline at end of file +}); diff --git a/projects/knora-ui/src/lib/viewer/viewer.module.ts b/projects/knora-ui/src/lib/viewer/viewer.module.ts index bff61ff79..94a9e0b3a 100644 --- a/projects/knora-ui/src/lib/viewer/viewer.module.ts +++ b/projects/knora-ui/src/lib/viewer/viewer.module.ts @@ -18,14 +18,13 @@ import {TimeValueComponent} from './values/time-value/time-value.component'; import {TimeInputComponent} from './values/time-value/time-input/time-input.component'; import {MatDatepickerModule} from '@angular/material'; import {MatJDNConvertibleCalendarDateAdapterModule} from 'jdnconvertiblecalendardateadapter'; -import {JDNDatepickerDirective} from './values/time-value/jdn-datepicker-directive/jdndatepicker.directive'; import {ColorPickerComponent} from './values/color-value/color-picker/color-picker.component'; import {MatOptionModule} from "@angular/material/core"; import {MatSelectModule} from "@angular/material/select"; import {DateValueComponent} from "./values/date-value/date-value.component"; import {CalendarHeaderComponent} from "./values/date-value/calendar-header/calendar-header.component"; import {DateInputComponent} from "./values/date-value/date-input/date-input.component"; -import {JDNDatepickerDirectiveComplex} from "./values/date-value/jdn-datepicker-directive/jdndatepicker.directive"; +import {JDNDatepickerDirective} from "./values/date-value/jdn-datepicker-directive/jdndatepicker.directive"; @NgModule({ declarations: [ @@ -39,11 +38,10 @@ import {JDNDatepickerDirectiveComplex} from "./values/date-value/jdn-datepicker- IntervalInputComponent, TimeValueComponent, TimeInputComponent, - JDNDatepickerDirective, ColorValueComponent, ColorPickerComponent, DateValueComponent, - JDNDatepickerDirectiveComplex, + JDNDatepickerDirective, DateInputComponent, CalendarHeaderComponent ], @@ -68,7 +66,8 @@ import {JDNDatepickerDirectiveComplex} from "./values/date-value/jdn-datepicker- DecimalValueComponent, UriValueComponent, IntervalValueComponent, - TimeValueComponent + TimeValueComponent, + DateValueComponent ] }) From 95348f23d6a7d078ae515244a333b5ca83905698 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Mon, 16 Mar 2020 11:14:24 +0100 Subject: [PATCH 10/60] refactor (value): unify use of jdndatepicker directive --- .../jdn-datepicker-directive/jdndatepicker.directive.spec.ts | 0 .../jdn-datepicker-directive/jdndatepicker.directive.ts | 2 +- .../values/time-value/time-input/time-input.component.spec.ts | 2 +- projects/knora-ui/src/lib/viewer/viewer.module.ts | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename projects/knora-ui/src/lib/viewer/values/{date-value => }/jdn-datepicker-directive/jdndatepicker.directive.spec.ts (100%) rename projects/knora-ui/src/lib/viewer/values/{date-value => }/jdn-datepicker-directive/jdndatepicker.directive.ts (92%) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.spec.ts b/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.spec.ts similarity index 100% rename from projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.spec.ts rename to projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.spec.ts diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts b/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.ts similarity index 92% rename from projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts rename to projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.ts index aa1777c92..8b28e76cc 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/jdn-datepicker-directive/jdndatepicker.directive.ts +++ b/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.ts @@ -2,7 +2,7 @@ import {Directive, Host, Inject, Input, OnChanges} from '@angular/core'; import {DateAdapter, MAT_DATE_LOCALE} from '@angular/material'; import {JDNConvertibleCalendar} from 'jdnconvertiblecalendar'; import {ACTIVE_CALENDAR, JDNConvertibleCalendarDateAdapter} from 'jdnconvertiblecalendardateadapter'; -import {DateInputComponent} from '../date-input/date-input.component'; +import {DateInputComponent} from '../date-value/date-input/date-input.component'; import {BehaviorSubject} from 'rxjs'; export function makeCalendarToken() { diff --git a/projects/knora-ui/src/lib/viewer/values/time-value/time-input/time-input.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/time-value/time-input/time-input.component.spec.ts index aa7f9800e..49b3bece5 100644 --- a/projects/knora-ui/src/lib/viewer/values/time-value/time-input/time-input.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/time-value/time-input/time-input.component.spec.ts @@ -9,7 +9,7 @@ import {By} from '@angular/platform-browser'; import {MatDatepickerModule} from '@angular/material/datepicker' import {GregorianCalendarDate, CalendarPeriod, CalendarDate} from 'jdnconvertiblecalendar'; import {MatJDNConvertibleCalendarDateAdapterModule} from 'jdnconvertiblecalendardateadapter'; -import {JDNDatepickerDirective} from "../../date-value/jdn-datepicker-directive/jdndatepicker.directive"; +import {JDNDatepickerDirective} from "../../jdn-datepicker-directive/jdndatepicker.directive"; /** diff --git a/projects/knora-ui/src/lib/viewer/viewer.module.ts b/projects/knora-ui/src/lib/viewer/viewer.module.ts index 94a9e0b3a..7b9308aee 100644 --- a/projects/knora-ui/src/lib/viewer/viewer.module.ts +++ b/projects/knora-ui/src/lib/viewer/viewer.module.ts @@ -24,7 +24,7 @@ import {MatSelectModule} from "@angular/material/select"; import {DateValueComponent} from "./values/date-value/date-value.component"; import {CalendarHeaderComponent} from "./values/date-value/calendar-header/calendar-header.component"; import {DateInputComponent} from "./values/date-value/date-input/date-input.component"; -import {JDNDatepickerDirective} from "./values/date-value/jdn-datepicker-directive/jdndatepicker.directive"; +import {JDNDatepickerDirective} from "./values/jdn-datepicker-directive/jdndatepicker.directive"; @NgModule({ declarations: [ From 1f1b8470ec40ada7225950c1b958b39e97e6b158 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Mon, 16 Mar 2020 11:23:57 +0100 Subject: [PATCH 11/60] test (value): add test component for date --- .../display-edit/display-edit.component.spec.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/projects/knora-ui/src/lib/viewer/operations/display-edit/display-edit.component.spec.ts b/projects/knora-ui/src/lib/viewer/operations/display-edit/display-edit.component.spec.ts index 6e3a1df71..2b9f16a97 100644 --- a/projects/knora-ui/src/lib/viewer/operations/display-edit/display-edit.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/operations/display-edit/display-edit.component.spec.ts @@ -148,6 +148,16 @@ class TestColorValueComponent { @Input() displayValue; } +@Component({ + selector: `kui-date-value`, + template: `` +}) +class TestDateValueComponent { + @Input() mode; + + @Input() displayValue; +} + /** * Test host component to simulate parent component. */ @@ -208,7 +218,8 @@ describe('DisplayEditComponent', () => { TestUriValueComponent, TestDecimalValueComponent, TestTimeValueComponent, - TestColorValueComponent + TestColorValueComponent, + TestDateValueComponent ], providers: [ { From 9d558218a88efffc2a1e1b63faf81943bc5a6fc3 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Mon, 16 Mar 2020 12:16:25 +0100 Subject: [PATCH 12/60] chore (package.json): use new version of date adapter --- package-lock.json | 4 +++- package.json | 2 +- yalc.lock | 7 +------ 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 52da4adfc..54b4cafb8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6846,7 +6846,9 @@ "integrity": "sha512-/yBqMepJNHxy+yS4Llt0KQPsHGkMi1FVwcE77cpiJZh2RwoNyGBXOwFz4Am5FNZYBF3oiL39FMzHRwwf6yl6xg==" }, "jdnconvertiblecalendardateadapter": { - "version": "file:.yalc/jdnconvertiblecalendardateadapter", + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/jdnconvertiblecalendardateadapter/-/jdnconvertiblecalendardateadapter-0.0.12.tgz", + "integrity": "sha512-dQ1PNHH0LnUjj1ZYiWH7ELdMgd2RpQR1TpqDY2afC07lB61B+Y9Jmdu5mSppgOI5v8foJCxgt9uRsamRQ0ya3w==", "requires": { "tslib": "^1.9.0" } diff --git a/package.json b/package.json index 25565205e..ed52f2903 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "@angular/router": "~8.2.14", "@knora/api": "file:.yalc/@knora/api", "jdnconvertiblecalendar": "^0.0.5", - "jdnconvertiblecalendardateadapter": "file:.yalc/jdnconvertiblecalendardateadapter", + "jdnconvertiblecalendardateadapter": "^0.0.12", "ngx-color-picker": "^8.2.0", "rxjs": "~6.4.0", "tslib": "^1.10.0", diff --git a/yalc.lock b/yalc.lock index 85addae7b..f116b9f21 100644 --- a/yalc.lock +++ b/yalc.lock @@ -2,13 +2,8 @@ "version": "v1", "packages": { "@knora/api": { - "signature": "d13352b37d1c81a041bdcbd0e77d7b23", + "signature": "3208f93884cf4115a1c97ef116855f3f", "file": true - }, - "jdnconvertiblecalendardateadapter": { - "signature": "bf9fbb4f18b1687cfade543bd6dc4eeb", - "file": true, - "replaced": "^0.0.10" } } } \ No newline at end of file From 5f603d89921a77430d1c9ddc543742a715ec88d1 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Mon, 16 Mar 2020 16:24:26 +0100 Subject: [PATCH 13/60] test (value): add test calendar header --- .../calendar-header.component.spec.ts | 55 +++++++++++++++++-- .../calendar-header.component.ts | 22 ++++---- 2 files changed, 62 insertions(+), 15 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts index ea62c52d1..37d8bab4f 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts @@ -1,17 +1,44 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import {async, ComponentFixture, fakeAsync, flush, TestBed} from '@angular/core/testing'; -import { CalendarHeaderComponent } from './calendar-header.component'; -import {JDNConvertibleCalendarDateAdapter} from "jdnconvertiblecalendardateadapter"; +import {CalendarHeaderComponent} from './calendar-header.component'; +import {ACTIVE_CALENDAR, JDNConvertibleCalendarDateAdapter} from "jdnconvertiblecalendardateadapter"; +import {MatSelectModule} from "@angular/material/select"; +import {DateAdapter, MatOptionModule} from "@angular/material/core"; +import {ReactiveFormsModule} from "@angular/forms"; +import {MatCalendar, MatDatepickerContent} from "@angular/material/datepicker"; +import {BehaviorSubject} from "rxjs"; +import {Component} from "@angular/core"; +import {By} from "@angular/platform-browser"; + +@Component({ + selector: `mat-calendar-header`, + template: `` +}) +class TestMatCalendarHeaderComponent { + +} describe('CalendarHeaderComponent', () => { let component: CalendarHeaderComponent; let fixture: ComponentFixture>; + beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ CalendarHeaderComponent ] + imports: [ + ReactiveFormsModule, + MatSelectModule, + MatOptionModule + ], + declarations: [CalendarHeaderComponent, TestMatCalendarHeaderComponent], + providers: [ + {provide: MatCalendar, useValue: {}}, + {provide: DateAdapter, useValue: {}}, + {provide: ACTIVE_CALENDAR, useValue: new BehaviorSubject('Gregorian')}, + {provide: MatDatepickerContent, useValue: {}} + ] }) - .compileComponents(); + .compileComponents(); })); beforeEach(() => { @@ -23,4 +50,22 @@ describe('CalendarHeaderComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); + + it('should set Gregorian as the active calendar in the selection', fakeAsync(() => { + + // https://github.com/angular/components/blob/941b5a3529727f583b76068835e07e412e69f4f7/src/material/select/select.spec.ts#L1674-L1692 + component.formControl.setValue('Gregorian'); + fixture.detectChanges(); + flush(); + + expect(component.formControl.value).toEqual('Gregorian'); + + const compDe = fixture.debugElement; + + const selectDebugElement = compDe.query(By.css('.mat-select-value')); + + console.log(selectDebugElement); + + })); + }); diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.ts index 16b82f23b..1bbebb46a 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.ts @@ -1,6 +1,6 @@ /** Custom header component containing a calendar format switcher */ import {JDNConvertibleCalendarDateAdapter} from 'jdnconvertiblecalendardateadapter'; -import {FormBuilder, FormGroup, Validators} from '@angular/forms'; +import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms'; import {JDNConvertibleCalendar} from 'jdnconvertiblecalendar'; import {MatCalendar, MatDatepickerContent} from '@angular/material/datepicker'; import {DateAdapter} from '@angular/material/core'; @@ -9,8 +9,8 @@ import {Component, Host, Inject, OnInit} from '@angular/core'; @Component({ selector: 'kui-calendar-header', template: ` - - {{cal}} + + {{cal}} `, @@ -24,25 +24,27 @@ export class CalendarHeaderComponent implements OnInit { } form: FormGroup; + formControl: FormControl; // a list of supported calendars (Gregorian and Julian) - supportedCalendarFormats = ['Gregorian', 'Julian']; - - // the currently active calendar - activeCal; + supportedCalendars = ['Gregorian', 'Julian']; ngOnInit() { - // get the currently active calendar format from the date adapter + let activeCal; + + // get the currently active calendar from the date adapter if (this._dateAdapter instanceof JDNConvertibleCalendarDateAdapter) { - this.activeCal = this._dateAdapter.activeCalendar; + activeCal = this._dateAdapter.activeCalendar; } else { console.log('date adapter is expected to be an instance of JDNConvertibleCalendarDateAdapter'); } + this.formControl = new FormControl(activeCal, Validators.required); + // build a form for the calendar format selection this.form = this.fb.group({ - calendar: [this.activeCal, Validators.required] + calendar: this.formControl }); // do the conversion when the user selects another calendar format From 9228f68c1f17a3a61b863c9e88d6a96c28178319 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Mon, 16 Mar 2020 16:40:46 +0100 Subject: [PATCH 14/60] test (value): add test calendar header --- .../calendar-header.component.spec.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts index 37d8bab4f..9243739f1 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts @@ -4,7 +4,7 @@ import {CalendarHeaderComponent} from './calendar-header.component'; import {ACTIVE_CALENDAR, JDNConvertibleCalendarDateAdapter} from "jdnconvertiblecalendardateadapter"; import {MatSelectModule} from "@angular/material/select"; import {DateAdapter, MatOptionModule} from "@angular/material/core"; -import {ReactiveFormsModule} from "@angular/forms"; +import {FormControl, ReactiveFormsModule} from "@angular/forms"; import {MatCalendar, MatDatepickerContent} from "@angular/material/datepicker"; import {BehaviorSubject} from "rxjs"; import {Component} from "@angular/core"; @@ -33,7 +33,7 @@ describe('CalendarHeaderComponent', () => { declarations: [CalendarHeaderComponent, TestMatCalendarHeaderComponent], providers: [ {provide: MatCalendar, useValue: {}}, - {provide: DateAdapter, useValue: {}}, + {provide: DateAdapter, useClass: JDNConvertibleCalendarDateAdapter}, {provide: ACTIVE_CALENDAR, useValue: new BehaviorSubject('Gregorian')}, {provide: MatDatepickerContent, useValue: {}} ] @@ -53,18 +53,18 @@ describe('CalendarHeaderComponent', () => { it('should set Gregorian as the active calendar in the selection', fakeAsync(() => { + expect(component.formControl.value).toEqual('Gregorian'); + // https://github.com/angular/components/blob/941b5a3529727f583b76068835e07e412e69f4f7/src/material/select/select.spec.ts#L1674-L1692 - component.formControl.setValue('Gregorian'); + component.formControl = new FormControl('Gregorian'); fixture.detectChanges(); flush(); - expect(component.formControl.value).toEqual('Gregorian'); - const compDe = fixture.debugElement; const selectDebugElement = compDe.query(By.css('.mat-select-value')); - console.log(selectDebugElement); + expect(selectDebugElement.nativeElement.textContent).toEqual('Gregorian'); })); From ced59d508c0490a007579419c3559b159bf971a7 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Tue, 17 Mar 2020 07:55:38 +0100 Subject: [PATCH 15/60] test (value): add test calendar header --- .../calendar-header.component.spec.ts | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts index 9243739f1..c0bb9de90 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts @@ -7,8 +7,9 @@ import {DateAdapter, MatOptionModule} from "@angular/material/core"; import {FormControl, ReactiveFormsModule} from "@angular/forms"; import {MatCalendar, MatDatepickerContent} from "@angular/material/datepicker"; import {BehaviorSubject} from "rxjs"; -import {Component} from "@angular/core"; +import {Component, DebugElement} from "@angular/core"; import {By} from "@angular/platform-browser"; +import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; @Component({ selector: `mat-calendar-header`, @@ -28,7 +29,8 @@ describe('CalendarHeaderComponent', () => { imports: [ ReactiveFormsModule, MatSelectModule, - MatOptionModule + MatOptionModule, + BrowserAnimationsModule ], declarations: [CalendarHeaderComponent, TestMatCalendarHeaderComponent], providers: [ @@ -51,20 +53,34 @@ describe('CalendarHeaderComponent', () => { expect(component).toBeTruthy(); }); - it('should set Gregorian as the active calendar in the selection', fakeAsync(() => { + it('should init the selected value and options correctly', fakeAsync(() => { expect(component.formControl.value).toEqual('Gregorian'); // https://github.com/angular/components/blob/941b5a3529727f583b76068835e07e412e69f4f7/src/material/select/select.spec.ts#L1674-L1692 component.formControl = new FormControl('Gregorian'); fixture.detectChanges(); - flush(); const compDe = fixture.debugElement; - const selectDebugElement = compDe.query(By.css('.mat-select-value')); + const selectValueDebugElement = compDe.query(By.css('.mat-select-value')); + + const selectDebugElement = compDe.query(By.css('.mat-select')); + + expect(selectValueDebugElement.nativeElement.textContent).toEqual('Gregorian'); + + const trigger = compDe.query(By.css('.mat-select-trigger')).nativeElement; + trigger.click(); + fixture.detectChanges(); + flush(); + + const options: DebugElement[] = selectDebugElement.queryAll(By.css('mat-option')); + + expect(options.length).toEqual(2); + + expect(options[0].nativeElement.innerText).toEqual('Gregorian'); - expect(selectDebugElement.nativeElement.textContent).toEqual('Gregorian'); + expect(options[1].nativeElement.innerText).toEqual('Julian'); })); From 82f395aaa57c9aba8f4c62aa332d18412c9c799a Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Tue, 17 Mar 2020 09:06:25 +0100 Subject: [PATCH 16/60] test (value): add test calendar header --- .../calendar-header.component.spec.ts | 54 +++++++++++++++++-- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts index c0bb9de90..80270d3c0 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts @@ -1,4 +1,4 @@ -import {async, ComponentFixture, fakeAsync, flush, TestBed} from '@angular/core/testing'; +import {async, ComponentFixture, fakeAsync, flush, inject, TestBed} from '@angular/core/testing'; import {CalendarHeaderComponent} from './calendar-header.component'; import {ACTIVE_CALENDAR, JDNConvertibleCalendarDateAdapter} from "jdnconvertiblecalendardateadapter"; @@ -10,6 +10,10 @@ import {BehaviorSubject} from "rxjs"; import {Component, DebugElement} from "@angular/core"; import {By} from "@angular/platform-browser"; import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; +import {MAT_JDN_DATE_FORMATS} from "jdnconvertiblecalendardateadapter/lib/jdnconvertible-calendar-date-formats"; +import {JDNConvertibleCalendarModule} from "jdnconvertiblecalendar/dist/src/JDNConvertibleCalendar"; +import GregorianCalendarDate = JDNConvertibleCalendarModule.GregorianCalendarDate; +import {CalendarDate, CalendarPeriod, JulianCalendarDate} from "jdnconvertiblecalendar"; @Component({ selector: `mat-calendar-header`, @@ -23,7 +27,6 @@ describe('CalendarHeaderComponent', () => { let component: CalendarHeaderComponent; let fixture: ComponentFixture>; - beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ @@ -34,10 +37,22 @@ describe('CalendarHeaderComponent', () => { ], declarations: [CalendarHeaderComponent, TestMatCalendarHeaderComponent], providers: [ - {provide: MatCalendar, useValue: {}}, + { + provide: MatCalendar, useValue: { + activeDate: new GregorianCalendarDate(new CalendarPeriod(new CalendarDate(2020, 3, 17), new CalendarDate(2020, 3, 17))), + updateTodaysDate: () => {} + } + }, {provide: DateAdapter, useClass: JDNConvertibleCalendarDateAdapter}, {provide: ACTIVE_CALENDAR, useValue: new BehaviorSubject('Gregorian')}, - {provide: MatDatepickerContent, useValue: {}} + { + provide: MatDatepickerContent, useValue: { + datepicker: { + select: () => { + } + } + } + } ] }) .compileComponents(); @@ -84,4 +99,35 @@ describe('CalendarHeaderComponent', () => { })); + it('should perform a calendar conversion when the selection is changed', () => { + + const dateAdapter = TestBed.get(DateAdapter); + + const dateAdapterSpy = spyOn(dateAdapter, 'convertCalendar').and.callFake( + (date, calendar) => { + return new JulianCalendarDate(new CalendarPeriod(new CalendarDate(2020, 3, 4), new CalendarDate(2020, 3, 4))); + }); + + const matCal = TestBed.get(MatCalendar); + + const matCalendarSpy = spyOn(matCal, 'updateTodaysDate').and.stub(); + + const datepickerContent = TestBed.get(MatDatepickerContent); + + const datepickerContentSpy = spyOn(datepickerContent.datepicker, 'select').and.stub(); + + component.formControl.setValue('Julian'); + + expect(dateAdapterSpy).toHaveBeenCalledTimes(1); + + expect(dateAdapterSpy).toHaveBeenCalledWith(new GregorianCalendarDate(new CalendarPeriod(new CalendarDate(2020, 3, 17), new CalendarDate(2020, 3, 17))), 'Julian'); + + expect(matCal.activeDate).toEqual(new JulianCalendarDate(new CalendarPeriod(new CalendarDate(2020, 3, 4), new CalendarDate(2020, 3, 4)))); + + expect(datepickerContentSpy).toHaveBeenCalledTimes(1); + + expect(matCalendarSpy).toHaveBeenCalledTimes(1); + + }); + }); From fe26c8053232d1b64f9a0a585f3e8c7733e1df66 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Tue, 17 Mar 2020 09:28:29 +0100 Subject: [PATCH 17/60] test (value): add test calendar header --- .../calendar-header.component.spec.ts | 38 ++++++++++++------- .../calendar-header.component.ts | 14 +++++-- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts index 80270d3c0..4f8733394 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.spec.ts @@ -1,19 +1,18 @@ -import {async, ComponentFixture, fakeAsync, flush, inject, TestBed} from '@angular/core/testing'; +import {async, ComponentFixture, fakeAsync, flush, TestBed} from '@angular/core/testing'; import {CalendarHeaderComponent} from './calendar-header.component'; -import {ACTIVE_CALENDAR, JDNConvertibleCalendarDateAdapter} from "jdnconvertiblecalendardateadapter"; -import {MatSelectModule} from "@angular/material/select"; -import {DateAdapter, MatOptionModule} from "@angular/material/core"; -import {FormControl, ReactiveFormsModule} from "@angular/forms"; -import {MatCalendar, MatDatepickerContent} from "@angular/material/datepicker"; -import {BehaviorSubject} from "rxjs"; -import {Component, DebugElement} from "@angular/core"; -import {By} from "@angular/platform-browser"; -import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; -import {MAT_JDN_DATE_FORMATS} from "jdnconvertiblecalendardateadapter/lib/jdnconvertible-calendar-date-formats"; -import {JDNConvertibleCalendarModule} from "jdnconvertiblecalendar/dist/src/JDNConvertibleCalendar"; +import {ACTIVE_CALENDAR, JDNConvertibleCalendarDateAdapter} from 'jdnconvertiblecalendardateadapter'; +import {MatSelectModule} from '@angular/material/select'; +import {DateAdapter, MatOptionModule} from '@angular/material/core'; +import {FormControl, ReactiveFormsModule} from '@angular/forms'; +import {MatCalendar, MatDatepickerContent} from '@angular/material/datepicker'; +import {BehaviorSubject} from 'rxjs'; +import {Component, DebugElement} from '@angular/core'; +import {By} from '@angular/platform-browser'; +import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; +import {JDNConvertibleCalendarModule} from 'jdnconvertiblecalendar/dist/src/JDNConvertibleCalendar'; +import {CalendarDate, CalendarPeriod, JulianCalendarDate} from 'jdnconvertiblecalendar'; import GregorianCalendarDate = JDNConvertibleCalendarModule.GregorianCalendarDate; -import {CalendarDate, CalendarPeriod, JulianCalendarDate} from "jdnconvertiblecalendar"; @Component({ selector: `mat-calendar-header`, @@ -40,7 +39,8 @@ describe('CalendarHeaderComponent', () => { { provide: MatCalendar, useValue: { activeDate: new GregorianCalendarDate(new CalendarPeriod(new CalendarDate(2020, 3, 17), new CalendarDate(2020, 3, 17))), - updateTodaysDate: () => {} + updateTodaysDate: () => { + } } }, {provide: DateAdapter, useClass: JDNConvertibleCalendarDateAdapter}, @@ -130,4 +130,14 @@ describe('CalendarHeaderComponent', () => { }); + it('should unsubscribe from value changes subscription when the component is destroyed', () => { + + expect(component.valueChangesSubscription.closed).toEqual(false); + + component.ngOnDestroy(); + + expect(component.valueChangesSubscription.closed).toEqual(true); + + }); + }); diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.ts index 1bbebb46a..6078e8f12 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/calendar-header/calendar-header.component.ts @@ -4,7 +4,8 @@ import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms'; import {JDNConvertibleCalendar} from 'jdnconvertiblecalendar'; import {MatCalendar, MatDatepickerContent} from '@angular/material/datepicker'; import {DateAdapter} from '@angular/material/core'; -import {Component, Host, Inject, OnInit} from '@angular/core'; +import {Component, Host, Inject, OnDestroy, OnInit} from '@angular/core'; +import {Subscription} from "rxjs"; @Component({ selector: 'kui-calendar-header', @@ -16,7 +17,7 @@ import {Component, Host, Inject, OnInit} from '@angular/core'; `, styleUrls: ['./calendar-header.component.scss'] }) -export class CalendarHeaderComponent implements OnInit { +export class CalendarHeaderComponent implements OnInit, OnDestroy { constructor(@Host() private _calendar: MatCalendar, private _dateAdapter: DateAdapter, private _datepickerContent: MatDatepickerContent, @@ -25,6 +26,7 @@ export class CalendarHeaderComponent implements OnInit { form: FormGroup; formControl: FormControl; + valueChangesSubscription: Subscription; // a list of supported calendars (Gregorian and Julian) supportedCalendars = ['Gregorian', 'Julian']; @@ -48,13 +50,19 @@ export class CalendarHeaderComponent implements OnInit { }); // do the conversion when the user selects another calendar format - this.form.valueChanges.subscribe((data) => { + this.valueChangesSubscription = this.form.valueChanges.subscribe((data) => { // pass the target calendar format to the conversion method this.convertDate(data.calendar); }); } + ngOnDestroy(): void { + if (this.valueChangesSubscription !== undefined) { + this.valueChangesSubscription.unsubscribe(); + } + } + /** * Converts the date into the target format. * From 00b5cfb6d55bd2ae42471f0c63f944882b0c96d5 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Tue, 17 Mar 2020 10:56:07 +0100 Subject: [PATCH 18/60] feature (values): handle calendar initialization --- .../date-input/date-input.component.html | 4 ++-- .../date-input/date-input.component.ts | 18 ++++++++--------- .../values/date-value/date-value.component.ts | 2 -- .../jdndatepicker.directive.ts | 20 ++++++++++++++++--- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html index 260f9ced5..28d0a9afd 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html @@ -1,13 +1,13 @@
- + - + diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts index 143b68dfd..265908501 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts @@ -51,8 +51,8 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal calendarHeaderComponent = CalendarHeaderComponent; period: boolean; - startCalendarName = 'Gregorian'; - endCalendarName?; + startDateControl: FormControl; + endDateControl: FormControl; onChange = (_: any) => { }; @@ -157,9 +157,9 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal dateStart: startDate, dateEnd: null }); + this.period = false; - this.startCalendarName = this.form.controls.dateStart.value.calendarName; - this.endCalendarName = undefined; + } else { // period const period = (date as KnoraPeriod); @@ -172,15 +172,11 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal }); this.period = true; - this.startCalendarName = this.form.controls.dateStart.value.calendarName; - this.endCalendarName = this.form.controls.dateEnd.value.calendarName; } } else { this.form.setValue({dateStart: null, dateEnd: null}); this.period = false; - this.startCalendarName = 'Gregorian'; - this.endCalendarName = undefined; } this.stateChanges.next(); } @@ -197,10 +193,12 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal super(_defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl); + this.startDateControl = new FormControl(null, Validators.required); + this.endDateControl = new FormControl(null); this.form = fb.group({ - dateStart: [null, Validators.required], - dateEnd: [null] + dateStart: this.startDateControl, + dateEnd: this.endDateControl }); diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts index 242f5e842..30f7da5da 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts @@ -100,8 +100,6 @@ export class DateValueComponent extends BaseValueComponent implements OnInit, On updatedDateValue.id = this.displayValue.id; - console.log(this.valueFormControl.value); - const dateOrPeriod = this.valueFormControl.value; if (dateOrPeriod instanceof KnoraDate) { diff --git a/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.ts b/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.ts index 8b28e76cc..6690b5286 100644 --- a/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.ts +++ b/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.ts @@ -1,4 +1,4 @@ -import {Directive, Host, Inject, Input, OnChanges} from '@angular/core'; +import {Directive, Host, Inject, Input, OnChanges, SimpleChanges} from '@angular/core'; import {DateAdapter, MAT_DATE_LOCALE} from '@angular/material'; import {JDNConvertibleCalendar} from 'jdnconvertiblecalendar'; import {ACTIVE_CALENDAR, JDNConvertibleCalendarDateAdapter} from 'jdnconvertiblecalendardateadapter'; @@ -18,12 +18,26 @@ export function makeCalendarToken() { }) export class JDNDatepickerDirective implements OnChanges { - @Input() activeCalendar: 'Gregorian' | 'Julian' | 'Islamic'; + private _activeCalendar: 'Gregorian' | 'Julian' | 'Islamic'; + + @Input() + set activeCalendar(value: 'Gregorian' | 'Julian' | 'Islamic' | null) { + if (value !== null && value !== undefined) { + this._activeCalendar = value; + } else { + this._activeCalendar = 'Gregorian'; + } + } + + get activeCalendar() { + return this._activeCalendar; + } constructor(@Inject(ACTIVE_CALENDAR) private activeCalendarToken, private adapter: DateAdapter) { } - ngOnChanges(): void { + ngOnChanges(changes: SimpleChanges): void { + console.log(changes, this.activeCalendarToken.getValue()) this.activeCalendarToken.next(this.activeCalendar); } From 867cecbe9e9ce542bf72813d755baace272bf21b Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Tue, 17 Mar 2020 13:17:24 +0100 Subject: [PATCH 19/60] test (value): specs for jdn datepicker directive --- .../int-value/int-value.component.spec.ts | 1 - .../jdndatepicker.directive.spec.ts | 93 ++++++++++++++++++- .../jdndatepicker.directive.ts | 3 +- 3 files changed, 92 insertions(+), 5 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/int-value/int-value.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/int-value/int-value.component.spec.ts index b3dfd4209..c58105613 100644 --- a/projects/knora-ui/src/lib/viewer/values/int-value/int-value.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/int-value/int-value.component.spec.ts @@ -6,7 +6,6 @@ import { OnInit, Component, ViewChild, DebugElement } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; import { MatInputModule } from '@angular/material'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { $ } from 'protractor'; import { By } from '@angular/platform-browser'; /** diff --git a/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.spec.ts b/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.spec.ts index 500e78c47..676aebf91 100644 --- a/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.spec.ts @@ -1,8 +1,95 @@ -import { JDNDatepickerDirective } from './jdndatepicker.directive'; +import {JDNDatepickerDirective} from './jdndatepicker.directive'; +import {Component, OnInit, ViewChild} from "@angular/core"; +import {async, ComponentFixture, TestBed} from "@angular/core/testing"; +import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; +import {ACTIVE_CALENDAR, JDNConvertibleCalendarDateAdapter} from "jdnconvertiblecalendardateadapter"; +import {DateAdapter} from "@angular/material/core"; + +/** + * Test host component to simulate parent component. + */ +@Component({ + template: ` + ` +}) +class TestHostComponent implements OnInit { + + @ViewChild(JDNDatepickerDirective, {static: false}) jdnDir; + + activeCalendar: string; + + ngOnInit() { + this.activeCalendar = 'Gregorian'; + } +} + describe('JDNDatepickerDirective', () => { + let testHostComponent: TestHostComponent; + let testHostFixture: ComponentFixture; + + let testBehaviourSubject; + let setNextCalSpy; + let setSubscribeSpy; + + let testBehaviourSubjSpy; + + beforeEach(async(() => { + + testBehaviourSubject = jasmine.createSpyObj('ACTIVE_CALENDAR', ['next', 'getValue', 'subscribe']); + + setNextCalSpy = testBehaviourSubject.next.and.stub(); + setSubscribeSpy = testBehaviourSubject.subscribe.and.stub(); + + TestBed.configureTestingModule({ + declarations: [ + JDNDatepickerDirective, + TestHostComponent + ], + providers: [ + { + provide: DateAdapter, useValue: {}}, + { + provide: ACTIVE_CALENDAR, useValue: testBehaviourSubject + } + ], + imports: [ + BrowserAnimationsModule + ], + }) + .compileComponents(); + + // overrides the injection token defined in JDNDatepickerDirective's metadata + TestBed.overrideProvider(ACTIVE_CALENDAR, {useValue: testBehaviourSubject}); + TestBed.overrideProvider(DateAdapter, {useValue: {}}); + + testBehaviourSubjSpy = TestBed.get(ACTIVE_CALENDAR); + })); + + beforeEach(() => { + testHostFixture = TestBed.createComponent(TestHostComponent); + testHostComponent = testHostFixture.componentInstance; + testHostFixture.detectChanges(); + + expect(testHostComponent).toBeTruthy(); + expect(testHostComponent.jdnDir).toBeTruthy(); + }); + it('should create an instance', () => { - //const directive = new JDNDatepickerDirective(); - //expect(directive).toBeTruthy(); + expect(testBehaviourSubjSpy.next).toHaveBeenCalledTimes(1); + expect(testBehaviourSubjSpy.next).toHaveBeenCalledWith('Gregorian'); + }); + + it('should update the calendar when the input changes', () => { + testHostComponent.activeCalendar = 'Julian'; + testHostFixture.detectChanges(); + + expect(testBehaviourSubjSpy.next).toHaveBeenCalledTimes(2); + + expect(testBehaviourSubjSpy.next.calls.all()[0].args).toEqual(['Gregorian']); + expect(testBehaviourSubjSpy.next.calls.all()[1].args).toEqual(['Julian']); + }); + + }); diff --git a/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.ts b/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.ts index 6690b5286..75e6e5c57 100644 --- a/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.ts +++ b/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.ts @@ -6,6 +6,7 @@ import {DateInputComponent} from '../date-value/date-input/date-input.component' import {BehaviorSubject} from 'rxjs'; export function makeCalendarToken() { + console.log('factory') return new BehaviorSubject('Gregorian'); } @@ -37,7 +38,7 @@ export class JDNDatepickerDirective implements OnChanges { } ngOnChanges(changes: SimpleChanges): void { - console.log(changes, this.activeCalendarToken.getValue()) + // console.log(changes, this.activeCalendarToken); this.activeCalendarToken.next(this.activeCalendar); } From e8704fcfe49afae90cc6a6530e228db55e6f74f9 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Tue, 17 Mar 2020 14:12:21 +0100 Subject: [PATCH 20/60] test (value): specs for jdn datepicker directive --- .../date-input/date-input.component.html | 4 +-- .../jdndatepicker.directive.spec.ts | 26 ++++++++++++++++--- .../jdndatepicker.directive.ts | 10 ++++--- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html index 28d0a9afd..8966ed115 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html @@ -2,14 +2,14 @@ - + - + diff --git a/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.spec.ts b/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.spec.ts index 676aebf91..74e0ac319 100644 --- a/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.spec.ts @@ -30,16 +30,16 @@ describe('JDNDatepickerDirective', () => { let testBehaviourSubject; let setNextCalSpy; - let setSubscribeSpy; + let setCompleteSpy; let testBehaviourSubjSpy; beforeEach(async(() => { - testBehaviourSubject = jasmine.createSpyObj('ACTIVE_CALENDAR', ['next', 'getValue', 'subscribe']); + testBehaviourSubject = jasmine.createSpyObj('ACTIVE_CALENDAR', ['next', 'complete']); setNextCalSpy = testBehaviourSubject.next.and.stub(); - setSubscribeSpy = testBehaviourSubject.subscribe.and.stub(); + setCompleteSpy = testBehaviourSubject.complete.and.stub(); TestBed.configureTestingModule({ declarations: [ @@ -91,5 +91,25 @@ describe('JDNDatepickerDirective', () => { }); + it('should set the calendar to Gregorian when called with null', () => { + testHostComponent.activeCalendar = null; + testHostFixture.detectChanges(); + + expect(testBehaviourSubjSpy.next).toHaveBeenCalledTimes(2); + + expect(testBehaviourSubjSpy.next.calls.all()[0].args).toEqual(['Gregorian']); + expect(testBehaviourSubjSpy.next.calls.all()[1].args).toEqual(['Gregorian']); + + }); + + it('should complete the BehaviourSubject when destroyed', () => { + + expect(setCompleteSpy).toHaveBeenCalledTimes(0); + + testHostComponent.jdnDir.ngOnDestroy(); + + expect(setCompleteSpy).toHaveBeenCalledTimes(1); + + }); }); diff --git a/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.ts b/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.ts index 75e6e5c57..c60b5d67e 100644 --- a/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.ts +++ b/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.ts @@ -1,4 +1,4 @@ -import {Directive, Host, Inject, Input, OnChanges, SimpleChanges} from '@angular/core'; +import {Directive, Host, Inject, Input, OnChanges, OnDestroy, SimpleChanges} from '@angular/core'; import {DateAdapter, MAT_DATE_LOCALE} from '@angular/material'; import {JDNConvertibleCalendar} from 'jdnconvertiblecalendar'; import {ACTIVE_CALENDAR, JDNConvertibleCalendarDateAdapter} from 'jdnconvertiblecalendardateadapter'; @@ -6,7 +6,6 @@ import {DateInputComponent} from '../date-value/date-input/date-input.component' import {BehaviorSubject} from 'rxjs'; export function makeCalendarToken() { - console.log('factory') return new BehaviorSubject('Gregorian'); } @@ -17,7 +16,7 @@ export function makeCalendarToken() { {provide: ACTIVE_CALENDAR, useFactory: makeCalendarToken} ] }) -export class JDNDatepickerDirective implements OnChanges { +export class JDNDatepickerDirective implements OnChanges, OnDestroy { private _activeCalendar: 'Gregorian' | 'Julian' | 'Islamic'; @@ -38,8 +37,11 @@ export class JDNDatepickerDirective implements OnChanges { } ngOnChanges(changes: SimpleChanges): void { - // console.log(changes, this.activeCalendarToken); this.activeCalendarToken.next(this.activeCalendar); } + ngOnDestroy(): void { + this.activeCalendarToken.complete(); + } + } From 15d6d090de028768220cd438294573193e1fc5bc Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Tue, 17 Mar 2020 14:32:59 +0100 Subject: [PATCH 21/60] test (value): specs for date input component --- .../date-input/date-input.component.spec.ts | 69 ++++++++++++++++--- .../date-input/date-input.component.ts | 16 +++-- .../jdndatepicker.directive.ts | 3 +- 3 files changed, 71 insertions(+), 17 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts index 2c9749dc4..1591a581a 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts @@ -1,25 +1,74 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; -import { DateInputComponent } from './date-input.component'; +import {DateInputComponent} from './date-input.component'; +import {Component, OnInit, ViewChild} from '@angular/core'; +import {FormBuilder, FormGroup, ReactiveFormsModule} from '@angular/forms'; +import {KnoraDate} from '@knora/api'; +import {JDNDatepickerDirective} from '../../jdn-datepicker-directive/jdndatepicker.directive'; +import {MatFormFieldModule} from '@angular/material/form-field'; +import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; +import {MatInputModule} from '@angular/material/input'; +import {MatDatepickerModule} from '@angular/material/datepicker'; +import {MatJDNConvertibleCalendarDateAdapterModule} from 'jdnconvertiblecalendardateadapter'; + +/** + * Test host component to simulate parent component. + */ +@Component({ + template: ` +
+ + + +
` +}) +class TestHostComponent implements OnInit { + + @ViewChild('dateInput', {static: false}) dateInputComponent: DateInputComponent; + + form: FormGroup; + + readonly = false; + + constructor(private fb: FormBuilder) { + } + + ngOnInit(): void { + + this.form = this.fb.group({ + date: [new KnoraDate('JULIAN', 'CE', 2018, 5, 19)] + }); + + } +} describe('DateInputComponent', () => { - let component: DateInputComponent; - let fixture: ComponentFixture; + let testHostComponent: TestHostComponent; + let testHostFixture: ComponentFixture; beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ DateInputComponent ] + imports: [ + ReactiveFormsModule, + MatFormFieldModule, + MatInputModule, + MatDatepickerModule, + MatJDNConvertibleCalendarDateAdapterModule, + BrowserAnimationsModule + ], + declarations: [DateInputComponent, TestHostComponent, JDNDatepickerDirective] }) - .compileComponents(); + .compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(DateInputComponent); - component = fixture.componentInstance; - fixture.detectChanges(); + testHostFixture = TestBed.createComponent(TestHostComponent); + testHostComponent = testHostFixture.componentInstance; + testHostFixture.detectChanges(); }); it('should create', () => { - expect(component).toBeTruthy(); + expect(testHostComponent).toBeTruthy(); + console.log(testHostComponent.dateInputComponent); }); }); diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts index 265908501..61d69bab4 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts @@ -1,15 +1,21 @@ import {Component, DoCheck, ElementRef, HostBinding, Input, OnDestroy, Optional, Self} from '@angular/core'; -import {ControlValueAccessor, FormBuilder, FormControl, FormGroup, FormGroupDirective, NgControl, NgForm, Validators} from '@angular/forms'; +import { + ControlValueAccessor, + FormBuilder, + FormControl, + FormGroup, + FormGroupDirective, + NgControl, + NgForm, + Validators +} from '@angular/forms'; import {MatFormFieldControl} from '@angular/material/form-field'; import {KnoraDate, KnoraPeriod} from '@knora/api'; import {CanUpdateErrorState, CanUpdateErrorStateCtor, ErrorStateMatcher, mixinErrorState} from '@angular/material/core'; import {Subject} from 'rxjs'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; import {FocusMonitor} from '@angular/cdk/a11y'; -import {JDNConvertibleCalendarModule} from 'jdnconvertiblecalendar/dist/src/JDNConvertibleCalendar'; -import {CalendarDate, JulianCalendarDate} from 'jdnconvertiblecalendar'; -import GregorianCalendarDate = JDNConvertibleCalendarModule.GregorianCalendarDate; -import CalendarPeriod = JDNConvertibleCalendarModule.CalendarPeriod; +import {CalendarDate, CalendarPeriod, GregorianCalendarDate, JulianCalendarDate} from 'jdnconvertiblecalendar'; import {CalendarHeaderComponent} from '../calendar-header/calendar-header.component'; /** Error when invalid control is dirty, touched, or submitted. */ diff --git a/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.ts b/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.ts index c60b5d67e..1c693134a 100644 --- a/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.ts +++ b/projects/knora-ui/src/lib/viewer/values/jdn-datepicker-directive/jdndatepicker.directive.ts @@ -1,8 +1,7 @@ -import {Directive, Host, Inject, Input, OnChanges, OnDestroy, SimpleChanges} from '@angular/core'; +import {Directive, Inject, Input, OnChanges, OnDestroy, SimpleChanges} from '@angular/core'; import {DateAdapter, MAT_DATE_LOCALE} from '@angular/material'; import {JDNConvertibleCalendar} from 'jdnconvertiblecalendar'; import {ACTIVE_CALENDAR, JDNConvertibleCalendarDateAdapter} from 'jdnconvertiblecalendardateadapter'; -import {DateInputComponent} from '../date-value/date-input/date-input.component'; import {BehaviorSubject} from 'rxjs'; export function makeCalendarToken() { From da95792d13f8232976e42837432cde66efdb7b7d Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Tue, 17 Mar 2020 14:43:02 +0100 Subject: [PATCH 22/60] test (value): specs for date value component --- .../date-value/date-value.component.spec.ts | 159 +++++++++++++++++- 1 file changed, 153 insertions(+), 6 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts index ea5ac8e5d..f1503cde5 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts @@ -1,6 +1,119 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; -import { DateValueComponent } from './date-value.component'; +import {DateValueComponent} from './date-value.component'; +import {Component, DebugElement, forwardRef, Input, OnInit, ViewChild} from '@angular/core'; +import {IntValueComponent} from '../int-value/int-value.component'; +import {KnoraDate, KnoraPeriod, MockResource, ReadDateValue} from '@knora/api'; +import {ControlValueAccessor, NG_VALUE_ACCESSOR, NgControl, ReactiveFormsModule} from '@angular/forms'; +import {MatFormFieldControl} from '@angular/material/form-field'; +import {Subject} from 'rxjs'; +import {ErrorStateMatcher} from '@angular/material/core'; +import {By} from '@angular/platform-browser'; +import {MatInputModule} from '@angular/material/input'; +import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; + +@Component({ + selector: `kui-date-input`, + template: ``, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + multi: true, + useExisting: forwardRef(() => TestDateInputComponent), + }, + {provide: MatFormFieldControl, useExisting: TestDateInputComponent} + ] +}) +class TestDateInputComponent implements ControlValueAccessor, MatFormFieldControl { + + @Input() readonly = false; + @Input() value; + @Input() disabled: boolean; + @Input() empty: boolean; + @Input() placeholder: string; + @Input() required: boolean; + @Input() shouldLabelFloat: boolean; + @Input() errorStateMatcher: ErrorStateMatcher; + + errorState = false; + focused = false; + id = 'testid'; + ngControl: NgControl | null; + onChange = (_: any) => { + }; + stateChanges = new Subject(); + + writeValue(date: KnoraDate | KnoraPeriod | null): void { + this.value = date; + } + + registerOnChange(fn: any): void { + this.onChange = fn; + } + + registerOnTouched(fn: any): void { + } + + onContainerClick(event: MouseEvent): void { + } + + setDescribedByIds(ids: string[]): void { + } + + _handleInput(): void { + this.onChange(this.value); + } + +} + +/** + * Test host component to simulate parent component. + */ +@Component({ + template: ` + ` +}) +class TestHostDisplayValueComponent implements OnInit { + + @ViewChild('inputVal', {static: false}) inputValueComponent: IntValueComponent; + + displayInputVal: ReadDateValue; + + mode: 'read' | 'update' | 'create' | 'search'; + + ngOnInit() { + + MockResource.getTestthing().subscribe(res => { + const inputVal: ReadDateValue = + res[0].getValuesAs('http://0.0.0.0:3333/ontology/0001/anything/v2#hasDate', ReadDateValue)[0]; + + this.displayInputVal = inputVal; + + this.mode = 'read'; + }); + + } +} + +/** + * Test host component to simulate parent component. + */ +@Component({ + template: ` + ` +}) +class TestHostCreateValueComponent implements OnInit { + + @ViewChild('inputVal', {static: false}) inputValueComponent: IntValueComponent; + + mode: 'read' | 'update' | 'create' | 'search'; + + ngOnInit() { + + this.mode = 'create'; + + } +} describe('DateValueComponent', () => { let component: DateValueComponent; @@ -8,9 +121,18 @@ describe('DateValueComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ DateValueComponent ] + imports: [ + ReactiveFormsModule, + MatInputModule, + BrowserAnimationsModule + ], + declarations: [ + DateValueComponent, + TestDateInputComponent, + TestHostDisplayValueComponent, + TestHostCreateValueComponent] }) - .compileComponents(); + .compileComponents(); })); beforeEach(() => { @@ -19,7 +141,32 @@ describe('DateValueComponent', () => { fixture.detectChanges(); }); - it('should create', () => { - expect(component).toBeTruthy(); + describe('display and edit an interval value', () => { + let testHostComponent: TestHostDisplayValueComponent; + let testHostFixture: ComponentFixture; + + let valueComponentDe: DebugElement; + let commentInputDebugElement: DebugElement; + let commentInputNativeElement; + + beforeEach(() => { + testHostFixture = TestBed.createComponent(TestHostDisplayValueComponent); + testHostComponent = testHostFixture.componentInstance; + testHostFixture.detectChanges(); + + expect(testHostComponent).toBeTruthy(); + expect(testHostComponent.inputValueComponent).toBeTruthy(); + + const hostCompDe = testHostFixture.debugElement; + + valueComponentDe = hostCompDe.query(By.directive(DateValueComponent)); + commentInputDebugElement = valueComponentDe.query(By.css('input.comment')); + commentInputNativeElement = commentInputDebugElement.nativeElement; + }); + + it('should display an existing value', () => { + expect(testHostComponent.inputValueComponent).toBeTruthy(); + // console.log(testHostComponent.inputValueComponent) + }); }); }); From 4c7676d79c2108157fcf2cb5890e62f44681c40d Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Fri, 20 Mar 2020 11:45:08 +0100 Subject: [PATCH 23/60] feature (values): override standardValidatorFunc for dates --- .../values/date-value/date-value.component.ts | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts index 30f7da5da..0293c3cbc 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts @@ -1,6 +1,14 @@ import {Component, Inject, Input, OnChanges, OnDestroy, OnInit, SimpleChanges} from '@angular/core'; import {CreateDateValue, KnoraDate, KnoraPeriod, ReadDateValue, UpdateDateValue} from '@knora/api'; -import {FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm} from '@angular/forms'; +import { + AbstractControl, + FormBuilder, + FormControl, + FormGroup, + FormGroupDirective, + NgForm, + ValidatorFn +} from '@angular/forms'; import {Subscription} from 'rxjs'; import {BaseValueComponent} from '../base-value.component'; import {ErrorStateMatcher} from '@angular/material'; @@ -29,6 +37,7 @@ export class DateValueComponent extends BaseValueComponent implements OnInit, On valueChangesSubscription: Subscription; + // TODO: check that both dates have the same calendar in case of a KnoraPeriod customValidators = []; matcher = new IntervalErrorStateMatcher(); @@ -37,6 +46,37 @@ export class DateValueComponent extends BaseValueComponent implements OnInit, On super(); } + /** + * Returns true if both dates are the same. + * + * @param date1 date for comparison with date2 + * @param date2 date for comparison with date 1 + */ + sameDate(date1: KnoraDate, date2: KnoraDate): boolean { + return (date1.calendar === date2.calendar && date1.year === date2.year && date1.month === date2.month && date1.day === date2.day); + } + + standardValidatorFunc: (val: any, comment: string, commentCtrl: FormControl) => ValidatorFn + = (initValue: any, initComment: string, commentFormControl: FormControl): ValidatorFn => { + return (control: AbstractControl): { [key: string]: any } | null => { + + let sameValue: boolean; + if (initValue instanceof KnoraDate && control.value instanceof KnoraDate) { + sameValue = this.sameDate(initValue, control.value); + } else if (initValue instanceof KnoraPeriod && control.value instanceof KnoraPeriod) { + sameValue = this.sameDate(initValue.start, control.value.start) && this.sameDate(initValue.end, control.value.end); + } else { + // init value and current value have different types + sameValue = false; + } + + const invalid = (sameValue && initValue.end === control.value.end) + && (initComment === commentFormControl.value || (initComment === null && commentFormControl.value === '')); + + return invalid ? {valueNotChanged: {value: control.value}} : null; + }; + }; + getInitValue(): KnoraDate | KnoraPeriod | null { if (this.displayValue !== undefined) { return this.displayValue.date; From 5c517e7fd6dbb267557b05d8b585e46f202a7ee4 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Fri, 20 Mar 2020 12:01:31 +0100 Subject: [PATCH 24/60] feature (values): populate update and creation value --- .../date-input/date-input.component.spec.ts | 2 +- .../values/date-value/date-value.component.ts | 82 +++++++++++-------- 2 files changed, 49 insertions(+), 35 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts index 1591a581a..77b5217b8 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts @@ -69,6 +69,6 @@ describe('DateInputComponent', () => { it('should create', () => { expect(testHostComponent).toBeTruthy(); - console.log(testHostComponent.dateInputComponent); + // console.log(testHostComponent.dateInputComponent); }); }); diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts index 0293c3cbc..804bdd2ee 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts @@ -115,6 +115,50 @@ export class DateValueComponent extends BaseValueComponent implements OnInit, On this.unsubscribeFromValueChanges(); } + /** + * Given a value and a period or Date, populates the value. + * + * @param value the value to be populated. + * @param dateOrPeriod the date or period to read from. + */ + populateValue(value: UpdateDateValue | CreateDateValue, dateOrPeriod: KnoraDate | KnoraPeriod) { + + if (dateOrPeriod instanceof KnoraDate) { + + value.calendar = dateOrPeriod.calendar; + value.startEra = dateOrPeriod.era; + value.startDay = dateOrPeriod.day; + value.startMonth = dateOrPeriod.month; + value.startYear = dateOrPeriod.year; + + // TODO: handle precision correctly + + value.endEra = value.startEra; + value.endDay = value.startDay; + value.endMonth = value.startMonth; + value.endYear = value.startYear; + + } else if (dateOrPeriod instanceof KnoraPeriod) { + + value.calendar = dateOrPeriod.start.calendar; + + // TODO: handle precision correctly + + value.startEra = dateOrPeriod.start.era; + value.startDay = dateOrPeriod.start.day; + value.startMonth = dateOrPeriod.start.month; + value.startYear = dateOrPeriod.start.year; + + // TODO: handle precision correctly + + value.endEra = dateOrPeriod.end.era; + value.endDay = dateOrPeriod.end.day; + value.endMonth = dateOrPeriod.end.month; + value.endYear = dateOrPeriod.start.year; + + } + } + getNewValue(): CreateDateValue | false { if (this.mode !== 'create' || !this.form.valid) { return false; @@ -122,7 +166,9 @@ export class DateValueComponent extends BaseValueComponent implements OnInit, On const newDateValue = new CreateDateValue(); - // newDateValue.int = this.valueFormControl.value; + const dateOrPeriod = this.valueFormControl.value; + + this.populateValue(newDateValue, dateOrPeriod); if (this.commentFormControl.value !== null && this.commentFormControl.value !== '') { newDateValue.valueHasComment = this.commentFormControl.value; @@ -142,39 +188,7 @@ export class DateValueComponent extends BaseValueComponent implements OnInit, On const dateOrPeriod = this.valueFormControl.value; - if (dateOrPeriod instanceof KnoraDate) { - - updatedDateValue.calendar = dateOrPeriod.calendar; - updatedDateValue.startEra = dateOrPeriod.era; - updatedDateValue.startDay = dateOrPeriod.day; - updatedDateValue.startMonth = dateOrPeriod.month; - updatedDateValue.startYear = dateOrPeriod.year; - - // TODO: handle precision correctly - - updatedDateValue.endEra = updatedDateValue.startEra; - updatedDateValue.endDay = updatedDateValue.startDay; - updatedDateValue.endMonth = updatedDateValue.startMonth; - updatedDateValue.endYear = updatedDateValue.startYear; - - } else if (dateOrPeriod instanceof KnoraPeriod) { - - updatedDateValue.calendar = dateOrPeriod.start.calendar; - - updatedDateValue.startEra = dateOrPeriod.start.era; - updatedDateValue.startDay = dateOrPeriod.start.day; - updatedDateValue.startMonth = dateOrPeriod.start.month; - updatedDateValue.startYear = dateOrPeriod.start.year; - - updatedDateValue.endEra = dateOrPeriod.end.era; - updatedDateValue.endDay = dateOrPeriod.end.day; - updatedDateValue.endMonth = dateOrPeriod.end.month; - updatedDateValue.endYear = dateOrPeriod.start.year; - - } else { - return false; - } - + this.populateValue(updatedDateValue, dateOrPeriod); // add the submitted comment to updatedIntValue only if user has added a comment if (this.commentFormControl.value !== null && this.commentFormControl.value !== '') { From 3f90159855014cd860ff95f750a157521fa6904b Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Mon, 23 Mar 2020 13:55:33 +0100 Subject: [PATCH 25/60] tests (values): add test for date value component --- .../date-value/date-value.component.html | 2 +- .../date-value/date-value.component.spec.ts | 18 +++++++++++++----- .../values/date-value/date-value.component.ts | 6 +++++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html index 2820447ab..3abce152d 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html @@ -1,6 +1,6 @@ - +
diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts index f1503cde5..b5c799e3c 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts @@ -2,7 +2,6 @@ import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {DateValueComponent} from './date-value.component'; import {Component, DebugElement, forwardRef, Input, OnInit, ViewChild} from '@angular/core'; -import {IntValueComponent} from '../int-value/int-value.component'; import {KnoraDate, KnoraPeriod, MockResource, ReadDateValue} from '@knora/api'; import {ControlValueAccessor, NG_VALUE_ACCESSOR, NgControl, ReactiveFormsModule} from '@angular/forms'; import {MatFormFieldControl} from '@angular/material/form-field'; @@ -75,7 +74,7 @@ class TestDateInputComponent implements ControlValueAccessor, MatFormFieldContro }) class TestHostDisplayValueComponent implements OnInit { - @ViewChild('inputVal', {static: false}) inputValueComponent: IntValueComponent; + @ViewChild('inputVal', {static: false}) inputValueComponent: DateValueComponent; displayInputVal: ReadDateValue; @@ -104,7 +103,7 @@ class TestHostDisplayValueComponent implements OnInit { }) class TestHostCreateValueComponent implements OnInit { - @ViewChild('inputVal', {static: false}) inputValueComponent: IntValueComponent; + @ViewChild('inputVal', {static: false}) inputValueComponent: DateValueComponent; mode: 'read' | 'update' | 'create' | 'search'; @@ -165,8 +164,17 @@ describe('DateValueComponent', () => { }); it('should display an existing value', () => { - expect(testHostComponent.inputValueComponent).toBeTruthy(); - // console.log(testHostComponent.inputValueComponent) + + expect(testHostComponent.inputValueComponent.displayValue.date).toEqual(new KnoraDate('GREGORIAN', 'CE', 2018, 5, 13)); + + expect(testHostComponent.inputValueComponent.form.valid).toBeTruthy(); + + expect(testHostComponent.inputValueComponent.mode).toEqual('read'); + + expect(testHostComponent.inputValueComponent.dateInputComponent.readonly).toEqual(true); + + expect(testHostComponent.inputValueComponent.dateInputComponent.value).toEqual(new KnoraDate('GREGORIAN', 'CE', 2018, 5, 13)); + }); }); }); diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts index 804bdd2ee..1d09abe7a 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, Input, OnChanges, OnDestroy, OnInit, SimpleChanges} from '@angular/core'; +import {Component, Inject, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewChild} from '@angular/core'; import {CreateDateValue, KnoraDate, KnoraPeriod, ReadDateValue, UpdateDateValue} from '@knora/api'; import { AbstractControl, @@ -12,6 +12,8 @@ import { import {Subscription} from 'rxjs'; import {BaseValueComponent} from '../base-value.component'; import {ErrorStateMatcher} from '@angular/material'; +import {IntervalInputComponent} from "../interval-value/interval-input/interval-input.component"; +import {DateInputComponent} from "./date-input/date-input.component"; /** Error when invalid control is dirty, touched, or submitted. */ export class IntervalErrorStateMatcher implements ErrorStateMatcher { @@ -28,6 +30,8 @@ export class IntervalErrorStateMatcher implements ErrorStateMatcher { }) export class DateValueComponent extends BaseValueComponent implements OnInit, OnChanges, OnDestroy { + @ViewChild('dateInput', {static: false}) dateInputComponent: DateInputComponent; + @Input() displayValue?: ReadDateValue; valueFormControl: FormControl; From a4ff803927aa9d700f059f5332f0641742cf1103 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Mon, 23 Mar 2020 16:18:04 +0100 Subject: [PATCH 26/60] tests (values): add test for date value component --- .../date-value/date-value.component.spec.ts | 45 ++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts index b5c799e3c..2aab4f7da 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts @@ -2,7 +2,7 @@ import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {DateValueComponent} from './date-value.component'; import {Component, DebugElement, forwardRef, Input, OnInit, ViewChild} from '@angular/core'; -import {KnoraDate, KnoraPeriod, MockResource, ReadDateValue} from '@knora/api'; +import {KnoraDate, KnoraPeriod, MockResource, ReadDateValue, UpdateDateValue, UpdateIntervalValue} from '@knora/api'; import {ControlValueAccessor, NG_VALUE_ACCESSOR, NgControl, ReactiveFormsModule} from '@angular/forms'; import {MatFormFieldControl} from '@angular/material/form-field'; import {Subject} from 'rxjs'; @@ -140,7 +140,7 @@ describe('DateValueComponent', () => { fixture.detectChanges(); }); - describe('display and edit an interval value', () => { + describe('display and edit a date value', () => { let testHostComponent: TestHostDisplayValueComponent; let testHostFixture: ComponentFixture; @@ -176,5 +176,46 @@ describe('DateValueComponent', () => { expect(testHostComponent.inputValueComponent.dateInputComponent.value).toEqual(new KnoraDate('GREGORIAN', 'CE', 2018, 5, 13)); }); + + it('should make an existing value editable', () => { + + testHostComponent.mode = 'update'; + + testHostFixture.detectChanges(); + + expect(testHostComponent.inputValueComponent.mode).toEqual('update'); + + expect(testHostComponent.inputValueComponent.dateInputComponent.readonly).toEqual(false); + + expect(testHostComponent.inputValueComponent.form.valid).toBeFalsy(); + + expect(testHostComponent.inputValueComponent.dateInputComponent.value).toEqual(new KnoraDate('GREGORIAN', 'CE', 2018, 5, 13)); + + // simulate user input + const newKnoraDate = new KnoraDate('GREGORIAN', 'CE', 2019, 5, 13); + + testHostComponent.inputValueComponent.dateInputComponent.value = newKnoraDate; + testHostComponent.inputValueComponent.dateInputComponent._handleInput(); + + testHostFixture.detectChanges(); + + expect(testHostComponent.inputValueComponent.valueFormControl.value).toBeTruthy(); + + expect(testHostComponent.inputValueComponent.form.valid).toBeTruthy(); + + const updatedValue = testHostComponent.inputValueComponent.getUpdatedValue(); + + expect(updatedValue instanceof UpdateDateValue).toBeTruthy(); + + expect((updatedValue as UpdateDateValue).calendar).toEqual('GREGORIAN'); + expect((updatedValue as UpdateDateValue).startYear).toEqual(2019); + expect((updatedValue as UpdateDateValue).endYear).toEqual(2019); + expect((updatedValue as UpdateDateValue).startMonth).toEqual(5); + expect((updatedValue as UpdateDateValue).endMonth).toEqual(5); + expect((updatedValue as UpdateDateValue).startDay).toEqual(13); + expect((updatedValue as UpdateDateValue).endDay).toEqual(13); + + }); + }); }); From 83c3766693dd04752518b1e92b6b4c079cb8b567 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Wed, 25 Mar 2020 10:23:37 +0100 Subject: [PATCH 27/60] tests (values): add test for date value component --- .../date-value/date-value.component.spec.ts | 33 ++++++++++++++++++- .../values/date-value/date-value.component.ts | 1 - 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts index 2aab4f7da..2d3f39cda 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts @@ -2,7 +2,7 @@ import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {DateValueComponent} from './date-value.component'; import {Component, DebugElement, forwardRef, Input, OnInit, ViewChild} from '@angular/core'; -import {KnoraDate, KnoraPeriod, MockResource, ReadDateValue, UpdateDateValue, UpdateIntervalValue} from '@knora/api'; +import {KnoraDate, KnoraPeriod, MockResource, ReadDateValue, UpdateDateValue} from '@knora/api'; import {ControlValueAccessor, NG_VALUE_ACCESSOR, NgControl, ReactiveFormsModule} from '@angular/forms'; import {MatFormFieldControl} from '@angular/material/form-field'; import {Subject} from 'rxjs'; @@ -217,5 +217,36 @@ describe('DateValueComponent', () => { }); + it('should validate an existing value with an added comment', () => { + + testHostComponent.mode = 'update'; + + testHostFixture.detectChanges(); + + expect(testHostComponent.inputValueComponent.mode).toEqual('update'); + + expect(testHostComponent.inputValueComponent.displayValue.date).toEqual(new KnoraDate('GREGORIAN', 'CE', 2018, 5, 13)); + + expect(testHostComponent.inputValueComponent.dateInputComponent.readonly).toEqual(false); + + expect(testHostComponent.inputValueComponent.form.valid).toBeFalsy(); + + commentInputNativeElement.value = 'this is a comment'; + + commentInputNativeElement.dispatchEvent(new Event('input')); + + testHostFixture.detectChanges(); + + expect(testHostComponent.inputValueComponent.form.valid).toBeTruthy(); + + const updatedValue = testHostComponent.inputValueComponent.getUpdatedValue(); + + expect(updatedValue instanceof UpdateDateValue).toBeTruthy(); + + expect((updatedValue as UpdateDateValue).valueHasComment).toEqual('this is a comment'); + + + }); + }); }); diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts index 1d09abe7a..e22ed63e9 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts @@ -12,7 +12,6 @@ import { import {Subscription} from 'rxjs'; import {BaseValueComponent} from '../base-value.component'; import {ErrorStateMatcher} from '@angular/material'; -import {IntervalInputComponent} from "../interval-value/interval-input/interval-input.component"; import {DateInputComponent} from "./date-input/date-input.component"; /** Error when invalid control is dirty, touched, or submitted. */ From 7496acbd58c910a09c20cc33177e65fd12afb360 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Wed, 25 Mar 2020 10:43:08 +0100 Subject: [PATCH 28/60] tests (values): add test for date value component --- .../date-value/date-value.component.spec.ts | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts index 2d3f39cda..276285e59 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts @@ -245,6 +245,60 @@ describe('DateValueComponent', () => { expect((updatedValue as UpdateDateValue).valueHasComment).toEqual('this is a comment'); + }); + + it('should not return an invalid update value', () => { + + testHostComponent.mode = 'update'; + + testHostFixture.detectChanges(); + + expect(testHostComponent.inputValueComponent.mode).toEqual('update'); + + expect(testHostComponent.inputValueComponent.dateInputComponent.readonly).toEqual(false); + + expect(testHostComponent.inputValueComponent.form.valid).toBeFalsy(); + + testHostComponent.inputValueComponent.dateInputComponent.value = null; + testHostComponent.inputValueComponent.dateInputComponent._handleInput(); + + testHostFixture.detectChanges(); + + expect(testHostComponent.inputValueComponent.form.valid).toBeFalsy(); + + const updatedValue = testHostComponent.inputValueComponent.getUpdatedValue(); + + expect(updatedValue).toBeFalsy(); + + }); + + it('should restore the initially displayed value', () => { + + testHostComponent.mode = 'update'; + + testHostFixture.detectChanges(); + + expect(testHostComponent.inputValueComponent.mode).toEqual('update'); + + expect(testHostComponent.inputValueComponent.dateInputComponent.readonly).toEqual(false); + + expect(testHostComponent.inputValueComponent.form.valid).toBeFalsy(); + + // simulate user input + const newKnoraDate = new KnoraDate('GREGORIAN', 'CE', 2019, 5, 13); + + testHostComponent.inputValueComponent.dateInputComponent.value = newKnoraDate; + testHostComponent.inputValueComponent.dateInputComponent._handleInput(); + + testHostFixture.detectChanges(); + + expect(testHostComponent.inputValueComponent.dateInputComponent.value).toEqual(new KnoraDate('GREGORIAN', 'CE', 2019, 5, 13)); + + testHostComponent.inputValueComponent.resetFormControl(); + + expect(testHostComponent.inputValueComponent.dateInputComponent.value).toEqual(new KnoraDate('GREGORIAN', 'CE', 2018, 5, 13)); + + expect(testHostComponent.inputValueComponent.form.valid).toBeFalsy(); }); From afdba7f75b740d733c402104e0137f4fbfbcfcc4 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Wed, 25 Mar 2020 10:55:21 +0100 Subject: [PATCH 29/60] tests (values): add test for date value component --- .../date-value/date-value.component.spec.ts | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts index 276285e59..edde47fdd 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts @@ -292,15 +292,44 @@ describe('DateValueComponent', () => { testHostFixture.detectChanges(); + expect(testHostComponent.inputValueComponent.valueFormControl.value).toEqual(new KnoraDate('GREGORIAN', 'CE', 2019, 5, 13)); + expect(testHostComponent.inputValueComponent.dateInputComponent.value).toEqual(new KnoraDate('GREGORIAN', 'CE', 2019, 5, 13)); testHostComponent.inputValueComponent.resetFormControl(); + expect(testHostComponent.inputValueComponent.valueFormControl.value).toEqual(new KnoraDate('GREGORIAN', 'CE', 2018, 5, 13)); + expect(testHostComponent.inputValueComponent.dateInputComponent.value).toEqual(new KnoraDate('GREGORIAN', 'CE', 2018, 5, 13)); expect(testHostComponent.inputValueComponent.form.valid).toBeFalsy(); }); + it('should set a new display value', done => { + + MockResource.getTestthing().subscribe(res => { + const newDate: ReadDateValue = + res[0].getValuesAs('http://0.0.0.0:3333/ontology/0001/anything/v2#hasDate', ReadDateValue)[0]; + + newDate.id = 'updatedId'; + + newDate.date = new KnoraDate('GREGORIAN', 'CE', 2019, 5, 13); + + testHostComponent.displayInputVal = newDate; + + testHostFixture.detectChanges(); + + expect(testHostComponent.inputValueComponent.valueFormControl.value).toEqual(new KnoraDate('GREGORIAN', 'CE', 2019, 5, 13)); + + expect(testHostComponent.inputValueComponent.dateInputComponent.value).toEqual(new KnoraDate('GREGORIAN', 'CE', 2019, 5, 13)); + + expect(testHostComponent.inputValueComponent.form.valid).toBeTruthy(); + + done(); + }); + + }); + }); }); From 3e22967cd720078f5befd5e43f6c11b480087f67 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Wed, 25 Mar 2020 10:58:16 +0100 Subject: [PATCH 30/60] tests (values): add test for date value component --- .../values/date-value/date-value.component.spec.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts index edde47fdd..6bb88cf69 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts @@ -331,5 +331,14 @@ describe('DateValueComponent', () => { }); + it('should unsubscribe when destroyed', () => { + expect(testHostComponent.inputValueComponent.valueChangesSubscription.closed).toBeFalsy(); + + testHostComponent.inputValueComponent.ngOnDestroy(); + + expect(testHostComponent.inputValueComponent.valueChangesSubscription.closed).toBeTruthy(); + + }); + }); }); From 1190f97ee1904af6144e4cd3a67cdfa4390d47c3 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Wed, 25 Mar 2020 11:06:30 +0100 Subject: [PATCH 31/60] tests (values): add test for date value component --- .../date-value/date-value.component.spec.ts | 66 ++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts index 6bb88cf69..1c0728b84 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts @@ -2,7 +2,7 @@ import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {DateValueComponent} from './date-value.component'; import {Component, DebugElement, forwardRef, Input, OnInit, ViewChild} from '@angular/core'; -import {KnoraDate, KnoraPeriod, MockResource, ReadDateValue, UpdateDateValue} from '@knora/api'; +import {CreateDateValue, KnoraDate, KnoraPeriod, MockResource, ReadDateValue, UpdateDateValue} from '@knora/api'; import {ControlValueAccessor, NG_VALUE_ACCESSOR, NgControl, ReactiveFormsModule} from '@angular/forms'; import {MatFormFieldControl} from '@angular/material/form-field'; import {Subject} from 'rxjs'; @@ -337,8 +337,70 @@ describe('DateValueComponent', () => { testHostComponent.inputValueComponent.ngOnDestroy(); expect(testHostComponent.inputValueComponent.valueChangesSubscription.closed).toBeTruthy(); - + + }); + + }); + + describe('create an interval value', () => { + + let testHostComponent: TestHostCreateValueComponent; + let testHostFixture: ComponentFixture; + + let valueComponentDe: DebugElement; + let commentInputDebugElement: DebugElement; + let commentInputNativeElement; + + beforeEach(() => { + testHostFixture = TestBed.createComponent(TestHostCreateValueComponent); + testHostComponent = testHostFixture.componentInstance; + testHostFixture.detectChanges(); + + expect(testHostComponent).toBeTruthy(); + expect(testHostComponent.inputValueComponent).toBeTruthy(); + + const hostCompDe = testHostFixture.debugElement; + + valueComponentDe = hostCompDe.query(By.directive(DateValueComponent)); + commentInputDebugElement = valueComponentDe.query(By.css('input.comment')); + commentInputNativeElement = commentInputDebugElement.nativeElement; + }); + + it('should create a value', () => { + + expect(testHostComponent.inputValueComponent.dateInputComponent.value).toEqual(null); + + // simulate user input + const newKnoraDate = new KnoraDate('JULIAN', 'CE', 2019, 5, 13); + + testHostComponent.inputValueComponent.dateInputComponent.value = newKnoraDate; + testHostComponent.inputValueComponent.dateInputComponent._handleInput(); + + testHostFixture.detectChanges(); + + expect(testHostComponent.inputValueComponent.mode).toEqual('create'); + + expect(testHostComponent.inputValueComponent.form.valid).toBeTruthy(); + + const newValue = testHostComponent.inputValueComponent.getNewValue(); + + expect(newValue instanceof CreateDateValue).toBeTruthy(); + + expect((newValue as CreateDateValue).calendar).toEqual('JULIAN'); + + expect((newValue as CreateDateValue).startDay).toEqual(13); + expect((newValue as CreateDateValue).endDay).toEqual(13); + expect((newValue as CreateDateValue).startMonth).toEqual(5); + expect((newValue as CreateDateValue).endMonth).toEqual(5); + expect((newValue as CreateDateValue).startYear).toEqual(2019); + expect((newValue as CreateDateValue).endYear).toEqual(2019); + + + + }); }); + + }); From 95165e5ee690d318ddef599d5e5c37520c29f7d5 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Wed, 25 Mar 2020 11:11:34 +0100 Subject: [PATCH 32/60] tests (values): add test for date value component --- .../date-value/date-value.component.spec.ts | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts index 1c0728b84..b4bdeee7a 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts @@ -395,8 +395,35 @@ describe('DateValueComponent', () => { expect((newValue as CreateDateValue).startYear).toEqual(2019); expect((newValue as CreateDateValue).endYear).toEqual(2019); + }); + + it('should reset form after cancellation', () => { + // simulate user input + // simulate user input + const newKnoraDate = new KnoraDate('JULIAN', 'CE', 2019, 5, 13); + + testHostComponent.inputValueComponent.dateInputComponent.value = newKnoraDate; + testHostComponent.inputValueComponent.dateInputComponent._handleInput(); + + testHostFixture.detectChanges(); + + commentInputNativeElement.value = 'created comment'; + + commentInputNativeElement.dispatchEvent(new Event('input')); + + testHostFixture.detectChanges(); + + expect(testHostComponent.inputValueComponent.mode).toEqual('create'); + + expect(testHostComponent.inputValueComponent.form.valid).toBeTruthy(); + + testHostComponent.inputValueComponent.resetFormControl(); + expect(testHostComponent.inputValueComponent.form.valid).toBeFalsy(); + + expect(testHostComponent.inputValueComponent.dateInputComponent.value).toEqual(null); + expect(commentInputNativeElement.value).toEqual(''); }); From 57414ebccfe6db28c16e17684ad3c1ea52a87fe2 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Wed, 25 Mar 2020 12:51:39 +0100 Subject: [PATCH 33/60] tests (values): add test for date value component --- .../date-value/date-value.component.spec.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts index b4bdeee7a..693b20e2a 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts @@ -340,6 +340,22 @@ describe('DateValueComponent', () => { }); + it('should compare two dates', () => { + + expect(testHostComponent.inputValueComponent.sameDate( + new KnoraDate('GREGORIAN', 'CE', 2018, 5, 13), + new KnoraDate('GREGORIAN', 'CE', 2018, 5, 13))).toEqual(true); + + expect(testHostComponent.inputValueComponent.sameDate( + new KnoraDate('JULIAN', 'CE', 2018, 5, 13), + new KnoraDate('GREGORIAN', 'CE', 2018, 5, 13))).toEqual(false); + + expect(testHostComponent.inputValueComponent.sameDate( + new KnoraDate('GREGORIAN', 'CE', 2018, 5, 13), + new KnoraDate('GREGORIAN', 'CE', 2019, 5, 13))).toEqual(false); + + }); + }); describe('create an interval value', () => { @@ -398,7 +414,7 @@ describe('DateValueComponent', () => { }); it('should reset form after cancellation', () => { - // simulate user input + // simulate user input const newKnoraDate = new KnoraDate('JULIAN', 'CE', 2019, 5, 13); From 37c9605e23c6e1d3d5f75be191367319a9532f23 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Thu, 2 Apr 2020 18:46:25 +0200 Subject: [PATCH 34/60] feature (value): handle periods in dates values --- projects/knora-ui/package.json | 2 +- .../date-input/date-input.component.html | 3 ++- .../date-input/date-input.component.ts | 27 +++++++++++-------- .../values/date-value/date-value.component.ts | 2 +- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/projects/knora-ui/package.json b/projects/knora-ui/package.json index 823d727d5..93b9d09ec 100644 --- a/projects/knora-ui/package.json +++ b/projects/knora-ui/package.json @@ -8,6 +8,6 @@ "@angular/cdk": "^8.2.3", "@knora/api": "file:.yalc/@knora/api", "jdnconvertiblecalendar": "^0.0.5", - "jdnconvertiblecalendardateadapter": "^0.0.10" + "jdnconvertiblecalendardateadapter": "^0.0.12" } } diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html index 8966ed115..49ab254de 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html @@ -6,7 +6,8 @@
- + + diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts index 61d69bab4..3b20c828c 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts @@ -56,9 +56,9 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal matcher = new DateInputErrorStateMatcher(); calendarHeaderComponent = CalendarHeaderComponent; - period: boolean; startDateControl: FormControl; endDateControl: FormControl; + isPeriodControl: FormControl; onChange = (_: any) => { }; @@ -123,9 +123,11 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal @Input() get value(): KnoraDate | KnoraPeriod | null { const userInput = this.form.value; - if (!this.period) { + console.log(this.isPeriodControl.value); + if (!this.isPeriodControl.value) { // single date if (userInput.dateStart !== null) { + console.log('getting ', new KnoraDate(userInput.dateStart.calendarName.toUpperCase(), 'CE', userInput.dateStart.calendarStart.year, userInput.dateStart.calendarStart.month, userInput.dateStart.calendarStart.day)) return new KnoraDate(userInput.dateStart.calendarName.toUpperCase(), 'CE', userInput.dateStart.calendarStart.year, userInput.dateStart.calendarStart.month, userInput.dateStart.calendarStart.day); } else { return null; @@ -135,6 +137,7 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal if (userInput.dateStart !== null && userInput.dateEnd !== null) { const start = new KnoraDate(userInput.dateStart.calendarName.toUpperCase(), 'CE', userInput.dateStart.calendarStart.year, userInput.dateStart.calendarStart.month, userInput.dateStart.calendarStart.day); const end = new KnoraDate(userInput.dateEnd.calendarName.toUpperCase(), 'CE', userInput.dateEnd.calendarStart.year, userInput.dateEnd.calendarStart.month, userInput.dateEnd.calendarStart.day); + console.log('getting ', new KnoraPeriod(start, end)); return new KnoraPeriod(start, end); } else { return null; @@ -143,6 +146,7 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal } set value(date: KnoraDate | KnoraPeriod | null) { + console.log('setting: ', date) if (date !== null) { if (date instanceof KnoraDate) { // single date @@ -161,28 +165,27 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal this.form.setValue({ dateStart: startDate, - dateEnd: null + dateEnd: null, + isPeriod: false }); - this.period = false; - } else { // period const period = (date as KnoraPeriod); const calendarDateStart = new CalendarDate(period.start.year, period.start.month, period.start.day); const calendarDateEnd = new CalendarDate(period.end.year, period.end.month, period.end.day); + // TODO: check for calendar like above + this.form.setValue({ dateStart: new GregorianCalendarDate(new CalendarPeriod(calendarDateStart, calendarDateStart)), - dateEnd: new GregorianCalendarDate(new CalendarPeriod(calendarDateEnd, calendarDateEnd)) + dateEnd: new GregorianCalendarDate(new CalendarPeriod(calendarDateEnd, calendarDateEnd)), + isPeriod: true }); - this.period = true; } } else { - this.form.setValue({dateStart: null, dateEnd: null}); - - this.period = false; + this.form.setValue({dateStart: null, dateEnd: null, isPeriod: false}); } this.stateChanges.next(); } @@ -201,10 +204,12 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal this.startDateControl = new FormControl(null, Validators.required); this.endDateControl = new FormControl(null); + this.isPeriodControl = new FormControl(null); this.form = fb.group({ dateStart: this.startDateControl, - dateEnd: this.endDateControl + dateEnd: this.endDateControl, + isPeriod: this.isPeriodControl }); diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts index e22ed63e9..ab80be5ae 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts @@ -157,7 +157,7 @@ export class DateValueComponent extends BaseValueComponent implements OnInit, On value.endEra = dateOrPeriod.end.era; value.endDay = dateOrPeriod.end.day; value.endMonth = dateOrPeriod.end.month; - value.endYear = dateOrPeriod.start.year; + value.endYear = dateOrPeriod.end.year; } } From c3aea1d8478d7275923be240e75ef515e5d29403 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Thu, 2 Apr 2020 18:51:47 +0200 Subject: [PATCH 35/60] test (value): fix spec --- .../values/date-value/date-input/date-input.component.spec.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts index 77b5217b8..1384729aa 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts @@ -10,6 +10,7 @@ import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {MatInputModule} from '@angular/material/input'; import {MatDatepickerModule} from '@angular/material/datepicker'; import {MatJDNConvertibleCalendarDateAdapterModule} from 'jdnconvertiblecalendardateadapter'; +import {MatCheckbox} from "@angular/material/checkbox"; /** * Test host component to simulate parent component. @@ -53,6 +54,7 @@ describe('DateInputComponent', () => { MatFormFieldModule, MatInputModule, MatDatepickerModule, + MatCheckbox, MatJDNConvertibleCalendarDateAdapterModule, BrowserAnimationsModule ], From 616bce394c98a23726cae510b765aef062c6a3fb Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Thu, 2 Apr 2020 18:52:36 +0200 Subject: [PATCH 36/60] test (value): fix spec --- .../values/date-value/date-input/date-input.component.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts index 1384729aa..d28c71a5f 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts @@ -10,7 +10,7 @@ import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {MatInputModule} from '@angular/material/input'; import {MatDatepickerModule} from '@angular/material/datepicker'; import {MatJDNConvertibleCalendarDateAdapterModule} from 'jdnconvertiblecalendardateadapter'; -import {MatCheckbox} from "@angular/material/checkbox"; +import {MatCheckboxModule} from '@angular/material/checkbox'; /** * Test host component to simulate parent component. @@ -54,7 +54,7 @@ describe('DateInputComponent', () => { MatFormFieldModule, MatInputModule, MatDatepickerModule, - MatCheckbox, + MatCheckboxModule, MatJDNConvertibleCalendarDateAdapterModule, BrowserAnimationsModule ], From f9749d68c190c95e63ded6829e52c9d7a8b0d27b Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Thu, 2 Apr 2020 19:21:22 +0200 Subject: [PATCH 37/60] feature (value): handle periods in dates values --- .../date-input/date-input.component.ts | 63 ++++++++++++------- 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts index 3b20c828c..bcaa4e292 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts @@ -15,7 +15,13 @@ import {CanUpdateErrorState, CanUpdateErrorStateCtor, ErrorStateMatcher, mixinEr import {Subject} from 'rxjs'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; import {FocusMonitor} from '@angular/cdk/a11y'; -import {CalendarDate, CalendarPeriod, GregorianCalendarDate, JulianCalendarDate} from 'jdnconvertiblecalendar'; +import { + CalendarDate, + CalendarPeriod, + GregorianCalendarDate, + JDNConvertibleCalendar, + JulianCalendarDate +} from 'jdnconvertiblecalendar'; import {CalendarHeaderComponent} from '../calendar-header/calendar-header.component'; /** Error when invalid control is dirty, touched, or submitted. */ @@ -135,8 +141,19 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal } else { // period if (userInput.dateStart !== null && userInput.dateEnd !== null) { + + // check if start is before end + const startAsJdnPeriod = (userInput.dateStart as JDNConvertibleCalendar).toJDNPeriod(); + const endAsJdnPeriod = (userInput.dateEnd as JDNConvertibleCalendar).toJDNPeriod(); + + if (startAsJdnPeriod.periodStart >= endAsJdnPeriod.periodStart) { + // start after end + return null; + } + const start = new KnoraDate(userInput.dateStart.calendarName.toUpperCase(), 'CE', userInput.dateStart.calendarStart.year, userInput.dateStart.calendarStart.month, userInput.dateStart.calendarStart.day); const end = new KnoraDate(userInput.dateEnd.calendarName.toUpperCase(), 'CE', userInput.dateEnd.calendarStart.year, userInput.dateEnd.calendarStart.month, userInput.dateEnd.calendarStart.day); + console.log('getting ', new KnoraPeriod(start, end)); return new KnoraPeriod(start, end); } else { @@ -150,36 +167,20 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal if (date !== null) { if (date instanceof KnoraDate) { // single date - // TODO: set correct calendar - const calendarDate = new CalendarDate(date.year, date.month, date.day); - let startDate; - - // determine calendar - if (date.calendar === 'GREGORIAN') { - startDate = new GregorianCalendarDate(new CalendarPeriod(calendarDate, calendarDate)); - } else if (date.calendar === 'JULIAN') { - startDate = new JulianCalendarDate(new CalendarPeriod(calendarDate, calendarDate)); - } else { - throw new Error('Unsupported calendar: ' + date.calendar); - } this.form.setValue({ - dateStart: startDate, + dateStart: this.createCalendarDate(date), dateEnd: null, isPeriod: false }); } else { // period - const period = (date as KnoraPeriod); - const calendarDateStart = new CalendarDate(period.start.year, period.start.month, period.start.day); - const calendarDateEnd = new CalendarDate(period.end.year, period.end.month, period.end.day); - - // TODO: check for calendar like above + const period = date as KnoraPeriod; this.form.setValue({ - dateStart: new GregorianCalendarDate(new CalendarPeriod(calendarDateStart, calendarDateStart)), - dateEnd: new GregorianCalendarDate(new CalendarPeriod(calendarDateEnd, calendarDateEnd)), + dateStart: this.createCalendarDate(period.start), + dateEnd: this.createCalendarDate(period.end), isPeriod: true }); @@ -190,6 +191,26 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal this.stateChanges.next(); } + /** + * Given a `KnoraDate`, creates a Gregorian or Julian calendar date. + * + * @param date the given KnoraDate. + */ + createCalendarDate(date: KnoraDate): GregorianCalendarDate | JulianCalendarDate { + + const calDate = new CalendarDate(date.year, date.month, date.day); + const period = new CalendarPeriod(calDate, calDate); + + // determine calendar + if (date.calendar === 'GREGORIAN') { + return new GregorianCalendarDate(period); + } else if (date.calendar === 'JULIAN') { + return new JulianCalendarDate(period); + } else { + throw new Error('Unsupported calendar: ' + date.calendar); + } + } + @Input() errorStateMatcher: ErrorStateMatcher; constructor(fb: FormBuilder, From 8e9847edda7e4709b1a7dfbb5c103ff46c656645 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Fri, 3 Apr 2020 09:00:12 +0200 Subject: [PATCH 38/60] feature (value): handle periods in dates values --- .../date-value/date-input/date-input.component.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts index bcaa4e292..db9bda70d 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts @@ -128,12 +128,16 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal @Input() get value(): KnoraDate | KnoraPeriod | null { + + if (!this.form.valid) { + return null; + } + const userInput = this.form.value; - console.log(this.isPeriodControl.value); + if (!this.isPeriodControl.value) { // single date if (userInput.dateStart !== null) { - console.log('getting ', new KnoraDate(userInput.dateStart.calendarName.toUpperCase(), 'CE', userInput.dateStart.calendarStart.year, userInput.dateStart.calendarStart.month, userInput.dateStart.calendarStart.day)) return new KnoraDate(userInput.dateStart.calendarName.toUpperCase(), 'CE', userInput.dateStart.calendarStart.year, userInput.dateStart.calendarStart.month, userInput.dateStart.calendarStart.day); } else { return null; @@ -142,6 +146,11 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal // period if (userInput.dateStart !== null && userInput.dateEnd !== null) { + // check that start and end date have the same calendar + if (userInput.dateStart.calendarName !== userInput.dateEnd.calendarName) { + return null; + } + // check if start is before end const startAsJdnPeriod = (userInput.dateStart as JDNConvertibleCalendar).toJDNPeriod(); const endAsJdnPeriod = (userInput.dateEnd as JDNConvertibleCalendar).toJDNPeriod(); @@ -154,7 +163,6 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal const start = new KnoraDate(userInput.dateStart.calendarName.toUpperCase(), 'CE', userInput.dateStart.calendarStart.year, userInput.dateStart.calendarStart.month, userInput.dateStart.calendarStart.day); const end = new KnoraDate(userInput.dateEnd.calendarName.toUpperCase(), 'CE', userInput.dateEnd.calendarStart.year, userInput.dateEnd.calendarStart.month, userInput.dateEnd.calendarStart.day); - console.log('getting ', new KnoraPeriod(start, end)); return new KnoraPeriod(start, end); } else { return null; @@ -163,7 +171,6 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal } set value(date: KnoraDate | KnoraPeriod | null) { - console.log('setting: ', date) if (date !== null) { if (date instanceof KnoraDate) { // single date From 9aed5b673237b0e75905a826bc297e41247023bb Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Fri, 3 Apr 2020 09:11:19 +0200 Subject: [PATCH 39/60] tests (value): add test for date value comp. --- .../date-value/date-value.component.spec.ts | 41 +++++++++++++++++++ .../values/date-value/date-value.component.ts | 6 --- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts index 693b20e2a..226580f7a 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts @@ -356,6 +356,47 @@ describe('DateValueComponent', () => { }); + it('should correctly populate an UpdateValue from a KnoraDate', () => { + + const date = new KnoraDate('GREGORIAN', 'CE', 2018, 5, 13); + + const updateVal = new UpdateDateValue(); + + testHostComponent.inputValueComponent.populateValue(updateVal, date); + + expect(updateVal.calendar).toEqual('GREGORIAN'); + expect(updateVal.startEra).toEqual('CE'); + expect(updateVal.startDay).toEqual(13); + expect(updateVal.startMonth).toEqual(5); + expect(updateVal.startYear).toEqual(2018); + expect(updateVal.endEra).toEqual('CE'); + expect(updateVal.endDay).toEqual(13); + expect(updateVal.endMonth).toEqual(5); + expect(updateVal.endYear).toEqual(2018); + + }); + + it('should correctly populate an UpdateValue from a KnoraPeriod', () => { + + const dateStart = new KnoraDate('GREGORIAN', 'CE', 2018, 5, 13); + const dateEnd = new KnoraDate('GREGORIAN', 'CE', 2019, 6, 14); + + const updateVal = new UpdateDateValue(); + + testHostComponent.inputValueComponent.populateValue(updateVal, new KnoraPeriod(dateStart, dateEnd)); + + expect(updateVal.calendar).toEqual('GREGORIAN'); + expect(updateVal.startEra).toEqual('CE'); + expect(updateVal.startDay).toEqual(13); + expect(updateVal.startMonth).toEqual(5); + expect(updateVal.startYear).toEqual(2018); + expect(updateVal.endEra).toEqual('CE'); + expect(updateVal.endDay).toEqual(14); + expect(updateVal.endMonth).toEqual(6); + expect(updateVal.endYear).toEqual(2019); + + }); + }); describe('create an interval value', () => { diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts index ab80be5ae..f66e75ce1 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.ts @@ -134,8 +134,6 @@ export class DateValueComponent extends BaseValueComponent implements OnInit, On value.startMonth = dateOrPeriod.month; value.startYear = dateOrPeriod.year; - // TODO: handle precision correctly - value.endEra = value.startEra; value.endDay = value.startDay; value.endMonth = value.startMonth; @@ -145,15 +143,11 @@ export class DateValueComponent extends BaseValueComponent implements OnInit, On value.calendar = dateOrPeriod.start.calendar; - // TODO: handle precision correctly - value.startEra = dateOrPeriod.start.era; value.startDay = dateOrPeriod.start.day; value.startMonth = dateOrPeriod.start.month; value.startYear = dateOrPeriod.start.year; - // TODO: handle precision correctly - value.endEra = dateOrPeriod.end.era; value.endDay = dateOrPeriod.end.day; value.endMonth = dateOrPeriod.end.month; From 3eb99cbcf6bbca9e739513086831e1867923667c Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Fri, 3 Apr 2020 09:21:29 +0200 Subject: [PATCH 40/60] tests (value): add test for date input comp. --- .../date-input/date-input.component.spec.ts | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts index d28c71a5f..72f302e25 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts @@ -11,6 +11,10 @@ import {MatInputModule} from '@angular/material/input'; import {MatDatepickerModule} from '@angular/material/datepicker'; import {MatJDNConvertibleCalendarDateAdapterModule} from 'jdnconvertiblecalendardateadapter'; import {MatCheckboxModule} from '@angular/material/checkbox'; +import {JDNConvertibleCalendarModule} from "jdnconvertiblecalendar/dist/src/JDNConvertibleCalendar"; +import JulianCalendarDate = JDNConvertibleCalendarModule.JulianCalendarDate; +import {CalendarDate} from "jdnconvertiblecalendar"; +import CalendarPeriod = JDNConvertibleCalendarModule.CalendarPeriod; /** * Test host component to simulate parent component. @@ -67,10 +71,21 @@ describe('DateInputComponent', () => { testHostFixture = TestBed.createComponent(TestHostComponent); testHostComponent = testHostFixture.componentInstance; testHostFixture.detectChanges(); - }); - it('should create', () => { expect(testHostComponent).toBeTruthy(); - // console.log(testHostComponent.dateInputComponent); + }); + + it('should initialize the date correctly', () => { + + expect(testHostComponent.dateInputComponent.value instanceof KnoraDate).toBe(true); + expect(testHostComponent.dateInputComponent.value) + .toEqual(new KnoraDate('JULIAN', 'CE', 2018, 5, 19)); + + expect(testHostComponent.dateInputComponent.startDateControl.value) + .toEqual(new JulianCalendarDate(new CalendarPeriod(new CalendarDate(2018, 5, 19), new CalendarDate(2018, 5, 19)))); + + expect(testHostComponent.dateInputComponent.isPeriodControl.value).toBe(false); + + expect(testHostComponent.dateInputComponent.endDateControl.value).toBe(null); }); }); From f32f59ccb0029e4e53b5870cbb65bcd0669cfc1e Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Fri, 3 Apr 2020 09:27:14 +0200 Subject: [PATCH 41/60] tests (value): add test for date input comp. --- .../date-input/date-input.component.spec.ts | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts index 72f302e25..4366bc6a2 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts @@ -3,7 +3,7 @@ import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {DateInputComponent} from './date-input.component'; import {Component, OnInit, ViewChild} from '@angular/core'; import {FormBuilder, FormGroup, ReactiveFormsModule} from '@angular/forms'; -import {KnoraDate} from '@knora/api'; +import {KnoraDate, KnoraPeriod} from '@knora/api'; import {JDNDatepickerDirective} from '../../jdn-datepicker-directive/jdndatepicker.directive'; import {MatFormFieldModule} from '@angular/material/form-field'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; @@ -75,7 +75,7 @@ describe('DateInputComponent', () => { expect(testHostComponent).toBeTruthy(); }); - it('should initialize the date correctly', () => { + it('should initialize a date correctly', () => { expect(testHostComponent.dateInputComponent.value instanceof KnoraDate).toBe(true); expect(testHostComponent.dateInputComponent.value) @@ -88,4 +88,20 @@ describe('DateInputComponent', () => { expect(testHostComponent.dateInputComponent.endDateControl.value).toBe(null); }); + + it('should initialize a period correctly', () => { + + testHostComponent.form.controls.date.setValue(new KnoraPeriod(new KnoraDate('JULIAN', 'CE', 2018, 5, 19), new KnoraDate('JULIAN', 'CE', 2019, 5, 19))); + + expect(testHostComponent.dateInputComponent.value instanceof KnoraPeriod).toBe(true); + expect(testHostComponent.dateInputComponent.value) + .toEqual(new KnoraPeriod(new KnoraDate('JULIAN', 'CE', 2018, 5, 19), new KnoraDate('JULIAN', 'CE', 2019, 5, 19))); + + expect(testHostComponent.dateInputComponent.startDateControl.value) + .toEqual(new JulianCalendarDate(new CalendarPeriod(new CalendarDate(2018, 5, 19), new CalendarDate(2018, 5, 19)))); + + expect(testHostComponent.dateInputComponent.isPeriodControl.value).toBe(true); + + expect(testHostComponent.dateInputComponent.endDateControl.value).toEqual(new JulianCalendarDate(new CalendarPeriod(new CalendarDate(2019, 5, 19), new CalendarDate(2019, 5, 19)))); + }) }); From 8a0e0215bdb6f3c5800a3c30bc4b29de90bc2678 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Fri, 3 Apr 2020 09:42:03 +0200 Subject: [PATCH 42/60] tests (value): add test for date input comp. --- .../date-input/date-input.component.spec.ts | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts index 4366bc6a2..5fdbca2da 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts @@ -102,6 +102,30 @@ describe('DateInputComponent', () => { expect(testHostComponent.dateInputComponent.isPeriodControl.value).toBe(true); - expect(testHostComponent.dateInputComponent.endDateControl.value).toEqual(new JulianCalendarDate(new CalendarPeriod(new CalendarDate(2019, 5, 19), new CalendarDate(2019, 5, 19)))); - }) + expect(testHostComponent.dateInputComponent.endDateControl.value) + .toEqual(new JulianCalendarDate(new CalendarPeriod(new CalendarDate(2019, 5, 19), new CalendarDate(2019, 5, 19)))); + }); + + it('should propagate changes made by the user for a single date', () => { + + testHostComponent.dateInputComponent.form.controls.dateStart.setValue(new JulianCalendarDate(new CalendarPeriod(new CalendarDate(2019, 5, 19), new CalendarDate(2019, 5, 19)))); + + testHostComponent.dateInputComponent._handleInput(); + + expect(testHostComponent.form.controls.date.value).toEqual(new KnoraDate('JULIAN', 'CE', 2019, 5, 19)); + }); + + it('should propagate changes made by the user for a period', () => { + + testHostComponent.dateInputComponent.form.controls.dateStart.setValue(new JulianCalendarDate(new CalendarPeriod(new CalendarDate(2019, 5, 19), new CalendarDate(2019, 5, 19)))); + + testHostComponent.dateInputComponent.form.controls.isPeriod.setValue(true); + + testHostComponent.dateInputComponent.form.controls.dateEnd.setValue(new JulianCalendarDate(new CalendarPeriod(new CalendarDate(2020, 5, 19), new CalendarDate(2020, 5, 19)))); + + testHostComponent.dateInputComponent._handleInput(); + + expect(testHostComponent.form.controls.date.value).toEqual(new KnoraPeriod(new KnoraDate('JULIAN', 'CE', 2019, 5, 19), new KnoraDate('JULIAN', 'CE', 2020, 5, 19))); + }); + }); From 2df7562fe1984d6badde52cc5db3a8e6d11ded32 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Fri, 3 Apr 2020 09:53:59 +0200 Subject: [PATCH 43/60] tests (value): add test for date input comp. --- .../date-input/date-input.component.spec.ts | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts index 5fdbca2da..6a3abed02 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts @@ -11,10 +11,7 @@ import {MatInputModule} from '@angular/material/input'; import {MatDatepickerModule} from '@angular/material/datepicker'; import {MatJDNConvertibleCalendarDateAdapterModule} from 'jdnconvertiblecalendardateadapter'; import {MatCheckboxModule} from '@angular/material/checkbox'; -import {JDNConvertibleCalendarModule} from "jdnconvertiblecalendar/dist/src/JDNConvertibleCalendar"; -import JulianCalendarDate = JDNConvertibleCalendarModule.JulianCalendarDate; -import {CalendarDate} from "jdnconvertiblecalendar"; -import CalendarPeriod = JDNConvertibleCalendarModule.CalendarPeriod; +import {CalendarDate, GregorianCalendarDate, CalendarPeriod, JulianCalendarDate} from 'jdnconvertiblecalendar'; /** * Test host component to simulate parent component. @@ -128,4 +125,40 @@ describe('DateInputComponent', () => { expect(testHostComponent.form.controls.date.value).toEqual(new KnoraPeriod(new KnoraDate('JULIAN', 'CE', 2019, 5, 19), new KnoraDate('JULIAN', 'CE', 2020, 5, 19))); }); + it('should return "null" for an invalid user input (start date greater than end date)', () => { + + testHostComponent.dateInputComponent.form.controls.dateStart.setValue(new JulianCalendarDate(new CalendarPeriod(new CalendarDate(2021, 5, 19), new CalendarDate(2021, 5, 19)))); + + testHostComponent.dateInputComponent.form.controls.isPeriod.setValue(true); + + testHostComponent.dateInputComponent.form.controls.dateEnd.setValue(new JulianCalendarDate(new CalendarPeriod(new CalendarDate(2020, 5, 19), new CalendarDate(2020, 5, 19)))); + + expect(testHostComponent.dateInputComponent.value).toEqual(null); + + }); + + it('should return "null" for an invalid user input (start date and end date have different calendars)', () => { + + testHostComponent.dateInputComponent.form.controls.dateStart.setValue(new JulianCalendarDate(new CalendarPeriod(new CalendarDate(2021, 5, 19), new CalendarDate(2021, 5, 19)))); + + testHostComponent.dateInputComponent.form.controls.isPeriod.setValue(true); + + testHostComponent.dateInputComponent.form.controls.dateEnd.setValue(new GregorianCalendarDate(new CalendarPeriod(new CalendarDate(2022, 5, 19), new CalendarDate(2022, 5, 19)))); + + expect(testHostComponent.dateInputComponent.value).toEqual(null); + + }); + + it('should return "null" for an invalid user input (start date is "null")', () => { + + testHostComponent.dateInputComponent.form.controls.dateStart.setValue(null); + + testHostComponent.dateInputComponent.form.controls.isPeriod.setValue(true); + + testHostComponent.dateInputComponent.form.controls.dateEnd.setValue(new JulianCalendarDate(new CalendarPeriod(new CalendarDate(2020, 5, 19), new CalendarDate(2020, 5, 19)))); + + expect(testHostComponent.dateInputComponent.value).toEqual(null); + + }); + }); From a777effb142f79bdaf84ad2cefd89043d262017a Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Fri, 3 Apr 2020 09:57:51 +0200 Subject: [PATCH 44/60] tests (value): add test for date input comp. --- .../date-value/date-input/date-input.component.spec.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts index 6a3abed02..39a107018 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts @@ -161,4 +161,14 @@ describe('DateInputComponent', () => { }); + it('should initialize the date with an empty value', () => { + + testHostComponent.form.controls.date.setValue(null); + + expect(testHostComponent.dateInputComponent.form.controls.dateStart.value).toBe(null); + expect(testHostComponent.dateInputComponent.form.controls.isPeriod.value).toBe(false); + expect(testHostComponent.dateInputComponent.form.controls.dateEnd.value).toBe(null); + + }); + }); From 3bff9e7dc4e3d2b2b4b6325c55c09a2cadde679c Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Fri, 3 Apr 2020 10:13:11 +0200 Subject: [PATCH 45/60] tests (value): add test for date input comp. --- .../date-input/date-input.component.html | 4 +- .../date-input/date-input.component.spec.ts | 44 +++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html index 49ab254de..e9b4912cb 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html @@ -1,5 +1,5 @@
- + @@ -7,7 +7,7 @@ - + diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts index 39a107018..32d3f8948 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts @@ -12,6 +12,7 @@ import {MatDatepickerModule} from '@angular/material/datepicker'; import {MatJDNConvertibleCalendarDateAdapterModule} from 'jdnconvertiblecalendardateadapter'; import {MatCheckboxModule} from '@angular/material/checkbox'; import {CalendarDate, GregorianCalendarDate, CalendarPeriod, JulianCalendarDate} from 'jdnconvertiblecalendar'; +import {By} from '@angular/platform-browser'; /** * Test host component to simulate parent component. @@ -171,4 +172,47 @@ describe('DateInputComponent', () => { }); + it('should show the toggle when not in readonly mode', () => { + + expect(testHostComponent.dateInputComponent.readonly).toBe(false); + + testHostComponent.dateInputComponent.form.controls.isPeriod.setValue(true); + + testHostFixture.detectChanges(); + + const hostCompDe = testHostFixture.debugElement; + const dateInputComponentDe = hostCompDe.query(By.directive(DateInputComponent)); + + const startDateToggle = dateInputComponentDe.query(By.css('.start mat-datepicker-toggle')); + + expect(startDateToggle).not.toBe(null); + + const endDateToggle = dateInputComponentDe.query(By.css('.end mat-datepicker-toggle')); + + expect(endDateToggle).not.toBe(null); + }); + + it('should not show the toggle when in readonly mode', () => { + + testHostComponent.readonly = true; + + testHostComponent.dateInputComponent.form.controls.isPeriod.setValue(true); + + testHostFixture.detectChanges(); + + expect(testHostComponent.dateInputComponent.readonly).toBe(true); + + const hostCompDe = testHostFixture.debugElement; + const dateInputComponentDe = hostCompDe.query(By.directive(DateInputComponent)); + + const startDateToggle = dateInputComponentDe.query(By.css('.start mat-datepicker-toggle')); + + expect(startDateToggle).toBe(null); + + const endDateToggle = dateInputComponentDe.query(By.css('.end mat-datepicker-toggle')); + + expect(endDateToggle).toBe(null); + + }); + }); From d6ed773ead4df40c74924b239061bac3b728e9af Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Fri, 3 Apr 2020 10:34:27 +0200 Subject: [PATCH 46/60] tests (value): add test for date input comp. --- .../date-input/date-input.component.html | 2 ++ .../date-input/date-input.component.spec.ts | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html index e9b4912cb..977364a25 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html @@ -1,5 +1,6 @@
+ {{startDateControl.value?.calendarName}} @@ -8,6 +9,7 @@ + {{endDateControl.value?.calendarName}} diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts index 32d3f8948..00661c620 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts @@ -215,4 +215,30 @@ describe('DateInputComponent', () => { }); + it('should not show the calendar when not in readonly mode', () => { + + const hostCompDe = testHostFixture.debugElement; + const dateInputComponentDe = hostCompDe.query(By.directive(DateInputComponent)); + + const startDateCalendar = dateInputComponentDe.query(By.css('.start span.calendar')); + + expect(startDateCalendar).toBe(null); + + }); + + it('should show the calendar when in readonly mode', () => { + + testHostComponent.readonly = true; + + testHostFixture.detectChanges(); + + const hostCompDe = testHostFixture.debugElement; + const dateInputComponentDe = hostCompDe.query(By.directive(DateInputComponent)); + + const startDateCalendar = dateInputComponentDe.query(By.css('.start span.calendar')); + + expect(startDateCalendar.nativeElement.innerText).toEqual('Julian'); + + }); + }); From 853c432108d065dd68ec2ccf413711a80f2662cb Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Fri, 3 Apr 2020 10:43:53 +0200 Subject: [PATCH 47/60] tests (value): adapt test for date input comp. --- .../date-input/date-input.component.html | 4 ++-- .../date-input/date-input.component.spec.ts | 19 ++----------------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html index 977364a25..2fd378067 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html @@ -1,6 +1,6 @@
- {{startDateControl.value?.calendarName}} + {{startDateControl.value?.calendarName}} @@ -9,7 +9,7 @@ - {{endDateControl.value?.calendarName}} + {{endDateControl.value?.calendarName}} diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts index 00661c620..cdfc8e0ea 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts @@ -215,29 +215,14 @@ describe('DateInputComponent', () => { }); - it('should not show the calendar when not in readonly mode', () => { + it('should show the calendar of a date', () => { const hostCompDe = testHostFixture.debugElement; const dateInputComponentDe = hostCompDe.query(By.directive(DateInputComponent)); const startDateCalendar = dateInputComponentDe.query(By.css('.start span.calendar')); - expect(startDateCalendar).toBe(null); - - }); - - it('should show the calendar when in readonly mode', () => { - - testHostComponent.readonly = true; - - testHostFixture.detectChanges(); - - const hostCompDe = testHostFixture.debugElement; - const dateInputComponentDe = hostCompDe.query(By.directive(DateInputComponent)); - - const startDateCalendar = dateInputComponentDe.query(By.css('.start span.calendar')); - - expect(startDateCalendar.nativeElement.innerText).toEqual('Julian'); + expect(startDateCalendar).not.toBe(null); }); From c4064584dbe886649b6f67f17044b3e1bb01a107 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Fri, 3 Apr 2020 11:13:39 +0200 Subject: [PATCH 48/60] fix (value): make input readonly in date input --- .../values/date-value/date-input/date-input.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html index 2fd378067..92a975bbe 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html @@ -2,7 +2,7 @@ {{startDateControl.value?.calendarName}} - + @@ -11,7 +11,7 @@ {{endDateControl.value?.calendarName}} - + From 87462a5e896eba60b427a1a0f8af4e000a8f8d67 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Mon, 6 Apr 2020 17:02:52 +0200 Subject: [PATCH 49/60] fix (value): remove obsolete file --- .../jdn-datepicker-directive/jdndatepicker.directive.spec.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 projects/knora-ui/src/lib/viewer/values/time-value/jdn-datepicker-directive/jdndatepicker.directive.spec.ts diff --git a/projects/knora-ui/src/lib/viewer/values/time-value/jdn-datepicker-directive/jdndatepicker.directive.spec.ts b/projects/knora-ui/src/lib/viewer/values/time-value/jdn-datepicker-directive/jdndatepicker.directive.spec.ts deleted file mode 100644 index e69de29bb..000000000 From def47c95b2cdd1b338e988292b6ed1e12323273d Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Mon, 6 Apr 2020 17:26:12 +0200 Subject: [PATCH 50/60] feature (value): adapt date to common value comp. structure --- .../display-edit/display-edit.component.ts | 5 ++--- .../date-input/date-input.component.html | 4 ++-- .../date-input/date-input.component.scss | 14 ++++++++++++++ .../values/date-value/date-value.component.html | 17 ++++++++++++++--- .../values/date-value/date-value.component.scss | 11 +++++++++++ 5 files changed, 43 insertions(+), 8 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/operations/display-edit/display-edit.component.ts b/projects/knora-ui/src/lib/viewer/operations/display-edit/display-edit.component.ts index a0d756f97..aca670226 100644 --- a/projects/knora-ui/src/lib/viewer/operations/display-edit/display-edit.component.ts +++ b/projects/knora-ui/src/lib/viewer/operations/display-edit/display-edit.component.ts @@ -40,7 +40,7 @@ export class DisplayEditComponent implements OnInit { editModeActive = false; shouldShowCommentToggle: boolean; - + // type of given displayValue // or knora-api-js-lib class representing the value valueTypeOrClass: string; @@ -135,7 +135,7 @@ export class DisplayEditComponent implements OnInit { checkCommentToggleVisibility() { this.shouldShowCommentToggle = (this.mode === 'read' && this.displayValue.valueHasComment !== '' && this.displayValue.valueHasComment !== undefined); } - + /** * Given a value, determines the type or class representing it. * @@ -174,7 +174,6 @@ export class DisplayEditComponent implements OnInit { isReadOnly(valueTypeOrClass: string): boolean { return valueTypeOrClass === this.readTextValueAsHtml || valueTypeOrClass === this.readTextValueAsXml || - valueTypeOrClass === this.constants.DateValue || valueTypeOrClass === this.constants.GeomValue || valueTypeOrClass === this.constants.GeonameValue; } diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html index 92a975bbe..d9d9755e5 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html @@ -1,5 +1,5 @@
- + {{startDateControl.value?.calendarName}} @@ -8,7 +8,7 @@ - + {{endDateControl.value?.calendarName}} diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.scss b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.scss index e69de29bb..671f9859c 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.scss +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.scss @@ -0,0 +1,14 @@ +/** + * CSS changed here must also be changed in each child component of a wrapped component + * time-input.component.scss, interval-input.component.scss, etc. + */ + +.child-input-component { + display: inline-block; + vertical-align: bottom; + width: 49%; +} + +.child-input-component:nth-child(2) { + padding-left: 2%; +} diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html index 3abce152d..7c376b12e 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html @@ -1,9 +1,20 @@ - +
- - + +
diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.scss b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.scss index e69de29bb..36fb61ae9 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.scss +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.scss @@ -0,0 +1,11 @@ +:host ::ng-deep .child-value-component { + .mat-form-field-underline { + display: none; + } + .mat-form-field-infix{ + border-top: 0.2em solid transparent !important; + .mat-form-field-underline{ + display: block; + } + } +} From 333b776deec975db0b2ef34ff62c891d747a5160 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Mon, 6 Apr 2020 17:31:27 +0200 Subject: [PATCH 51/60] tests (value): adapt tests for date comp. comment --- .../date-value/date-value.component.spec.ts | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts index 226580f7a..988590142 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.spec.ts @@ -145,8 +145,8 @@ describe('DateValueComponent', () => { let testHostFixture: ComponentFixture; let valueComponentDe: DebugElement; - let commentInputDebugElement: DebugElement; - let commentInputNativeElement; + let commentTextareaDebugElement: DebugElement; + let commentTextareaNativeElement; beforeEach(() => { testHostFixture = TestBed.createComponent(TestHostDisplayValueComponent); @@ -159,8 +159,7 @@ describe('DateValueComponent', () => { const hostCompDe = testHostFixture.debugElement; valueComponentDe = hostCompDe.query(By.directive(DateValueComponent)); - commentInputDebugElement = valueComponentDe.query(By.css('input.comment')); - commentInputNativeElement = commentInputDebugElement.nativeElement; + }); it('should display an existing value', () => { @@ -223,6 +222,9 @@ describe('DateValueComponent', () => { testHostFixture.detectChanges(); + commentTextareaDebugElement = valueComponentDe.query(By.css('textarea.comment')); + commentTextareaNativeElement = commentTextareaDebugElement.nativeElement; + expect(testHostComponent.inputValueComponent.mode).toEqual('update'); expect(testHostComponent.inputValueComponent.displayValue.date).toEqual(new KnoraDate('GREGORIAN', 'CE', 2018, 5, 13)); @@ -231,9 +233,9 @@ describe('DateValueComponent', () => { expect(testHostComponent.inputValueComponent.form.valid).toBeFalsy(); - commentInputNativeElement.value = 'this is a comment'; + commentTextareaNativeElement.value = 'this is a comment'; - commentInputNativeElement.dispatchEvent(new Event('input')); + commentTextareaNativeElement.dispatchEvent(new Event('input')); testHostFixture.detectChanges(); @@ -405,8 +407,8 @@ describe('DateValueComponent', () => { let testHostFixture: ComponentFixture; let valueComponentDe: DebugElement; - let commentInputDebugElement: DebugElement; - let commentInputNativeElement; + let commentTextareaDebugElement: DebugElement; + let commentTextareaNativeElement; beforeEach(() => { testHostFixture = TestBed.createComponent(TestHostCreateValueComponent); @@ -419,8 +421,8 @@ describe('DateValueComponent', () => { const hostCompDe = testHostFixture.debugElement; valueComponentDe = hostCompDe.query(By.directive(DateValueComponent)); - commentInputDebugElement = valueComponentDe.query(By.css('input.comment')); - commentInputNativeElement = commentInputDebugElement.nativeElement; + commentTextareaDebugElement = valueComponentDe.query(By.css('textarea.comment')); + commentTextareaNativeElement = commentTextareaDebugElement.nativeElement; }); it('should create a value', () => { @@ -464,9 +466,9 @@ describe('DateValueComponent', () => { testHostFixture.detectChanges(); - commentInputNativeElement.value = 'created comment'; + commentTextareaNativeElement.value = 'created comment'; - commentInputNativeElement.dispatchEvent(new Event('input')); + commentTextareaNativeElement.dispatchEvent(new Event('input')); testHostFixture.detectChanges(); @@ -480,7 +482,7 @@ describe('DateValueComponent', () => { expect(testHostComponent.inputValueComponent.dateInputComponent.value).toEqual(null); - expect(commentInputNativeElement.value).toEqual(''); + expect(commentTextareaNativeElement.value).toEqual(''); }); From dabcc2e6943a97de02e383092007ef782dec5d8b Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Tue, 7 Apr 2020 09:17:36 +0200 Subject: [PATCH 52/60] refactor (value): define validator for date input to check for same calendar in a period --- .../date-input/date-input.component.html | 8 ++++++- .../date-input/date-input.component.spec.ts | 2 ++ .../date-input/date-input.component.ts | 24 ++++++++++++++----- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html index d9d9755e5..6735372e9 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html @@ -2,7 +2,13 @@ {{startDateControl.value?.calendarName}} - + + + Start date is required + + + In a period, start and end date must have the same calendar + diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts index cdfc8e0ea..b6fab3b32 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts @@ -146,6 +146,8 @@ describe('DateInputComponent', () => { testHostComponent.dateInputComponent.form.controls.dateEnd.setValue(new GregorianCalendarDate(new CalendarPeriod(new CalendarDate(2022, 5, 19), new CalendarDate(2022, 5, 19)))); + testHostComponent.dateInputComponent._handleInput(); + expect(testHostComponent.dateInputComponent.value).toEqual(null); }); diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts index db9bda70d..fb0373a96 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts @@ -1,5 +1,6 @@ import {Component, DoCheck, ElementRef, HostBinding, Input, OnDestroy, Optional, Self} from '@angular/core'; import { + AbstractControl, ControlValueAccessor, FormBuilder, FormControl, @@ -7,6 +8,7 @@ import { FormGroupDirective, NgControl, NgForm, + ValidatorFn, Validators } from '@angular/forms'; import {MatFormFieldControl} from '@angular/material/form-field'; @@ -32,6 +34,19 @@ export class DateInputErrorStateMatcher implements ErrorStateMatcher { } } +/** If a period is defined, start and end date must have the same calendar */ +export function sameCalendarValidator(isPeriod: FormControl, endDate: FormControl): ValidatorFn { + return (control: AbstractControl): { [key: string]: any } | null => { + + if (isPeriod.value) { + const invalid = control.value === null || endDate.value === null || control.value.calendarName !== endDate.value.calendarName; + return invalid ? {'sameCalendarRequired': {value: control.value}} : null; + } + + return null; + }; +} + class MatInputBase { constructor(public _defaultErrorStateMatcher: ErrorStateMatcher, public _parentForm: NgForm, @@ -146,11 +161,6 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal // period if (userInput.dateStart !== null && userInput.dateEnd !== null) { - // check that start and end date have the same calendar - if (userInput.dateStart.calendarName !== userInput.dateEnd.calendarName) { - return null; - } - // check if start is before end const startAsJdnPeriod = (userInput.dateStart as JDNConvertibleCalendar).toJDNPeriod(); const endAsJdnPeriod = (userInput.dateEnd as JDNConvertibleCalendar).toJDNPeriod(); @@ -230,9 +240,9 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal super(_defaultErrorStateMatcher, _parentForm, _parentFormGroup, ngControl); - this.startDateControl = new FormControl(null, Validators.required); this.endDateControl = new FormControl(null); this.isPeriodControl = new FormControl(null); + this.startDateControl = new FormControl(null, [Validators.required, sameCalendarValidator(this.isPeriodControl, this.endDateControl)]); this.form = fb.group({ dateStart: this.startDateControl, @@ -284,6 +294,8 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal } _handleInput(): void { + // trigger evaluation of validators defined for start date + this.startDateControl.updateValueAndValidity(); this.onChange(this.value); } From 7f20d79471a58af7f947af0b6f5ece520693c6a8 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Tue, 7 Apr 2020 09:42:12 +0200 Subject: [PATCH 53/60] refactor (value): define validator for date input to check for start before end in a period --- .../date-input/date-input.component.html | 3 ++ .../date-input/date-input.component.spec.ts | 2 + .../date-input/date-input.component.ts | 52 +++++++++++++++---- 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html index 6735372e9..133765630 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.html @@ -9,6 +9,9 @@ In a period, start and end date must have the same calendar + + In a period, start must be before end +
diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts index b6fab3b32..46b59d5c0 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts @@ -134,6 +134,8 @@ describe('DateInputComponent', () => { testHostComponent.dateInputComponent.form.controls.dateEnd.setValue(new JulianCalendarDate(new CalendarPeriod(new CalendarDate(2020, 5, 19), new CalendarDate(2020, 5, 19)))); + testHostComponent.dateInputComponent._handleInput(); + expect(testHostComponent.dateInputComponent.value).toEqual(null); }); diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts index fb0373a96..6ec1416e3 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.ts @@ -39,7 +39,12 @@ export function sameCalendarValidator(isPeriod: FormControl, endDate: FormContro return (control: AbstractControl): { [key: string]: any } | null => { if (isPeriod.value) { - const invalid = control.value === null || endDate.value === null || control.value.calendarName !== endDate.value.calendarName; + + let invalid = true; + if (control.value instanceof JDNConvertibleCalendar && endDate.value instanceof JDNConvertibleCalendar) { + invalid = control.value.calendarName !== endDate.value.calendarName; + } + return invalid ? {'sameCalendarRequired': {value: control.value}} : null; } @@ -47,6 +52,30 @@ export function sameCalendarValidator(isPeriod: FormControl, endDate: FormContro }; } +/** If a period is defined, start date must be before end date */ +export function periodStartEndValidator(isPeriod: FormControl, endDate: FormControl): ValidatorFn { + return (control: AbstractControl): { [key: string]: any } | null => { + + if (isPeriod.value) { + let invalid = true; + + if (control.value instanceof JDNConvertibleCalendar && endDate.value instanceof JDNConvertibleCalendar) { + + // check if start is before end + const startAsJdnPeriod = (control.value as JDNConvertibleCalendar).toJDNPeriod(); + const endAsJdnPeriod = (endDate.value as JDNConvertibleCalendar).toJDNPeriod(); + + // check for start after end + invalid = startAsJdnPeriod.periodStart >= endAsJdnPeriod.periodStart; + } + + return invalid ? {'periodStartEnd': {value: control.value}} : null; + } + + return null; + }; +} + class MatInputBase { constructor(public _defaultErrorStateMatcher: ErrorStateMatcher, public _parentForm: NgForm, @@ -161,15 +190,6 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal // period if (userInput.dateStart !== null && userInput.dateEnd !== null) { - // check if start is before end - const startAsJdnPeriod = (userInput.dateStart as JDNConvertibleCalendar).toJDNPeriod(); - const endAsJdnPeriod = (userInput.dateEnd as JDNConvertibleCalendar).toJDNPeriod(); - - if (startAsJdnPeriod.periodStart >= endAsJdnPeriod.periodStart) { - // start after end - return null; - } - const start = new KnoraDate(userInput.dateStart.calendarName.toUpperCase(), 'CE', userInput.dateStart.calendarStart.year, userInput.dateStart.calendarStart.month, userInput.dateStart.calendarStart.day); const end = new KnoraDate(userInput.dateEnd.calendarName.toUpperCase(), 'CE', userInput.dateEnd.calendarStart.year, userInput.dateEnd.calendarStart.month, userInput.dateEnd.calendarStart.day); @@ -191,6 +211,8 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal isPeriod: false }); + this.startDateControl.updateValueAndValidity(); + } else { // period const period = date as KnoraPeriod; @@ -201,9 +223,13 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal isPeriod: true }); + this.startDateControl.updateValueAndValidity(); + } } else { this.form.setValue({dateStart: null, dateEnd: null, isPeriod: false}); + + this.startDateControl.updateValueAndValidity(); } this.stateChanges.next(); } @@ -242,7 +268,11 @@ export class DateInputComponent extends _MatInputMixinBase implements ControlVal this.endDateControl = new FormControl(null); this.isPeriodControl = new FormControl(null); - this.startDateControl = new FormControl(null, [Validators.required, sameCalendarValidator(this.isPeriodControl, this.endDateControl)]); + this.startDateControl + = new FormControl( + null, + [Validators.required, sameCalendarValidator(this.isPeriodControl, this.endDateControl), periodStartEndValidator(this.isPeriodControl, this.endDateControl)] + ); this.form = fb.group({ dateStart: this.startDateControl, From 0bee998ec0ee602d253ebc6119ad8daf72b0eb33 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Tue, 7 Apr 2020 09:51:04 +0200 Subject: [PATCH 54/60] tests (value): adapt assertions for date input comp. comment --- .../date-input/date-input.component.spec.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts index 46b59d5c0..50268ed0a 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-input/date-input.component.spec.ts @@ -85,6 +85,9 @@ describe('DateInputComponent', () => { expect(testHostComponent.dateInputComponent.isPeriodControl.value).toBe(false); expect(testHostComponent.dateInputComponent.endDateControl.value).toBe(null); + + expect(testHostComponent.dateInputComponent.form.valid).toBe(true); + }); it('should initialize a period correctly', () => { @@ -102,6 +105,9 @@ describe('DateInputComponent', () => { expect(testHostComponent.dateInputComponent.endDateControl.value) .toEqual(new JulianCalendarDate(new CalendarPeriod(new CalendarDate(2019, 5, 19), new CalendarDate(2019, 5, 19)))); + + expect(testHostComponent.dateInputComponent.form.valid).toBe(true); + }); it('should propagate changes made by the user for a single date', () => { @@ -110,6 +116,8 @@ describe('DateInputComponent', () => { testHostComponent.dateInputComponent._handleInput(); + expect(testHostComponent.dateInputComponent.form.valid).toBe(true); + expect(testHostComponent.form.controls.date.value).toEqual(new KnoraDate('JULIAN', 'CE', 2019, 5, 19)); }); @@ -123,6 +131,8 @@ describe('DateInputComponent', () => { testHostComponent.dateInputComponent._handleInput(); + expect(testHostComponent.dateInputComponent.form.valid).toBe(true); + expect(testHostComponent.form.controls.date.value).toEqual(new KnoraPeriod(new KnoraDate('JULIAN', 'CE', 2019, 5, 19), new KnoraDate('JULIAN', 'CE', 2020, 5, 19))); }); @@ -136,6 +146,8 @@ describe('DateInputComponent', () => { testHostComponent.dateInputComponent._handleInput(); + expect(testHostComponent.dateInputComponent.form.valid).toBe(false); + expect(testHostComponent.dateInputComponent.value).toEqual(null); }); @@ -150,6 +162,8 @@ describe('DateInputComponent', () => { testHostComponent.dateInputComponent._handleInput(); + expect(testHostComponent.dateInputComponent.form.valid).toBe(false); + expect(testHostComponent.dateInputComponent.value).toEqual(null); }); @@ -162,6 +176,8 @@ describe('DateInputComponent', () => { testHostComponent.dateInputComponent.form.controls.dateEnd.setValue(new JulianCalendarDate(new CalendarPeriod(new CalendarDate(2020, 5, 19), new CalendarDate(2020, 5, 19)))); + expect(testHostComponent.dateInputComponent.form.valid).toBe(false); + expect(testHostComponent.dateInputComponent.value).toEqual(null); }); @@ -174,6 +190,8 @@ describe('DateInputComponent', () => { expect(testHostComponent.dateInputComponent.form.controls.isPeriod.value).toBe(false); expect(testHostComponent.dateInputComponent.form.controls.dateEnd.value).toBe(null); + expect(testHostComponent.dateInputComponent.form.valid).toBe(false); + }); it('should show the toggle when not in readonly mode', () => { From 720106f54b75c9af94ee8b55d3379b9862defa44 Mon Sep 17 00:00:00 2001 From: Tobias Schweizer Date: Tue, 7 Apr 2020 09:52:47 +0200 Subject: [PATCH 55/60] fix (value): remove
in date value comp. template --- .../src/lib/viewer/values/date-value/date-value.component.html | 1 - 1 file changed, 1 deletion(-) diff --git a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html index 7c376b12e..0b9484aaa 100644 --- a/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html +++ b/projects/knora-ui/src/lib/viewer/values/date-value/date-value.component.html @@ -2,7 +2,6 @@ -